From 55175938e32fabe64a27e0f2a524749629f2da82 Mon Sep 17 00:00:00 2001 From: Helmut Hummel Date: Mon, 16 Apr 2012 18:13:50 +0200 Subject: [PATCH] Import all phpunit and other necessary files --- README | 2 + dbimport/cli_users.sql | 1 + dbimport/introduction.sql | 2298 ++++++++ typo3conf/ext/phpunit/Changelog | 547 ++ .../ext/phpunit/Classes/BackEnd/Ajax.php | 81 + .../ext/phpunit/Classes/BackEnd/Module.php | 889 +++ .../phpunit/Classes/BackEnd/TestListener.php | 585 ++ .../ext/phpunit/Classes/BackEnd/conf.php | 9 + .../ext/phpunit/Classes/BackEnd/index.php | 48 + .../ext/phpunit/Classes/Cli/TestRunner.php | 82 + .../ext/phpunit/Classes/Database/TestCase.php | 399 ++ .../phpunit/Classes/Exception/Database.php | 51 + .../Classes/Exception/EmptyQueryResult.php | 50 + .../Classes/Exception/NoTestsDirectory.php | 36 + typo3conf/ext/phpunit/Classes/Framework.php | 1911 +++++++ .../Interface/FrameworkCleanupHook.php | 42 + .../ext/phpunit/Classes/Reports/Status.php | 270 + .../ext/phpunit/Classes/Selenium/TestCase.php | 187 + .../ext/phpunit/Classes/Service/Database.php | 745 +++ .../phpunit/Classes/Service/TestFinder.php | 405 ++ typo3conf/ext/phpunit/Classes/TestCase.php | 95 + .../ext/phpunit/Classes/TestableCode.php | 311 ++ .../ext/phpunit/Configuration/TCA/TCA.php | 91 + typo3conf/ext/phpunit/PEAR/Archive/Tar.php | 1909 +++++++ typo3conf/ext/phpunit/PEAR/Cache/Lite.php | 846 +++ .../ext/phpunit/PEAR/Cache/Lite/File.php | 93 + .../ext/phpunit/PEAR/Cache/Lite/Function.php | 211 + .../ext/phpunit/PEAR/Cache/Lite/Output.php | 72 + typo3conf/ext/phpunit/PEAR/Console/Getopt.php | 366 ++ typo3conf/ext/phpunit/PEAR/File/Iterator.php | 197 + .../phpunit/PEAR/File/Iterator/Factory.php | 159 + typo3conf/ext/phpunit/PEAR/OS/Guess.php | 338 ++ typo3conf/ext/phpunit/PEAR/PEAR.php | 1063 ++++ .../ext/phpunit/PEAR/PEAR/Autoloader.php | 218 + typo3conf/ext/phpunit/PEAR/PEAR/Builder.php | 489 ++ .../ext/phpunit/PEAR/PEAR/ChannelFile.php | 1559 ++++++ .../phpunit/PEAR/PEAR/ChannelFile/Parser.php | 68 + typo3conf/ext/phpunit/PEAR/PEAR/Command.php | 414 ++ .../ext/phpunit/PEAR/PEAR/Command/Auth.php | 81 + .../ext/phpunit/PEAR/PEAR/Command/Auth.xml | 30 + .../ext/phpunit/PEAR/PEAR/Command/Build.php | 85 + .../ext/phpunit/PEAR/PEAR/Command/Build.xml | 10 + .../phpunit/PEAR/PEAR/Command/Channels.php | 883 +++ .../phpunit/PEAR/PEAR/Command/Channels.xml | 123 + .../ext/phpunit/PEAR/PEAR/Command/Common.php | 273 + .../ext/phpunit/PEAR/PEAR/Command/Config.php | 413 ++ .../ext/phpunit/PEAR/PEAR/Command/Config.xml | 92 + .../ext/phpunit/PEAR/PEAR/Command/Install.php | 1268 +++++ .../ext/phpunit/PEAR/PEAR/Command/Install.xml | 276 + .../ext/phpunit/PEAR/PEAR/Command/Mirror.php | 139 + .../ext/phpunit/PEAR/PEAR/Command/Mirror.xml | 18 + .../ext/phpunit/PEAR/PEAR/Command/Package.php | 1124 ++++ .../ext/phpunit/PEAR/PEAR/Command/Package.xml | 237 + .../ext/phpunit/PEAR/PEAR/Command/Pickle.php | 421 ++ .../ext/phpunit/PEAR/PEAR/Command/Pickle.xml | 36 + .../phpunit/PEAR/PEAR/Command/Registry.php | 1145 ++++ .../phpunit/PEAR/PEAR/Command/Registry.xml | 58 + .../ext/phpunit/PEAR/PEAR/Command/Remote.php | 810 +++ .../ext/phpunit/PEAR/PEAR/Command/Remote.xml | 109 + .../ext/phpunit/PEAR/PEAR/Command/Test.php | 337 ++ .../ext/phpunit/PEAR/PEAR/Command/Test.xml | 54 + typo3conf/ext/phpunit/PEAR/PEAR/Common.php | 837 +++ typo3conf/ext/phpunit/PEAR/PEAR/Config.php | 2097 ++++++++ .../ext/phpunit/PEAR/PEAR/Dependency2.php | 1358 +++++ .../ext/phpunit/PEAR/PEAR/DependencyDB.php | 769 +++ .../ext/phpunit/PEAR/PEAR/Downloader.php | 1766 ++++++ .../phpunit/PEAR/PEAR/Downloader/Package.php | 1988 +++++++ .../ext/phpunit/PEAR/PEAR/ErrorStack.php | 985 ++++ typo3conf/ext/phpunit/PEAR/PEAR/Exception.php | 389 ++ .../phpunit/PEAR/PEAR/FixPHP5PEARWarnings.php | 7 + typo3conf/ext/phpunit/PEAR/PEAR/Frontend.php | 228 + .../ext/phpunit/PEAR/PEAR/Frontend/CLI.php | 751 +++ typo3conf/ext/phpunit/PEAR/PEAR/Installer.php | 1830 +++++++ .../ext/phpunit/PEAR/PEAR/Installer/Role.php | 276 + .../phpunit/PEAR/PEAR/Installer/Role/Cfg.php | 106 + .../phpunit/PEAR/PEAR/Installer/Role/Cfg.xml | 15 + .../PEAR/PEAR/Installer/Role/Common.php | 174 + .../phpunit/PEAR/PEAR/Installer/Role/Data.php | 28 + .../phpunit/PEAR/PEAR/Installer/Role/Data.xml | 15 + .../phpunit/PEAR/PEAR/Installer/Role/Doc.php | 28 + .../phpunit/PEAR/PEAR/Installer/Role/Doc.xml | 15 + .../phpunit/PEAR/PEAR/Installer/Role/Ext.php | 28 + .../phpunit/PEAR/PEAR/Installer/Role/Ext.xml | 12 + .../phpunit/PEAR/PEAR/Installer/Role/Php.php | 28 + .../phpunit/PEAR/PEAR/Installer/Role/Php.xml | 15 + .../PEAR/PEAR/Installer/Role/Script.php | 28 + .../PEAR/PEAR/Installer/Role/Script.xml | 15 + .../phpunit/PEAR/PEAR/Installer/Role/Src.php | 34 + .../phpunit/PEAR/PEAR/Installer/Role/Src.xml | 12 + .../phpunit/PEAR/PEAR/Installer/Role/Test.php | 28 + .../phpunit/PEAR/PEAR/Installer/Role/Test.xml | 15 + .../phpunit/PEAR/PEAR/Installer/Role/Www.php | 28 + .../phpunit/PEAR/PEAR/Installer/Role/Www.xml | 15 + .../ext/phpunit/PEAR/PEAR/PackageFile.php | 492 ++ .../PEAR/PEAR/PackageFile/Generator/v1.php | 1284 +++++ .../PEAR/PEAR/PackageFile/Generator/v2.php | 893 +++ .../PEAR/PEAR/PackageFile/Parser/v1.php | 459 ++ .../PEAR/PEAR/PackageFile/Parser/v2.php | 113 + .../ext/phpunit/PEAR/PEAR/PackageFile/v1.php | 1612 ++++++ .../ext/phpunit/PEAR/PEAR/PackageFile/v2.php | 2049 +++++++ .../PEAR/PEAR/PackageFile/v2/Validator.php | 2154 ++++++++ .../phpunit/PEAR/PEAR/PackageFile/v2/rw.php | 1604 ++++++ typo3conf/ext/phpunit/PEAR/PEAR/Packager.php | 201 + typo3conf/ext/phpunit/PEAR/PEAR/REST.php | 483 ++ typo3conf/ext/phpunit/PEAR/PEAR/REST/10.php | 871 +++ typo3conf/ext/phpunit/PEAR/PEAR/REST/11.php | 341 ++ typo3conf/ext/phpunit/PEAR/PEAR/REST/13.php | 299 ++ typo3conf/ext/phpunit/PEAR/PEAR/Registry.php | 2395 +++++++++ typo3conf/ext/phpunit/PEAR/PEAR/RunTest.php | 966 ++++ .../ext/phpunit/PEAR/PEAR/Task/Common.php | 202 + .../PEAR/PEAR/Task/Postinstallscript.php | 323 ++ .../PEAR/PEAR/Task/Postinstallscript/rw.php | 169 + .../ext/phpunit/PEAR/PEAR/Task/Replace.php | 176 + .../ext/phpunit/PEAR/PEAR/Task/Replace/rw.php | 61 + .../ext/phpunit/PEAR/PEAR/Task/Unixeol.php | 77 + .../ext/phpunit/PEAR/PEAR/Task/Unixeol/rw.php | 56 + .../ext/phpunit/PEAR/PEAR/Task/Windowseol.php | 77 + .../phpunit/PEAR/PEAR/Task/Windowseol/rw.php | 56 + typo3conf/ext/phpunit/PEAR/PEAR/Validate.php | 629 +++ .../ext/phpunit/PEAR/PEAR/Validator/PECL.php | 63 + typo3conf/ext/phpunit/PEAR/PEAR/XMLParser.php | 253 + typo3conf/ext/phpunit/PEAR/PEAR5.php | 33 + .../ext/phpunit/PEAR/PHP/CodeCoverage.php | 613 +++ .../phpunit/PEAR/PHP/CodeCoverage/Driver.php | 71 + .../PEAR/PHP/CodeCoverage/Driver/Xdebug.php | 91 + .../phpunit/PEAR/PHP/CodeCoverage/Filter.php | 334 ++ .../PEAR/PHP/CodeCoverage/Report/Clover.php | 467 ++ .../PEAR/PHP/CodeCoverage/Report/HTML.php | 419 ++ .../PHP/CodeCoverage/Report/HTML/Node.php | 512 ++ .../Report/HTML/Node/Directory.php | 430 ++ .../CodeCoverage/Report/HTML/Node/File.php | 916 ++++ .../Report/HTML/Node/Iterator.php | 149 + .../Report/HTML/Template/RGraph.bar.js | 1653 ++++++ .../HTML/Template/RGraph.common.core.js | 2454 +++++++++ .../HTML/Template/RGraph.common.tooltips.js | 502 ++ .../Report/HTML/Template/RGraph.scatter.js | 1168 ++++ .../Report/HTML/Template/butter.png | Bin 0 -> 150 bytes .../Report/HTML/Template/chameleon.png | Bin 0 -> 150 bytes .../Report/HTML/Template/close12_1.gif | Bin 0 -> 85 bytes .../Report/HTML/Template/container-min.js | 19 + .../Report/HTML/Template/container.css | 324 ++ .../Report/HTML/Template/dashboard.html.dist | 86 + .../Report/HTML/Template/directory.html.dist | 71 + .../Report/HTML/Template/directory.png | Bin 0 -> 581 bytes .../HTML/Template/directory_item.html.dist | 31 + .../HTML/Template/excanvas.compressed.js | Bin 0 -> 8660 bytes .../Report/HTML/Template/file.html.dist | 120 + .../Report/HTML/Template/file.png | Bin 0 -> 333 bytes .../Report/HTML/Template/file_item.html.dist | 32 + .../HTML/Template/file_no_yui.html.dist | 79 + .../Report/HTML/Template/glass.png | Bin 0 -> 167 bytes .../HTML/Template/method_item.html.dist | 23 + .../Report/HTML/Template/scarlet_red.png | Bin 0 -> 150 bytes .../Report/HTML/Template/snow.png | Bin 0 -> 141 bytes .../Report/HTML/Template/style.css | 459 ++ .../Report/HTML/Template/yahoo-dom-event.js | 14 + .../Report/HTML/Template/yui_item.js | 5 + .../PEAR/PHP/CodeCoverage/TextUI/Command.php | 268 + .../phpunit/PEAR/PHP/CodeCoverage/Util.php | 643 +++ typo3conf/ext/phpunit/PEAR/PHP/Timer.php | 139 + typo3conf/ext/phpunit/PEAR/PHP/Token.php | 475 ++ .../ext/phpunit/PEAR/PHP/Token/Exception.php | 56 + .../ext/phpunit/PEAR/PHP/Token/Stream.php | 378 ++ .../PEAR/PHP/Token/Stream/CachingFactory.php | 75 + .../PEAR/PHP/Token/Stream/TextUI/Command.php | 181 + .../ext/phpunit/PEAR/PHPUnit/Autoload.php | 89 + .../Extensions/Database/AbstractTester.php | 195 + .../Database/Constraint/DataSetIsEqual.php | 122 + .../Database/Constraint/TableIsEqual.php | 123 + .../Extensions/Database/DB/DataSet.php | 173 + .../Database/DB/DefaultDatabaseConnection.php | 210 + .../Database/DB/FilteredDataSet.php | 84 + .../Database/DB/IDatabaseConnection.php | 136 + .../Extensions/Database/DB/IMetaData.php | 105 + .../Extensions/Database/DB/MetaData.php | 226 + .../DB/MetaData/InformationSchema.php | 174 + .../Extensions/Database/DB/MetaData/MySQL.php | 123 + .../Extensions/Database/DB/MetaData/Oci.php | 180 + .../Extensions/Database/DB/MetaData/PgSQL.php | 193 + .../Database/DB/MetaData/Sqlite.php | 143 + .../Extensions/Database/DB/ResultSetTable.php | 81 + .../PHPUnit/Extensions/Database/DB/Table.php | 73 + .../Extensions/Database/DB/TableIterator.php | 165 + .../Extensions/Database/DB/TableMetaData.php | 65 + .../Database/DataSet/AbstractDataSet.php | 167 + .../Database/DataSet/AbstractTable.php | 212 + .../DataSet/AbstractTableMetaData.php | 125 + .../Database/DataSet/AbstractXmlDataSet.php | 151 + .../Database/DataSet/CompositeDataSet.php | 120 + .../Database/DataSet/CsvDataSet.php | 160 + .../Database/DataSet/DataSetFilter.php | 196 + .../Database/DataSet/DefaultDataSet.php | 97 + .../Database/DataSet/DefaultTable.php | 117 + .../Database/DataSet/DefaultTableIterator.php | 161 + .../Database/DataSet/DefaultTableMetaData.php | 80 + .../Database/DataSet/FlatXmlDataSet.php | 99 + .../Extensions/Database/DataSet/IDataSet.php | 95 + .../Database/DataSet/IPersistable.php | 66 + .../Extensions/Database/DataSet/ISpec.php | 65 + .../Extensions/Database/DataSet/ITable.php | 95 + .../Database/DataSet/ITableIterator.php | 72 + .../Database/DataSet/ITableMetaData.php | 86 + .../Database/DataSet/MysqlXmlDataSet.php | 141 + .../Database/DataSet/Persistors/Abstract.php | 127 + .../Database/DataSet/Persistors/Factory.php | 87 + .../Database/DataSet/Persistors/FlatXml.php | 147 + .../Database/DataSet/Persistors/MysqlXml.php | 165 + .../Database/DataSet/Persistors/Xml.php | 151 + .../Database/DataSet/Persistors/Yaml.php | 109 + .../Database/DataSet/QueryDataSet.php | 128 + .../Database/DataSet/QueryTable.php | 160 + .../Database/DataSet/ReplacementDataSet.php | 129 + .../Database/DataSet/ReplacementTable.php | 246 + .../DataSet/ReplacementTableIterator.php | 185 + .../Extensions/Database/DataSet/Specs/Csv.php | 125 + .../Database/DataSet/Specs/DbQuery.php | 111 + .../Database/DataSet/Specs/DbTable.php | 109 + .../Database/DataSet/Specs/Factory.php | 89 + .../Database/DataSet/Specs/FlatXml.php | 75 + .../Database/DataSet/Specs/IFactory.php | 65 + .../Extensions/Database/DataSet/Specs/Xml.php | 75 + .../Database/DataSet/Specs/Yaml.php | 75 + .../Database/DataSet/TableFilter.php | 136 + .../Database/DataSet/TableMetaDataFilter.php | 165 + .../Database/DataSet/XmlDataSet.php | 132 + .../Database/DataSet/YamlDataSet.php | 168 + .../Extensions/Database/DefaultTester.php | 84 + .../Database/IDatabaseListConsumer.php | 64 + .../PHPUnit/Extensions/Database/ITester.php | 119 + .../Database/Operation/Composite.php | 94 + .../Extensions/Database/Operation/Delete.php | 86 + .../Database/Operation/DeleteAll.php | 75 + .../Database/Operation/Exception.php | 129 + .../Extensions/Database/Operation/Factory.php | 138 + .../Database/Operation/IDatabaseOperation.php | 69 + .../Extensions/Database/Operation/Insert.php | 96 + .../Extensions/Database/Operation/Null.php | 63 + .../Extensions/Database/Operation/Replace.php | 142 + .../Database/Operation/RowBased.php | 122 + .../Database/Operation/Truncate.php | 84 + .../Extensions/Database/Operation/Update.php | 90 + .../PHPUnit/Extensions/Database/TestCase.php | 250 + .../Extensions/Database/UI/Command.php | 89 + .../Extensions/Database/UI/Context.php | 100 + .../Extensions/Database/UI/IMedium.php | 72 + .../Extensions/Database/UI/IMediumPrinter.php | 72 + .../PHPUnit/Extensions/Database/UI/IMode.php | 66 + .../Extensions/Database/UI/IModeFactory.php | 73 + .../Database/UI/InvalidModeException.php | 96 + .../Extensions/Database/UI/Mediums/Text.php | 138 + .../Extensions/Database/UI/ModeFactory.php | 130 + .../Database/UI/Modes/ExportDataSet.php | 119 + .../UI/Modes/ExportDataSet/Arguments.php | 153 + .../PHPUnit/Extensions/GroupTestSuite.php | 100 + .../PHPUnit/Extensions/OutputTestCase.php | 202 + .../PEAR/PHPUnit/Extensions/PhptTestCase.php | 277 + .../Extensions/PhptTestCase/Logger.php | 63 + .../PEAR/PHPUnit/Extensions/PhptTestSuite.php | 86 + .../PEAR/PHPUnit/Extensions/RepeatedTest.php | 154 + .../PHPUnit/Extensions/SeleniumTestCase.php | 1067 ++++ .../Extensions/SeleniumTestCase/Driver.php | 1218 +++++ .../Extensions/SeleniumTestCase/append.php | 69 + .../SeleniumTestCase/phpunit_coverage.php | 86 + .../Extensions/SeleniumTestCase/prepend.php | 59 + .../PEAR/PHPUnit/Extensions/Story/Given.php | 71 + .../Extensions/Story/ResultPrinter.php | 102 + .../Extensions/Story/ResultPrinter/HTML.php | 212 + .../ResultPrinter/Template/scenario.html.dist | 13 + .../Template/scenario_header.html.dist | 6 + .../Template/scenarios.html.dist | 60 + .../ResultPrinter/Template/step.html.dist | 6 + .../Extensions/Story/ResultPrinter/Text.php | 150 + .../PHPUnit/Extensions/Story/Scenario.php | 189 + .../Extensions/Story/SeleniumTestCase.php | 204 + .../PEAR/PHPUnit/Extensions/Story/Step.php | 128 + .../PHPUnit/Extensions/Story/TestCase.php | 210 + .../PEAR/PHPUnit/Extensions/Story/Then.php | 71 + .../PEAR/PHPUnit/Extensions/Story/When.php | 71 + .../PEAR/PHPUnit/Extensions/TestDecorator.php | 151 + .../PHPUnit/Extensions/TicketListener.php | 225 + .../Extensions/TicketListener/GitHub.php | 204 + .../Extensions/TicketListener/GoogleCode.php | 275 + .../Extensions/TicketListener/Trac.php | 189 + .../ext/phpunit/PEAR/PHPUnit/Framework.php | 50 + .../phpunit/PEAR/PHPUnit/Framework/Assert.php | 2620 +++++++++ .../PHPUnit/Framework/Assert/Functions.php | 1831 +++++++ .../Framework/AssertionFailedError.php | 69 + .../PHPUnit/Framework/ComparisonFailure.php | 208 + .../Framework/ComparisonFailure/Array.php | 140 + .../Framework/ComparisonFailure/Object.php | 170 + .../Framework/ComparisonFailure/Scalar.php | 74 + .../Framework/ComparisonFailure/String.php | 82 + .../Framework/ComparisonFailure/Type.php | 73 + .../PEAR/PHPUnit/Framework/Constraint.php | 170 + .../PEAR/PHPUnit/Framework/Constraint/And.php | 160 + .../Framework/Constraint/ArrayHasKey.php | 113 + .../Framework/Constraint/Attribute.php | 149 + .../Constraint/ClassHasAttribute.php | 110 + .../Constraint/ClassHasStaticAttribute.php | 97 + .../Framework/Constraint/FileExists.php | 112 + .../Framework/Constraint/GreaterThan.php | 95 + .../Framework/Constraint/IsAnything.php | 103 + .../PHPUnit/Framework/Constraint/IsEmpty.php | 102 + .../PHPUnit/Framework/Constraint/IsEqual.php | 386 ++ .../PHPUnit/Framework/Constraint/IsFalse.php | 81 + .../Framework/Constraint/IsIdentical.php | 140 + .../Framework/Constraint/IsInstanceOf.php | 128 + .../PHPUnit/Framework/Constraint/IsNull.php | 81 + .../PHPUnit/Framework/Constraint/IsTrue.php | 81 + .../PHPUnit/Framework/Constraint/IsType.php | 183 + .../PHPUnit/Framework/Constraint/LessThan.php | 95 + .../PEAR/PHPUnit/Framework/Constraint/Not.php | 141 + .../Constraint/ObjectHasAttribute.php | 84 + .../PEAR/PHPUnit/Framework/Constraint/Or.php | 137 + .../Framework/Constraint/PCREMatch.php | 104 + .../Framework/Constraint/StringContains.php | 121 + .../Framework/Constraint/StringEndsWith.php | 95 + .../Framework/Constraint/StringMatches.php | 140 + .../Framework/Constraint/StringStartsWith.php | 95 + .../Constraint/TraversableContains.php | 127 + .../Constraint/TraversableContainsOnly.php | 115 + .../PEAR/PHPUnit/Framework/Constraint/Xor.php | 144 + .../phpunit/PEAR/PHPUnit/Framework/Error.php | 77 + .../PEAR/PHPUnit/Framework/Error/Notice.php | 66 + .../PEAR/PHPUnit/Framework/Error/Warning.php | 66 + .../PEAR/PHPUnit/Framework/Exception.php | 60 + .../Framework/ExpectationFailedException.php | 124 + .../PEAR/PHPUnit/Framework/IncompleteTest.php | 61 + .../PHPUnit/Framework/IncompleteTestError.php | 61 + .../Framework/MockObject/Builder/Identity.php | 70 + .../MockObject/Builder/InvocationMocker.php | 193 + .../Framework/MockObject/Builder/Match.php | 66 + .../MockObject/Builder/MethodNameMatch.php | 68 + .../MockObject/Builder/Namespace.php | 79 + .../MockObject/Builder/ParametersMatch.php | 89 + .../Framework/MockObject/Builder/Stub.php | 66 + .../Framework/MockObject/Generator.php | 687 +++ .../Generator/mocked_class.tpl.dist | 46 + .../Generator/mocked_clone.tpl.dist | 4 + .../Generator/mocked_object_method.tpl.dist | 22 + .../Generator/mocked_static_method.tpl.dist | 22 + .../Generator/unmocked_clone.tpl.dist | 5 + .../MockObject/Generator/wsdl_class.tpl.dist | 7 + .../MockObject/Generator/wsdl_method.tpl.dist | 4 + .../Framework/MockObject/Invocation.php | 58 + .../MockObject/Invocation/Object.php | 74 + .../MockObject/Invocation/Static.php | 185 + .../Framework/MockObject/InvocationMocker.php | 183 + .../Framework/MockObject/Invokable.php | 79 + .../PHPUnit/Framework/MockObject/Matcher.php | 303 ++ .../MockObject/Matcher/AnyInvokedCount.php | 72 + .../MockObject/Matcher/AnyParameters.php | 74 + .../MockObject/Matcher/Invocation.php | 88 + .../MockObject/Matcher/InvokedAtIndex.php | 127 + .../MockObject/Matcher/InvokedAtLeastOnce.php | 85 + .../MockObject/Matcher/InvokedCount.php | 143 + .../MockObject/Matcher/InvokedRecorder.php | 107 + .../MockObject/Matcher/MethodName.php | 102 + .../MockObject/Matcher/Parameters.php | 162 + .../Matcher/StatelessInvocation.php | 96 + .../Framework/MockObject/MockBuilder.php | 218 + .../Framework/MockObject/MockObject.php | 94 + .../PHPUnit/Framework/MockObject/Stub.php | 71 + .../MockObject/Stub/ConsecutiveCalls.php | 87 + .../Framework/MockObject/Stub/Exception.php | 80 + .../MockObject/Stub/MatcherCollection.php | 66 + .../Framework/MockObject/Stub/Return.php | 78 + .../MockObject/Stub/ReturnArgument.php | 78 + .../MockObject/Stub/ReturnCallback.php | 94 + .../Framework/MockObject/Verifiable.php | 65 + .../Framework/Process/TestCaseMethod.tpl.dist | 48 + .../PEAR/PHPUnit/Framework/SelfDescribing.php | 66 + .../PEAR/PHPUnit/Framework/SkippedTest.php | 60 + .../PHPUnit/Framework/SkippedTestError.php | 61 + .../Framework/SkippedTestSuiteError.php | 61 + .../PEAR/PHPUnit/Framework/SyntheticError.php | 122 + .../phpunit/PEAR/PHPUnit/Framework/Test.php | 67 + .../PEAR/PHPUnit/Framework/TestCase.php | 1513 ++++++ .../PEAR/PHPUnit/Framework/TestFailure.php | 228 + .../PEAR/PHPUnit/Framework/TestListener.php | 127 + .../PEAR/PHPUnit/Framework/TestResult.php | 907 ++++ .../PEAR/PHPUnit/Framework/TestSuite.php | 932 ++++ .../Framework/TestSuite/DataProvider.php | 71 + .../PEAR/PHPUnit/Framework/Warning.php | 126 + .../PEAR/PHPUnit/Runner/BaseTestRunner.php | 190 + .../Runner/IncludePathTestCollector.php | 144 + .../Runner/StandardTestSuiteLoader.php | 153 + .../PEAR/PHPUnit/Runner/TestCollector.php | 65 + .../PEAR/PHPUnit/Runner/TestSuiteLoader.php | 72 + .../phpunit/PEAR/PHPUnit/Runner/Version.php | 77 + .../phpunit/PEAR/PHPUnit/TextUI/Command.php | 886 +++ .../PEAR/PHPUnit/TextUI/ResultPrinter.php | 612 +++ .../PEAR/PHPUnit/TextUI/TestRunner.php | 774 +++ .../ext/phpunit/PEAR/PHPUnit/Util/Class.php | 401 ++ .../PEAR/PHPUnit/Util/Configuration.php | 862 +++ .../PEAR/PHPUnit/Util/DeprecatedFeature.php | 103 + .../PHPUnit/Util/DeprecatedFeature/Logger.php | 202 + .../ext/phpunit/PEAR/PHPUnit/Util/Diff.php | 261 + .../PEAR/PHPUnit/Util/ErrorHandler.php | 124 + .../ext/phpunit/PEAR/PHPUnit/Util/File.php | 310 ++ .../phpunit/PEAR/PHPUnit/Util/Fileloader.php | 140 + .../phpunit/PEAR/PHPUnit/Util/Filesystem.php | 154 + .../ext/phpunit/PEAR/PHPUnit/Util/Filter.php | 138 + .../ext/phpunit/PEAR/PHPUnit/Util/Getopt.php | 208 + .../phpunit/PEAR/PHPUnit/Util/GlobalState.php | 354 ++ .../PHPUnit/Util/InvalidArgumentHelper.php | 80 + .../phpunit/PEAR/PHPUnit/Util/Log/DBUS.php | 236 + .../phpunit/PEAR/PHPUnit/Util/Log/JSON.php | 240 + .../phpunit/PEAR/PHPUnit/Util/Log/JUnit.php | 485 ++ .../ext/phpunit/PEAR/PHPUnit/Util/Log/TAP.php | 253 + .../phpunit/PEAR/PHPUnit/Util/Log/XHProf.php | 252 + .../ext/phpunit/PEAR/PHPUnit/Util/PHP.php | 277 + .../phpunit/PEAR/PHPUnit/Util/PHP/Default.php | 68 + .../phpunit/PEAR/PHPUnit/Util/PHP/Windows.php | 91 + .../ext/phpunit/PEAR/PHPUnit/Util/Printer.php | 209 + .../phpunit/PEAR/PHPUnit/Util/Skeleton.php | 146 + .../PEAR/PHPUnit/Util/Skeleton/Class.php | 327 ++ .../Util/Skeleton/Template/Class.tpl.dist | 7 + .../Template/IncompleteTestMethod.tpl.dist | 11 + .../Util/Skeleton/Template/Method.tpl.dist | 9 + .../Util/Skeleton/Template/TestClass.tpl.dist | 31 + .../Skeleton/Template/TestMethod.tpl.dist | 11 + .../Skeleton/Template/TestMethodBool.tpl.dist | 10 + .../Template/TestMethodBoolStatic.tpl.dist | 10 + .../Template/TestMethodException.tpl.dist | 9 + .../TestMethodExceptionStatic.tpl.dist | 9 + .../Template/TestMethodStatic.tpl.dist | 11 + .../PEAR/PHPUnit/Util/Skeleton/Test.php | 379 ++ .../ext/phpunit/PEAR/PHPUnit/Util/Test.php | 473 ++ .../PHPUnit/Util/TestDox/NamePrettifier.php | 178 + .../PHPUnit/Util/TestDox/ResultPrinter.php | 348 ++ .../Util/TestDox/ResultPrinter/HTML.php | 124 + .../Util/TestDox/ResultPrinter/Text.php | 96 + .../PEAR/PHPUnit/Util/TestSuiteIterator.php | 149 + .../ext/phpunit/PEAR/PHPUnit/Util/Type.php | 192 + .../ext/phpunit/PEAR/PHPUnit/Util/XML.php | 957 ++++ .../ext/phpunit/PEAR/Structures/Graph.php | 154 + .../Graph/Manipulator/AcyclicTest.php | 136 + .../Graph/Manipulator/TopologicalSorter.php | 153 + .../phpunit/PEAR/Structures/Graph/Node.php | 342 ++ .../PEAR/SymfonyComponents/YAML/sfYaml.php | 135 + .../SymfonyComponents/YAML/sfYamlDumper.php | 60 + .../SymfonyComponents/YAML/sfYamlInline.php | 442 ++ .../SymfonyComponents/YAML/sfYamlParser.php | 600 +++ typo3conf/ext/phpunit/PEAR/System.php | 621 +++ typo3conf/ext/phpunit/PEAR/Text/Template.php | 153 + .../phpunit/PEAR/Text/Template/Autoload.php | 65 + .../ext/phpunit/PEAR/XML/RPC2/Backend.php | 191 + .../PEAR/XML/RPC2/Backend/Php/Client.php | 143 + .../PEAR/XML/RPC2/Backend/Php/Request.php | 205 + .../PEAR/XML/RPC2/Backend/Php/Response.php | 142 + .../PEAR/XML/RPC2/Backend/Php/Server.php | 142 + .../PEAR/XML/RPC2/Backend/Php/Value.php | 302 ++ .../PEAR/XML/RPC2/Backend/Php/Value/Array.php | 131 + .../XML/RPC2/Backend/Php/Value/Base64.php | 135 + .../XML/RPC2/Backend/Php/Value/Boolean.php | 108 + .../XML/RPC2/Backend/Php/Value/Datetime.php | 209 + .../XML/RPC2/Backend/Php/Value/Double.php | 96 + .../XML/RPC2/Backend/Php/Value/Integer.php | 96 + .../XML/RPC2/Backend/Php/Value/Integer64.php | 97 + .../PEAR/XML/RPC2/Backend/Php/Value/Nil.php | 90 + .../XML/RPC2/Backend/Php/Value/Scalar.php | 179 + .../XML/RPC2/Backend/Php/Value/String.php | 110 + .../XML/RPC2/Backend/Php/Value/Struct.php | 140 + .../XML/RPC2/Backend/Xmlrpcext/Client.php | 143 + .../XML/RPC2/Backend/Xmlrpcext/Server.php | 175 + .../PEAR/XML/RPC2/Backend/Xmlrpcext/Value.php | 101 + .../phpunit/PEAR/XML/RPC2/CachedClient.php | 361 ++ .../phpunit/PEAR/XML/RPC2/CachedServer.php | 416 ++ .../ext/phpunit/PEAR/XML/RPC2/Client.php | 261 + .../phpunit/PEAR/XML/RPC2/ClientHelper.php | 118 + .../ext/phpunit/PEAR/XML/RPC2/Exception.php | 360 ++ .../ext/phpunit/PEAR/XML/RPC2/Server.php | 355 ++ .../PEAR/XML/RPC2/Server/CallHandler.php | 129 + .../XML/RPC2/Server/CallHandler/Class.php | 150 + .../XML/RPC2/Server/CallHandler/Instance.php | 148 + .../phpunit/PEAR/XML/RPC2/Server/Input.php | 68 + .../PEAR/XML/RPC2/Server/Input/PhpInput.php | 79 + .../XML/RPC2/Server/Input/RawPostData.php | 82 + .../phpunit/PEAR/XML/RPC2/Server/Method.php | 391 ++ .../PEAR/XML/RPC2/Util/HTTPRequest.php | 248 + typo3conf/ext/phpunit/PEAR/XML/RPC2/Value.php | 81 + typo3conf/ext/phpunit/PEAR/XML/Util.php | 911 ++++ .../PEAR/data/Base/design/class_diagram.png | Bin 0 -> 233811 bytes .../phpunit/PEAR/data/Base/design/design.txt | 9 + .../ConsoleTools/design/class_diagram.png | Bin 0 -> 871054 bytes .../PEAR/data/ConsoleTools/design/console.png | Bin 0 -> 16645 bytes .../PEAR/data/ConsoleTools/design/console.xml | 3117 +++++++++++ .../design/console_parameters.png | Bin 0 -> 8606 bytes .../data/ConsoleTools/design/design-1.3.txt | 578 ++ .../PEAR/data/ConsoleTools/design/design.txt | 114 + .../ext/phpunit/PEAR/data/PEAR/package.dtd | 103 + .../ext/phpunit/PEAR/data/PEAR/template.spec | 72 + .../PEAR/data/Structures_Graph/LICENSE | 504 ++ .../ext/phpunit/PEAR/data/XML_RPC2/Makefile | 15 + .../ext/phpunit/PEAR/data/vfsStream/LICENSE | 27 + .../ext/phpunit/PEAR/data/vfsStream/VERSION | 1 + .../docs/Archive_Tar/docs/Archive_Tar.txt | 461 ++ .../ext/phpunit/PEAR/docs/Base/docs/CREDITS | 16 + .../ext/phpunit/PEAR/docs/Base/docs/LICENSE | 32 + .../PEAR/docs/Base/docs/repos/Me/myclass1.php | 9 + .../PEAR/docs/Base/docs/repos/Me/myclass2.php | 9 + .../docs/Base/docs/repos/You/yourclass1.php | 9 + .../docs/Base/docs/repos/You/yourclass2.php | 9 + .../Base/docs/repos/autoloads/my_autoload.php | 6 + .../docs/repos/autoloads/your_autoload.php | 6 + .../phpunit/PEAR/docs/Base/docs/tutorial.txt | 240 + .../PEAR/docs/Base/docs/tutorial_autoload.php | 20 + .../docs/Base/docs/tutorial_example_01.php | 9 + .../docs/Base/docs/tutorial_example_02.php | 11 + .../docs/Base/docs/tutorial_example_03.php | 6 + .../docs/Base/docs/tutorial_example_04.php | 42 + .../docs/tutorial_lazy_initialization.php | 38 + .../ext/phpunit/PEAR/docs/Cache_Lite/LICENSE | 458 ++ .../ext/phpunit/PEAR/docs/Cache_Lite/TODO | 46 + .../PEAR/docs/Cache_Lite/docs/examples | 254 + .../PEAR/docs/Cache_Lite/docs/technical | 28 + .../phpunit/PEAR/docs/Cache_Lite/tests/readme | 17 + .../PEAR/docs/ConsoleTools/docs/CREDITS | 16 + .../PEAR/docs/ConsoleTools/docs/LICENSE | 32 + .../docs/ConsoleTools/docs/example_input.php | 104 + .../docs/example_menu_dialog_full.php | 30 + .../docs/ConsoleTools/docs/example_output.php | 64 + .../ConsoleTools/docs/example_progressbar.php | 75 + .../docs/example_progressmonitor.php | 52 + ...xample_question_dialog_collection_full.php | 25 + .../example_question_dialog_factory_yesno.php | 25 + .../example_question_dialog_type_full.php | 30 + .../ConsoleTools/docs/example_statusbar.php | 49 + .../docs/ConsoleTools/docs/example_table.php | 77 + .../ConsoleTools/docs/example_table_2.php | 65 + .../img/consoletools_tutorial_example_06.png | Bin 0 -> 489 bytes .../img/consoletools_tutorial_example_07.png | Bin 0 -> 671 bytes .../img/consoletools_tutorial_example_08.png | Bin 0 -> 844 bytes .../img/consoletools_tutorial_example_09.png | Bin 0 -> 3577 bytes .../img/consoletools_tutorial_example_10.png | Bin 0 -> 2964 bytes .../PEAR/docs/ConsoleTools/docs/tutorial.txt | 564 ++ .../ConsoleTools/docs/tutorial_autoload.php | 20 + .../docs/tutorial_example_01_output_basic.php | 11 + .../tutorial_example_02_output_advanced.php | 25 + .../tutorial_example_03_output_options.php | 27 + .../docs/tutorial_example_04_input_basic.php | 32 + .../tutorial_example_05_input_advanced.php | 55 + .../tutorial_example_06_progressbar_basic.php | 19 + ...torial_example_07_progressbar_advanced.php | 29 + .../docs/tutorial_example_08_statusbar.php | 27 + .../docs/tutorial_example_09_table_basic.php | 43 + .../tutorial_example_10_table_advanced.php | 38 + .../tutorial_example_11_progressmonitor.php | 18 + .../tutorial_example_12_input_arguments.php | 48 + .../tutorial_example_13_dialog_question.php | 24 + ...torial_example_14_dialog_yesnoquestion.php | 21 + .../docs/tutorial_example_15_dialog_menu.php | 32 + .../docs/tutorial_example_output_targets.php | 13 + .../PEAR/docs/DbUnit/ChangeLog.markdown | 22 + .../ext/phpunit/PEAR/docs/DbUnit/LICENSE | 33 + .../Samples/BankAccountDB/BankAccount.php | 206 + .../BankAccountDB/BankAccountDBTest.php | 146 + .../BankAccountDB/BankAccountDBTestMySQL.php | 146 + .../_files/bank-account-after-deposits.xml | 6 + .../_files/bank-account-after-new-account.xml | 7 + .../_files/bank-account-after-withdrawals.xml | 6 + .../_files/bank-account-seed.xml | 6 + typo3conf/ext/phpunit/PEAR/docs/PEAR/INSTALL | 54 + typo3conf/ext/phpunit/PEAR/docs/PEAR/LICENSE | 27 + typo3conf/ext/phpunit/PEAR/docs/PEAR/README | 32 + .../PEAR/docs/PHPUnit/ChangeLog.markdown | 150 + .../ext/phpunit/PEAR/docs/PHPUnit/LICENSE | 33 + .../phpunit/PEAR/docs/PHPUnit/README.markdown | 86 + .../PHPUnit_MockObject/ChangeLog.markdown | 57 + .../PEAR/docs/PHPUnit_MockObject/LICENSE | 33 + .../docs/PHPUnit_Selenium/ChangeLog.markdown | 25 + .../PEAR/docs/PHPUnit_Selenium/LICENSE | 33 + .../docs/PHP_CodeCoverage/ChangeLog.markdown | 38 + .../PEAR/docs/PHP_CodeCoverage/LICENSE | 33 + .../docs/Structures_Graph/docs/generate.sh | 8 + .../Structures_Graph/Structures_Graph.html | 243 + ...uctures_Graph_Manipulator_AcyclicTest.html | 105 + ...s_Graph_Manipulator_TopologicalSorter.html | 107 + .../Structures_Graph_Node.html | 549 ++ ...res_Graph_Manipulator_AcyclicTest_php.html | 119 + ...aph_Manipulator_TopologicalSorter_php.html | 133 + .../_Structures_Graph_Node_php.html | 105 + .../_Structures_Graph_php.html | 136 + .../tutorial_Structures_Graph.pkg.html | 75 + .../html/classtrees_Structures_Graph.html | 36 + .../docs/html/elementindex.html | 339 ++ .../html/elementindex_Structures_Graph.html | 336 ++ .../Structures_Graph/docs/html/errors.html | 16 + .../Structures_Graph/docs/html/index.html | 24 + .../docs/html/li_Structures_Graph.html | 53 + .../docs/html/media/banner.css | 32 + .../docs/html/media/stylesheet.css | 134 + .../Structures_Graph/docs/html/packages.html | 27 + .../Structures_Graph/docs/html/todolist.html | 21 + .../Structures_Graph/Structures_Graph.pkg | 98 + .../docs/XML_RPC2/docs/tutorials/XML_RPC2.lyx | 320 ++ .../PEAR/docs/XML_Util/examples/example.php | 299 ++ .../PEAR/docs/XML_Util/examples/example2.php | 145 + typo3conf/ext/phpunit/PEAR/docs/YAML/LICENSE | 19 + .../phpunit/PEAR/docs/YAML/README.markdown | 15 + .../fsource_bovigo_vfs__vfsStream.php.html | 210 + ...igo_vfs__vfsStreamAbstractContent.php.html | 342 ++ ...ce_bovigo_vfs__vfsStreamContainer.php.html | 72 + ...o_vfs__vfsStreamContainerIterator.php.html | 108 + ...urce_bovigo_vfs__vfsStreamContent.php.html | 213 + ...ce_bovigo_vfs__vfsStreamDirectory.php.html | 231 + ...ce_bovigo_vfs__vfsStreamException.php.html | 36 + ...fsource_bovigo_vfs__vfsStreamFile.php.html | 222 + ...urce_bovigo_vfs__vfsStreamWrapper.php.html | 700 +++ .../PEAR/docs/vfsStream/docs/api/blank.html | 13 + .../docs/api/bovigo_vfs/_vfsStream.php.html | 144 + .../_vfsStreamAbstractContent.php.html | 144 + .../bovigo_vfs/_vfsStreamContainer.php.html | 144 + .../_vfsStreamContainerIterator.php.html | 144 + .../api/bovigo_vfs/_vfsStreamContent.php.html | 144 + .../bovigo_vfs/_vfsStreamDirectory.php.html | 202 + .../bovigo_vfs/_vfsStreamException.php.html | 144 + .../api/bovigo_vfs/_vfsStreamFile.php.html | 144 + .../api/bovigo_vfs/_vfsStreamWrapper.php.html | 187 + .../docs/api/bovigo_vfs/vfsStream.html | 716 +++ .../bovigo_vfs/vfsStreamAbstractContent.html | 1322 +++++ .../api/bovigo_vfs/vfsStreamContainer.html | 332 ++ .../vfsStreamContainerIterator.html | 442 ++ .../docs/api/bovigo_vfs/vfsStreamContent.html | 952 ++++ .../api/bovigo_vfs/vfsStreamDirectory.html | 813 +++ .../api/bovigo_vfs/vfsStreamException.html | 212 + .../docs/api/bovigo_vfs/vfsStreamFile.html | 803 +++ .../docs/api/bovigo_vfs/vfsStreamWrapper.html | 1507 ++++++ .../docs/api/classtrees_bovigo_vfs.html | 49 + .../docs/vfsStream/docs/api/elementindex.html | 1538 ++++++ .../docs/api/elementindex_bovigo_vfs.html | 1535 ++++++ .../PEAR/docs/vfsStream/docs/api/errors.html | 19 + .../PEAR/docs/vfsStream/docs/api/index.html | 24 + .../vfsStream/docs/api/li_bovigo_vfs.html | 219 + .../docs/vfsStream/docs/api/media/banner.css | 32 + .../docs/api/media/images/AbstractClass.png | Bin 0 -> 620 bytes .../api/media/images/AbstractClass_logo.png | Bin 0 -> 1232 bytes .../docs/api/media/images/AbstractMethod.png | Bin 0 -> 696 bytes .../api/media/images/AbstractPrivateClass.png | Bin 0 -> 848 bytes .../images/AbstractPrivateClass_logo.png | Bin 0 -> 1615 bytes .../media/images/AbstractPrivateMethod.png | Bin 0 -> 874 bytes .../vfsStream/docs/api/media/images/Class.png | Bin 0 -> 570 bytes .../docs/api/media/images/Class_logo.png | Bin 0 -> 1600 bytes .../docs/api/media/images/Constant.png | Bin 0 -> 752 bytes .../docs/api/media/images/Constructor.png | Bin 0 -> 865 bytes .../docs/api/media/images/Destructor.png | Bin 0 -> 956 bytes .../docs/api/media/images/Function.png | Bin 0 -> 596 bytes .../docs/api/media/images/Global.png | Bin 0 -> 712 bytes .../vfsStream/docs/api/media/images/I.png | Bin 0 -> 148 bytes .../vfsStream/docs/api/media/images/Index.png | Bin 0 -> 584 bytes .../docs/api/media/images/Interface.png | Bin 0 -> 1083 bytes .../docs/api/media/images/Interface_logo.png | Bin 0 -> 1600 bytes .../vfsStream/docs/api/media/images/L.png | Bin 0 -> 153 bytes .../docs/api/media/images/Lminus.png | Bin 0 -> 219 bytes .../vfsStream/docs/api/media/images/Lplus.png | Bin 0 -> 224 bytes .../docs/api/media/images/Method.png | Bin 0 -> 661 bytes .../vfsStream/docs/api/media/images/Page.png | Bin 0 -> 592 bytes .../docs/api/media/images/Page_logo.png | Bin 0 -> 1369 bytes .../docs/api/media/images/PrivateClass.png | Bin 0 -> 790 bytes .../api/media/images/PrivateClass_logo.png | Bin 0 -> 1836 bytes .../docs/api/media/images/PrivateMethod.png | Bin 0 -> 918 bytes .../docs/api/media/images/PrivateVariable.png | Bin 0 -> 772 bytes .../docs/api/media/images/StaticMethod.png | Bin 0 -> 661 bytes .../docs/api/media/images/StaticVariable.png | Bin 0 -> 688 bytes .../vfsStream/docs/api/media/images/T.png | Bin 0 -> 152 bytes .../docs/api/media/images/Tminus.png | Bin 0 -> 207 bytes .../vfsStream/docs/api/media/images/Tplus.png | Bin 0 -> 222 bytes .../docs/api/media/images/Variable.png | Bin 0 -> 688 bytes .../vfsStream/docs/api/media/images/blank.png | Bin 0 -> 144 bytes .../docs/api/media/images/class_folder.png | Bin 0 -> 633 bytes .../vfsStream/docs/api/media/images/empty.png | Bin 0 -> 90 bytes .../vfsStream/docs/api/media/images/file.png | Bin 0 -> 462 bytes .../docs/api/media/images/folder.png | Bin 0 -> 492 bytes .../docs/api/media/images/function_folder.png | Bin 0 -> 605 bytes .../vfsStream/docs/api/media/images/minus.gif | Bin 0 -> 54 bytes .../docs/api/media/images/next_button.png | Bin 0 -> 657 bytes .../api/media/images/next_button_disabled.png | Bin 0 -> 543 bytes .../docs/api/media/images/package.png | Bin 0 -> 668 bytes .../docs/api/media/images/package_folder.png | Bin 0 -> 564 bytes .../vfsStream/docs/api/media/images/plus.gif | Bin 0 -> 56 bytes .../docs/api/media/images/previous_button.png | Bin 0 -> 644 bytes .../media/images/previous_button_disabled.png | Bin 0 -> 541 bytes .../api/media/images/private_class_logo.png | Bin 0 -> 1836 bytes .../docs/api/media/images/tutorial.png | Bin 0 -> 431 bytes .../docs/api/media/images/tutorial_folder.png | Bin 0 -> 572 bytes .../docs/api/media/images/up_button.png | Bin 0 -> 668 bytes .../vfsStream/docs/api/media/lib/classTree.js | 454 ++ .../vfsStream/docs/api/media/stylesheet.css | 181 + .../docs/vfsStream/docs/api/packages.html | 29 + .../docs/vfsStream/docs/api/todolist.html | 20 + .../docs/vfsStream/docs/coverage/butter.png | Bin 0 -> 150 bytes .../vfsStream/docs/coverage/chameleon.png | Bin 0 -> 150 bytes .../vfsStream/docs/coverage/close12_1.gif | Bin 0 -> 85 bytes .../vfsStream/docs/coverage/container-min.js | 19 + .../vfsStream/docs/coverage/container.css | 324 ++ .../docs/vfsStream/docs/coverage/glass.png | Bin 0 -> 167 bytes .../docs/vfsStream/docs/coverage/index.html | 291 + .../vfsStream/docs/coverage/scarlet_red.png | Bin 0 -> 150 bytes .../docs/vfsStream/docs/coverage/snow.png | Bin 0 -> 141 bytes .../docs/vfsStream/docs/coverage/style.css | 450 ++ .../docs/coverage/vfsStream.php.html | 696 +++ .../vfsStreamAbstractContent.php.html | 1222 +++++ .../vfsStreamContainerIterator.php.html | 485 ++ .../docs/coverage/vfsStreamDirectory.php.html | 892 +++ .../docs/coverage/vfsStreamFile.php.html | 838 +++ .../docs/coverage/vfsStreamWrapper.php.html | 2572 +++++++++ .../docs/coverage/yahoo-dom-event.js | 14 + .../PEAR/docs/vfsStream/docs/metrics.xml | 114 + .../PEAR/docs/vfsStream/docs/pmd-cpd.xml | 2 + .../phpunit/PEAR/docs/vfsStream/docs/pmd.xml | 11 + .../PEAR/docs/vfsStream/examples/Example.php | 55 + .../examples/ExampleTestCaseOldWay.php | 50 + .../examples/ExampleTestCaseWithVfsStream.php | 39 + .../vfsStream/examples/FailureExample.php | 51 + .../examples/FailureExampleTestCase.php | 60 + .../FileModeExampleTestCaseOldWay.php | 69 + .../examples/FilePermissionsExample.php | 30 + .../FilePermissionsExampleTestCase.php | 46 + .../vfsStream/examples/FilemodeExample.php | 63 + .../FilemodeExampleTestCaseWithVfsStream.php | 48 + typo3conf/ext/phpunit/PEAR/ezc/Base/base.php | 658 +++ .../phpunit/PEAR/ezc/Base/base_autoload.php | 47 + .../PEAR/ezc/Base/exceptions/autoload.php | 38 + .../double_class_repository_prefix.php | 34 + .../PEAR/ezc/Base/exceptions/exception.php | 43 + .../Base/exceptions/extension_not_found.php | 38 + .../ezc/Base/exceptions/file_exception.php | 25 + .../PEAR/ezc/Base/exceptions/file_io.php | 50 + .../ezc/Base/exceptions/file_not_found.php | 43 + .../ezc/Base/exceptions/file_permission.php | 63 + .../functionality_not_supported.php | 31 + .../exceptions/init_callback_configured.php | 31 + .../exceptions/invalid_callback_class.php | 31 + .../Base/exceptions/invalid_parent_class.php | 29 + .../Base/exceptions/property_not_found.php | 30 + .../Base/exceptions/property_permission.php | 42 + .../ezc/Base/exceptions/setting_not_found.php | 29 + .../ezc/Base/exceptions/setting_value.php | 42 + .../PEAR/ezc/Base/exceptions/value.php | 43 + .../PEAR/ezc/Base/exceptions/whatever.php | 40 + .../phpunit/PEAR/ezc/Base/ezc_bootstrap.php | 40 + .../ext/phpunit/PEAR/ezc/Base/features.php | 365 ++ typo3conf/ext/phpunit/PEAR/ezc/Base/file.php | 495 ++ typo3conf/ext/phpunit/PEAR/ezc/Base/init.php | 125 + .../interfaces/configuration_initializer.php | 32 + .../PEAR/ezc/Base/interfaces/exportable.php | 33 + .../PEAR/ezc/Base/interfaces/persistable.php | 40 + .../ext/phpunit/PEAR/ezc/Base/metadata.php | 120 + .../phpunit/PEAR/ezc/Base/metadata/pear.php | 129 + .../PEAR/ezc/Base/metadata/tarball.php | 153 + .../ext/phpunit/PEAR/ezc/Base/options.php | 174 + .../PEAR/ezc/Base/options/autoload.php | 75 + .../ext/phpunit/PEAR/ezc/Base/struct.php | 42 + .../ezc/Base/structs/file_find_context.php | 72 + .../ezc/Base/structs/repository_directory.php | 83 + .../ezc/ConsoleTools/console_autoload.php | 76 + .../ezc/ConsoleTools/dialog/menu_dialog.php | 217 + .../ConsoleTools/dialog/question_dialog.php | 251 + .../dialog/validators/menu_dialog_default.php | 199 + .../validators/question_dialog_collection.php | 186 + .../validators/question_dialog_mapping.php | 142 + .../validators/question_dialog_regex.php | 169 + .../validators/question_dialog_type.php | 227 + .../PEAR/ezc/ConsoleTools/dialog_viewer.php | 68 + .../ezc/ConsoleTools/exceptions/argument.php | 23 + .../argument_already_registered.php | 54 + .../argument_mandatory_violation.php | 33 + .../exceptions/argument_too_many.php | 33 + .../exceptions/argument_type_violation.php | 40 + .../ConsoleTools/exceptions/dialog_abort.php | 30 + .../ezc/ConsoleTools/exceptions/exception.php | 20 + .../exceptions/invalid_option_name.php | 32 + .../exceptions/invalid_output_target.php | 32 + .../exceptions/no_position_stored.php | 30 + .../exceptions/no_valid_dialog_result.php | 32 + .../ezc/ConsoleTools/exceptions/option.php | 22 + .../exceptions/option_already_registered.php | 31 + .../exceptions/option_arguments_violation.php | 32 + .../option_dependency_violation.php | 39 + .../exceptions/option_exclusion_violation.php | 39 + .../exceptions/option_mandatory_violation.php | 32 + .../exceptions/option_missing_value.php | 32 + .../exceptions/option_no_alias.php | 31 + .../exceptions/option_not_exists.php | 31 + .../option_string_not_wellformed.php | 31 + .../exceptions/option_too_many_values.php | 32 + .../exceptions/option_type_violation.php | 42 + .../phpunit/PEAR/ezc/ConsoleTools/input.php | 1396 +++++ .../PEAR/ezc/ConsoleTools/input/argument.php | 180 + .../PEAR/ezc/ConsoleTools/input/arguments.php | 246 + .../input/help_generators/standard.php | 391 ++ .../PEAR/ezc/ConsoleTools/input/option.php | 585 ++ .../input/validators/standard.php | 171 + .../ezc/ConsoleTools/interfaces/dialog.php | 82 + .../interfaces/dialog_validator.php | 57 + .../interfaces/input_help_generator.php | 170 + .../interfaces/input_validator.php | 41 + .../interfaces/menu_dialog_validator.php | 29 + .../interfaces/question_dialog_validator.php | 30 + .../PEAR/ezc/ConsoleTools/options/dialog.php | 70 + .../ezc/ConsoleTools/options/menu_dialog.php | 116 + .../PEAR/ezc/ConsoleTools/options/output.php | 111 + .../ezc/ConsoleTools/options/progressbar.php | 127 + .../ConsoleTools/options/progressmonitor.php | 57 + .../ConsoleTools/options/question_dialog.php | 96 + .../ezc/ConsoleTools/options/statusbar.php | 61 + .../PEAR/ezc/ConsoleTools/options/table.php | 199 + .../phpunit/PEAR/ezc/ConsoleTools/output.php | 580 ++ .../PEAR/ezc/ConsoleTools/progressbar.php | 462 ++ .../PEAR/ezc/ConsoleTools/progressmonitor.php | 215 + .../PEAR/ezc/ConsoleTools/statusbar.php | 261 + .../ezc/ConsoleTools/structs/option_rule.php | 167 + .../ConsoleTools/structs/output_format.php | 186 + .../ConsoleTools/structs/output_formats.php | 181 + .../phpunit/PEAR/ezc/ConsoleTools/table.php | 875 +++ .../PEAR/ezc/ConsoleTools/table/cell.php | 152 + .../PEAR/ezc/ConsoleTools/table/row.php | 372 ++ .../PEAR/ezc/ConsoleTools/tools/string.php | 184 + .../PEAR/ezc/autoload/base_autoload.php | 47 + .../PEAR/ezc/autoload/console_autoload.php | 76 + .../ext/phpunit/PEAR/vfsStream/vfsStream.php | 191 + .../vfsStream/vfsStreamAbstractContent.php | 323 ++ .../PEAR/vfsStream/vfsStreamContainer.php | 53 + .../vfsStream/vfsStreamContainerIterator.php | 89 + .../PEAR/vfsStream/vfsStreamContent.php | 194 + .../PEAR/vfsStream/vfsStreamDirectory.php | 212 + .../PEAR/vfsStream/vfsStreamException.php | 17 + .../phpunit/PEAR/vfsStream/vfsStreamFile.php | 203 + .../PEAR/vfsStream/vfsStreamWrapper.php | 681 +++ .../Private/Language/locallang_backend.xml | 172 + .../Private/Language/locallang_report.xml | 95 + .../phpunit/Resources/Public/CSS/BackEnd.css | 214 + .../Resources/Public/Icons/BackEndModule.gif | Bin 0 -> 563 bytes .../phpunit/Resources/Public/Icons/Runner.gif | Bin 0 -> 960 bytes .../Resources/Public/Icons/RunnerRunning.gif | Bin 0 -> 839 bytes .../phpunit/Resources/Public/Icons/Typo3.png | Bin 0 -> 712 bytes .../Resources/Public/JavaScript/BackEnd.js | 205 + .../phpunit/Resources/Public/YUI/base-min.css | 7 + .../Resources/Public/YUI/connection-min.js | 8 + .../phpunit/Resources/Public/YUI/json-min.js | 7 + .../Public/YUI/reset-fonts-grids.css | 7 + .../Resources/Public/YUI/yahoo-dom-event.js | 13 + .../ext/phpunit/Tests/BackEnd/AjaxTest.php | 244 + .../Fixtures/AnotherDataProviderTest.php | 81 + .../BackEnd/Fixtures/DataProviderTest.php | 81 + .../phpunit/Tests/BackEnd/Fixtures/LoadMe.php | 3 + .../Tests/BackEnd/Fixtures/LoadMeToo.php | 3 + .../ext/phpunit/Tests/BackEnd/ModuleTest.php | 767 +++ .../Tests/BackEnd/TestListenerTest.php | 930 ++++ .../Tests/Database/Fixtures/DataSet.xml | 22 + .../phpunit/Tests/Database/TestCaseTest.php | 269 + .../phpunit/Tests/Exception/DatabaseTest.php | 43 + .../Tests/Exception/EmptyQueryResultTest.php | 83 + .../Tests/Exception/NoTestsDirectoryTest.php | 43 + .../Fixtures/Extensions/aaa/ext_emconf.php | 44 + .../Fixtures/Extensions/aaa/ext_icon.gif | Bin 0 -> 630 bytes .../Fixtures/Extensions/aaa/ext_tables.php | 22 + .../Fixtures/Extensions/aaa/ext_tables.sql | 15 + .../Extensions/aaa/icon_tx_aaa_test.gif | Bin 0 -> 135 bytes .../Fixtures/Extensions/aaa/locallang_db.xml | 12 + .../Tests/Fixtures/Extensions/aaa/tca.php | 27 + .../Fixtures/Extensions/bbb/ext_emconf.php | 45 + .../Fixtures/Extensions/bbb/ext_icon.gif | Bin 0 -> 630 bytes .../Fixtures/Extensions/bbb/ext_tables.php | 39 + .../Fixtures/Extensions/bbb/ext_tables.sql | 24 + .../Extensions/bbb/icon_tx_bbb_test.gif | Bin 0 -> 135 bytes .../Fixtures/Extensions/bbb/locallang_db.xml | 13 + .../Tests/Fixtures/Extensions/bbb/tca.php | 27 + .../Fixtures/Extensions/ccc/ext_emconf.php | 45 + .../Fixtures/Extensions/ccc/ext_icon.gif | Bin 0 -> 630 bytes .../Fixtures/Extensions/ccc/ext_tables.php | 42 + .../Fixtures/Extensions/ccc/ext_tables.sql | 51 + .../Extensions/ccc/icon_tx_ccc_data.gif | Bin 0 -> 135 bytes .../Extensions/ccc/icon_tx_ccc_test.gif | Bin 0 -> 135 bytes .../Fixtures/Extensions/ccc/locallang_db.xml | 13 + .../Tests/Fixtures/Extensions/ccc/tca.php | 75 + .../Fixtures/Extensions/ddd/ext_emconf.php | 45 + .../Fixtures/Extensions/ddd/ext_icon.gif | Bin 0 -> 630 bytes .../Fixtures/Extensions/ddd/ext_tables.php | 22 + .../Fixtures/Extensions/ddd/ext_tables.sql | 15 + .../Extensions/ddd/icon_tx_ddd_test.gif | Bin 0 -> 135 bytes .../Fixtures/Extensions/ddd/locallang_db.xml | 12 + .../Tests/Fixtures/Extensions/ddd/tca.php | 27 + .../user_phpunittest/ext_emconf.php | 46 + .../Extensions/user_phpunittest/ext_icon.gif | Bin 0 -> 630 bytes .../user_phpunittest/ext_tables.php | 24 + .../user_phpunittest/ext_tables.sql | 37 + .../icon_user_oelibtest_test.gif | Bin 0 -> 135 bytes .../user_phpunittest/locallang_db.xml | 13 + .../Extensions/user_phpunittest/tca.php | 64 + .../user_phpunittest2/ext_emconf.php | 46 + .../Extensions/user_phpunittest2/ext_icon.gif | Bin 0 -> 630 bytes .../user_phpunittest2/ext_tables.php | 24 + .../user_phpunittest2/ext_tables.sql | 31 + .../icon_user_oelibtest2_test.gif | Bin 0 -> 652 bytes .../user_phpunittest2/locallang_db.xml | 13 + .../Extensions/user_phpunittest2/tca.php | 64 + .../ext/phpunit/Tests/Fixtures/LoadMe.php | 3 + typo3conf/ext/phpunit/Tests/Fixtures/test.png | Bin 0 -> 158 bytes typo3conf/ext/phpunit/Tests/FrameworkTest.php | 4772 +++++++++++++++++ .../phpunit/Tests/Selenium/TestCaseTest.php | 265 + .../phpunit/Tests/Service/DatabaseTest.php | 1519 ++++++ .../Service/Fixtures/NonPhpFiles/test.txt | 1 + .../Service/Fixtures/NonTestFiles/Nothing.php | 2 + .../Tests/Service/Fixtures/OneTest.php | 2 + .../Fixtures/Subfolder/AnotherTest.php | 2 + .../phpunit/Tests/Service/Fixtures/XTest.php | 2 + .../phpunit/Tests/Service/TestFinderTest.php | 1041 ++++ typo3conf/ext/phpunit/Tests/TestCaseTest.php | 54 + .../ext/phpunit/Tests/TestableCodeTest.php | 329 ++ typo3conf/ext/phpunit/Tests/VfsStreamTest.php | 78 + .../phpunit/Tests/tx_phpunit_testsuite.php | 41 + .../class.tx_phpunit_database_testcase.php | 6 + .../class.tx_phpunit_selenium_testcase.php | 6 + .../ext/phpunit/class.tx_phpunit_testcase.php | 6 + .../ext/phpunit/doc/Framework/annotated.html | 43 + typo3conf/ext/phpunit/doc/Framework/bc_s.png | Bin 0 -> 677 bytes .../class_tx___phpunit___framework.html | 2139 ++++++++ .../class_tx___phpunit___test_case.html | 76 + .../class_tx___phpunit___testable_code.html | 462 ++ .../ext/phpunit/doc/Framework/classes.html | 42 + .../ext/phpunit/doc/Framework/closed.png | Bin 0 -> 126 bytes .../ext/phpunit/doc/Framework/deprecated.html | 36 + .../ext/phpunit/doc/Framework/doxygen.css | 656 +++ .../ext/phpunit/doc/Framework/doxygen.png | Bin 0 -> 3942 bytes .../ext/phpunit/doc/Framework/functions.html | 358 ++ .../phpunit/doc/Framework/functions_func.html | 358 ++ .../ext/phpunit/doc/Framework/index.html | 32 + .../doc/Framework/namespace_t_y_p_o3.html | 62 + .../ext/phpunit/doc/Framework/namespaces.html | 39 + typo3conf/ext/phpunit/doc/Framework/nav_f.png | Bin 0 -> 159 bytes typo3conf/ext/phpunit/doc/Framework/nav_h.png | Bin 0 -> 97 bytes typo3conf/ext/phpunit/doc/Framework/open.png | Bin 0 -> 118 bytes .../ext/phpunit/doc/Framework/pages.html | 35 + typo3conf/ext/phpunit/doc/Framework/tab_a.png | Bin 0 -> 140 bytes typo3conf/ext/phpunit/doc/Framework/tab_b.png | Bin 0 -> 178 bytes typo3conf/ext/phpunit/doc/Framework/tab_h.png | Bin 0 -> 192 bytes typo3conf/ext/phpunit/doc/Framework/tab_s.png | Bin 0 -> 189 bytes typo3conf/ext/phpunit/doc/Framework/tabs.css | 59 + typo3conf/ext/phpunit/doc/manual.sxw | Bin 0 -> 96971 bytes typo3conf/ext/phpunit/ext_autoload.php | 32 + typo3conf/ext/phpunit/ext_conf_template.txt | 14 + typo3conf/ext/phpunit/ext_emconf.php | 48 + typo3conf/ext/phpunit/ext_icon.gif | Bin 0 -> 630 bytes typo3conf/ext/phpunit/ext_localconf.php | 26 + typo3conf/ext/phpunit/ext_tables.php | 52 + typo3conf/ext/phpunit/ext_tables.sql | 120 + typo3conf/localconf.php | 55 + 949 files changed, 196000 insertions(+) create mode 100644 README create mode 100644 dbimport/cli_users.sql create mode 100644 dbimport/introduction.sql create mode 100644 typo3conf/ext/phpunit/Changelog create mode 100644 typo3conf/ext/phpunit/Classes/BackEnd/Ajax.php create mode 100644 typo3conf/ext/phpunit/Classes/BackEnd/Module.php create mode 100644 typo3conf/ext/phpunit/Classes/BackEnd/TestListener.php create mode 100644 typo3conf/ext/phpunit/Classes/BackEnd/conf.php create mode 100644 typo3conf/ext/phpunit/Classes/BackEnd/index.php create mode 100644 typo3conf/ext/phpunit/Classes/Cli/TestRunner.php create mode 100644 typo3conf/ext/phpunit/Classes/Database/TestCase.php create mode 100644 typo3conf/ext/phpunit/Classes/Exception/Database.php create mode 100644 typo3conf/ext/phpunit/Classes/Exception/EmptyQueryResult.php create mode 100644 typo3conf/ext/phpunit/Classes/Exception/NoTestsDirectory.php create mode 100644 typo3conf/ext/phpunit/Classes/Framework.php create mode 100644 typo3conf/ext/phpunit/Classes/Interface/FrameworkCleanupHook.php create mode 100644 typo3conf/ext/phpunit/Classes/Reports/Status.php create mode 100644 typo3conf/ext/phpunit/Classes/Selenium/TestCase.php create mode 100644 typo3conf/ext/phpunit/Classes/Service/Database.php create mode 100644 typo3conf/ext/phpunit/Classes/Service/TestFinder.php create mode 100644 typo3conf/ext/phpunit/Classes/TestCase.php create mode 100644 typo3conf/ext/phpunit/Classes/TestableCode.php create mode 100644 typo3conf/ext/phpunit/Configuration/TCA/TCA.php create mode 100644 typo3conf/ext/phpunit/PEAR/Archive/Tar.php create mode 100644 typo3conf/ext/phpunit/PEAR/Cache/Lite.php create mode 100644 typo3conf/ext/phpunit/PEAR/Cache/Lite/File.php create mode 100644 typo3conf/ext/phpunit/PEAR/Cache/Lite/Function.php create mode 100644 typo3conf/ext/phpunit/PEAR/Cache/Lite/Output.php create mode 100644 typo3conf/ext/phpunit/PEAR/Console/Getopt.php create mode 100644 typo3conf/ext/phpunit/PEAR/File/Iterator.php create mode 100644 typo3conf/ext/phpunit/PEAR/File/Iterator/Factory.php create mode 100644 typo3conf/ext/phpunit/PEAR/OS/Guess.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Autoloader.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Builder.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/ChannelFile.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/ChannelFile/Parser.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Auth.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Auth.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Build.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Build.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Channels.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Channels.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Common.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Config.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Config.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Install.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Install.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Mirror.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Mirror.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Package.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Package.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Pickle.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Pickle.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Registry.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Registry.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Remote.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Remote.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Test.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Command/Test.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Common.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Config.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Dependency2.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/DependencyDB.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Downloader.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Downloader/Package.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/ErrorStack.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Exception.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/FixPHP5PEARWarnings.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Frontend.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Frontend/CLI.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Cfg.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Cfg.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Common.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Data.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Data.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Doc.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Doc.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Ext.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Ext.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Php.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Php.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Script.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Script.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Src.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Src.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Test.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Test.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Www.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Www.xml create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/PackageFile.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/Generator/v1.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/Generator/v2.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/Parser/v1.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/Parser/v2.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v1.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v2.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v2/Validator.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v2/rw.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Packager.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/REST.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/REST/10.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/REST/11.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/REST/13.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Registry.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/RunTest.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Task/Common.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Task/Postinstallscript.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Task/Postinstallscript/rw.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Task/Replace.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Task/Replace/rw.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Task/Unixeol.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Task/Unixeol/rw.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Task/Windowseol.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Task/Windowseol/rw.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Validate.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/Validator/PECL.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR/XMLParser.php create mode 100644 typo3conf/ext/phpunit/PEAR/PEAR5.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Driver.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Driver/Xdebug.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Filter.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/Clover.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node/Directory.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node/File.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node/Iterator.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.bar.js create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.common.core.js create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.common.tooltips.js create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.scatter.js create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/butter.png create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/chameleon.png create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/close12_1.gif create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/container-min.js create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/container.css create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/dashboard.html.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/directory.html.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/directory.png create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/directory_item.html.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/excanvas.compressed.js create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/file.html.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/file.png create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/file_item.html.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/file_no_yui.html.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/glass.png create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/method_item.html.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/scarlet_red.png create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/snow.png create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/style.css create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/yahoo-dom-event.js create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/yui_item.js create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/TextUI/Command.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Util.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/Timer.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/Token.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/Token/Exception.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/Token/Stream.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/Token/Stream/CachingFactory.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHP/Token/Stream/TextUI/Command.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Autoload.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/AbstractTester.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Constraint/DataSetIsEqual.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Constraint/TableIsEqual.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/DataSet.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/DefaultDatabaseConnection.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/FilteredDataSet.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/IDatabaseConnection.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/IMetaData.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/InformationSchema.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/MySQL.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/Oci.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/PgSQL.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/Sqlite.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/ResultSetTable.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/Table.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/TableIterator.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/TableMetaData.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractDataSet.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractTable.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractTableMetaData.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractXmlDataSet.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/CompositeDataSet.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/CsvDataSet.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DataSetFilter.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultDataSet.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultTable.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultTableIterator.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultTableMetaData.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/FlatXmlDataSet.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/IDataSet.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/IPersistable.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ISpec.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ITable.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ITableIterator.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ITableMetaData.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/MysqlXmlDataSet.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Abstract.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Factory.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/FlatXml.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/MysqlXml.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Xml.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Yaml.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/QueryDataSet.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/QueryTable.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ReplacementDataSet.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ReplacementTable.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ReplacementTableIterator.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Csv.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/DbQuery.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/DbTable.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Factory.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/FlatXml.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/IFactory.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Xml.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Yaml.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/TableFilter.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/TableMetaDataFilter.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/XmlDataSet.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/YamlDataSet.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DefaultTester.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/IDatabaseListConsumer.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/ITester.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Composite.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Delete.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/DeleteAll.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Exception.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Factory.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/IDatabaseOperation.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Insert.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Null.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Replace.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/RowBased.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Truncate.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Update.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/TestCase.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Command.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Context.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IMedium.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IMediumPrinter.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IMode.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IModeFactory.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/InvalidModeException.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Mediums/Text.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/ModeFactory.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Modes/ExportDataSet.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Modes/ExportDataSet/Arguments.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/GroupTestSuite.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/OutputTestCase.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/PhptTestCase.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/PhptTestCase/Logger.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/PhptTestSuite.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/RepeatedTest.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/Driver.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/append.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/phpunit_coverage.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/prepend.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Given.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/HTML.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/scenario.html.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/scenario_header.html.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/scenarios.html.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/step.html.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Text.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Scenario.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/SeleniumTestCase.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Step.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/TestCase.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Then.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/When.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TestDecorator.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener/GitHub.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener/GoogleCode.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener/Trac.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Assert.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Assert/Functions.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/AssertionFailedError.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Array.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Object.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Scalar.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/String.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Type.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/And.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ArrayHasKey.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Attribute.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ClassHasAttribute.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ClassHasStaticAttribute.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/FileExists.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/GreaterThan.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsAnything.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsEmpty.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsEqual.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsFalse.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsIdentical.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsInstanceOf.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsNull.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsTrue.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsType.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/LessThan.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Not.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ObjectHasAttribute.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Or.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/PCREMatch.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringContains.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringEndsWith.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringMatches.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringStartsWith.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/TraversableContains.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/TraversableContainsOnly.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Xor.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Error.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Error/Notice.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Error/Warning.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Exception.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ExpectationFailedException.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/IncompleteTest.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/IncompleteTestError.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Identity.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/InvocationMocker.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Match.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/MethodNameMatch.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Namespace.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/ParametersMatch.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Stub.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_class.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_clone.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_object_method.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_static_method.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/unmocked_clone.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/wsdl_class.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/wsdl_method.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invocation.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invocation/Object.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invocation/Static.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/InvocationMocker.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invokable.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/AnyInvokedCount.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/AnyParameters.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/Invocation.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedAtIndex.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedAtLeastOnce.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedCount.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedRecorder.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/MethodName.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/Parameters.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/StatelessInvocation.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/MockBuilder.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/MockObject.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/ConsecutiveCalls.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/Exception.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/MatcherCollection.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/Return.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/ReturnArgument.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/ReturnCallback.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Verifiable.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Process/TestCaseMethod.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SelfDescribing.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SkippedTest.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SkippedTestError.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SkippedTestSuiteError.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SyntheticError.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Test.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestCase.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestFailure.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestListener.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestResult.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestSuite.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestSuite/DataProvider.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Warning.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/BaseTestRunner.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/IncludePathTestCollector.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/StandardTestSuiteLoader.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/TestCollector.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/TestSuiteLoader.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/Version.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/TextUI/Command.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/TextUI/ResultPrinter.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/TextUI/TestRunner.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Class.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Configuration.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/DeprecatedFeature.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/DeprecatedFeature/Logger.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Diff.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/ErrorHandler.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/File.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Fileloader.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Filesystem.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Filter.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Getopt.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/GlobalState.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/InvalidArgumentHelper.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/DBUS.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/JSON.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/JUnit.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/TAP.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/XHProf.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/PHP.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/PHP/Default.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/PHP/Windows.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Printer.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Class.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/Class.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/IncompleteTestMethod.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/Method.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestClass.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethod.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodBool.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodBoolStatic.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodException.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodExceptionStatic.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodStatic.tpl.dist create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Test.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Test.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/NamePrettifier.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/ResultPrinter.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/ResultPrinter/HTML.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/ResultPrinter/Text.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestSuiteIterator.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Type.php create mode 100644 typo3conf/ext/phpunit/PEAR/PHPUnit/Util/XML.php create mode 100644 typo3conf/ext/phpunit/PEAR/Structures/Graph.php create mode 100644 typo3conf/ext/phpunit/PEAR/Structures/Graph/Manipulator/AcyclicTest.php create mode 100644 typo3conf/ext/phpunit/PEAR/Structures/Graph/Manipulator/TopologicalSorter.php create mode 100644 typo3conf/ext/phpunit/PEAR/Structures/Graph/Node.php create mode 100644 typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYaml.php create mode 100644 typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYamlDumper.php create mode 100644 typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYamlInline.php create mode 100644 typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYamlParser.php create mode 100644 typo3conf/ext/phpunit/PEAR/System.php create mode 100644 typo3conf/ext/phpunit/PEAR/Text/Template.php create mode 100644 typo3conf/ext/phpunit/PEAR/Text/Template/Autoload.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Client.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Request.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Response.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Server.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Array.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Base64.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Boolean.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Datetime.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Double.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Integer.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Integer64.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Nil.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Scalar.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/String.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Struct.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Xmlrpcext/Client.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Xmlrpcext/Server.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Xmlrpcext/Value.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/CachedClient.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/CachedServer.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Client.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/ClientHelper.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Exception.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Server.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/CallHandler.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/CallHandler/Class.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/CallHandler/Instance.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Input.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Input/PhpInput.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Input/RawPostData.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Method.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Util/HTTPRequest.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/RPC2/Value.php create mode 100644 typo3conf/ext/phpunit/PEAR/XML/Util.php create mode 100644 typo3conf/ext/phpunit/PEAR/data/Base/design/class_diagram.png create mode 100644 typo3conf/ext/phpunit/PEAR/data/Base/design/design.txt create mode 100644 typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/class_diagram.png create mode 100644 typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/console.png create mode 100644 typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/console.xml create mode 100644 typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/console_parameters.png create mode 100644 typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/design-1.3.txt create mode 100644 typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/design.txt create mode 100644 typo3conf/ext/phpunit/PEAR/data/PEAR/package.dtd create mode 100644 typo3conf/ext/phpunit/PEAR/data/PEAR/template.spec create mode 100644 typo3conf/ext/phpunit/PEAR/data/Structures_Graph/LICENSE create mode 100644 typo3conf/ext/phpunit/PEAR/data/XML_RPC2/Makefile create mode 100644 typo3conf/ext/phpunit/PEAR/data/vfsStream/LICENSE create mode 100644 typo3conf/ext/phpunit/PEAR/data/vfsStream/VERSION create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Archive_Tar/docs/Archive_Tar.txt create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Base/docs/CREDITS create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Base/docs/LICENSE create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/Me/myclass1.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/Me/myclass2.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/You/yourclass1.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/You/yourclass2.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/autoloads/my_autoload.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/autoloads/your_autoload.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial.txt create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_autoload.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_01.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_02.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_03.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_04.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_lazy_initialization.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/LICENSE create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/TODO create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/docs/examples create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/docs/technical create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/tests/readme create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/CREDITS create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/LICENSE create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_input.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_menu_dialog_full.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_output.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_progressbar.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_progressmonitor.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_question_dialog_collection_full.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_question_dialog_factory_yesno.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_question_dialog_type_full.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_statusbar.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_table.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_table_2.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_06.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_07.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_08.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_09.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_10.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial.txt create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_autoload.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_01_output_basic.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_02_output_advanced.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_03_output_options.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_04_input_basic.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_05_input_advanced.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_06_progressbar_basic.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_07_progressbar_advanced.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_08_statusbar.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_09_table_basic.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_10_table_advanced.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_11_progressmonitor.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_12_input_arguments.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_13_dialog_question.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_14_dialog_yesnoquestion.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_15_dialog_menu.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_output_targets.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/DbUnit/ChangeLog.markdown create mode 100644 typo3conf/ext/phpunit/PEAR/docs/DbUnit/LICENSE create mode 100644 typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/BankAccount.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/BankAccountDBTest.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/BankAccountDBTestMySQL.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-after-deposits.xml create mode 100644 typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-after-new-account.xml create mode 100644 typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-after-withdrawals.xml create mode 100644 typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-seed.xml create mode 100644 typo3conf/ext/phpunit/PEAR/docs/PEAR/INSTALL create mode 100644 typo3conf/ext/phpunit/PEAR/docs/PEAR/LICENSE create mode 100644 typo3conf/ext/phpunit/PEAR/docs/PEAR/README create mode 100644 typo3conf/ext/phpunit/PEAR/docs/PHPUnit/ChangeLog.markdown create mode 100644 typo3conf/ext/phpunit/PEAR/docs/PHPUnit/LICENSE create mode 100644 typo3conf/ext/phpunit/PEAR/docs/PHPUnit/README.markdown create mode 100644 typo3conf/ext/phpunit/PEAR/docs/PHPUnit_MockObject/ChangeLog.markdown create mode 100644 typo3conf/ext/phpunit/PEAR/docs/PHPUnit_MockObject/LICENSE create mode 100644 typo3conf/ext/phpunit/PEAR/docs/PHPUnit_Selenium/ChangeLog.markdown create mode 100644 typo3conf/ext/phpunit/PEAR/docs/PHPUnit_Selenium/LICENSE create mode 100644 typo3conf/ext/phpunit/PEAR/docs/PHP_CodeCoverage/ChangeLog.markdown create mode 100644 typo3conf/ext/phpunit/PEAR/docs/PHP_CodeCoverage/LICENSE create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/generate.sh create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Node.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Manipulator_AcyclicTest_php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Manipulator_TopologicalSorter_php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Node_php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/tutorial_Structures_Graph.pkg.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/classtrees_Structures_Graph.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/elementindex.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/elementindex_Structures_Graph.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/errors.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/index.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/li_Structures_Graph.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/media/banner.css create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/media/stylesheet.css create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/packages.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/todolist.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/tutorials/Structures_Graph/Structures_Graph.pkg create mode 100644 typo3conf/ext/phpunit/PEAR/docs/XML_RPC2/docs/tutorials/XML_RPC2.lyx create mode 100644 typo3conf/ext/phpunit/PEAR/docs/XML_Util/examples/example.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/XML_Util/examples/example2.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/YAML/LICENSE create mode 100644 typo3conf/ext/phpunit/PEAR/docs/YAML/README.markdown create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStream.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamAbstractContent.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamContainer.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamContainerIterator.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamContent.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamDirectory.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamException.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamFile.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamWrapper.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/blank.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStream.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamAbstractContent.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamContainer.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamContainerIterator.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamContent.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamDirectory.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamException.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamFile.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamWrapper.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStream.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamAbstractContent.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamContainer.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamContainerIterator.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamContent.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamDirectory.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamException.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamFile.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamWrapper.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/classtrees_bovigo_vfs.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/elementindex.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/elementindex_bovigo_vfs.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/errors.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/index.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/li_bovigo_vfs.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/banner.css create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractClass.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractClass_logo.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractMethod.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractPrivateClass.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractPrivateClass_logo.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractPrivateMethod.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Class.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Class_logo.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Constant.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Constructor.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Destructor.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Function.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Global.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/I.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Index.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Interface.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Interface_logo.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/L.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Lminus.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Lplus.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Method.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Page.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Page_logo.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/PrivateClass.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/PrivateClass_logo.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/PrivateMethod.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/PrivateVariable.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/StaticMethod.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/StaticVariable.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/T.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Tminus.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Tplus.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Variable.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/blank.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/class_folder.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/empty.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/file.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/folder.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/function_folder.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/minus.gif create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/next_button.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/next_button_disabled.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/package.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/package_folder.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/plus.gif create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/previous_button.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/previous_button_disabled.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/private_class_logo.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/tutorial.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/tutorial_folder.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/up_button.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/lib/classTree.js create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/stylesheet.css create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/packages.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/todolist.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/butter.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/chameleon.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/close12_1.gif create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/container-min.js create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/container.css create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/glass.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/index.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/scarlet_red.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/snow.png create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/style.css create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStream.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamAbstractContent.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamContainerIterator.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamDirectory.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamFile.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamWrapper.php.html create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/yahoo-dom-event.js create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/metrics.xml create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/pmd-cpd.xml create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/pmd.xml create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/Example.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/ExampleTestCaseOldWay.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/ExampleTestCaseWithVfsStream.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FailureExample.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FailureExampleTestCase.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FileModeExampleTestCaseOldWay.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilePermissionsExample.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilePermissionsExampleTestCase.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilemodeExample.php create mode 100644 typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilemodeExampleTestCaseWithVfsStream.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/base.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/base_autoload.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/autoload.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/double_class_repository_prefix.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/exception.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/extension_not_found.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_exception.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_io.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_not_found.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_permission.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/functionality_not_supported.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/init_callback_configured.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/invalid_callback_class.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/invalid_parent_class.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/property_not_found.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/property_permission.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/setting_not_found.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/setting_value.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/value.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/whatever.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/ezc_bootstrap.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/features.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/file.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/init.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/interfaces/configuration_initializer.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/interfaces/exportable.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/interfaces/persistable.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/metadata.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/metadata/pear.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/metadata/tarball.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/options.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/options/autoload.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/struct.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/structs/file_find_context.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/Base/structs/repository_directory.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/console_autoload.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/menu_dialog.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/question_dialog.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/menu_dialog_default.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_collection.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_mapping.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_regex.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_type.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog_viewer.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_already_registered.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_mandatory_violation.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_too_many.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_type_violation.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/dialog_abort.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/exception.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/invalid_option_name.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/invalid_output_target.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/no_position_stored.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/no_valid_dialog_result.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_already_registered.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_arguments_violation.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_dependency_violation.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_exclusion_violation.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_mandatory_violation.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_missing_value.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_no_alias.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_not_exists.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_string_not_wellformed.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_too_many_values.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_type_violation.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/argument.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/arguments.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/help_generators/standard.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/option.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/validators/standard.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/interfaces/dialog.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/interfaces/dialog_validator.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/interfaces/input_help_generator.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/interfaces/input_validator.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/interfaces/menu_dialog_validator.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/interfaces/question_dialog_validator.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/options/dialog.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/options/menu_dialog.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/options/output.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/options/progressbar.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/options/progressmonitor.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/options/question_dialog.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/options/statusbar.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/options/table.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/output.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/progressbar.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/progressmonitor.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/statusbar.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/structs/option_rule.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/structs/output_format.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/structs/output_formats.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/table.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/table/cell.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/table/row.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/tools/string.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/autoload/base_autoload.php create mode 100644 typo3conf/ext/phpunit/PEAR/ezc/autoload/console_autoload.php create mode 100644 typo3conf/ext/phpunit/PEAR/vfsStream/vfsStream.php create mode 100644 typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamAbstractContent.php create mode 100644 typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamContainer.php create mode 100644 typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamContainerIterator.php create mode 100644 typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamContent.php create mode 100644 typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamDirectory.php create mode 100644 typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamException.php create mode 100644 typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamFile.php create mode 100644 typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamWrapper.php create mode 100644 typo3conf/ext/phpunit/Resources/Private/Language/locallang_backend.xml create mode 100644 typo3conf/ext/phpunit/Resources/Private/Language/locallang_report.xml create mode 100644 typo3conf/ext/phpunit/Resources/Public/CSS/BackEnd.css create mode 100644 typo3conf/ext/phpunit/Resources/Public/Icons/BackEndModule.gif create mode 100644 typo3conf/ext/phpunit/Resources/Public/Icons/Runner.gif create mode 100644 typo3conf/ext/phpunit/Resources/Public/Icons/RunnerRunning.gif create mode 100644 typo3conf/ext/phpunit/Resources/Public/Icons/Typo3.png create mode 100644 typo3conf/ext/phpunit/Resources/Public/JavaScript/BackEnd.js create mode 100644 typo3conf/ext/phpunit/Resources/Public/YUI/base-min.css create mode 100644 typo3conf/ext/phpunit/Resources/Public/YUI/connection-min.js create mode 100644 typo3conf/ext/phpunit/Resources/Public/YUI/json-min.js create mode 100644 typo3conf/ext/phpunit/Resources/Public/YUI/reset-fonts-grids.css create mode 100644 typo3conf/ext/phpunit/Resources/Public/YUI/yahoo-dom-event.js create mode 100644 typo3conf/ext/phpunit/Tests/BackEnd/AjaxTest.php create mode 100644 typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/AnotherDataProviderTest.php create mode 100644 typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/DataProviderTest.php create mode 100644 typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/LoadMe.php create mode 100644 typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/LoadMeToo.php create mode 100644 typo3conf/ext/phpunit/Tests/BackEnd/ModuleTest.php create mode 100644 typo3conf/ext/phpunit/Tests/BackEnd/TestListenerTest.php create mode 100644 typo3conf/ext/phpunit/Tests/Database/Fixtures/DataSet.xml create mode 100644 typo3conf/ext/phpunit/Tests/Database/TestCaseTest.php create mode 100644 typo3conf/ext/phpunit/Tests/Exception/DatabaseTest.php create mode 100644 typo3conf/ext/phpunit/Tests/Exception/EmptyQueryResultTest.php create mode 100644 typo3conf/ext/phpunit/Tests/Exception/NoTestsDirectoryTest.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/ext_emconf.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/ext_icon.gif create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/ext_tables.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/ext_tables.sql create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/icon_tx_aaa_test.gif create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/locallang_db.xml create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/tca.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/ext_emconf.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/ext_icon.gif create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/ext_tables.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/ext_tables.sql create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/icon_tx_bbb_test.gif create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/locallang_db.xml create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/tca.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/ext_emconf.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/ext_icon.gif create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/ext_tables.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/ext_tables.sql create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/icon_tx_ccc_data.gif create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/icon_tx_ccc_test.gif create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/locallang_db.xml create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/tca.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/ext_emconf.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/ext_icon.gif create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/ext_tables.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/ext_tables.sql create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/icon_tx_ddd_test.gif create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/locallang_db.xml create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/tca.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/ext_emconf.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/ext_icon.gif create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/ext_tables.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/ext_tables.sql create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/icon_user_oelibtest_test.gif create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/locallang_db.xml create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/tca.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/ext_emconf.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/ext_icon.gif create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/ext_tables.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/ext_tables.sql create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/icon_user_oelibtest2_test.gif create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/locallang_db.xml create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/tca.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/LoadMe.php create mode 100644 typo3conf/ext/phpunit/Tests/Fixtures/test.png create mode 100644 typo3conf/ext/phpunit/Tests/FrameworkTest.php create mode 100644 typo3conf/ext/phpunit/Tests/Selenium/TestCaseTest.php create mode 100644 typo3conf/ext/phpunit/Tests/Service/DatabaseTest.php create mode 100644 typo3conf/ext/phpunit/Tests/Service/Fixtures/NonPhpFiles/test.txt create mode 100644 typo3conf/ext/phpunit/Tests/Service/Fixtures/NonTestFiles/Nothing.php create mode 100644 typo3conf/ext/phpunit/Tests/Service/Fixtures/OneTest.php create mode 100644 typo3conf/ext/phpunit/Tests/Service/Fixtures/Subfolder/AnotherTest.php create mode 100644 typo3conf/ext/phpunit/Tests/Service/Fixtures/XTest.php create mode 100644 typo3conf/ext/phpunit/Tests/Service/TestFinderTest.php create mode 100644 typo3conf/ext/phpunit/Tests/TestCaseTest.php create mode 100644 typo3conf/ext/phpunit/Tests/TestableCodeTest.php create mode 100644 typo3conf/ext/phpunit/Tests/VfsStreamTest.php create mode 100644 typo3conf/ext/phpunit/Tests/tx_phpunit_testsuite.php create mode 100644 typo3conf/ext/phpunit/class.tx_phpunit_database_testcase.php create mode 100644 typo3conf/ext/phpunit/class.tx_phpunit_selenium_testcase.php create mode 100644 typo3conf/ext/phpunit/class.tx_phpunit_testcase.php create mode 100644 typo3conf/ext/phpunit/doc/Framework/annotated.html create mode 100644 typo3conf/ext/phpunit/doc/Framework/bc_s.png create mode 100644 typo3conf/ext/phpunit/doc/Framework/class_tx___phpunit___framework.html create mode 100644 typo3conf/ext/phpunit/doc/Framework/class_tx___phpunit___test_case.html create mode 100644 typo3conf/ext/phpunit/doc/Framework/class_tx___phpunit___testable_code.html create mode 100644 typo3conf/ext/phpunit/doc/Framework/classes.html create mode 100644 typo3conf/ext/phpunit/doc/Framework/closed.png create mode 100644 typo3conf/ext/phpunit/doc/Framework/deprecated.html create mode 100644 typo3conf/ext/phpunit/doc/Framework/doxygen.css create mode 100644 typo3conf/ext/phpunit/doc/Framework/doxygen.png create mode 100644 typo3conf/ext/phpunit/doc/Framework/functions.html create mode 100644 typo3conf/ext/phpunit/doc/Framework/functions_func.html create mode 100644 typo3conf/ext/phpunit/doc/Framework/index.html create mode 100644 typo3conf/ext/phpunit/doc/Framework/namespace_t_y_p_o3.html create mode 100644 typo3conf/ext/phpunit/doc/Framework/namespaces.html create mode 100644 typo3conf/ext/phpunit/doc/Framework/nav_f.png create mode 100644 typo3conf/ext/phpunit/doc/Framework/nav_h.png create mode 100644 typo3conf/ext/phpunit/doc/Framework/open.png create mode 100644 typo3conf/ext/phpunit/doc/Framework/pages.html create mode 100644 typo3conf/ext/phpunit/doc/Framework/tab_a.png create mode 100644 typo3conf/ext/phpunit/doc/Framework/tab_b.png create mode 100644 typo3conf/ext/phpunit/doc/Framework/tab_h.png create mode 100644 typo3conf/ext/phpunit/doc/Framework/tab_s.png create mode 100644 typo3conf/ext/phpunit/doc/Framework/tabs.css create mode 100644 typo3conf/ext/phpunit/doc/manual.sxw create mode 100644 typo3conf/ext/phpunit/ext_autoload.php create mode 100644 typo3conf/ext/phpunit/ext_conf_template.txt create mode 100644 typo3conf/ext/phpunit/ext_emconf.php create mode 100644 typo3conf/ext/phpunit/ext_icon.gif create mode 100644 typo3conf/ext/phpunit/ext_localconf.php create mode 100644 typo3conf/ext/phpunit/ext_tables.php create mode 100644 typo3conf/ext/phpunit/ext_tables.sql create mode 100644 typo3conf/localconf.php diff --git a/README b/README new file mode 100644 index 0000000..cd03c38 --- /dev/null +++ b/README @@ -0,0 +1,2 @@ +This repo contains all files needed to integrate the TYPO3 into travis infrastructure + diff --git a/dbimport/cli_users.sql b/dbimport/cli_users.sql new file mode 100644 index 0000000..dc48d5c --- /dev/null +++ b/dbimport/cli_users.sql @@ -0,0 +1 @@ +INSERT INTO be_users (pid, tstamp, username, password, admin, usergroup, disable, starttime, endtime, lang, email) VALUES (0,1276860841,'_cli_phpunit','5f4dcc3b5aa765d61d8327deb882cf99',0,'1',0,0,0,'','_cli_phpunit@example.com'); diff --git a/dbimport/introduction.sql b/dbimport/introduction.sql new file mode 100644 index 0000000..e46465f --- /dev/null +++ b/dbimport/introduction.sql @@ -0,0 +1,2298 @@ +-- MySQL dump 10.13 Distrib 5.1.57, for apple-darwin11.0.0 (i386) +-- +-- Host: 127.0.0.1 Database: t3_ip46_integration +-- ------------------------------------------------------ +-- Server version 5.1.57 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `backend_layout` +-- + +DROP TABLE IF EXISTS backend_layout; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE backend_layout ( + uid int(11) NOT NULL AUTO_INCREMENT, + pid int(11) NOT NULL DEFAULT '0', + t3ver_oid int(11) NOT NULL DEFAULT '0', + t3ver_id int(11) NOT NULL DEFAULT '0', + t3ver_wsid int(11) NOT NULL DEFAULT '0', + t3ver_label varchar(255) DEFAULT NULL, + t3ver_state tinyint(4) NOT NULL DEFAULT '0', + t3ver_stage int(11) NOT NULL DEFAULT '0', + t3ver_count int(11) NOT NULL DEFAULT '0', + t3ver_tstamp int(11) NOT NULL DEFAULT '0', + t3ver_move_id int(11) NOT NULL DEFAULT '0', + t3_origuid int(11) NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + crdate int(11) unsigned NOT NULL DEFAULT '0', + cruser_id int(11) unsigned NOT NULL DEFAULT '0', + hidden tinyint(4) unsigned NOT NULL DEFAULT '0', + deleted tinyint(4) NOT NULL DEFAULT '0', + sorting int(11) unsigned NOT NULL DEFAULT '0', + title varchar(255) DEFAULT NULL, + description text NOT NULL, + config text NOT NULL, + icon text NOT NULL, + PRIMARY KEY (uid), + KEY parent (pid), + KEY t3ver_oid (t3ver_oid,t3ver_wsid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `backend_layout` +-- + +LOCK TABLES backend_layout WRITE; +/*!40000 ALTER TABLE backend_layout DISABLE KEYS */; +/*!40000 ALTER TABLE backend_layout ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `be_groups` +-- + +DROP TABLE IF EXISTS be_groups; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE be_groups ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + pid int(11) unsigned NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + title varchar(50) DEFAULT NULL, + non_exclude_fields text, + explicit_allowdeny text, + allowed_languages varchar(255) DEFAULT NULL, + custom_options text, + db_mountpoints varchar(255) DEFAULT NULL, + pagetypes_select varchar(255) DEFAULT NULL, + tables_select text, + tables_modify text, + crdate int(11) unsigned NOT NULL DEFAULT '0', + cruser_id int(11) unsigned NOT NULL DEFAULT '0', + groupMods text, + file_mountpoints varchar(255) DEFAULT NULL, + fileoper_perms tinyint(4) NOT NULL DEFAULT '0', + hidden tinyint(1) unsigned NOT NULL DEFAULT '0', + inc_access_lists tinyint(3) unsigned NOT NULL DEFAULT '0', + description text, + lockToDomain varchar(50) DEFAULT NULL, + deleted tinyint(1) unsigned NOT NULL DEFAULT '0', + TSconfig text, + subgroup varchar(255) DEFAULT NULL, + hide_in_lists tinyint(4) NOT NULL DEFAULT '0', + workspace_perms tinyint(3) NOT NULL DEFAULT '1', + tt_news_categorymounts varchar(255) DEFAULT NULL, + PRIMARY KEY (uid), + KEY parent (pid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `be_groups` +-- + +LOCK TABLES be_groups WRITE; +/*!40000 ALTER TABLE be_groups DISABLE KEYS */; +INSERT INTO be_groups (uid, pid, tstamp, title, non_exclude_fields, explicit_allowdeny, allowed_languages, custom_options, db_mountpoints, pagetypes_select, tables_select, tables_modify, crdate, cruser_id, groupMods, file_mountpoints, fileoper_perms, hidden, inc_access_lists, description, lockToDomain, deleted, TSconfig, subgroup, hide_in_lists, workspace_perms, tt_news_categorymounts) VALUES (1,0,1280259524,'Simple editors',NULL,'tt_content:CType:--div--:DENY,tt_content:CType:image:DENY,tt_content:CType:uploads:DENY,tt_content:CType:mailform:DENY,tt_content:CType:search:DENY,tt_content:CType:login:DENY,tt_content:CType:shortcut:DENY,tt_content:CType:list:DENY,tt_content:CType:script:DENY,tt_content:CType:html:DENY','',NULL,'4','1,4',NULL,'pages,tt_content',1258379735,2,'web,web_layout,web_view,user,user_task,user_setup','3',7,0,1,'The simple editors group demonstrates a handy and realistic set of permissions and options for every day backend users who simply manages content and pages. More detailed and advanced features are hidden for embers of this user group to give a more simple interface\r\n','',0,'','5',0,0,''),(2,0,1280415712,'Advanced editors','pages:doktype,pages:hidden,pages:starttime,pages:endtime,pages:fe_group,pages:nav_title,pages:nav_hide,pages:lastUpdated,pages:no_cache,pages:no_search,pages:shortcut_mode,pages:keywords,pages:description,pages:abstract,pages:author,pages:author_email,pages:media,pages:fe_login_mode,pages:l18n_cfg,tt_content:starttime,tt_content:endtime,tt_content:fe_group,tt_content:image_zoom,tt_content:image_effects,tt_content:image_compression,tt_content:linkToTop,tt_content:pi_flexform;login;sDEF;pages,tt_content:pi_flexform;9;s_misc;PIDitemDisplay,tt_content:pi_flexform;9;s_misc;backPid,tt_content:pi_flexform;9;s_misc;pages,tt_content:pi_flexform;9;s_misc;myTS',NULL,'',NULL,'1','1,4,3','','pages,tt_content,pages_language_overlay,sys_note,tt_news,tt_news_cat',1258379744,2,'web,web_layout,web_view,web_list,web_info,web_perm,web_func,user,user_task,user_setup','3,2,1',7,0,1,'The advanced editors user group, is an example implementation of a user group with a wide range of permissions and available options for making and editing an advanced set of features for pages and page content. The meta group \"All users\", which includes a basic configuration that can be applied to all user groups, is included as Sub Group below','',0,'','5,3',0,0,''),(3,0,1260570724,'News editors','tt_news_cat:fe_group,tt_news_cat:image,tt_news_cat:description,tt_news_cat:hidden,tt_news_cat:shortcut,tt_news_cat:parent_category,tt_news_cat:single_pid,tt_news_cat:starttime,tt_news_cat:endtime,tt_news_cat:shortcut_target,tt_news:archivedate,tt_news:author,tt_news:imagecaption,tt_news:category,tt_news:datetime,tt_news:news_files,tt_news:hidden,tt_news:imagealttext,tt_news:imagetitletext,tt_news:image,tt_news:keywords,tt_news:links,tt_news:related,tt_news:page,tt_news:starttime,tt_news:endtime,tt_news:short,tt_news:type',NULL,'',NULL,'18','','tt_news,tt_news_cat','tt_news,tt_news_cat',1258379753,2,'web_txttnewsM1','1',7,0,1,'The news editor group demonstrates the possibilities of fully narrowing down permissions and options for certain editors. Members of the news editor group only allows members of this group to add news records to the News folder.','',0,'','5',0,0,'1,3,2'),(4,0,1258640038,'Administrators',NULL,NULL,'',NULL,'','',NULL,NULL,1258379764,2,NULL,'',7,0,0,'Assign all administrators to this group, if you wish to make a special configuration for all administrators, like specific file mounts, backend configuraton etc.','',0,'','',0,0,''),(5,0,1260568202,'All users','tt_content:imagecaption_position,tt_content:imageborder,tt_content:image_zoom,tt_content:colPos,tt_content:date,tt_content:image_effects,tt_content:image_frames,tt_content:imageheight,tt_content:hidden,tt_content:image_compression,tt_content:sys_language_uid,tt_content:image_link,tt_content:starttime,tt_content:endtime,tt_content:subheader,tt_content:l18n_parent,tt_content:header_layout,tt_content:imagewidth,pages:abstract,pages:author,pages:description,pages:author_email,pages:nav_hide,pages:hidden,pages:keywords,pages:layout,pages:nav_title,pages:shortcut_mode,pages:starttime,pages:endtime,tt_content:pi_flexform;login;sDEF;pages,tt_content:pi_flexform;9;s_misc;pages,tt_content:pi_flexform;9;s_misc;PIDitemDisplay,tt_content:pi_flexform;9;s_misc;backPid,tt_content:pi_flexform;9;s_misc;myTS',NULL,'',NULL,'','','pages,tt_content','',1258381355,2,'web,file,file_list,user_task,user_setup','',7,0,1,'Basic configuration shared for all users. All other user groups can include this group as sub group to share a default set of permissions and options','',0,'','',0,0,''); +/*!40000 ALTER TABLE be_groups ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `be_sessions` +-- + +DROP TABLE IF EXISTS be_sessions; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE be_sessions ( + ses_id varchar(32) NOT NULL DEFAULT '', + ses_name varchar(32) NOT NULL DEFAULT '', + ses_iplock varchar(39) DEFAULT NULL, + ses_hashlock int(11) NOT NULL DEFAULT '0', + ses_userid int(11) unsigned NOT NULL DEFAULT '0', + ses_tstamp int(11) unsigned NOT NULL DEFAULT '0', + ses_data longtext, + ses_backuserid int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (ses_id,ses_name), + KEY ses_tstamp (ses_tstamp) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `be_sessions` +-- + +LOCK TABLES be_sessions WRITE; +/*!40000 ALTER TABLE be_sessions DISABLE KEYS */; +/*!40000 ALTER TABLE be_sessions ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `be_users` +-- + +DROP TABLE IF EXISTS be_users; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE be_users ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + pid int(11) unsigned NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + username varchar(50) DEFAULT NULL, + `password` varchar(60) NOT NULL DEFAULT '', + admin tinyint(4) unsigned NOT NULL DEFAULT '0', + usergroup varchar(255) DEFAULT NULL, + `disable` tinyint(1) unsigned NOT NULL DEFAULT '0', + starttime int(11) unsigned NOT NULL DEFAULT '0', + endtime int(11) unsigned NOT NULL DEFAULT '0', + lang char(2) DEFAULT NULL, + email varchar(80) DEFAULT NULL, + db_mountpoints varchar(255) DEFAULT NULL, + `options` tinyint(4) unsigned NOT NULL DEFAULT '0', + crdate int(11) unsigned NOT NULL DEFAULT '0', + cruser_id int(11) unsigned NOT NULL DEFAULT '0', + realName varchar(80) DEFAULT NULL, + userMods varchar(255) DEFAULT NULL, + allowed_languages varchar(255) DEFAULT NULL, + uc mediumtext, + file_mountpoints varchar(255) DEFAULT NULL, + fileoper_perms tinyint(4) NOT NULL DEFAULT '0', + workspace_perms tinyint(3) NOT NULL DEFAULT '1', + lockToDomain varchar(50) DEFAULT NULL, + disableIPlock tinyint(1) unsigned NOT NULL DEFAULT '0', + deleted tinyint(1) unsigned NOT NULL DEFAULT '0', + TSconfig text, + lastlogin int(10) unsigned NOT NULL DEFAULT '0', + createdByAction int(11) NOT NULL DEFAULT '0', + usergroup_cached_list varchar(255) DEFAULT NULL, + workspace_id int(11) NOT NULL DEFAULT '0', + workspace_preview tinyint(3) NOT NULL DEFAULT '1', + tt_news_categorymounts varchar(255) DEFAULT NULL, + PRIMARY KEY (uid), + KEY parent (pid), + KEY username (username) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `be_users` +-- + +LOCK TABLES be_users WRITE; +/*!40000 ALTER TABLE be_users DISABLE KEYS */; +INSERT INTO be_users (uid, pid, tstamp, username, password, admin, usergroup, disable, starttime, endtime, lang, email, db_mountpoints, options, crdate, cruser_id, realName, userMods, allowed_languages, uc, file_mountpoints, fileoper_perms, workspace_perms, lockToDomain, disableIPlock, deleted, TSconfig, lastlogin, createdByAction, usergroup_cached_list, workspace_id, workspace_preview, tt_news_categorymounts) VALUES (2,0,1276860841,'simple_editor','5f4dcc3b5aa765d61d8327deb882cf99',0,'1',0,0,0,'','username@example.com','',3,1258379847,1,'Simple McEditor','','','a:25:{s:14:\"interfaceSetup\";N;s:10:\"moduleData\";a:9:{s:12:\"alt_menu.php\";a:0:{}s:10:\"web_layout\";a:8:{s:8:\"tt_board\";s:1:\"0\";s:10:\"tt_address\";s:1:\"0\";s:8:\"tt_links\";s:1:\"0\";s:11:\"tt_calender\";s:1:\"0\";s:11:\"tt_products\";s:1:\"0\";s:8:\"function\";s:1:\"1\";s:8:\"language\";s:1:\"0\";s:7:\"tt_news\";s:1:\"0\";}s:16:\"xMOD_alt_doc.php\";a:1:{s:12:\"showPalettes\";s:2:\"on\";}s:11:\"alt_doc.php\";a:2:{i:0;a:3:{s:32:\"b2b752dec07f5af0d5985500ba0a1fbe\";a:4:{i:0;s:0:\"\";i:1;a:7:{s:4:\"edit\";a:1:{s:10:\"tt_content\";a:1:{i:27;s:4:\"edit\";}}s:7:\"defVals\";N;s:12:\"overrideVals\";N;s:11:\"columnsOnly\";N;s:7:\"disHelp\";N;s:6:\"noView\";N;s:24:\"editRegularContentFromId\";N;}i:2;s:105:\"&edit[tt_content][27]=edit&defVals=&overrideVals=&columnsOnly=&disHelp=&noView=&editRegularContentFromId=\";i:3;b:0;}s:32:\"08df4da8064a72474ca9e45e8894ce29\";a:4:{i:0;s:98:\"Multiple Layouts for Standard ...\";i:1;a:7:{s:4:\"edit\";a:1:{s:10:\"tt_content\";a:1:{i:186;s:4:\"edit\";}}s:7:\"defVals\";N;s:12:\"overrideVals\";N;s:11:\"columnsOnly\";N;s:7:\"disHelp\";N;s:6:\"noView\";N;s:24:\"editRegularContentFromId\";N;}i:2;s:106:\"&edit[tt_content][186]=edit&defVals=&overrideVals=&columnsOnly=&disHelp=&noView=&editRegularContentFromId=\";i:3;a:5:{s:5:\"table\";s:10:\"tt_content\";s:3:\"uid\";s:3:\"186\";s:3:\"pid\";s:2:\"37\";s:3:\"cmd\";s:4:\"edit\";s:12:\"deleteAccess\";i:1;}}s:32:\"67c9080398a17f01c52cb350d4fd67a8\";a:4:{i:0;s:0:\"\";i:1;a:7:{s:4:\"edit\";a:1:{s:10:\"tt_content\";a:1:{i:26;s:4:\"edit\";}}s:7:\"defVals\";N;s:12:\"overrideVals\";N;s:11:\"columnsOnly\";N;s:7:\"disHelp\";N;s:6:\"noView\";N;s:24:\"editRegularContentFromId\";N;}i:2;s:105:\"&edit[tt_content][26]=edit&defVals=&overrideVals=&columnsOnly=&disHelp=&noView=&editRegularContentFromId=\";i:3;b:0;}}i:1;s:32:\"67c9080398a17f01c52cb350d4fd67a8\";}s:29:\"t3lib_BEfunc::getUpdateSignal\";a:0:{}s:9:\"file_list\";a:0:{}s:8:\"web_list\";a:0:{}s:9:\"menuState\";a:1:{s:12:\"modmenu_file\";i:0;}s:16:\"opendocs::recent\";a:3:{s:32:\"03d0f3c3101c964862db62fe2f22400e\";a:4:{i:0;s:22:\"Powerful Form Handling\";i:1;a:7:{s:4:\"edit\";a:1:{s:10:\"tt_content\";a:1:{i:188;s:4:\"edit\";}}s:7:\"defVals\";N;s:12:\"overrideVals\";N;s:11:\"columnsOnly\";N;s:7:\"disHelp\";N;s:6:\"noView\";N;s:24:\"editRegularContentFromId\";N;}i:2;s:106:\"&edit[tt_content][188]=edit&defVals=&overrideVals=&columnsOnly=&disHelp=&noView=&editRegularContentFromId=\";i:3;a:5:{s:5:\"table\";s:10:\"tt_content\";s:3:\"uid\";s:3:\"188\";s:3:\"pid\";s:2:\"36\";s:3:\"cmd\";s:4:\"edit\";s:12:\"deleteAccess\";i:1;}}s:32:\"67c9080398a17f01c52cb350d4fd67a8\";a:4:{i:0;s:0:\"\";i:1;a:7:{s:4:\"edit\";a:1:{s:10:\"tt_content\";a:1:{i:26;s:4:\"edit\";}}s:7:\"defVals\";N;s:12:\"overrideVals\";N;s:11:\"columnsOnly\";N;s:7:\"disHelp\";N;s:6:\"noView\";N;s:24:\"editRegularContentFromId\";N;}i:2;s:105:\"&edit[tt_content][26]=edit&defVals=&overrideVals=&columnsOnly=&disHelp=&noView=&editRegularContentFromId=\";i:3;b:0;}s:32:\"9970344687dec2cd13fe6bd583f67c68\";a:4:{i:0;s:25:\"TYPO3 knows no boundaries\";i:1;a:7:{s:4:\"edit\";a:1:{s:10:\"tt_content\";a:1:{i:185;s:4:\"edit\";}}s:7:\"defVals\";N;s:12:\"overrideVals\";N;s:11:\"columnsOnly\";N;s:7:\"disHelp\";N;s:6:\"noView\";N;s:24:\"editRegularContentFromId\";N;}i:2;s:106:\"&edit[tt_content][185]=edit&defVals=&overrideVals=&columnsOnly=&disHelp=&noView=&editRegularContentFromId=\";i:3;a:5:{s:5:\"table\";s:10:\"tt_content\";s:3:\"uid\";s:3:\"185\";s:3:\"pid\";s:2:\"25\";s:3:\"cmd\";s:4:\"edit\";s:12:\"deleteAccess\";i:1;}}}}s:19:\"thumbnailsByDefault\";i:0;s:14:\"emailMeAtLogin\";i:0;s:13:\"condensedMode\";i:0;s:10:\"noMenuMode\";i:0;s:11:\"startModule\";s:17:\"help_aboutmodules\";s:18:\"hideSubmoduleIcons\";i:0;s:8:\"helpText\";i:1;s:8:\"titleLen\";i:30;s:17:\"edit_wideDocument\";s:1:\"0\";s:18:\"edit_showFieldHelp\";s:4:\"icon\";s:8:\"edit_RTE\";s:1:\"1\";s:20:\"edit_docModuleUpload\";s:1:\"1\";s:19:\"enableFlashUploader\";s:1:\"1\";s:15:\"disableCMlayers\";i:0;s:13:\"navFrameWidth\";s:0:\"\";s:17:\"navFrameResizable\";i:0;s:15:\"resizeTextareas\";i:1;s:25:\"resizeTextareas_MaxHeight\";i:300;s:24:\"resizeTextareas_Flexible\";i:1;s:4:\"lang\";s:0:\"\";s:15:\"moduleSessionID\";a:7:{s:10:\"web_layout\";s:32:\"29e40a3fd460aebd1ea92637c6f746b2\";s:16:\"xMOD_alt_doc.php\";s:32:\"bc14977d04f2d090085b481222031111\";s:11:\"alt_doc.php\";s:32:\"29e40a3fd460aebd1ea92637c6f746b2\";s:29:\"t3lib_BEfunc::getUpdateSignal\";s:32:\"29e40a3fd460aebd1ea92637c6f746b2\";s:9:\"file_list\";s:32:\"ebb483883d0bb287f13f505c11529766\";s:8:\"web_list\";s:32:\"ebb483883d0bb287f13f505c11529766\";s:16:\"opendocs::recent\";s:32:\"29e40a3fd460aebd1ea92637c6f746b2\";}s:11:\"browseTrees\";a:2:{s:11:\"browsePages\";s:32:\"a:1:{i:0;a:2:{i:1;i:1;i:4;i:1;}}\";s:6:\"folder\";s:36:\"a:1:{i:45849;a:1:{i:102439331;i:1;}}\";}s:19:\"firstLoginTimeStamp\";i:1276970161;}','',0,3,'',0,0,'',0,0,'5,1',0,1,''),(3,0,1276860818,'advanced_editor','5f4dcc3b5aa765d61d8327deb882cf99',0,'2',0,0,0,'','username@example.com','',3,1258379875,1,'Advanced McEditor','','','a:26:{s:14:\"interfaceSetup\";N;s:10:\"moduleData\";a:12:{s:12:\"alt_menu.php\";a:0:{}s:9:\"file_list\";a:0:{}s:10:\"web_layout\";a:8:{s:8:\"tt_board\";s:1:\"0\";s:10:\"tt_address\";s:1:\"0\";s:8:\"tt_links\";s:1:\"0\";s:11:\"tt_calender\";s:1:\"0\";s:11:\"tt_products\";s:1:\"0\";s:8:\"function\";s:1:\"1\";s:8:\"language\";s:1:\"0\";s:7:\"tt_news\";s:1:\"0\";}s:8:\"web_list\";a:1:{s:15:\"bigControlPanel\";s:1:\"1\";}s:16:\"xMOD_alt_doc.php\";a:1:{s:12:\"showPalettes\";s:2:\"on\";}s:11:\"alt_doc.php\";a:2:{i:0;a:1:{s:32:\"b2b752dec07f5af0d5985500ba0a1fbe\";a:4:{i:0;s:11:\"Latest news\";i:1;a:7:{s:4:\"edit\";a:1:{s:10:\"tt_content\";a:1:{i:27;s:4:\"edit\";}}s:7:\"defVals\";N;s:12:\"overrideVals\";N;s:11:\"columnsOnly\";N;s:7:\"disHelp\";N;s:6:\"noView\";N;s:24:\"editRegularContentFromId\";N;}i:2;s:105:\"&edit[tt_content][27]=edit&defVals=&overrideVals=&columnsOnly=&disHelp=&noView=&editRegularContentFromId=\";i:3;a:5:{s:5:\"table\";s:10:\"tt_content\";s:3:\"uid\";s:2:\"27\";s:3:\"pid\";s:2:\"23\";s:3:\"cmd\";s:4:\"edit\";s:12:\"deleteAccess\";i:1;}}}i:1;s:32:\"b2b752dec07f5af0d5985500ba0a1fbe\";}s:29:\"t3lib_BEfunc::getUpdateSignal\";a:0:{}s:8:\"web_perm\";a:2:{s:5:\"depth\";s:2:\"10\";s:4:\"mode\";s:5:\"perms\";}s:8:\"web_func\";a:3:{s:8:\"function\";s:22:\"tx_funcwizards_webfunc\";s:3:\"wiz\";s:28:\"tx_wizardsortpages_webfunc_2\";s:6:\"cr_333\";s:1:\"0\";}s:16:\"opendocs::recent\";a:2:{s:32:\"9970344687dec2cd13fe6bd583f67c68\";a:4:{i:0;s:25:\"TYPO3 knows no boundaries\";i:1;a:7:{s:4:\"edit\";a:1:{s:10:\"tt_content\";a:1:{i:185;s:4:\"edit\";}}s:7:\"defVals\";N;s:12:\"overrideVals\";N;s:11:\"columnsOnly\";N;s:7:\"disHelp\";N;s:6:\"noView\";N;s:24:\"editRegularContentFromId\";N;}i:2;s:106:\"&edit[tt_content][185]=edit&defVals=&overrideVals=&columnsOnly=&disHelp=&noView=&editRegularContentFromId=\";i:3;a:5:{s:5:\"table\";s:10:\"tt_content\";s:3:\"uid\";s:3:\"185\";s:3:\"pid\";s:2:\"25\";s:3:\"cmd\";s:4:\"edit\";s:12:\"deleteAccess\";i:1;}}s:32:\"2413c3fea06994ab817643b5dd9eab33\";a:4:{i:0;s:15:\"Text mit Bild 1\";i:1;a:7:{s:4:\"edit\";a:1:{s:10:\"tt_content\";a:1:{i:11;s:4:\"edit\";}}s:7:\"defVals\";N;s:12:\"overrideVals\";N;s:11:\"columnsOnly\";N;s:7:\"disHelp\";N;s:6:\"noView\";N;s:24:\"editRegularContentFromId\";N;}i:2;s:105:\"&edit[tt_content][11]=edit&defVals=&overrideVals=&columnsOnly=&disHelp=&noView=&editRegularContentFromId=\";i:3;a:5:{s:5:\"table\";s:10:\"tt_content\";s:3:\"uid\";s:2:\"11\";s:3:\"pid\";s:1:\"4\";s:3:\"cmd\";s:4:\"edit\";s:12:\"deleteAccess\";i:1;}}}s:16:\"web_txrecyclerM1\";a:1:{s:8:\"function\";s:0:\"\";}s:11:\"db_list.php\";a:1:{s:10:\"tt_content\";s:1:\"0\";}}s:19:\"thumbnailsByDefault\";i:0;s:14:\"emailMeAtLogin\";i:0;s:13:\"condensedMode\";i:0;s:10:\"noMenuMode\";i:0;s:11:\"startModule\";s:17:\"help_aboutmodules\";s:18:\"hideSubmoduleIcons\";i:0;s:8:\"helpText\";i:1;s:8:\"titleLen\";i:30;s:17:\"edit_wideDocument\";s:1:\"0\";s:18:\"edit_showFieldHelp\";s:4:\"icon\";s:8:\"edit_RTE\";s:1:\"1\";s:20:\"edit_docModuleUpload\";s:1:\"1\";s:19:\"enableFlashUploader\";s:1:\"1\";s:15:\"disableCMlayers\";i:0;s:13:\"navFrameWidth\";s:0:\"\";s:17:\"navFrameResizable\";i:0;s:15:\"resizeTextareas\";i:1;s:25:\"resizeTextareas_MaxHeight\";i:300;s:24:\"resizeTextareas_Flexible\";i:1;s:4:\"lang\";s:0:\"\";s:15:\"moduleSessionID\";a:10:{s:9:\"file_list\";s:32:\"7b3b01525b24e11f79225a7735293a91\";s:10:\"web_layout\";s:32:\"bc14977d04f2d090085b481222031111\";s:8:\"web_list\";s:32:\"a16818f1abd66b2d74b97b705f96bc2d\";s:16:\"xMOD_alt_doc.php\";s:32:\"bc14977d04f2d090085b481222031111\";s:11:\"alt_doc.php\";s:32:\"29e40a3fd460aebd1ea92637c6f746b2\";s:29:\"t3lib_BEfunc::getUpdateSignal\";s:32:\"29e40a3fd460aebd1ea92637c6f746b2\";s:8:\"web_perm\";s:32:\"ebb483883d0bb287f13f505c11529766\";s:8:\"web_func\";s:32:\"ebb483883d0bb287f13f505c11529766\";s:16:\"opendocs::recent\";s:32:\"bc14977d04f2d090085b481222031111\";s:16:\"web_txrecyclerM1\";s:32:\"ebb483883d0bb287f13f505c11529766\";}s:11:\"browseTrees\";a:2:{s:6:\"folder\";s:64:\"a:2:{i:49780;a:1:{i:28247455;i:1;}i:7076;a:1:{i:249015978;i:1;}}\";s:11:\"browsePages\";s:41:\"a:1:{i:0;a:3:{i:1;i:1;i:4;i:1;i:19;i:1;}}\";}s:11:\"tx_recycler\";a:2:{s:14:\"tableSelection\";s:5:\"pages\";s:14:\"depthSelection\";i:0;}s:19:\"firstLoginTimeStamp\";i:1276926761;}','',0,3,'',0,0,'',0,0,'5,2',0,1,''),(4,0,1276860831,'news_editor','5f4dcc3b5aa765d61d8327deb882cf99',0,'3',0,0,0,'','username@example.com','',3,1258379922,1,'News McEditor','','','a:25:{s:14:\"interfaceSetup\";N;s:10:\"moduleData\";a:13:{s:12:\"alt_menu.php\";a:0:{}s:10:\"web_layout\";a:7:{s:8:\"tt_board\";s:1:\"0\";s:10:\"tt_address\";s:1:\"0\";s:8:\"tt_links\";s:1:\"0\";s:11:\"tt_calender\";s:1:\"0\";s:11:\"tt_products\";s:1:\"0\";s:8:\"function\";s:1:\"1\";s:8:\"language\";s:1:\"0\";}s:8:\"web_list\";a:2:{s:15:\"bigControlPanel\";s:1:\"1\";s:9:\"clipBoard\";s:1:\"1\";}s:9:\"file_list\";a:1:{s:13:\"displayThumbs\";s:1:\"1\";}s:16:\"xMOD_alt_doc.php\";a:1:{s:12:\"showPalettes\";s:2:\"on\";}s:9:\"clipboard\";a:6:{s:6:\"normal\";a:2:{s:2:\"el\";a:1:{s:9:\"tt_news|1\";s:1:\"1\";}s:4:\"mode\";s:4:\"copy\";}s:5:\"tab_1\";a:1:{s:4:\"mode\";s:0:\"\";}s:5:\"tab_2\";a:0:{}s:5:\"tab_3\";a:0:{}s:7:\"current\";s:5:\"tab_1\";s:9:\"_setThumb\";N;}s:25:\"db_list.php/displayFields\";a:1:{s:7:\"tt_news\";a:1:{i:0;s:8:\"category\";}}s:11:\"alt_doc.php\";a:2:{i:0;a:0:{}i:1;s:32:\"b875728ae2a6095e921b7c49462c48fe\";}s:29:\"t3lib_BEfunc::getUpdateSignal\";a:0:{}s:16:\"opendocs::recent\";a:3:{s:32:\"b875728ae2a6095e921b7c49462c48fe\";a:4:{i:0;s:88:\"TYPO3 celebrates 20th annivers...\";i:1;a:7:{s:4:\"edit\";a:1:{s:7:\"tt_news\";a:1:{i:1;s:4:\"edit\";}}s:7:\"defVals\";N;s:12:\"overrideVals\";N;s:11:\"columnsOnly\";N;s:7:\"disHelp\";N;s:6:\"noView\";N;s:24:\"editRegularContentFromId\";N;}i:2;s:101:\"&edit[tt_news][1]=edit&defVals=&overrideVals=&columnsOnly=&disHelp=&noView=&editRegularContentFromId=\";i:3;a:5:{s:5:\"table\";s:7:\"tt_news\";s:3:\"uid\";s:1:\"1\";s:3:\"pid\";s:2:\"18\";s:3:\"cmd\";s:4:\"edit\";s:12:\"deleteAccess\";i:1;}}s:32:\"4f2e01240a842d54b044ec3f6ce982bd\";a:4:{i:0;s:22:\"Vivamus elementum dui \";i:1;a:7:{s:4:\"edit\";a:1:{s:7:\"tt_news\";a:1:{i:2;s:4:\"edit\";}}s:7:\"defVals\";N;s:12:\"overrideVals\";N;s:11:\"columnsOnly\";N;s:7:\"disHelp\";N;s:6:\"noView\";N;s:24:\"editRegularContentFromId\";N;}i:2;s:101:\"&edit[tt_news][2]=edit&defVals=&overrideVals=&columnsOnly=&disHelp=&noView=&editRegularContentFromId=\";i:3;a:5:{s:5:\"table\";s:7:\"tt_news\";s:3:\"uid\";s:1:\"2\";s:3:\"pid\";s:2:\"18\";s:3:\"cmd\";s:4:\"edit\";s:12:\"deleteAccess\";i:1;}}s:32:\"922d4d09f0871251bc6983963add4d20\";a:4:{i:0;s:90:\"Lorem ipsum dolor sit amet (co...\";i:1;a:7:{s:4:\"edit\";a:1:{s:7:\"tt_news\";a:1:{s:5:\"2,3,4\";s:4:\"edit\";}}s:7:\"defVals\";N;s:12:\"overrideVals\";N;s:11:\"columnsOnly\";N;s:7:\"disHelp\";s:1:\"1\";s:6:\"noView\";N;s:24:\"editRegularContentFromId\";N;}i:2;s:106:\"&edit[tt_news][2,3,4]=edit&defVals=&overrideVals=&columnsOnly=&disHelp=1&noView=&editRegularContentFromId=\";i:3;a:5:{s:5:\"table\";s:7:\"tt_news\";s:3:\"uid\";s:1:\"2\";s:3:\"pid\";s:2:\"18\";s:3:\"cmd\";s:4:\"edit\";s:12:\"deleteAccess\";i:1;}}}s:13:\"xMOD_tximpexp\";a:1:{s:8:\"function\";s:0:\"\";}s:14:\"web_txttnewsM1\";a:7:{s:8:\"function\";s:1:\"1\";s:12:\"searchLevels\";s:2:\"-1\";s:8:\"language\";s:1:\"0\";s:9:\"expandAll\";s:1:\"0\";s:20:\"showHiddenCategories\";s:1:\"0\";s:16:\"showOnlyEditable\";s:1:\"0\";s:13:\"showEditIcons\";s:1:\"0\";}s:9:\"menuState\";a:1:{s:12:\"modmenu_help\";i:1;}}s:19:\"thumbnailsByDefault\";i:0;s:14:\"emailMeAtLogin\";i:0;s:13:\"condensedMode\";i:0;s:10:\"noMenuMode\";i:0;s:11:\"startModule\";s:17:\"help_aboutmodules\";s:18:\"hideSubmoduleIcons\";i:0;s:8:\"helpText\";i:1;s:8:\"titleLen\";i:30;s:17:\"edit_wideDocument\";s:1:\"0\";s:18:\"edit_showFieldHelp\";s:4:\"icon\";s:8:\"edit_RTE\";s:1:\"1\";s:20:\"edit_docModuleUpload\";s:1:\"1\";s:19:\"enableFlashUploader\";s:1:\"1\";s:15:\"disableCMlayers\";i:0;s:13:\"navFrameWidth\";s:0:\"\";s:17:\"navFrameResizable\";i:0;s:15:\"resizeTextareas\";i:1;s:25:\"resizeTextareas_MaxHeight\";i:300;s:24:\"resizeTextareas_Flexible\";i:1;s:4:\"lang\";s:0:\"\";s:15:\"moduleSessionID\";a:11:{s:10:\"web_layout\";s:32:\"ebb483883d0bb287f13f505c11529766\";s:8:\"web_list\";s:32:\"ebb483883d0bb287f13f505c11529766\";s:9:\"file_list\";s:32:\"bc14977d04f2d090085b481222031111\";s:16:\"xMOD_alt_doc.php\";s:32:\"bc14977d04f2d090085b481222031111\";s:9:\"clipboard\";s:32:\"ebb483883d0bb287f13f505c11529766\";s:25:\"db_list.php/displayFields\";s:32:\"ebb483883d0bb287f13f505c11529766\";s:11:\"alt_doc.php\";s:32:\"bc14977d04f2d090085b481222031111\";s:29:\"t3lib_BEfunc::getUpdateSignal\";s:32:\"bc14977d04f2d090085b481222031111\";s:16:\"opendocs::recent\";s:32:\"bc14977d04f2d090085b481222031111\";s:13:\"xMOD_tximpexp\";s:32:\"ebb483883d0bb287f13f505c11529766\";s:14:\"web_txttnewsM1\";s:32:\"29e40a3fd460aebd1ea92637c6f746b2\";}s:11:\"browseTrees\";a:3:{s:11:\"browsePages\";s:44:\"a:2:{i:0;a:1:{i:18;i:1;}i:1;a:1:{i:23;i:1;}}\";s:6:\"folder\";s:35:\"a:1:{i:7076;a:1:{i:249015978;i:1;}}\";s:10:\"ttnewstree\";s:24:\"a:1:{i:0;a:1:{i:0;i:1;}}\";}s:19:\"firstLoginTimeStamp\";i:1276866471;}','',0,3,'',0,0,'',1260653081,0,'5,3',0,1,''); +/*!40000 ALTER TABLE be_users ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `cache_extensions` +-- + +DROP TABLE IF EXISTS cache_extensions; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE cache_extensions ( + extkey varchar(60) NOT NULL DEFAULT '', + repository int(11) unsigned NOT NULL DEFAULT '1', + version varchar(10) NOT NULL DEFAULT '', + alldownloadcounter int(11) unsigned NOT NULL DEFAULT '0', + downloadcounter int(11) unsigned NOT NULL DEFAULT '0', + title varchar(150) DEFAULT NULL, + description mediumtext, + state int(4) NOT NULL DEFAULT '0', + reviewstate int(4) NOT NULL DEFAULT '0', + category int(4) NOT NULL DEFAULT '0', + lastuploaddate int(11) unsigned NOT NULL DEFAULT '0', + dependencies mediumtext, + authorname varchar(100) DEFAULT NULL, + authoremail varchar(100) DEFAULT NULL, + ownerusername varchar(50) DEFAULT NULL, + t3xfilemd5 varchar(35) DEFAULT NULL, + uploadcomment mediumtext, + authorcompany varchar(100) DEFAULT NULL, + intversion int(11) NOT NULL DEFAULT '0', + lastversion int(3) NOT NULL DEFAULT '0', + lastreviewedversion int(3) NOT NULL DEFAULT '0', + PRIMARY KEY (extkey,version,repository) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `cache_extensions` +-- + +LOCK TABLES cache_extensions WRITE; +/*!40000 ALTER TABLE cache_extensions DISABLE KEYS */; +/*!40000 ALTER TABLE cache_extensions ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `cache_imagesizes` +-- + +DROP TABLE IF EXISTS cache_imagesizes; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE cache_imagesizes ( + md5hash varchar(32) DEFAULT NULL, + md5filename varchar(32) NOT NULL DEFAULT '', + tstamp int(11) NOT NULL DEFAULT '0', + filename varchar(255) DEFAULT NULL, + imagewidth mediumint(11) unsigned NOT NULL DEFAULT '0', + imageheight mediumint(11) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (md5filename) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `cache_imagesizes` +-- + +LOCK TABLES cache_imagesizes WRITE; +/*!40000 ALTER TABLE cache_imagesizes DISABLE KEYS */; +/*!40000 ALTER TABLE cache_imagesizes ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `cache_md5params` +-- + +DROP TABLE IF EXISTS cache_md5params; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE cache_md5params ( + md5hash varchar(20) NOT NULL DEFAULT '', + tstamp int(11) NOT NULL DEFAULT '0', + `type` tinyint(3) NOT NULL DEFAULT '0', + params text, + PRIMARY KEY (md5hash) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `cache_md5params` +-- + +LOCK TABLES cache_md5params WRITE; +/*!40000 ALTER TABLE cache_md5params DISABLE KEYS */; +/*!40000 ALTER TABLE cache_md5params ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `cache_treelist` +-- + +DROP TABLE IF EXISTS cache_treelist; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE cache_treelist ( + md5hash char(32) NOT NULL DEFAULT '', + pid int(11) NOT NULL DEFAULT '0', + treelist text, + tstamp int(11) NOT NULL DEFAULT '0', + expires int(11) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (md5hash) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `cache_treelist` +-- + +LOCK TABLES cache_treelist WRITE; +/*!40000 ALTER TABLE cache_treelist DISABLE KEYS */; +/*!40000 ALTER TABLE cache_treelist ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `cache_typo3temp_log` +-- + +DROP TABLE IF EXISTS cache_typo3temp_log; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE cache_typo3temp_log ( + md5hash varchar(32) NOT NULL DEFAULT '', + tstamp int(11) NOT NULL DEFAULT '0', + filename varchar(255) DEFAULT NULL, + orig_filename varchar(255) DEFAULT NULL, + PRIMARY KEY (md5hash) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `cache_typo3temp_log` +-- + +LOCK TABLES cache_typo3temp_log WRITE; +/*!40000 ALTER TABLE cache_typo3temp_log DISABLE KEYS */; +/*!40000 ALTER TABLE cache_typo3temp_log ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `fe_groups` +-- + +DROP TABLE IF EXISTS fe_groups; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE fe_groups ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + pid int(11) unsigned NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + crdate int(11) unsigned NOT NULL DEFAULT '0', + cruser_id int(11) unsigned NOT NULL DEFAULT '0', + title varchar(50) DEFAULT NULL, + hidden tinyint(3) unsigned NOT NULL DEFAULT '0', + lockToDomain varchar(50) DEFAULT NULL, + deleted tinyint(3) unsigned NOT NULL DEFAULT '0', + description text, + subgroup tinytext, + TSconfig text, + felogin_redirectPid tinytext, + tx_extbase_type varchar(255) DEFAULT NULL, + PRIMARY KEY (uid), + KEY parent (pid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `fe_groups` +-- + +LOCK TABLES fe_groups WRITE; +/*!40000 ALTER TABLE fe_groups DISABLE KEYS */; +INSERT INTO fe_groups (uid, pid, tstamp, crdate, cruser_id, title, hidden, lockToDomain, deleted, description, subgroup, TSconfig, felogin_redirectPid, tx_extbase_type) VALUES (1,29,1258481005,1258479481,4,'Customers',0,'',0,'Visitors who are members of this group can login on page \'Customer login\' to get access to the protected pages below that page','','','30',''),(2,29,1258481134,1258481134,4,'Others',0,'',0,'This is a dummy group for visitors who have an account but are not member of any specific group','','','',''); +/*!40000 ALTER TABLE fe_groups ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `fe_session_data` +-- + +DROP TABLE IF EXISTS fe_session_data; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE fe_session_data ( + `hash` varchar(32) NOT NULL DEFAULT '', + content mediumblob, + tstamp int(11) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`hash`), + KEY tstamp (tstamp) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `fe_session_data` +-- + +LOCK TABLES fe_session_data WRITE; +/*!40000 ALTER TABLE fe_session_data DISABLE KEYS */; +/*!40000 ALTER TABLE fe_session_data ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `fe_sessions` +-- + +DROP TABLE IF EXISTS fe_sessions; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE fe_sessions ( + ses_id varchar(32) NOT NULL DEFAULT '', + ses_name varchar(32) NOT NULL DEFAULT '', + ses_iplock varchar(39) DEFAULT NULL, + ses_hashlock int(11) NOT NULL DEFAULT '0', + ses_userid int(11) unsigned NOT NULL DEFAULT '0', + ses_tstamp int(11) unsigned NOT NULL DEFAULT '0', + ses_data blob, + ses_permanent tinyint(1) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (ses_id,ses_name), + KEY ses_tstamp (ses_tstamp) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `fe_sessions` +-- + +LOCK TABLES fe_sessions WRITE; +/*!40000 ALTER TABLE fe_sessions DISABLE KEYS */; +/*!40000 ALTER TABLE fe_sessions ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `fe_users` +-- + +DROP TABLE IF EXISTS fe_users; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE fe_users ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + pid int(11) unsigned NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + username varchar(50) DEFAULT NULL, + `password` varchar(60) NOT NULL DEFAULT '', + usergroup tinytext, + `disable` tinyint(4) unsigned NOT NULL DEFAULT '0', + starttime int(11) unsigned NOT NULL DEFAULT '0', + endtime int(11) unsigned NOT NULL DEFAULT '0', + `name` varchar(80) DEFAULT NULL, + first_name varchar(50) DEFAULT NULL, + middle_name varchar(50) DEFAULT NULL, + last_name varchar(50) DEFAULT NULL, + address varchar(255) DEFAULT NULL, + telephone varchar(20) DEFAULT NULL, + fax varchar(20) DEFAULT NULL, + email varchar(80) DEFAULT NULL, + crdate int(11) unsigned NOT NULL DEFAULT '0', + cruser_id int(11) unsigned NOT NULL DEFAULT '0', + lockToDomain varchar(50) DEFAULT NULL, + deleted tinyint(3) unsigned NOT NULL DEFAULT '0', + uc blob, + title varchar(40) DEFAULT NULL, + zip varchar(10) DEFAULT NULL, + city varchar(50) DEFAULT NULL, + country varchar(40) DEFAULT NULL, + www varchar(80) DEFAULT NULL, + company varchar(80) DEFAULT NULL, + image tinytext, + TSconfig text, + fe_cruser_id int(10) unsigned NOT NULL DEFAULT '0', + lastlogin int(10) unsigned NOT NULL DEFAULT '0', + is_online int(10) unsigned NOT NULL DEFAULT '0', + felogin_redirectPid tinytext, + felogin_forgotHash varchar(80) DEFAULT NULL, + tx_extbase_type varchar(255) DEFAULT NULL, + PRIMARY KEY (uid), + KEY parent (pid,username), + KEY username (username), + KEY is_online (is_online) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `fe_users` +-- + +LOCK TABLES fe_users WRITE; +/*!40000 ALTER TABLE fe_users DISABLE KEYS */; +INSERT INTO fe_users (uid, pid, tstamp, username, password, usergroup, disable, starttime, endtime, name, first_name, middle_name, last_name, address, telephone, fax, email, crdate, cruser_id, lockToDomain, deleted, uc, title, zip, city, country, www, company, image, TSconfig, fe_cruser_id, lastlogin, is_online, felogin_redirectPid, felogin_forgotHash, tx_extbase_type) VALUES (1,29,1277033438,'customer1','customer1','1',0,0,0,'','','','','','1258479637','4','',0,0,'',0,'','','','','','','0','1277209978','1277209978',0,1319441428,1319441428,'','',''),(2,29,1277033450,'someone','someone','2',0,0,0,'','','','','','1258479661','4','',0,0,'',0,'','','','','','','0','1277209987','1277209987',0,1290503042,1290503042,'','',''); +/*!40000 ALTER TABLE fe_users ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `index_config` +-- + +DROP TABLE IF EXISTS index_config; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE index_config ( + uid int(11) NOT NULL AUTO_INCREMENT, + pid int(11) NOT NULL DEFAULT '0', + tstamp int(11) NOT NULL DEFAULT '0', + crdate int(11) NOT NULL DEFAULT '0', + cruser_id int(11) NOT NULL DEFAULT '0', + hidden tinyint(4) NOT NULL DEFAULT '0', + starttime int(11) NOT NULL DEFAULT '0', + set_id int(11) NOT NULL DEFAULT '0', + session_data mediumtext, + title varchar(255) DEFAULT NULL, + description text, + `type` varchar(30) DEFAULT NULL, + depth int(11) unsigned NOT NULL DEFAULT '0', + table2index varchar(255) DEFAULT NULL, + alternative_source_pid int(11) unsigned NOT NULL DEFAULT '0', + get_params varchar(255) DEFAULT NULL, + fieldlist varchar(255) DEFAULT NULL, + externalUrl varchar(255) DEFAULT NULL, + indexcfgs text, + chashcalc tinyint(3) unsigned NOT NULL DEFAULT '0', + filepath varchar(255) DEFAULT NULL, + extensions varchar(255) DEFAULT NULL, + timer_next_indexing int(11) NOT NULL DEFAULT '0', + timer_frequency int(11) NOT NULL DEFAULT '0', + timer_offset int(11) NOT NULL DEFAULT '0', + url_deny text, + recordsbatch int(11) NOT NULL DEFAULT '0', + records_indexonchange tinyint(4) NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY parent (pid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `index_config` +-- + +LOCK TABLES index_config WRITE; +/*!40000 ALTER TABLE index_config DISABLE KEYS */; +/*!40000 ALTER TABLE index_config ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `index_debug` +-- + +DROP TABLE IF EXISTS index_debug; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE index_debug ( + phash int(11) NOT NULL DEFAULT '0', + debuginfo mediumtext, + PRIMARY KEY (phash) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `index_debug` +-- + +LOCK TABLES index_debug WRITE; +/*!40000 ALTER TABLE index_debug DISABLE KEYS */; +/*!40000 ALTER TABLE index_debug ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `index_fulltext` +-- + +DROP TABLE IF EXISTS index_fulltext; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE index_fulltext ( + phash int(11) NOT NULL DEFAULT '0', + fulltextdata mediumtext, + PRIMARY KEY (phash) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `index_fulltext` +-- + +LOCK TABLES index_fulltext WRITE; +/*!40000 ALTER TABLE index_fulltext DISABLE KEYS */; +/*!40000 ALTER TABLE index_fulltext ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `index_grlist` +-- + +DROP TABLE IF EXISTS index_grlist; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE index_grlist ( + phash int(11) NOT NULL DEFAULT '0', + phash_x int(11) NOT NULL DEFAULT '0', + hash_gr_list int(11) NOT NULL DEFAULT '0', + gr_list varchar(255) DEFAULT NULL, + uniqid int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (uniqid), + KEY joinkey (phash,hash_gr_list), + KEY phash_grouping (phash_x,hash_gr_list) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `index_grlist` +-- + +LOCK TABLES index_grlist WRITE; +/*!40000 ALTER TABLE index_grlist DISABLE KEYS */; +/*!40000 ALTER TABLE index_grlist ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `index_phash` +-- + +DROP TABLE IF EXISTS index_phash; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE index_phash ( + phash int(11) NOT NULL DEFAULT '0', + phash_grouping int(11) NOT NULL DEFAULT '0', + cHashParams blob, + data_filename varchar(255) DEFAULT NULL, + data_page_id int(11) unsigned NOT NULL DEFAULT '0', + data_page_reg1 int(11) unsigned NOT NULL DEFAULT '0', + data_page_type int(11) unsigned NOT NULL DEFAULT '0', + data_page_mp varchar(255) DEFAULT NULL, + gr_list varchar(255) DEFAULT NULL, + item_type varchar(5) DEFAULT NULL, + item_title varchar(255) DEFAULT NULL, + item_description varchar(255) DEFAULT NULL, + item_mtime int(11) NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + item_size int(11) NOT NULL DEFAULT '0', + contentHash int(11) NOT NULL DEFAULT '0', + crdate int(11) NOT NULL DEFAULT '0', + parsetime int(11) NOT NULL DEFAULT '0', + sys_language_uid int(11) NOT NULL DEFAULT '0', + item_crdate int(11) NOT NULL DEFAULT '0', + externalUrl tinyint(3) NOT NULL DEFAULT '0', + recordUid int(11) NOT NULL DEFAULT '0', + freeIndexUid int(11) NOT NULL DEFAULT '0', + freeIndexSetId int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (phash), + KEY phash_grouping (phash_grouping), + KEY freeIndexUid (freeIndexUid) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `index_phash` +-- + +LOCK TABLES index_phash WRITE; +/*!40000 ALTER TABLE index_phash DISABLE KEYS */; +/*!40000 ALTER TABLE index_phash ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `index_rel` +-- + +DROP TABLE IF EXISTS index_rel; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE index_rel ( + phash int(11) NOT NULL DEFAULT '0', + wid int(11) NOT NULL DEFAULT '0', + count tinyint(3) unsigned NOT NULL DEFAULT '0', + `first` tinyint(3) unsigned NOT NULL DEFAULT '0', + freq smallint(5) unsigned NOT NULL DEFAULT '0', + flags tinyint(3) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (phash,wid), + KEY wid (wid,phash) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `index_rel` +-- + +LOCK TABLES index_rel WRITE; +/*!40000 ALTER TABLE index_rel DISABLE KEYS */; +/*!40000 ALTER TABLE index_rel ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `index_section` +-- + +DROP TABLE IF EXISTS index_section; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE index_section ( + phash int(11) NOT NULL DEFAULT '0', + phash_t3 int(11) NOT NULL DEFAULT '0', + rl0 int(11) unsigned NOT NULL DEFAULT '0', + rl1 int(11) unsigned NOT NULL DEFAULT '0', + rl2 int(11) unsigned NOT NULL DEFAULT '0', + page_id int(11) NOT NULL DEFAULT '0', + uniqid int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (uniqid), + KEY joinkey (phash,rl0), + KEY page_id (page_id), + KEY rl0 (rl0,rl1,phash), + KEY rl0_2 (rl0,phash) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `index_section` +-- + +LOCK TABLES index_section WRITE; +/*!40000 ALTER TABLE index_section DISABLE KEYS */; +/*!40000 ALTER TABLE index_section ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `index_stat_search` +-- + +DROP TABLE IF EXISTS index_stat_search; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE index_stat_search ( + uid int(11) NOT NULL AUTO_INCREMENT, + searchstring varchar(255) DEFAULT NULL, + searchoptions blob, + tstamp int(11) NOT NULL DEFAULT '0', + feuser_id int(11) unsigned NOT NULL DEFAULT '0', + cookie varchar(10) DEFAULT NULL, + IP varchar(255) DEFAULT NULL, + hits int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (uid) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `index_stat_search` +-- + +LOCK TABLES index_stat_search WRITE; +/*!40000 ALTER TABLE index_stat_search DISABLE KEYS */; +/*!40000 ALTER TABLE index_stat_search ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `index_stat_word` +-- + +DROP TABLE IF EXISTS index_stat_word; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE index_stat_word ( + uid int(11) NOT NULL AUTO_INCREMENT, + word varchar(30) DEFAULT NULL, + index_stat_search_id int(11) NOT NULL DEFAULT '0', + tstamp int(11) NOT NULL DEFAULT '0', + pageid int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY tstamp (tstamp,word) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `index_stat_word` +-- + +LOCK TABLES index_stat_word WRITE; +/*!40000 ALTER TABLE index_stat_word DISABLE KEYS */; +/*!40000 ALTER TABLE index_stat_word ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `index_words` +-- + +DROP TABLE IF EXISTS index_words; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE index_words ( + wid int(11) NOT NULL DEFAULT '0', + baseword varchar(60) DEFAULT NULL, + metaphone int(11) NOT NULL DEFAULT '0', + is_stopword tinyint(3) NOT NULL DEFAULT '0', + PRIMARY KEY (wid), + KEY baseword (baseword,wid), + KEY metaphone (metaphone,wid) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `index_words` +-- + +LOCK TABLES index_words WRITE; +/*!40000 ALTER TABLE index_words DISABLE KEYS */; +/*!40000 ALTER TABLE index_words ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `pages` +-- + +DROP TABLE IF EXISTS pages; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE pages ( + uid int(11) NOT NULL AUTO_INCREMENT, + pid int(11) NOT NULL DEFAULT '0', + t3ver_oid int(11) NOT NULL DEFAULT '0', + t3ver_id int(11) NOT NULL DEFAULT '0', + t3ver_wsid int(11) NOT NULL DEFAULT '0', + t3ver_label varchar(255) DEFAULT NULL, + t3ver_state tinyint(4) NOT NULL DEFAULT '0', + t3ver_stage int(11) NOT NULL DEFAULT '0', + t3ver_count int(11) NOT NULL DEFAULT '0', + t3ver_tstamp int(11) NOT NULL DEFAULT '0', + t3ver_swapmode tinyint(4) NOT NULL DEFAULT '0', + t3ver_move_id int(11) NOT NULL DEFAULT '0', + t3_origuid int(11) NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + sorting int(11) unsigned NOT NULL DEFAULT '0', + deleted tinyint(1) unsigned NOT NULL DEFAULT '0', + perms_userid int(11) unsigned NOT NULL DEFAULT '0', + perms_groupid int(11) unsigned NOT NULL DEFAULT '0', + perms_user tinyint(4) unsigned NOT NULL DEFAULT '0', + perms_group tinyint(4) unsigned NOT NULL DEFAULT '0', + perms_everybody tinyint(4) unsigned NOT NULL DEFAULT '0', + editlock tinyint(4) unsigned NOT NULL DEFAULT '0', + crdate int(11) unsigned NOT NULL DEFAULT '0', + cruser_id int(11) unsigned NOT NULL DEFAULT '0', + hidden tinyint(4) unsigned NOT NULL DEFAULT '0', + title varchar(255) DEFAULT NULL, + doktype tinyint(3) unsigned NOT NULL DEFAULT '0', + TSconfig text, + storage_pid int(11) NOT NULL DEFAULT '0', + is_siteroot tinyint(4) NOT NULL DEFAULT '0', + php_tree_stop tinyint(4) NOT NULL DEFAULT '0', + tx_impexp_origuid int(11) NOT NULL DEFAULT '0', + url varchar(255) DEFAULT NULL, + starttime int(11) unsigned NOT NULL DEFAULT '0', + endtime int(11) unsigned NOT NULL DEFAULT '0', + urltype tinyint(4) unsigned NOT NULL DEFAULT '0', + shortcut int(10) unsigned NOT NULL DEFAULT '0', + shortcut_mode int(10) unsigned NOT NULL DEFAULT '0', + no_cache int(10) unsigned NOT NULL DEFAULT '0', + fe_group varchar(100) NOT NULL DEFAULT '0', + subtitle varchar(255) DEFAULT NULL, + layout tinyint(3) unsigned NOT NULL DEFAULT '0', + url_scheme tinyint(3) unsigned NOT NULL DEFAULT '0', + target varchar(80) DEFAULT NULL, + media text, + lastUpdated int(10) unsigned NOT NULL DEFAULT '0', + keywords text, + cache_timeout int(10) unsigned NOT NULL DEFAULT '0', + newUntil int(10) unsigned NOT NULL DEFAULT '0', + description text, + no_search tinyint(3) unsigned NOT NULL DEFAULT '0', + SYS_LASTCHANGED int(10) unsigned NOT NULL DEFAULT '0', + abstract text, + module varchar(10) DEFAULT NULL, + extendToSubpages tinyint(3) unsigned NOT NULL DEFAULT '0', + author varchar(255) DEFAULT NULL, + author_email varchar(80) DEFAULT NULL, + nav_title varchar(255) DEFAULT NULL, + nav_hide tinyint(4) NOT NULL DEFAULT '0', + content_from_pid int(10) unsigned NOT NULL DEFAULT '0', + mount_pid int(10) unsigned NOT NULL DEFAULT '0', + mount_pid_ol tinyint(4) NOT NULL DEFAULT '0', + alias varchar(32) DEFAULT NULL, + l18n_cfg tinyint(4) NOT NULL DEFAULT '0', + fe_login_mode tinyint(4) NOT NULL DEFAULT '0', + backend_layout int(10) NOT NULL DEFAULT '0', + backend_layout_next_level int(10) NOT NULL DEFAULT '0', + tx_realurl_pathsegment varchar(255) DEFAULT NULL, + tx_realurl_pathoverride int(1) NOT NULL DEFAULT '0', + tx_realurl_exclude int(1) NOT NULL DEFAULT '0', + tx_realurl_nocache int(1) NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY t3ver_oid (t3ver_oid,t3ver_wsid), + KEY parent (pid,deleted,sorting), + KEY alias (alias) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `pages` +-- + +LOCK TABLES pages WRITE; +/*!40000 ALTER TABLE pages DISABLE KEYS */; +INSERT INTO pages (uid, pid, t3ver_oid, t3ver_id, t3ver_wsid, t3ver_label, t3ver_state, t3ver_stage, t3ver_count, t3ver_tstamp, t3ver_swapmode, t3ver_move_id, t3_origuid, tstamp, sorting, deleted, perms_userid, perms_groupid, perms_user, perms_group, perms_everybody, editlock, crdate, cruser_id, hidden, title, doktype, TSconfig, storage_pid, is_siteroot, php_tree_stop, tx_impexp_origuid, url, starttime, endtime, urltype, shortcut, shortcut_mode, no_cache, fe_group, subtitle, layout, url_scheme, target, media, lastUpdated, keywords, cache_timeout, newUntil, description, no_search, SYS_LASTCHANGED, abstract, module, extendToSubpages, author, author_email, nav_title, nav_hide, content_from_pid, mount_pid, mount_pid_ol, alias, l18n_cfg, fe_login_mode, backend_layout, backend_layout_next_level, tx_realurl_pathsegment, tx_realurl_pathoverride, tx_realurl_exclude, tx_realurl_nocache) VALUES (1,0,0,0,0,'',0,0,0,0,0,0,0,1280227997,256,0,3,5,31,27,0,0,1257766279,1,0,'Home',4,'# Show only the chosen columns in the page module\r\n# 0=normal, 1=left, 2=right, 3=border\r\nmod.SHARED.colPos_list = 1,0,2\r\n\r\n# Set the default label and flag\r\nmod.SHARED.defaultLanguageLabel = English\r\nmod.SHARED.defaultLanguageFlag = gb.gif\r\n\r\n# Show the content element wizard with tabs (for consistency)\r\nmod.wizards.newContentElement.renderMode = tabs\r\n\r\nTCEFORM {\r\n pages {\r\n layout {\r\n # Rename the default options for the layout field in table pages\r\n altLabels.0 = Standard 3 columns\r\n altLabels.1 = Columns left & main\r\n altLabels.2 = Columns main & right\r\n altLabels.3 = Column main only\r\n }\r\n # There is no need for the Alias field in page properties when we use RealURL\r\n alias.disabled = 1\r\n }\r\n \r\n tt_content {\r\n # Remove the \'border\' option from selectbox \'column\' in content records\r\n colPos.keepItems = 1,0,2\r\n }\r\n}\r\n/*\r\n##frames\r\nTCEFORM.tt_content.section_frame{\r\n addItems {\r\n 30 = Frame 3, width 2/3 \r\n 31 = Frame 4, width 1/3 \r\n }\r\n}\r\n*/\r\n\r\n // If an editor creates a page it should be visible to all editors and admins\r\nTCEMAIN {\r\n // group \"all users\"\r\n permissions.groupid = 5\r\n\r\n user = show,edit,delete,new,editcontent\r\n group = show,edit,delete,new,editcontent\r\n everybody = \r\n}\r\n',18,1,0,1,'',0,0,1,6,0,0,'','',0,0,'','',0,'',0,0,'',0,0,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(2,1,0,0,0,'',0,0,0,0,0,0,0,1276970409,256,0,3,5,31,27,0,0,1257766279,1,0,'Feedback',1,'',0,0,0,67,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,1319060202,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(3,1,0,0,0,'',0,0,0,0,0,0,0,1276970409,60,0,3,5,31,27,0,0,1257766279,1,0,'Customizing TYPO3',1,'',0,0,0,63,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,1290049034,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(4,1,0,0,0,'',0,0,0,0,0,0,33,1276970421,64,0,2,5,31,27,0,0,1257766279,1,0,'Examples',1,'',0,0,0,48,'',0,0,1,0,0,0,'','How does our subtitle render in the frontend?',0,0,'','',0,'',0,0,'',0,1280747403,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(6,1,0,0,0,'',0,0,0,0,0,0,0,1276970409,32,0,3,5,31,27,0,0,1257766279,1,0,'Welcome to TYPO3',1,'',0,0,0,9,'',0,0,1,0,0,0,'','',2,0,'','',0,'typo3, introduction package, install, example setup',0,0,'This website is a default website setup for TYPO3. You can use it to demonstrate the basic features of the TYPO3 Content Management System, but you are also welcome to use it as a basis for your own website projects. Please have a look at how it works and how it is structured. In building this package, we have tried to combine a lot of best practices. Feel free to use these structures and use elements of it for your own way of working.',0,1280747403,'Homepage for the Introduction Package of TYPO3','',0,'','','Get Started',0,0,0,0,'',0,0,0,1,'0',0,0,0),(25,4,0,0,0,'',0,0,0,0,0,0,0,1276970421,64,0,2,5,31,27,0,0,1258457261,3,0,'Any language, any character',1,'',0,0,0,0,'',0,0,1,0,0,0,'','',0,0,'','',0,'Content elements',0,0,'',0,1280747403,'','',0,'','','Languages & characters',0,0,0,0,'',0,0,0,0,'0',0,0,0),(8,0,0,0,0,'',0,0,0,0,0,0,0,1276970355,512,0,1,4,31,27,0,0,1258294829,3,0,'TypoScript Templates',254,'mod {\r\n web_list {\r\n allowedNewTables := addToList(sys_template)\r\n\r\n}',8,0,0,3,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,0,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(9,8,0,0,0,'',0,0,0,0,0,0,0,1276970355,768,0,1,4,31,27,0,0,1258294829,3,0,'extension_configuration',254,'',0,0,0,173,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,0,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(11,8,0,0,0,'',0,0,0,0,0,0,0,1276970355,960,0,1,4,31,27,0,0,1258294829,3,0,'page_blocks_configuration',254,'',0,0,0,238,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,0,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(12,8,0,0,0,'',0,0,0,0,0,0,0,1276970355,512,0,1,4,31,27,0,0,1258294829,3,0,'system_configuration',254,'',0,0,0,172,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,0,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(13,8,0,0,0,'',0,0,0,0,0,0,0,1276970355,896,0,1,4,31,27,0,0,1258294829,3,0,'menu_configuration',254,'',0,0,0,171,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,0,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(14,8,0,0,0,'',0,0,0,0,0,0,0,1276970355,1024,0,1,4,31,27,0,0,1258294829,3,0,'page_configuration',254,'',0,0,0,170,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,0,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(15,69,0,0,0,'',0,0,0,0,0,0,0,1277207824,224,0,3,5,31,27,0,0,1258384670,2,0,'--------------',199,'',0,0,0,0,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,0,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(16,69,0,0,0,'',0,0,0,0,0,0,0,1277207764,256,0,3,5,31,27,0,0,1258384807,2,0,'404',1,'',0,0,0,0,'',0,0,1,0,0,0,'','',2,0,'',NULL,0,NULL,0,0,NULL,1,1280747403,NULL,'',0,'','','',1,0,0,0,'',0,0,0,0,'0',0,0,0),(17,69,0,0,0,'',0,0,0,0,0,0,0,1277207771,512,0,3,5,31,27,0,0,1258384853,2,0,'Search',1,'',0,0,0,0,'',0,0,1,0,0,0,'','',3,0,'','',0,'',0,0,'',1,1280747403,'','',0,'','','',1,0,0,0,'',0,0,0,0,'0',0,0,0),(18,1,0,0,0,'',0,0,0,0,0,0,0,1276970409,1280,0,3,5,31,27,0,0,1258384881,2,0,'News entries',254,'mod.web_list {\r\n # limit the creation of new records in this sysFolder to these types\r\n allowedNewTables = tt_news,tt_news_cat,sys_note\r\n}\r\n\r\n# This will open the news singleView page (id 23) when clicking \'preview\' for a news record\r\ntx_ttnews.singlePid = 23\r\n\r\nTCEMAIN {\r\n # Clear cache of the News page after content of the News folder has changed\r\n clearCacheCmd = 23\r\n clearCache_pageSiblingChildren = 1\r\n}\r\n',0,0,0,0,'',0,0,1,0,0,0,'','',3,0,'','',0,'',0,0,'',0,0,'','news',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(19,1,0,0,0,'',0,0,0,0,0,0,0,1276970409,1152,0,3,5,31,27,0,0,1258387691,4,0,'Generated content',254,'',0,0,0,0,'',0,0,1,0,0,0,'','',3,0,'','',0,'',0,0,'',0,0,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(20,19,0,0,0,'',0,0,0,0,0,0,0,1276970409,256,0,3,5,31,27,0,0,1258387753,4,0,'Footer content',254,'',0,0,0,0,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,0,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(21,19,0,0,0,'',0,0,0,0,0,0,0,1276970409,512,0,3,5,31,27,0,0,1258387830,4,0,'Login box',254,'',0,0,0,0,'',0,0,1,0,0,0,'0','',0,0,'','',0,NULL,0,0,NULL,0,0,NULL,'',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(23,4,0,0,0,'',0,0,0,0,0,0,0,1276970421,1280,0,2,5,31,27,0,0,1258388433,4,0,'News',1,'',0,0,0,0,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,1280747403,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(67,2,0,0,0,'',0,0,0,0,0,0,0,1277154544,256,0,23,5,31,27,0,0,1277149038,23,0,'Thank you for your feedback',1,'',0,0,0,0,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,1277154544,'','',0,'','','Thank You',1,0,0,0,'',0,0,0,0,'0',0,0,0),(70,1,0,0,0,'',0,0,0,0,0,0,15,1277207850,448,0,24,5,31,27,0,0,1277207837,24,0,'--------------',199,'',0,0,0,0,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,0,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(28,69,0,0,0,'',0,0,0,0,0,0,0,1277207810,192,0,3,5,31,27,0,0,1258478965,4,0,'Customer login',1,'',0,0,0,0,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,1280747403,'','',0,'','','',1,0,0,0,'',0,0,0,0,'0',0,0,0),(29,1,0,0,0,'',0,0,0,0,0,0,0,1276970409,1536,0,3,5,31,27,0,0,1258479224,4,0,'Frontend users and groups',254,'mod.web_list {\r\n # limit the creation of new records in this sysFolder to these types\r\n allowedNewTables = fe_groups,fe_users,sys_note\r\n}\r\n',0,0,0,0,'',0,0,1,0,0,0,'0','',3,0,'','',0,NULL,0,0,NULL,0,0,NULL,'fe_users',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(30,28,0,0,0,'',0,0,0,0,0,0,0,1276970409,128,0,3,5,31,27,0,0,1258479801,4,0,'Protected customer page',1,'',0,0,0,0,'',0,0,1,0,0,0,'1','',0,0,'','',0,'',0,0,'',0,1277112544,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(31,28,0,0,0,'',0,0,0,0,0,0,0,1276970409,256,0,3,5,31,27,0,0,1258479835,4,0,'Any login page',1,'',0,0,0,0,'',0,0,1,0,0,0,'-2','',0,0,'','',0,'',0,0,'',0,1277112418,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(32,69,0,0,0,'',0,0,0,0,0,0,0,1277208116,128,0,3,5,31,27,0,0,1258481339,4,0,'Protected page',1,'',0,0,0,0,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,0,'','',0,'','','',1,0,0,0,'',0,0,0,0,'0',0,0,0),(34,4,0,0,0,'',0,0,0,0,0,0,0,1276970421,2048,0,2,5,31,27,0,0,1258542915,4,0,'Site map',1,'',0,0,0,52,'',0,0,1,0,0,0,'','',0,0,'','',0,'Content elements',0,0,'',0,1280747403,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(35,4,0,0,0,'',0,0,0,0,0,0,0,1276970421,256,0,2,5,31,27,0,0,1258542915,4,0,'File downloads',1,'',0,0,0,48,'',0,0,1,0,0,0,'','',0,0,'','',0,'Content elements',0,0,'',0,1280747403,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(36,4,0,0,0,'',0,0,0,0,0,0,0,1276970421,512,0,2,5,31,27,0,0,1258542915,4,0,'Forms',1,'',0,0,0,40,'',0,0,1,0,0,0,'','',0,0,'','',0,'Content elements',0,0,'',0,1319061974,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(37,4,0,0,0,'',0,0,0,0,0,0,0,1277149610,128,0,2,5,31,27,0,0,1258542915,4,0,'Lists',1,'',0,0,0,54,'',0,0,1,0,0,0,'','',0,0,'','',0,'Content elements',0,0,'',0,1280747403,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(38,4,0,0,0,'',0,0,0,0,0,0,0,1276970421,126,0,2,5,31,27,0,0,1258542915,4,0,'Tables',1,'',0,0,0,39,'',0,0,1,0,0,0,'','Examples for different table layouts',0,0,'','',0,'Content elements',0,0,'',0,1280747403,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(39,4,0,0,0,'',0,0,0,0,0,0,0,1276970421,124,0,2,5,31,27,0,0,1258542915,4,0,'Image effects',1,'',0,0,0,38,'',0,0,1,0,0,0,'','',0,0,'','',0,'Content elements',0,0,'',0,1280747403,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(40,4,0,0,0,'',0,0,0,0,0,0,0,1276970421,120,0,2,5,31,27,0,0,1258542915,4,0,'Image groups',1,'',0,0,0,37,'',0,0,1,0,0,0,'','',1,0,'','',0,'Content elements',0,0,'',0,1280747403,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(41,4,0,0,0,'',0,0,0,0,0,0,0,1276970421,116,0,2,5,31,27,0,0,1258542915,4,0,'Images with links',1,'',0,0,0,36,'',0,0,1,0,0,0,'','',0,0,'','',0,'Content elements',0,0,'',0,1280747403,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(42,4,0,0,0,'',0,0,0,0,0,0,0,1276970421,112,0,2,5,31,27,0,0,1258542915,4,0,'Text and images',1,'',0,0,0,35,'',0,0,1,0,0,0,'','',0,0,'','',0,'Content elements',0,0,'',0,1280747403,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(43,4,0,0,0,'',0,0,0,0,0,0,0,1277083029,96,0,2,5,31,27,0,0,1258542915,4,0,'Examples of Rich Text',1,'',0,0,0,34,'',0,0,1,0,0,0,'','',0,0,'','',0,'Content elements',0,0,'',0,1280747403,'','',0,'','','Text',0,0,0,0,'',0,0,0,0,'0',0,0,0),(44,4,0,0,0,'',0,0,0,0,0,0,0,1276970421,104,0,2,5,31,27,0,0,1258542915,4,0,'Headers',1,'',0,0,0,33,'',0,0,1,0,0,0,'','Examples for headers in TYPO3',0,0,'','',0,'Content elements',0,0,'',0,1280747403,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(45,4,0,0,0,'',0,0,0,0,0,0,0,1276970421,127,0,2,5,31,27,0,0,1258548941,11,0,'Frames',1,'',0,0,0,0,'',0,0,1,0,0,0,'','',0,0,'','',0,'Content elements',0,0,'',0,1280747403,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(51,1,0,0,0,'',0,0,0,0,0,0,6,1276970409,48,0,3,5,31,27,0,0,1258560852,12,0,'About TYPO3',1,'',0,0,0,9,'',0,0,1,0,0,0,'','',0,0,'','',0,'typo3, introduction package, install, example setup',0,0,'This website is a default website setup for TYPO3. You can use it to demonstrate the basic features of the TYPO3 Content Management System, but you are also welcome to use it as a basis for your own website projects. Please have a look at how it works and how it is structured. In building this package, we have tried to combine a lot of best practices. Feel free to use these structures and use elements of it for your own way of working.',0,1280747403,'Homepage for the Introduction Package of TYPO3','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(52,51,0,0,0,'',0,0,0,0,0,0,0,1276970409,256,0,3,5,31,27,0,0,1258561250,12,0,'History',1,NULL,0,0,0,0,'',0,0,1,0,0,0,'','',0,0,'',NULL,0,NULL,0,0,NULL,0,1280747403,NULL,'',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(53,51,0,0,0,'',0,0,0,0,0,0,0,1276970409,512,0,3,5,31,27,0,0,1258561250,12,0,'Community',1,NULL,0,0,0,0,'',0,0,1,0,0,0,'','',0,0,'',NULL,0,NULL,0,0,NULL,0,1319444085,NULL,'',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(57,1,0,0,0,'',0,0,0,0,0,0,0,1276970409,56,0,3,5,31,27,0,0,1258639563,12,0,'Features',1,'',0,0,0,0,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,1280747403,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(69,1,0,0,0,'',0,0,0,0,0,0,0,1277207783,640,0,24,5,31,27,0,0,1277207757,24,0,'Special pages',254,'',0,0,0,0,'',0,0,1,0,0,0,'0','',0,0,'',NULL,0,NULL,0,0,NULL,0,0,NULL,'',0,'','','',0,0,0,0,'',0,0,0,1,'0',0,0,0),(62,1,0,0,0,'',0,0,0,0,0,0,0,1276970409,62,0,3,5,31,27,0,0,1276894889,22,0,'Resources',1,'',0,0,0,0,'',0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,1280747403,'','',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(63,62,0,0,0,'',0,0,0,0,0,0,0,1276970409,256,0,3,5,31,27,0,0,1276894949,22,0,'Consultancies',1,NULL,0,0,0,0,'',0,0,1,0,0,0,'0','',0,0,'',NULL,0,NULL,0,0,NULL,0,1280747403,NULL,'',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(64,62,0,0,0,'',0,0,0,0,0,0,0,1276970409,512,0,3,5,31,27,0,0,1276894949,22,0,'Documentation',1,NULL,0,0,0,0,'',0,0,1,0,0,0,'0','',0,0,'',NULL,0,NULL,0,0,NULL,0,1280747403,NULL,'',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(65,62,0,0,0,'',0,0,0,0,0,0,0,1276970409,768,0,3,5,31,27,0,0,1276894949,22,0,'TYPO3 Association',1,NULL,0,0,0,0,'',0,0,1,0,0,0,'0','',0,0,'',NULL,0,NULL,0,0,NULL,0,1280747403,NULL,'',0,'','','',0,0,0,0,'',0,0,0,0,'0',0,0,0),(71,1,0,0,1,'INITIAL PLACEHOLDER',1,0,0,0,0,0,0,1290048956,61,0,1,5,31,27,0,0,1290048956,1,1,'Page added in Workspace',1,NULL,0,0,0,0,NULL,0,0,1,0,0,0,'0',NULL,0,0,NULL,NULL,0,NULL,0,0,NULL,0,1290049001,NULL,'',0,NULL,NULL,NULL,0,0,0,0,NULL,0,0,0,0,NULL,0,0,0),(72,-1,71,1,1,'First draft version',-1,0,0,0,-1,0,0,1290048956,61,0,1,5,31,27,0,0,1290048956,1,0,'Page added in Workspace',1,'',0,0,0,0,NULL,0,0,1,0,0,0,'','',0,0,'','',0,'',0,0,'',0,0,'','',0,'','','',0,0,0,0,NULL,0,0,0,0,'',0,0,0); +/*!40000 ALTER TABLE pages ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `pages_language_overlay` +-- + +DROP TABLE IF EXISTS pages_language_overlay; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE pages_language_overlay ( + uid int(11) NOT NULL AUTO_INCREMENT, + pid int(11) NOT NULL DEFAULT '0', + doktype tinyint(3) unsigned NOT NULL DEFAULT '0', + t3ver_oid int(11) NOT NULL DEFAULT '0', + t3ver_id int(11) NOT NULL DEFAULT '0', + t3ver_wsid int(11) NOT NULL DEFAULT '0', + t3ver_label varchar(255) DEFAULT NULL, + t3ver_state tinyint(4) NOT NULL DEFAULT '0', + t3ver_stage int(11) NOT NULL DEFAULT '0', + t3ver_count int(11) NOT NULL DEFAULT '0', + t3ver_tstamp int(11) NOT NULL DEFAULT '0', + t3_origuid int(11) NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + crdate int(11) unsigned NOT NULL DEFAULT '0', + cruser_id int(11) unsigned NOT NULL DEFAULT '0', + sys_language_uid int(11) unsigned NOT NULL DEFAULT '0', + title varchar(255) DEFAULT NULL, + hidden tinyint(4) unsigned NOT NULL DEFAULT '0', + starttime int(11) unsigned NOT NULL DEFAULT '0', + endtime int(11) unsigned NOT NULL DEFAULT '0', + deleted tinyint(3) unsigned NOT NULL DEFAULT '0', + subtitle varchar(255) DEFAULT NULL, + nav_title varchar(255) DEFAULT NULL, + media text, + keywords text, + description text, + abstract text, + author varchar(255) DEFAULT NULL, + author_email varchar(80) DEFAULT NULL, + tx_impexp_origuid int(11) NOT NULL DEFAULT '0', + l18n_diffsource mediumblob, + url varchar(255) DEFAULT NULL, + urltype tinyint(4) unsigned NOT NULL DEFAULT '0', + shortcut int(10) unsigned NOT NULL DEFAULT '0', + shortcut_mode int(10) unsigned NOT NULL DEFAULT '0', + tx_realurl_pathsegment varchar(255) DEFAULT NULL, + PRIMARY KEY (uid), + KEY t3ver_oid (t3ver_oid,t3ver_wsid), + KEY parent (pid,sys_language_uid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `pages_language_overlay` +-- + +LOCK TABLES pages_language_overlay WRITE; +/*!40000 ALTER TABLE pages_language_overlay DISABLE KEYS */; +INSERT INTO pages_language_overlay (uid, pid, doktype, t3ver_oid, t3ver_id, t3ver_wsid, t3ver_label, t3ver_state, t3ver_stage, t3ver_count, t3ver_tstamp, t3_origuid, tstamp, crdate, cruser_id, sys_language_uid, title, hidden, starttime, endtime, deleted, subtitle, nav_title, media, keywords, description, abstract, author, author_email, tx_impexp_origuid, l18n_diffsource, url, urltype, shortcut, shortcut_mode, tx_realurl_pathsegment) VALUES (1,25,1,0,0,0,'',0,0,0,0,0,1277119518,1258457354,3,1,'Alle sprog, ethvert tegnsæt',0,0,0,0,'','Sprog og tegnsæt','','','','','','',0,'a:15:{s:6:\"hidden\";s:1:\"0\";s:16:\"sys_language_uid\";N;s:5:\"title\";s:27:\"Any language, any character\";s:8:\"subtitle\";s:0:\"\";s:9:\"nav_title\";s:22:\"Languages & characters\";s:6:\"author\";s:0:\"\";s:12:\"author_email\";s:0:\"\";s:8:\"abstract\";s:0:\"\";s:8:\"keywords\";s:16:\"Content elements\";s:11:\"description\";s:0:\"\";s:5:\"media\";s:0:\"\";s:9:\"starttime\";s:1:\"0\";s:7:\"endtime\";s:1:\"0\";s:7:\"doktype\";s:1:\"1\";s:22:\"tx_realurl_pathsegment\";s:0:\"\";}','',1,0,0,''); +/*!40000 ALTER TABLE pages_language_overlay ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `static_tsconfig_help` +-- + +DROP TABLE IF EXISTS static_tsconfig_help; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE static_tsconfig_help ( + uid int(11) NOT NULL AUTO_INCREMENT, + guide int(11) NOT NULL DEFAULT '0', + md5hash varchar(32) DEFAULT NULL, + description text, + obj_string varchar(255) DEFAULT NULL, + appdata blob, + title varchar(255) DEFAULT NULL, + PRIMARY KEY (uid), + KEY guide (guide,md5hash) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `static_tsconfig_help` +-- + +LOCK TABLES static_tsconfig_help WRITE; +/*!40000 ALTER TABLE static_tsconfig_help DISABLE KEYS */; +INSERT INTO static_tsconfig_help (uid, guide, md5hash, description, obj_string, appdata, title) VALUES (1,15468566,'004ad0c011cac5a5fcbc294774cb0281','','page:RTE','a:1:{s:4:\"rows\";a:1:{i:0;a:6:{s:8:\"property\";s:32:\" classes.[classname]\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:841:\"Defines the classes available in the RTE. classname is the actual name of the style-class you're configuring. Notice you must specifically assign the classes to the various facilities also. See later.
 
Properties:
 .name = Label of the class
 .value = The style for the class
 .noShow = Boolean; if set, the style of the class is not used to render it in the pop-up selector.
 
Example:

# General configuration of the available classes:
RTE.classes {
   mainBodyText {
     name = Body Text (Primary)
     value = font:bold; color:blue;
   }
}
# Specific configuration for the Character/Text Style menu:
RTE.default.classesCharacter = mainBodyText\";s:7:\"default\";N;s:12:\"column_count\";i:2;s:16:\"is_propertyTable\";i:1;}}}',''),(2,15468566,'0804220e572dfe172ec49025a2c2c0b6','','page:RTE (1)','a:1:{s:4:\"rows\";a:1:{i:0;a:6:{s:8:\"property\";s:31:\" colors.[id-string]\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:828:\"Defines the colors available in the RTE.
 
Properties:
 .name = Label of the color in menu
 .value = The HTML-color value
 
Example:

# General configuration of the available colors:
RTE.colors {
   color1 {
     name = Background color
     value = blue
   }
   color2 {
     name = Another color I like!
     value = #775533
   }
   noColor {
     name = No color
     value =
   }
}
# Specific setting for the font color selector:
RTE.default.colors = color1, color2, noColor\";s:7:\"default\";N;s:12:\"column_count\";i:2;s:16:\"is_propertyTable\";i:1;}}}',''),(3,15468566,'3cf8da0790d4c4a193bb0063d3854fa1','','page:RTE (2)','a:1:{s:4:\"rows\";a:1:{i:0;a:6:{s:8:\"property\";s:30:\" fonts.[id-string]\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:814:\"Defines the fonts available in the RTE.
 
Properties:
 .name = Label of the font in menu
 .value = The font face value
 
Example:

# General configuration of the available fonts:
RTE.fonts {
   face1 {
     name = Verdana
     value = verdana, arial
   }
   face2 {
     name = Comic Sans
     value = Comic Sans MS
   }
   noFace {
     name = No font
     value =
   }
}
# Specific setting for the fontstyle selector:
RTE.default.fontFace = face2 , face1, noFace\";s:7:\"default\";N;s:12:\"column_count\";i:2;s:16:\"is_propertyTable\";i:1;}}}',''),(4,15468566,'59fc94bd610e53db6d78233908e29e91','','page:RTE (3)','a:1:{s:4:\"rows\";a:1:{i:0;a:6:{s:8:\"property\";s:133:\"default.[...]
config.[tablename].[field].[...]
config.[tablename].[field].types.[type].[...]\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:580:\"  This is a description of how you can customize in general and override for specific fields/types.
'RTE.default' configures the RTE for all tables/fields/types
'RTE.config.[tablename].[field]' configures a specific field. The values inherit the values from 'RTE.default' in fact this is overriding values.
'RTE.config.[tablename].[field].types.[type]' configures a specific field in case the 'type'-value of the field matches type. Again this overrides the former settings.\";s:7:\"default\";N;s:12:\"column_count\";i:2;s:16:\"is_propertyTable\";i:1;}}}',''),(5,15468566,'2d88f60bc82382f1ed40901ed9ed363a','','page:RTE.default/RTE.default.FE/RTE.config.(table).(field)/RTE.config.(table).(field).types.(type)','a:1:{s:4:\"rows\";a:62:{i:0;a:6:{s:8:\"property\";s:8:\"disabled\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:31:\"If set, the editor is disabled.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:16:\"classesParagraph\";s:8:\"datatype\";s:18:\"list of id-strings\";s:11:\"description\";s:1167:\"Classes available in the Paragraph Style selector.
The Paragraph Style selector lets you format a block of content also known typographically as a paragraph (the section between two linebreaks). The content of the paragraph is wrapped in block-tags and by default you can select between <Hx>, <P> and <PRE> formatting (you can disable any or all of these default values by the 'hidePStyleItems', see later).
 
Example:

This configuration would result in this Paragraph style selector (provided that the classes 'mainBodyText' and 'header2' are found in the RTE.classes definition, see above):
 
RTE.default {
   classesParagraph = mainBodyText, header2
}
 
In the case of htmlArea RTE, the classes must be defined either in one of the occurrences of the inlineStyle property or in the CSS file specified contentCSS property.
 
In the case of the Classic RTE, the classes defined in the 'classesParagraph' value are prepended to the types of paragraphs options. They are inserted as <DIV>-tags with a class-parameter.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:17:\"classesCharacter \";s:8:\"datatype\";s:18:\"list of id-strings\";s:11:\"description\";s:1039:\"Classes available for the Text Style selector.
 
The Character Style selector is used to format any string of text inside a paragraph, tablecell. So this formatting relates to the selected piece of text in opposition to the Paragraph Styles which always formats the current paragraph no matter the selection.
 
In the case of htmlArea RTE, the classes must be defined either in one of the occurrences of the inlineStyle property or in the CSS file specified contentCSS property.
 
In the case of htmlArea RTE, if the property is empty, classes associated with the span tag in either the inlineSyle properties or in the contentCSS file are used.
 
In the case of the Classic RTE, although the Character Style selector is aimed at text-formatting, it will also apply classes to other elements, for instance tables or images if selected as well as links and table-cells. The allowed classes for these operations may be configured separately by listing the classes with the options, you find below. \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:41:\"showTagFreeClasses
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:200:\"Specifies that CSS classes not associated with any tag in the contentCSS style sheet should be or should not be shown in the paragraph style and the text style selection lists.
 
Default: 0\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:17:\"disablePCexamples\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:216:\"If set, the examples of classes in Paragraph and Character selectors are disabled.
 
Note: In the case of htmlArea RTE, the styling is removed on the options of the Paragraph and Text style selector lists.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:44:\"disableTYPO3Browsers
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:265:\"If set, the TYPO3 element and image browsers are disabled.
 
Default: 0
 
Note: If set, the htmlArea plugin TYPO3Browsers is disabled.
 
Note: The TYPO3Browsers plugin is not available when the editor is used in the TYPO3 front end.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:12:\"classesImage\";s:8:\"datatype\";s:18:\"list of id-strings\";s:11:\"description\";s:458:\"Classes available for images.
 
In the case of htmlArea RTE, each of the listed class must be defined either in one of the occurrences of the inlineStyle property or in the CSS file specified by contentCSS property.
 
In the case of htmlArea RTE, the same list of classes is used in the class selection list of the Insert/Modify image dialog.
 
In the case of the Classic RTE, see description of 'classesCharacter'.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:17:\"blindImageOptions\";s:8:\"datatype\";s:15:\"list of strings\";s:11:\"description\";s:83:\"List of tab items in the image selector to remove. Key list is magic,plain,dragdrop\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:56:\"buttons.image.options.removeItems
(htmlArea RTE only)\";s:8:\"datatype\";s:15:\"list of strings\";s:11:\"description\";s:278:\"List of tab items to remove from the dialog of the image button. Possible tab items are: page,file,url,mail,spec
 
Note: If integration with DAM is enabled, upload is also a possible tab.
 
Note: This property is a synonymous of property blindImageOptions.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:59:\"buttons.image.options.magic.maxWidth
(htmlArea RTE only)\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:66:\"Maximum width of magic images in pixels.
 
Default: 300\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:60:\"buttons.image.options.magic.maxHeight
(htmlArea RTE only)\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:168:\"Maximum height of magic images in pixels.
 
Default: 1000
 
Note: By setting a large enough height, images should be resized based on their width.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:59:\"buttons.image.options.plain.maxWidth
(htmlArea RTE only)\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:77:\"Maximum width of selectable plain images in pixels.
 
Default: 640\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:60:\"buttons.image.options.plain.maxHeight
(htmlArea RTE only)\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:78:\"Maximum height of selectable plain images in pixels.
 
Default: 680\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:32:\"buttons.image.title.useDAMColumn\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:260:\"Name of the column of the tx_dam table that will be used to set the image title attribute.
 
Default: caption
 
Note: This property is ignore if the extension configuration variable “Enable the DAM media browser” is not set.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:36:\"classesAnchor
(htmlArea RTE only)\";s:8:\"datatype\";s:18:\"list of id-strings\";s:11:\"description\";s:392:\"Classes available in the Insert/Modify link dialog.
 
These classes must be defined by the RTE.classesAnchor property.
 
The following property specifies the default class of the class selector of the corresponding tab:
.default {
 page = className
 url = className
 file = className
 mail = className
} \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:13:\"classesLinks \";s:8:\"datatype\";s:18:\"list of id-strings\";s:11:\"description\";s:154:\"Classes available for links. See description of 'classesCharacter'.
 
In the case of htmlArea RTE, classesAnchor offers more options.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:17:\"defaultLinkTarget\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:54:\"This sets the default target for new links in the RTE.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:16:\"blindLinkOptions\";s:8:\"datatype\";s:15:\"list of strings\";s:11:\"description\";s:85:\"List of tab items in the link selector to remove. Key list is page,file,url,mail,spec\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:55:\"buttons.link.options.removeItems
(htmlArea RTE only)\";s:8:\"datatype\";s:15:\"list of strings\";s:11:\"description\";s:190:\"List of tab items to remove from the dialog of the link button. Possible tab items are: page,file,url,mail,spec
 
Note: This property is a synonymous of property blindLinkOptions.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:19;a:6:{s:8:\"property\";s:59:\"buttons.link.targetSelector.disabled
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:111:\"If set, the selection of link target is removed from the link insertion/update dialog.
 
Default : 0\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:20;a:6:{s:8:\"property\";s:58:\"buttons.link.popupSelector.disabled
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:127:\"If set the selection of a popup window as link target is removed from the link insertion/update dialog.
 
Default: 0\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:21;a:6:{s:8:\"property\";s:13:\"classesTable \";s:8:\"datatype\";s:18:\"list of id-strings\";s:11:\"description\";s:407:\"Classes available for tables. See description of 'classesCharacter'.
 
In the case of htmlArea RTE, each of the listed class must be defined either in one of the occurrences of the inlineStyle property or in the CSS file specified contentCSS property.
 
In the case of htmlArea RTE, the same list of classes is used in the class selection list of the Table Properties dialog.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:22;a:6:{s:8:\"property\";s:10:\"classesTD \";s:8:\"datatype\";s:18:\"list of id-strings\";s:11:\"description\";s:410:\"Classes available for tablecells. See description of 'classesCharacter'.
 
In the case of htmlArea RTE, each of the listed class must be defined either in one of the occurrences of the inlineStyle property or in the CSS file specified contentCSS property.
 
In the case of htmlArea RTE, the same list of classes is used in the class selection list of the Cell Properties dialog.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:23;a:6:{s:8:\"property\";s:7:\"colors \";s:8:\"datatype\";s:18:\"list of id-strings\";s:11:\"description\";s:260:\"Defines the specific colors generally available in the color selectors. The id-strings must be configured in the RTE.colors array (see description earlier).
 
Example:

RTE.default {
   colors = color1, color2,noColor
}\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:24;a:6:{s:8:\"property\";s:18:\"disableColorPicker\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:249:\"Disables the color picker matrix in all color dialogs. The color picker lets you select web-colors.
 
Note: In the case of htmlArea RTE, this applies only when the TYPO3 configurable color selection dialog is enabled (plugin SelectColor).\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:25;a:6:{s:8:\"property\";s:41:\"disableSelectColor
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:162:\"If set, the TYPO3 configurable color selection dialog is disabled.
 
Default: 0
 
Note: If set, the htmlArea plugin SelectColor is disabled.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:26;a:6:{s:8:\"property\";s:14:\"hideFontFaces \";s:8:\"datatype\";s:36:\"list of id-numbers,
* removes all\";s:11:\"description\";s:278:\"Lets you disable any of the default font faces in the Font Style selector. These are the possible values you can set:
 
1: Arial
2: Arial Black
3: Verdana
4: Times New Roman
5: Garamond
6: Lucida Handwriting
7: Courier
8: Webdings
9: Wingdings\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:27;a:6:{s:8:\"property\";s:9:\"fontFace \";s:8:\"datatype\";s:18:\"list of id-strings\";s:11:\"description\";s:152:\"Defines the specific fonts generally available in the font selector. The id-strings must be configured in the RTE.fonts array (see description earlier).\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:28;a:6:{s:8:\"property\";s:14:\"hideFontSizes \";s:8:\"datatype\";s:38:\"list of size-numbers,
* removes all\";s:11:\"description\";s:112:\"Lets you disable any of the default font sizes available in the Font Size selector. Values are ranging from 1-7.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:29;a:6:{s:8:\"property\";s:27:\"showButtons
hideButtons \";s:8:\"datatype\";s:18:\"list of id-strings\";s:11:\"description\";s:1224:\"Note: In the case of htmlArea RTE, available buttons are: blockstylelabel, blockstyle, textstylelabel, textstyle, fontstyle, fontsize, formatblock, bold, italic, underline, strikethrough, subscript, superscript, lefttoright, righttoleft, left, center, right, justifyfull, orderedlist, unorderedlist, outdent, indent, textcolor, bgcolor, textindicator, emoticon, insertcharacter, line, link, image, table, user, acronym, findreplace, spellcheck, chMode, inserttag, removeformat, copy, cut, paste, undo, redo, showhelp, about, toggleborders, tableproperties, rowproperties, rowinsertabove, rowinsertunder, rowdelete, rowsplit, columninsertbefore, columninsertafter, columndelete, columnsplit, cellproperties, cellinsertbefore, cellinsertafter, celldelete, cellsplit, cellmerge
 
Note: In the case of htmlArea RTE, if extension sr_static_info is not installed, the spellcheck button is not enabled.
 
Note:In the case of htmlArea RTE, the following elements will always be shown: undo redo, about.
 
Note: In the case of htmlArea RTE, buttons user and acronym are never available in the front end.
 
Note: In the case of htmlArea RTE, button Acronym is not currently available in IE.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:30;a:6:{s:8:\"property\";s:35:\"toolbarOrder
(htmlArea RTE only)\";s:8:\"datatype\";s:18:\"list of id-strings\";s:11:\"description\";s:1075:\"Specifies the order and grouping of buttons in the RTE tool bar. The keywords space, bar and linebreak may be used to insert a space, a separator or a line break at the corresponding position in the tool bar.
 
Default: blockstylelabel, blockstyle, space, textstylelabel, textstyle, bar, linebreak, fontstyle, space, fontsize, space, formatblock, bar, bold, italic, underline, bar, strikethrough, subscript, superscript, bar, lefttoright, righttoleft, bar, left, center, right, justifyfull, bar, orderedlist, unorderedlist, outdent, indent, bar, textcolor, bgcolor, textindicator, bar, emoticon, insertcharacter, line, link, image, table, user, acronym, bar, findreplace, spellcheck, bar, chMode, inserttag, removeformat, bar, copy, cut, paste, bar, undo, redo, bar, showhelp, about, linebreak, toggleborders, bar, tableproperties, bar, rowproperties, rowinsertabove, rowinsertunder, rowdelete, rowsplit, bar, columninsertbefore, columninsertafter, columndelete, columnsplit, bar, cellproperties, cellinsertbefore, cellinsertafter, celldelete, cellsplit, cellmerge\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:31;a:6:{s:8:\"property\";s:46:\"keepButtonGroupTogether
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:335:\"Specifies that all buttons of a button group are displayed on the same line of the tool bar. A button group is delimited by a linebreak or by a bar.
 
Default: 0
 
Note: If enabled, the setting is honored only by Mozilla/Firefox. It is ignored when the browser is Internet Explorer, Safari, Opera or Mozilla 1.3. \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:32;a:6:{s:8:\"property\";s:51:\"hideTableOperationsInToolbar
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:246:\"Specifies that table operations buttons should be hidden in the tool bar or not.
 
Default: 0
 
Note: If enabled, table operations will appear only in the context menu, provided that they may be enabled in the given context.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:33;a:6:{s:8:\"property\";s:49:\"keepToggleBordersInToolbar
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:77:\"This property is deprecated. Use property buttons.toggleborders.keepInToolbar\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:34;a:6:{s:8:\"property\";s:58:\"buttons.toggleborders.keepInToolbar
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:139:\"If set, the toggleborders button will be kept in the tool bar even if property hideTableOperationsInToolbar is set.
 
Default: 0\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:35;a:6:{s:8:\"property\";s:63:\"buttons.toggleborders.setOnTableCreation
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:142:\"If set, and if the toggleborders button is enabled, the table borders will be toggled on when a new table is created.
 
Default : 0\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:36;a:6:{s:8:\"property\";s:41:\"disableContextMenu
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:162:\"Specifies that the context menu should be disabled or not.
 
Default: 0
 
Note: This property is a synonymous of disableRightClick property.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:37;a:6:{s:8:\"property\";s:17:\"disableRightClick\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:62:\"If set, the right click (context) menu of the RTE is disabled.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:38;a:6:{s:8:\"property\";s:36:\"showStatusBar
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:88:\"Specifies that the editor status bar should be displayed or not.
 
Default: 0\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:39;a:6:{s:8:\"property\";s:18:\"mainStyleOverride \";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:1085:\"By default the editor style section is set with the CSS-code below. However you may override this by this option.
 
Default for Classic RTE:
 
BODY {
   border: 1px black solid;
   border-top: none;
   margin : 2 2 2 2;
   font-family:Verdana;
   font-size:10px;
   color:black;
   background-color:white;
}
TD {font-family:Verdana; font-size:10px;}
P {margin-top:0px; margin-bottom:5px;}
DIV {margin-top:0px; margin-bottom:5px;}
OL {margin: 5px 10px 5px;}
UL {margin: 5px 10px 5px;}
BLOCKQUOTE {margin-top:0px; margin-bottom:0px;}
 
Default for htmlArea RTE:
 

body.htmlarea-content-body {
 font-family: Verdana,sans-serif;
 font-size: 12px;
 color: black;
 background-color: white;
}
td { }
div { }
pre { }
ol { }
ul { }
blockquote { }
 
Note: In the case of htmlArea RTE, see also property ignoreMainStyleOverride.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:40;a:6:{s:8:\"property\";s:34:\"mainStyleOverride_add.[key]\";s:8:\"datatype\";s:18:\"string (css-style)\";s:11:\"description\";s:316:\"Allows to add style configuration to the values above (for .mainStyleOverride above)
Keys are:
.P / .DIV / .TD /.BODY / .BLOCKQUOTE /.OL / .UL / .PRE / .Hx will all take values which are prepended to the above settings.
 
Note: In the case of htmlArea RTE, see also property ignoreMainStyleOverride.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:41;a:6:{s:8:\"property\";s:72:\"mainStyle_font
mainStyle_size
mainStyle_color
mainStyle_bgcolor\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:269:\"Setting the default font-family (verdana) , font-size (10px), font-color (black) and background color (white)
The default is shown in “.mainStyleOverride” above.
 
Note: In the case of htmlArea RTE, see also property ignoreMainStyleOverride.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:42;a:6:{s:8:\"property\";s:33:\"inlineStyle.[any keysting]\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:196:\"CSS code to be included in the editor style section. This will be included after the default code.
 
Note: In the case of htmlArea RTE, see also property ignoreMainStyleOverride.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:43;a:6:{s:8:\"property\";s:27:\"skin
(htmlArea RTE only)\";s:8:\"datatype\";s:8:\"resource\";s:11:\"description\";s:809:\"The skin contains the CSS files and the images used to style the editor.
The skin is specified by specifying the location of the main CSS file to be used to style the editor. The folder containing the CSS file MUST also contain a structure of folders and files identical to the structure found in the folder of the default skin. All folder names and all file names must be identical.
 
Default: EXT:rtehtmlarea/htmlarea/skins/default/htmlarea.css
 
Note: Extensions sr_rtehtmlarea_bluelook and sr_rtehtmlarea_xpblue provide two additional example skins.
 
Note: these example skins do not work in Mozilla 1.3; if the property is set to one of them, the default skin will be used when the browser is Mozilla 1.3.
 
Note: See also property ignoreMainStyleOverride.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:44;a:6:{s:8:\"property\";s:33:\"contentCSS
(htmlArea RTE only)\";s:8:\"datatype\";s:8:\"resource\";s:11:\"description\";s:485:\"The CSS file that contains the style definitions that should be applied to the edited contents.
The selectors defined in this file will also be used by the DynamicCSS and InlineCSS plugins in the block style and text style selection lists.
 
Default: EXT:rtehtmlarea/htmlarea/plugins/DynamicCSS/dynamiccss.css
 
For example, this default could be overridden with: fileadmin/styles/my_contentCSS.css
 
Note: See also property ignoreMainStyleOverride.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:45;a:6:{s:8:\"property\";s:46:\"ignoreMainStyleOverride
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:678:\"Instruct htmlArea RTE to ignore properties mainStyleOverride and inlineStyle.
 
Default: 0
 
Note: In htmlArea RTE, the following style sheets apply to the contents of the editing area and are linked in the following order:
1. the htmlarea-edited-content.css file from the skin being used (contains selectors for use in the editor but not intended to be applied in the frontend);
2. a css file generated from the mainStyleOverride and inlineStyle assignments;
3. the css file specified by contentCSS in Page TSConfig.
When ignoreMainStyleOverride is enabled, the middle style sheet is ignored and only the first and third style sheets are used.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:46;a:6:{s:8:\"property\";s:4:\"proc\";s:8:\"datatype\";s:9:\"->PROC\";s:11:\"description\";s:104:\"Customization of the server processing of the content - also called 'transformations'.
See \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:47;a:6:{s:8:\"property\";s:38:\"enableWordClean
(htmlArea RTE only)\";s:8:\"datatype\";s:27:\"boolean/
->HTMLparser\";s:11:\"description\";s:592:\"Specifies that text pasted from external sources, presumably from Microsoft Word, should be “cleaned” or not.
 
Default: 0
 
Note:If no HTMLparser configuration is specified, a limited default cleaning operation will be performed. If a HTMLparser specification is specified, parsing will be performed on the server at the time of the paste operation.
 
Note: The HTMLparser configuration is ignored If TYPO3HtmlParser plugin is disabled.
 
Note: Additional cleanup may be performed by the user when the removeformat button is enabled.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:48;a:6:{s:8:\"property\";s:37:\"removeComments
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:134:\"Specifies that html comments should be removed or not by the editor on save and on toggle to HTML source mode.
 
Default: 0\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:49;a:6:{s:8:\"property\";s:33:\"removeTags
(htmlArea RTE only)\";s:8:\"datatype\";s:12:\"list of tags\";s:11:\"description\";s:92:\"List of tags that should be removed by the editor on save and on toggle to HTML source mode.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:50;a:6:{s:8:\"property\";s:44:\"removeTagsAndContents
(htmlArea RTE only)\";s:8:\"datatype\";s:12:\"list of tags\";s:11:\"description\";s:171:\"List of tags that should be removed by the editor, contents included, on save and on toggle to HTML source mode. The tags and the contents inside the tags will be removed.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:51;a:6:{s:8:\"property\";s:29:\"useCSS
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:198:\"Specifies that Mozilla/Firefox should use style attributes or not. When enabled, Mozilla/Firefox use span tags with style attributes rather than tags such as b, i, font, etc.
 
Default: 0\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:52;a:6:{s:8:\"property\";s:45:\"disableEnterParagraphs
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:549:\"Specifies that the insertion of paragraphs when hitting the Enter key in Mozilla/Firefox, Safari or Opera should be disabled.
 
Default: 0
 
Note: If NOT enabled, the behavior of Mozilla/Firefox, Safari and Opera is modified as follows: when the Enter key is pressed, instead of inserting a br tag, the behavior of Internet Explorer is simulated and a new paragraph is created.
 
Note: If enabled, the behavior of Mozilla/Firefox, Safari and Opera is not modified: a br tag is inserted when the Enter key is pressed.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:53;a:6:{s:8:\"property\";s:39:\"removeTrailingBR
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:398:\"Specifies that trailing br tags should be removed from block elements.
 
Default: 0
 
Note: If set, any trailing br tag in a block element will be removed on save and/or change mode. However, multiple trailing br tags will be preserved.
 
Note: In Mozilla/Firefox/Netscape, whenever some text is entered in an empty block, a trailing br tag is added by the browser.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:54;a:6:{s:8:\"property\";s:31:\"hideTags
(htmlArea RTE only)\";s:8:\"datatype\";s:12:\"list of tags\";s:11:\"description\";s:78:\"This property is deprecated. Use property buttons.inserttag.denyTags
 \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:55;a:6:{s:8:\"property\";s:49:\"buttons.inserttag.denyTags
(htmlArea RTE only)\";s:8:\"datatype\";s:12:\"list of tags\";s:11:\"description\";s:331:\"List of tag names that should NOT be shown by the dialog of the inserttag button.
 
Note: Listed tag names should be among the following: a, abbr, acronym, address, b, big, blockquote, cite, code, div, em, fieldset, font, h1, h2, h3, h4, h5, h6, i, legend, li, ol, p, pre, q, small, span, strong, sub, sup, table, tt, ul\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:56;a:6:{s:8:\"property\";s:55:\"buttons.inserttag.allowedAttribs
(htmlArea RTE only)\";s:8:\"datatype\";s:18:\"list of attributes\";s:11:\"description\";s:346:\"List of attribute names that should be shown for all tags in the dialog of the inserttag button.
 
Note: Listed attribute names should be among the following: class, dir, id, lang, onFocus, onBlur, onClick, onDblClick, onMouseDown, onMouseUp, onMouseOver, onMouseMove, onMouseOut, onKeyPress, onKeyDown, onKeyUp, style, title, xml:lang\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:57;a:6:{s:8:\"property\";s:77:\"buttons.inserttag.tags.[tagname].allowedAttribs
(htmlArea RTE only)\";s:8:\"datatype\";s:18:\"list of attributes\";s:11:\"description\";s:207:\"List of attribute names that should be shown for the specified tagname in the dialog of the inserttag button, in addition to the attribute names specified by property buttons.inserttag.allowedAttribs.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:58;a:6:{s:8:\"property\";s:233:\"disableAlignmentFieldsetInTableOperations
disableSpacingFieldsetInTableOperations
disableColorFieldsetInTableOperations
disableLayoutFieldsetInTableOperations
disableBordersFieldsetInTableOperations
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:93:\"Disables the corresponding fieldsets of the table operations dialogs.
 
Default: 0\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:59;a:6:{s:8:\"property\";s:42:\"enablePersonalDicts
(htmlArea RTE only)\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:393:\"Specify that personal dictionaries should be enabled or not.
 
Default: 0
 
Note: The SpellChecker plgin must be enabled.
 
Note: The option is ignored if PHP safe_mode is enabled on the server.
 
Note: The feature must also be enabled in User TSConfig.
 
Note: Personal dictionaries are stored in subdirectories of uploads/tx_rtehtmlarea\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:60;a:6:{s:8:\"property\";s:16:\"userElements.[#]\";s:8:\"datatype\";s:24:\"string/->userCategory\";s:11:\"description\";s:166:\"Configuration of the categories of user elements
The string value sets the name of the category. Value is language-splitted (by |) to allow for multiple languages.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:61;a:6:{s:8:\"property\";s:13:\"userLinks.[#]\";s:8:\"datatype\";s:21:\"string/->userLinks\";s:11:\"description\";s:154:\"Configuration of user defined links.
The string value sets the name of the category. Value is language-splitted (by |) to allow for multiple languages.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}}}',''),(6,15468566,'99b7f3224572b281e0d0c4e5fe5efb01','','page:RTE (4)','a:1:{s:4:\"rows\";a:1:{i:0;a:6:{s:8:\"property\";s:55:\"classesAnchor.[id-string]
(htmlArea RTE only)\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:1489:\"Attaches special properties to the classes available in the Insert/Modify link dialog.
 
Properties:
 
.class = CSS-class-name: the name of the CSS class to which the properties are attached
 
.type = page, url, file, mail or spec: specifies that the class applies to anchors for internal pages, external URL's, files, email addresses or special user-defined links respectively; the class will be presented only in the corresponding tab of the TYPO3 link browser
 
.image = URL of an icon file that will prefix the content of the anchor when the class is applied to an anchor; the TYPO3 syntax EXT:extension-key/sub-directory/image-file-name may be used
 
.altText = the text that will be used as altText for the image when the class is applied to an anchor; may be language-splitted; the TYPO3 syntax LLL:EXT:extension-key/sub-directory/locallang.php:label-index may also be used in order for the text to be localized to the language of the content using the specified language file and label index
 
.titleText = the text that will be used as title for the anchor when the class is applied to an anchor; may be language-splitted; the TYPO3 syntax LLL:EXT:extension-key/sub-directory/locallang.php:label-index may also be used in order for the text to be localized to the language of the content using the specified language file and label index
 
See the Demo default configuration for a complete example.\";s:7:\"default\";N;s:12:\"column_count\";i:2;s:16:\"is_propertyTable\";i:1;}}}',''),(7,15468566,'6da9b57fd30da516b101104fc9ea2d0b','','page:->userCategory','a:1:{s:4:\"rows\";a:4:{i:0;a:6:{s:8:\"property\";s:4:\"load\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:320:\"If set, the a predefined set of user element is loaded into this category. They are always loaded in the key starting with 100 and then forward in steps of 10.
Current options are:
“images_from_folder”: Loads gif,jpg,jpeg,png images from the specified folder (defined by the .path property)
 \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:5:\"merge\";s:8:\"datatype\";s:7:\"Boolean\";s:11:\"description\";s:106:\"If set, then any manually configured user elements are merged onto the ones loaded by the .load operation.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:4:\"path\";s:8:\"datatype\";s:6:\"String\";s:11:\"description\";s:198:\"(Applies for load=images_from_folder only)
 
Sets the path of the folder from which to fetch the images (gif,jpg,jpeg,png)
 
Example:

.path = fileadmin/istate/\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:3:\"[#]\";s:8:\"datatype\";s:24:\"string/->userElements\";s:11:\"description\";s:1942:\"Configuration of the user elements.
The string value is the name of the user element. Language-splitted.
 
Example:

 
RTE.default.userElements {
     # Category with various elements
   10 = Various elements | Diverse elements
   10 {
       # An image is inserted
     1 = Logo 1 | Bomærke 1
     1.description = This is the logo number 1. | Dette er logo nummer 1
     1.content = <img src="###_URL###fileadmin/istate/curro.png">
 
       # The text-selection is wrapped with <sup> tags.
     2 = Subscript
     2.description = Selected text is wrapped in <sup>-tags.
     2.mode = wrap
     2.content = <sup>|</sup>
 
       # This submits the selected text content to the script, rte_cleaner.php
     5 = Strip all tags
     5.description = All HTML-codes are removed from selection.
     5.mode = processor
     5.submitToScript = typo3/rte_cleaner.php
   }
 
     # Category with images from the fileadmin/istate/ folder
   2.load = images_from_folder
   2.merge = 1
   2.path = fileadmin/istate/
     # here the logo from “Various elements” is included as well
   2.1 < .10.1
}
   # Show the user-button, if not existing
RTE.default.showButtons = user
 \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}}}',''),(8,15468566,'e65752d4886a06cb12258917b801963b','','page:->userElements','a:1:{s:4:\"rows\";a:5:{i:0;a:6:{s:8:\"property\";s:4:\"mode\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:609:\"Which kind of object it is.
 
Options:
“wrap”: If a wrap, then the content is exploded by “|” and wrapped around the current text selection.
 
“processor”: The content is submitted to the php-script defined by .submitToScript. GPvar(“processContent”) carries the selection content of the RTE and GPvar(“returnUrl”) contains the return url. (The “content” property is not used here!)
 
default: The content is just inserted (pasted into) at the cursor or substituting any current selection.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:11:\"description\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:75:\"A short description shown beneath the user element title (which is in bold)\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:7:\"content\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:41:\"The content inserted/wrapped into the RTE\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:14:\"submitToScript\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:353:\"(Applies only to mode=processor)
 
PHP script to which the current text selection of the RTE is submitted. The script must be relative to the site-url or a full url starting with http://...
 
Example:

.submitToScript = typo3/rte_cleaner.php
or
.submitToScript = http://www.domain.org/some_extenal_script.php\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:17:\"dontInsertSiteUrl\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:254:\"If set, the marker ###_URL### in the content property's content IS NOT substituted by the current site url. Normally you wish to do this for all image-references which must be prepended with the absolute url in order to display correctly in the RTE!\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}}}',''),(9,15468566,'50145cc03f5f985111bb4fe700f38bdb','','page:->userLinks','a:1:{s:4:\"rows\";a:3:{i:0;a:6:{s:8:\"property\";s:3:\"url\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:120:\"The url.
If set, the marker ###_URL### in the content property's content is substituted by the current site url.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:11:\"description\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:67:\"A short description shown beneath the link title (which is in bold)\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:6:\"target\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:27:\"Default target (if isset())\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}}}',''),(10,12476640,'76a6a76544ea76b5e7ba2a6a1fba2965','','page:RTE (5)','a:1:{s:4:\"rows\";a:2:{i:0;a:6:{s:8:\"property\";s:133:\"default.[...]
config.[tablename].[field].[...]
config.[tablename].[field].types.[type].[...]\";s:8:\"datatype\";s:12:\"->RTEconf\";s:11:\"description\";s:610:\"  This is a description of how you can customize in general and override for specific fields/types.
 
'RTE.default' configures the RTE for all tables/fields/types
 
'RTE.config.[tablename].[field]' configures a specific field. The values inherit the values from 'RTE.default' in fact this is overriding values.
 
'RTE.config.[tablename].[field].types.[type]' configures a specific field in case the 'type'-value of the field matches type. Again this overrides the former settings.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:24:\"[individual RTE options]\";s:8:\"datatype\";s:1:\"-\";s:11:\"description\";s:469:\"There are other options to set for the RTE toplevel object. These depends on the individual RTEs though! So there can be no further reference in this table to these properties.
Generally the "rte" (classic MSIE RTE) will set the standard for configuration options, so you can refer to the documentation for that RTE for more details. On the top level of the RTE object you will normally find that general collections of classes, styles etc. are configured.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}}}',''),(11,12476640,'ccb0322c7d1f7b0e49e1c8b981aacd1e','','page:->RTEconf','a:1:{s:4:\"rows\";a:3:{i:0;a:6:{s:8:\"property\";s:8:\"disabled\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:128:\"If set, the editor is disabled.
This option is evaluated in t3lib_TCEforms where it determines if the RTE is rendered or not.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:4:\"proc\";s:8:\"datatype\";s:9:\"->PROC\";s:11:\"description\";s:446:\"Customization of the server processing of the content - also called 'transformations'. See table below.
The transformations are only initialized, if they are configured (“rte_transform” must be set for the field in the types-definition in TCA.)
The "->PROC" object is processed in "t3lib_parsehtml_proc" and is independant of the particular RTE used (like transformations generally is!)\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:24:\"[individual RTE options]\";s:8:\"datatype\";s:1:\"-\";s:11:\"description\";s:200:\"Each RTE may use additional properties for the RTE. Typically such properties relates to the features of the RTE application. For instance you could configure which tool bar buttons are available etc.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}}}',''),(12,12476640,'11acbecfba402c242e0ad130ba3140d1','','page:->PROC','a:1:{s:4:\"rows\";a:28:{i:0;a:6:{s:8:\"property\";s:12:\"overruleMode\";s:8:\"datatype\";s:28:\"List of RTE transformations \";s:11:\"description\";s:171:\"This can overrule the RTE transformation set from TCA.
 
Notice, this is a comma list of transformation keys. (Not a "dash-list" like in $TCA).\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:8:\"typolist\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:294:\"(Applies for “ts_transform” only)
 
This enables/disables the conversion between <TYPOLIST> and <UL> sections. Default (if unset) is that "typolist" is enabled.
 
Example that disables "typolist":

typolist = 0\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:8:\"typohead\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:234:\"(Applies for “ts_transform” only)
 
This enables/disables the conversion between <TYPOHEAD> and <Hx> sections.
 
Example that disables "typohead":

typohead = 0\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:13:\"preserveTags \";s:8:\"datatype\";s:12:\"list of tags\";s:11:\"description\";s:843:\"(DEPRECATED)
 
Here you may specify a list of tags - possibly user-defined pseudo tags - which you wish to preserve from being removed by the RTE. See the information about preservation in the description of transformations.
 
Example:

In the default TypoScript configuration of content rendering the tags typotags <LINK>, <TYPOLIST> and <TYPOHEAD> are the most widely used. However the <TYPOCODE>-tag is also configured to let you define a section being formatted in monospace. Lets also imaging, you have defined a custom tag, <MYTAG>. In order to preserve these tag from removal by the RTE, you should configure like this.
 
RTE.default.proc {
   preserveTags = TYPOCODE, MYTAG
}
 
Relates to the transformation 'ts_preserve'\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:21:\"dontConvBRtoParagraph\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:297:\"(Applies for “ts_transform” and "css_transform" only (function divideIntoLines))
 
 By default <BR> tags in the content are converted to paragraphs. Setting this value will prevent the convertion of <BR>-tags to new-lines (chr(10))\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:19:\"internalizeFontTags\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:548:\"(Applies for “ts_transform” and "css_transform" only (function divideIntoLines))
 
This splits the content into font-tag chunks.
If there are any <P>/<DIV> sections inside of them, the font-tag is wrapped AROUND the content INSIDE of the P/DIV sections and the outer font-tag is removed.
This functions seems to be a good choice for pre-processing content if it has been pasted into the RTE from eg. star-office.
In that case the font-tags is normally on the OUTSIDE of the sections.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:16:\"allowTagsOutside\";s:8:\"datatype\";s:20:\"commalist of strings\";s:11:\"description\";s:294:\"(Applies for “ts_transform” and "css_transform" only (function divideIntoLines))
 
 Enter tags which are allowed outside of <P> and <DIV> sections when converted back to database.
Default is “img”
Example:
IMG,HR\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:20:\"allowTagsInTypolists\";s:8:\"datatype\";s:20:\"commalist of strings\";s:11:\"description\";s:221:\"(Applies for “ts_transform” only)
 
Enter tags which are allowed inside of <typolist> tags when content is sent to the database.
Default is “br,font,b,i,u,a,img,span”\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:9:\"allowTags\";s:8:\"datatype\";s:20:\"commalist of strings\";s:11:\"description\";s:348:\"(Applies for “ts_transform” and "css_transform" only (function getKeepTags))
 
Tags to allow. Notice, this list is added to the default list, which you see here:
b,i,u,a,img,br,div,center,pre,font,hr,sub,sup,p,strong,em,li,ul,ol,blockquote,strike,span
If you wish to deny some tags, see below.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:8:\"denyTags\";s:8:\"datatype\";s:20:\"commalist of strings\";s:11:\"description\";s:154:\"(Applies for “ts_transform” and "css_transform" only (function getKeepTags))
 
Tags from above list to disallow.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:31:\"HTMLparser_rte
HTMLparser_db\";s:8:\"datatype\";s:15:\"->HTMLparser\";s:11:\"description\";s:955:\"(Applies for “ts_transform” and "css_transform" only (function getKeepTags))
 
This is additional options to the HTML-parser calls which strips of tags when the content is prepared for the RTE and DB respectively. You can configure additional rules, like which other tags to preserve, which attributes to preserve, which values are allowed as attributes of a certain tag etc.
 .nestingGlobal for HTMLparser_db is set by default to “b,i,u,a,center,font,sub,sup,strong,em,strike,span” unless another value is set.
Also B/I tags are mapped to STRONG/EM tags in the RTE direction and vise versa.
This parsing is done on a per-line basis, so you cannot expect the paragraph tags (P or DIV) to be included.
 

 Notice the ->HTMLparser options, “keepNonMatchedTags” and “htmlSpecialChars” is NOT observed. They are preset internally\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:24:\"dontRemoveUnknownTags_db\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:532:\"(Applies for “ts_transform” and "css_transform" only (function HTMLcleaner_db))
 
Direction: To database
Default is to remove all unknown tags in the content going to the database. (See HTMLparser_db above for default tags). Generally this is a very usefull thing, because all kinds of bogus tags from pasted content like that from Word etc. will be removed to have clean content in the database.
However this disables that and allows all tags, that are not in the HTMLparser_db-list.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:14:\"dontUndoHSC_db\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:335:\"(Applies for “ts_transform” and "css_transform" only (function HTMLcleaner_db))
 
Direction: To database
Default is to re-convert literals to characters (that is &lt; to <) outside of HTML-tags. This is disabled by this boolean. (HSC means HtmlSpecialChars - which is a PHP function)\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:26:\"dontProtectUnknownTags_rte\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:574:\"(Applies for “ts_transform” and "css_transform" only (function setDivTags))
 
Direction: To RTE
 Default is that tags unknown to HTMLparser_rte is “protected” when sent to the RTE. This means they are converted from eg <MYTAG> to &lt;MYTAG&gt;. This is normally very fine, because it can be edited plainly by the editor and when returned to the database the tag is (by default, disabled by .dontUndoHSC_db) converted back.
Setting this option will prevent unknown tags from becoming protected.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:11:\"dontHSC_rte\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:348:\"(Applies for “ts_transform” and "css_transform" only (function setDivTags))
 
Direction: To RTE
Default is that all content outside of HTML-tags is passed through htmlspecialchars(). This will disable that. (opposite to .dontUndoHSC_db)
This option disables the default htmlspecialchars() conversion.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:21:\"dontConvAmpInNBSP_rte\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:299:\"(Applies for “ts_transform” and "css_transform" only (function setDivTags))
 
Direction: To RTE
By default all &nbsp; codes are NOT converted to &amp;nbsp; which they naturally word (unless .dontHSC_rte is set). You can disable that by this flag.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:17:\"allowedFontColors\";s:8:\"datatype\";s:18:\"list of HTMLcolors\";s:11:\"description\";s:226:\"(Applies for “ts_transform” and "css_transform" only (function getKeepTags))
 
Direction: To DB
If set, this is the only colors which will be allowed in font-tags! Case insensitive.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:14:\"allowedClasses\";s:8:\"datatype\";s:15:\"list of strings\";s:11:\"description\";s:644:\"(Applies for “ts_transform” and "css_transform" only (function getKeepTags))
 
Direction: To DB
 Allowed general classnames when content is stored in database. Could be a list matching the number of defined classes you have. Case-insensitive.
This might be a really good idea to do, because when pasting in content from MS word for instance there are a lot of <SPAN> and <P> tags which may have class-names in. So by setting a list of allowed classes, such foreign classnames are removed.
If a classname is not found in this list, the default is to remove the class-attribute.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:22:\"skipAlign
skipClass\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:372:\"(Applies for “ts_transform” and "css_transform" only (function divideIntoLines))
 
If set, then the align and class attributes of <P>/<DIV> sections (respectively) will be ignored. Normally <P>/<DIV> tags are preserved if one or both of these attributes are present in the tag. Otherwise it's removed.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:19;a:6:{s:8:\"property\";s:15:\"keepPDIVattribs\";s:8:\"datatype\";s:32:\"list of tag attributes (strings)\";s:11:\"description\";s:299:\"(Applies for “ts_transform” and "css_transform" only (function divideIntoLines))
 
“align” and “class” are the only attributes preserved for <P>/<DIV> tags. Here you can specify a list of other attributes to preserve.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:20;a:6:{s:8:\"property\";s:17:\"remapParagraphTag\";s:8:\"datatype\";s:16:\"string / boolean\";s:11:\"description\";s:536:\"(Applies for “ts_transform” and "css_transform" only (function divideIntoLines))
 
When <P>/<DIV> sections are converted to be put into the database, the tag - P or DIV - is preserved. However setting this options to either P or DIV will force the section to be converted to the one or the other.
If the value is set true (1), then it works as a general disable-flag for the whole section-convertion stuff here and the result will be no tags preserved what so ever. Just removed.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:21;a:6:{s:8:\"property\";s:27:\"useDIVasParagraphTagForRTE \";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:288:\"(Applies for “ts_transform” only and "css_transform" (function TS_transform_rte))
 
Use <DIV>-tags for sections when converting lines from database to RTE. Default is <P>. Applies only to lines which has NO tag wrapped around already.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:22;a:6:{s:8:\"property\";s:14:\"preserveTables\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:91:\"(Applies for “ts_transform”)
 
If set, tables are preserved\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:23;a:6:{s:8:\"property\";s:20:\"dontFetchExtPictures\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:208:\"(Applies for “ts_images”)
 
If set, images from external urls are not fetched for the page if content is pasted from external sources. Normally this process of copying is done.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:24;a:6:{s:8:\"property\";s:14:\"plainImageMode\";s:8:\"datatype\";s:14:\"boolean/string\";s:11:\"description\";s:1107:\"(Applies for “ts_images”)
 
If set, all “plain” local images (those that are not magic images) will be cleaned up in some way.
If the value is just set, then the style attribute will be removed after detecting any special width/height CSS attributes (which is what the RTE will set if you scale the image manually) and the border attribute is set to zero.
You can also configure with special keywords. So setting “plainImageMode” to any of the value below will perform special processing:
 
“lockDimensions” : This will read the real dimensions of the image file and force these values into the <img> tag. Thus this option will prevent any user applied scaling in the image!
“lockRatio” : This will allow users to scale the image but will automatically correct the height dimension so the aspect ratio from the original image file is preserved.
“lockRatioWhenSmaller” : Like “lockRatio”, but will not allow any scaling larger than the original size of the image.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:25;a:6:{s:8:\"property\";s:84:\"exitHTMLparser_rte
exitHTMLparser_db
entryHTMLparser_rte
entryHTMLparser_db\";s:8:\"datatype\";s:23:\"boolean/->HTMLparser\";s:11:\"description\";s:274:\"(Applies for all kinds of processing)
 
Allows you to enable/disable the HTMLparser for the content before (entry) and after (exit) the content is processed with the predefined processors (eg. ts_images or ts_transform).
There is no default values set. \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:26;a:6:{s:8:\"property\";s:22:\"disableUnifyLineBreaks\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:250:\"(Applies for all kinds of processing)
 
When entering the processor all rn linebreaks are converted to n (13-10 to 10). When leaving the processor all n is reconverted to rn (10 to 13-10).
This options disables that processing...\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:27;a:6:{s:8:\"property\";s:43:\"usertrans.[user-defined transformation key]\";s:8:\"datatype\";s:1:\"-\";s:11:\"description\";s:110:\"Custom option-space for userdefined transformations.
See example from section about custom transformations.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}}}',''),(13,6356713,'284eaff2c8b565d4257002d25e85e0ec','','beuser','a:1:{s:4:\"rows\";a:9:{i:0;a:6:{s:8:\"property\";s:8:\"admPanel\";s:8:\"datatype\";s:13:\"->ADMPANEL\";s:11:\"description\";s:43:\"Options regarding the front-end admin panel\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:7:\"options\";s:8:\"datatype\";s:12:\"->OPTIONS\";s:11:\"description\";s:29:\"Options for the user, various\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:3:\"mod\";s:8:\"datatype\";s:38:\"(see ->MOD of Page TSconfig)\";s:11:\"description\";s:91:\"Overriding values for the backend modules
 Deprecated. Use page.mod instead!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:32:\"setup.defaults
setup.override\";s:8:\"datatype\";s:10:\"->SETUP\";s:11:\"description\";s:481:\"Default values and override values for the user settings known from the setup module.
 
Notice:

There is a tricky aspect to these settings; If first you have set a value by setup.override and then removes it again you will experience that the value persists to exist. This is because it is saved in the backend users profile. Therefore, if you have once set a value, do not remove it again by rather set it blank if you want to disable the effect again!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:31:\"TCAdefaults.[tablename].[field]\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:754:\"Sets default values for records. The order of default values when creating new records in the backend is this:
Value from $TCA
Value from User TSconfig (these settings)
Value from “defVals” GET vars (see alt_doc.php)
Value from previous record based on 'useColumnsForDefaultValues'
 
However the order for default values used by tcemain.php if a certain field is not granted access to for user will be:
Value from $TCA
Value from User TSconfig (these settings)
 
So these values will be authoritative if the user has no access to the field anyway.
 
Example:

This sets the default hidden flag for pages to “clear”
 
TCAdefaults.pages.hidden = 0\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:4:\"user\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:87:\"This is for custom purposes.
Deprecated, use "tx_*" below from extensions\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:4:\"auth\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:203:\"Configuration for authentication services. Currently these are the options:
 
auth.BE.redirectToURL

Specifies a URL to redirect to after login is performed in the backend login form.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:4:\"page\";s:8:\"datatype\";s:28:\"all page TSconfig properties\";s:11:\"description\";s:195:\"You can override all page TSconfig properties by putting them into user
TSconfig and prefixing them with page.
 
Example:

page.TCEMAIN.table.pages.disablePrependAtCopy = 1\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:37:\"tx_[extension key with no underscore]\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:38:\"This is reserved space for extensions.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(14,6356713,'7cd94e953cc449fe4c0856671acf229d','','beuser:admPanel','a:1:{s:4:\"rows\";a:4:{i:0;a:6:{s:8:\"property\";s:6:\"enable\";s:8:\"datatype\";s:8:\"[object]\";s:11:\"description\";s:253:\"Used to enable the various parts of the panel for users.
All values are 0/1 booleans.
 

General:

.all: enables all modules
 

Modules:

.preview
.cache
.publish
.edit
.tsdebug
.info\";s:7:\"default\";s:57:\"(For admin-users, all = 1 is default! Hardcoded in class)\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:4:\"hide\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:93:\"If set, the panel will not display in the bottom of the page. This has only a visual effect. \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:8:\"override\";s:8:\"datatype\";s:8:\"[object]\";s:11:\"description\";s:944:\"Override all admin panel settings:
.[modulename].[propertyname]
 
Note:

You have to activate a module first by setting
.modulename = 1
 
Full reference:

To find out the name of a modulename/property, you can have a look at the HTML code of the admin panel and watch the names of the form elements. In this example, the module name is “tsdebug”, and the property is called “displayTimes”:
name="TSFE_ADMIN_PANEL[tsdebug_displayTimes]"

 
Most common options

.preview.showHiddenPages (boolean)
.preview.showHiddenRecords (boolean)
.preview.simulateDate (timestamp)
.preview.simulateUserGroup (integer)
 
.cache.noCache (boolean)
.cache.clearCacheLevels (integer)
 
.edit.displayFieldIcons (boolean)
.edit.displayIcons (boolean)
.edit.editFormsOnPage (boolean)
.edit.editNoPopup (boolean)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:11:\"module.edit\";s:8:\"datatype\";s:8:\"[object]\";s:11:\"description\";s:703:\" DEPRECATED, use override.* instead (see above).
 

 .forceDisplayIcons (boolean):
Forces edit-panels to appear regardless of the selectorbox.

 .forceDisplayFieldIcons (boolean):
Forces edit-icons to appear regardless of the selectorbox.

 .forceNoPopup (boolean):
Forces edit-forms to open in same window - not pop up window.

 

Example, that forces the display of the edit icons without displaying the admin-panel itself:

 
admPanel {
   enable.edit = 1
   module.edit.forceDisplayFieldIcons = 1
   hide = 1
}\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(15,6356713,'114e940842aa2d2d8a1efb37b1191103','','beuser:options','a:1:{s:4:\"rows\";a:35:{i:0;a:6:{s:8:\"property\";s:20:\"dontMountAdminMounts\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:158:\"This options prevents the root to be mounted for an admin user.
 

 NOTE: Only for admin-users. For other users it has no effect.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:10:\"RTEkeyList\";s:8:\"datatype\";s:18:\"[list of keywords]\";s:11:\"description\";s:299:\"This is a list of the Rich Text Editor buttons the user may see displayed. The user will not see any buttons not listed here.
 
Either enter a comma list of button keywords (see “TYPO3 Core API / RTE section”) or specify all with a wildcard “*” for everything.\";s:7:\"default\";s:48:\"*
(If value is not set at all, *, is default)\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:16:\"clearCache.pages\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:53:\"This will allow a user to clear the whole page cache.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:14:\"clearCache.all\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:82:\"This will allow a user to clear all cache (that is everything including templates)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:8:\"lockToIP\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:566:\"List of IP-numbers with wildcards.
 
 Note: This option is enabled only if the TYPO3_CONF_VARS[BE][enabledBeUserIPLock] configuration is true.
 

Examples:

192.168.*.*    
- will allow all from 192.168-network
 
192.168.*.*, 212.22.33.44    
- will allow all from 192.168-network plus all from REMOTE_ADDR 212.22.33.44
 
192.168, 212.22.33.44    
- the same as the previous. Leaving out parts of the IP address is the same as wild cards...\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:13:\"saveClipboard\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:129:\"If set, the clipboard content will be preserved for the next login. Normally the clipboard content lasts only during the session.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:19:\"clipboardNumberPads\";s:8:\"datatype\";s:10:\"int (0-20)\";s:11:\"description\";s:65:\"This allows you to enter how many pads you want on the clipboard.\";s:7:\"default\";s:1:\"3\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:20:\"disableDocModuleInAB\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:82:\"If set, the doc module is not displayed in the backend even if enabled in general.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:13:\"shortcutFrame\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:63:\"If set, the shortcut frame in the bottom of the window appears.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:14:\"shortcutGroups\";s:8:\"datatype\";s:25:\"Array of integers/strings\";s:11:\"description\";s:819:\"Set shortCutGroups that can be accessed by the user.
By default, 5 default groups will be defined globally (shared, can only be set by admins) and also for each user (personal shortcuts):
 
1: Pages
2: Records
3: Files
4: Tools
5: Miscellaneous
 
Set 0 to disable one of these group IDs, 1 to enable it (this is the
default) or "string" to change the label accordingly.
 
Example:

shortcutGroups {
   1=1
   2=My Group
   3=0
   4=
}
 
Shortcut group 1 is loaded with the default label (Pages), group 2 is loaded and labeled as "My Group" and groups 3 and 4 are disabled. Group 5 has not been set, so it will be displayed by default, just like group 1.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:33:\"shortcut_onEditId_dontSetPageTree\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:131:\"If set, the page tree is not opened to the page being edited when an id number is entered in the “Edit Id” box\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:38:\"shortcut_onEditId_keepExistingExpanded\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:189:\"If set, the existing expanded pages in the page tree are not collapsed when an id is entered in the “Edit Id” box.
(provided .shortcut_onEditId_dontSetPageTree is not set!)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:25:\"mayNotCreateEditShortcuts\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:91:\"If set, then the user cannot create or edit shortcuts. Depends on .shortcutFrame being set.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:17:\"createFoldersInEB\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:103:\"If set, a createFolders option appears in the element browser (for admin-users this is always enabled).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:12:\"noThumbsInEB\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:67:\"If set, then image thumbnails are not shown in the element browser.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:24:\"noThumbsInRTEimageSelect\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:61:\"As .noThumbsInEB but for the Rich Text Editor image selector.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:21:\"uploadFieldsInTopOfEB\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:82:\"If set, the upload-fields in the element browser are put in the top of the window.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:32:\"saveDocNew
saveDocNew.[table]\";s:8:\"datatype\";s:29:\"boolean / “top”\";s:11:\"description\";s:487:\"If set, a button “Save and create new” will appear in TCEFORMs.
Any value set for a single table will override the default value set to the object “saveDocNew”.
 
Example:

In this example the button is disabled for all tables, except tt_content where it will appear, and in addition create the records in the top of the page (default is after instead of top).
 
options.saveDocNew = 0
options.saveDocNew.tt_content = top\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:38:\"disableDelete
disableDelete.[table]\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:133:\"Disables the “Delete” button in TCEFORMs.
Overriding for single tables works like “saveDocNew” above.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:19;a:6:{s:8:\"property\";s:34:\"showHistory
showHistory.[table]\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:130:\"Shows link to the history for the record in TCEFORMs.
Overriding for single tables works like “saveDocNew” above.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:20;a:6:{s:8:\"property\";s:80:\"pageTree.disableIconLinkToContextmenu
folderTree.disableIconLinkToContextmenu\";s:8:\"datatype\";s:35:\"boolean / “titlelink”\";s:11:\"description\";s:207:\"If set, the page/folder-icons in the page/folder tree will not activate the clickmenu.
If the value is set “titlelink” then the icon will instead be wrapped with the same link as the title.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:21;a:6:{s:8:\"property\";s:30:\"pageTree.disableTitleHighlight\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:78:\"If set, the page titles in the page tree will not be highlighted when clicked.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:22;a:6:{s:8:\"property\";s:28:\"pageTree.showPageIdWithTitle\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:109:\"If set, the titles in the page navigation tree will have their ID numbers printed before the clickable title.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:23;a:6:{s:8:\"property\";s:32:\"pageTree.showDomainNameWithTitle\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:204:\"If set, the domain name will be appended to the page title for
pages that have "Is root of web site?" checked in the page properties.
Useful if there are several domains in one page tree.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:24;a:6:{s:8:\"property\";s:28:\"pageTree.onlineWorkspaceInfo\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:135:\"If set, the workspace info box will also be shown in the page tree even in online mode. Recommended when working with workspaces a lot.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:25;a:6:{s:8:\"property\";s:43:\" contextMenu.[key].disableItems\";s:8:\"datatype\";s:13:\"list of items\";s:11:\"description\";s:895:\"List of context menu (“clickmenu”) items to disable.
“key” points to which kind of icon that brings up the menu, and possible options are “pageTree”, “pageList”, “folderTree”, “folderList”. “page” and “folder” obviously points to either the Web og File main module. “Tree” and “List” points to whether the menu is activated from the page/folder tree or the listing of records/files
Items to disable are (for “page” type - that is database records):
 
view,edit,hide,new,info,copy,cut,paste,delete,move_wizard,
history,perms,new_wizard,hide,edit_access,edit_pageheader,db_list
 
Items to disable are (for “folder” type - that is files/folders):
edit,upload,rename,new,info,copy,cut,paste,delete\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:26;a:6:{s:8:\"property\";s:29:\"contextMenu.options.leftIcons\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:70:\"If set, the icons in the clickmenu appear to the left instead of right\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:27;a:6:{s:8:\"property\";s:42:\" contextMenu.options.clickMenuTimeOut\";s:8:\"datatype\";s:10:\"int, 1-100\";s:11:\"description\";s:93:\"Number of seconds the click menu is visible in the top frame before it disappears by it self.\";s:7:\"default\";s:1:\"5\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:28;a:6:{s:8:\"property\";s:55:\" contextMenu.options.alwaysShowClickMenuInTopFrame\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:153:\"If set, then the clickmenu in the top frame is always shown. Default is that it's shown only if the pop-up menus are disabled by user or by browser.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:29;a:6:{s:8:\"property\";s:18:\"overridePageModule\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:296:\"By this value you can substitute the default “Web > Page” module key (“web_layout”) with another backend module key.
 
Example:

options.overridePageModule = web_txtemplavoilaM1
This will enable TemplaVoila page module as default page module.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:30;a:6:{s:8:\"property\";s:21:\"moduleMenuCollapsable\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:60:\"If set, the user can collapse main modules in the left menu.\";s:7:\"default\";s:1:\"1\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:31;a:6:{s:8:\"property\";s:11:\"alertPopups\";s:8:\"datatype\";s:7:\"bitmask\";s:11:\"description\";s:261:\"Configure which Javascript popup alerts have to be displayed and which not:
 
1 – onTypeChange
2 – copy / move / paste
4 - delete
8 – FE editing
128 - other (not used yet)
 
Default: 255 (show all warnings)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:32;a:6:{s:8:\"property\";s:18:\"defaultFileUploads\";s:8:\"datatype\";s:7:\"integer\";s:11:\"description\";s:69:\"Default number of file upload forms shown in the File->List module\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:33;a:6:{s:8:\"property\";s:19:\"hideRecords.[table]\";s:8:\"datatype\";s:21:\"[list of record uids]\";s:11:\"description\";s:555:\"This hides records in the backend user interface. It is not an access
restriction but makes defined records invisible. That means in principle
those records can still be edited if the rights allow. This makes sense if a
specialized module should be used only to edit those records.
 
This option is currently implemented for pages only and has an effect in
following places:
 
- Pagetree navigation frame
- Web>List module
- New record wizard
 
Example:

options.hideRecords.pages = 12,45\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:34;a:6:{s:8:\"property\";s:26:\"additionalPreviewLanguages\";s:8:\"datatype\";s:34:\"[list of sys_language record uids]\";s:11:\"description\";s:129:\"The user will see these additional languages when localizing stuff in TCEforms. The list are uid numbers of sys_language records.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(16,6356713,'64dfc4b3acce1eaea54363c984c36980','','beuser:setup.default/setup.override','a:1:{s:4:\"rows\";a:23:{i:0;a:6:{s:8:\"property\";s:19:\"thumbnailsByDefault\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:26:\"Show Thumbnails by default\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:14:\"emailMeAtLogin\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:57:\"Notify me by email, when somebody logs in from my account\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:17:\"startInTaskCenter\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:102:\"If set, then the backend will start up in the task center (task center should be enabled for the user)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:8:\"helpText\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:30:\"Show help text when applicable\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:8:\"titleLen\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:17:\"Max. Title Length\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:17:\"edit_wideDocument\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:24:\"Wide document background\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:8:\"edit_RTE\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:23:\"Enable Rich Text Editor\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:20:\"edit_docModuleUpload\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:35:\"File upload directly in Doc. module\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:18:\"edit_showFieldHelp\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:134:\"Keywords: “”, “icon” or “text”
Determines the type of help text mode for TCA form fields.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:13:\"navFrameWidth\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:77:\"The width in pixels of the navigation frame in the Page and File main modules\";s:7:\"default\";s:10:\"245 pixels\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:17:\"navFrameResizable\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:99:\"If set, the frameset modules will have the border between the navigation and list frame resizable. \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:4:\"lang\";s:8:\"datatype\";s:12:\"language-key\";s:11:\"description\";s:143:\"One of the language-keys. See t3lib/config_default.php for current options. Eg. “dk”, “de”, “es” etc.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:10:\"copyLevels\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:84:\"Recursive Copy: Enter the number of page sublevels to include, when a page is copied\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:15:\"recursiveDelete\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:74:\"Recursive Delete(!): Allow ALL subpages to be deleted when deleting a page\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:16:\"allSaveFunctions\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:45:\"Display all save functions in Doc-module menu\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:15:\"neverHideAtCopy\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:72:\"If set, then the hideAtCopy feature for records in TCE will not be used.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:13:\"condensedMode\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:213:\"If set, the backend will not load the Web-submodules and File-submodules in a frameset but allow the page and folder trees to load the submodule in its own frame. This allows for a better display on small screens.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:10:\"noMenuMode\";s:8:\"datatype\";s:16:\"boolean / string\";s:11:\"description\";s:588:\"If set, the backend will not load the left menu frame but rather put a selector-box menu in the topframe. This saves a lot of space on small screens. Also icons will not be displayed in the clickmenu panel in the top.
 
Value “icons”:

Setting noMenuMode to “icons” will still remove the menu, but instead of the selectorbox menu you will have the whole clickmenu panel as a menu with the icons only as the hidden state of the clickmenu panel. This is extremely nice (in my opinion) for experienced users who know the icons of the modules.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:19:\"classicPageEditMode\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:287:\"Setting this option will not open the Web>Page module but rather load the content elements (normal column/default language) together with the page header in one big form when a page is edited (clicking a page icon in the page tree). This simulates the old behaviour in Classic Backend\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:19;a:6:{s:8:\"property\";s:18:\"hideSubmoduleIcons\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:78:\"If set then submodule icons will not be shown in the left menu of the backend.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:20;a:6:{s:8:\"property\";s:27:\"dontShowPalettesOnFocusInAB\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:82:\"If set, palettes are not activated in the TCEFORMs when focus is moved to a field.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:21;a:6:{s:8:\"property\";s:15:\"disableCMlayers\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:47:\"Disable the context menu layers in the backend.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:22;a:6:{s:8:\"property\";s:20:\"disableTabInTextarea\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:213:\"If you are using IE or Mozilla, TYPO3 will load a little JavaScript file that makes it possible to use the <tab> key in textareas. If you don't like the feature for some reason, you can disable it here.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(17,6356713,'71860c77c6745379b0d44304d66b6a13','','page','a:1:{s:4:\"rows\";a:7:{i:0;a:6:{s:8:\"property\";s:3:\"mod\";s:8:\"datatype\";s:8:\"->MOD\";s:11:\"description\";s:157:\"Options for the backend modules.
 
Notice that these options are merged with settings from User TSconfig (TLO: mod) which takes precedence.
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:3:\"RTE\";s:8:\"datatype\";s:8:\"->RTE\";s:11:\"description\";s:96:\"This defines configuration for the Rich Text Editor.
 
Please refer to the document.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:7:\"TCEMAIN\";s:8:\"datatype\";s:12:\"->TCEMAIN\";s:11:\"description\";s:49:\"Configuration for the TYPO3 Core Engine (TCEmain)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:7:\"TCEFORM\";s:8:\"datatype\";s:12:\"->TCEFORM\";s:11:\"description\";s:82:\"Extra configuration for the form fields rendered by the TCEforms-class in general.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:4:\"TSFE\";s:8:\"datatype\";s:9:\"->TSFE\";s:11:\"description\";s:38:\"Options for the TSFE front end object.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:4:\"user\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:87:\"This is for custom purposes.
Deprecated, use "tx_*" below from extensions\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:37:\"tx_[extension key with no underscore]\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:38:\"This is reserved space for extensions.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(18,6356713,'7868483dcb3f552ecc4d86326398cc9e','','page:mod; beuser:mod','a:1:{s:4:\"rows\";a:6:{i:0;a:6:{s:8:\"property\";s:24:\"web_layout.menu.function\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:879:\"Web > Page module
 
 
 
Option tags:

 
<select name="SET[function]">
     <option value="1">Columns</option>
     <option value="0">QuickEdit</option>
     <option value="2">Languages</option>
     <option value="3">Page information</option>
</select>
Example:

 
   # Disables all items except the "QuickEdit" item:
 mod.web_layout.menu.function {
   1 = 0
   2 = 0
   3 = 0
}
\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:22:\"web_info.menu.function\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:1023:\"Web > Info module
 
 
Option tags:

 
<select name="SET[function]">
     <option value="tx_cms_webinfo_page">Pagetree overview</option>
     <option value="tx_belog_webinfo">Log</option>
     <option value="tx_infopagetsconfig_webinfo">Page TSconfig</option>
     <option value="tx_cms_webinfo_hits">Hit Statistics</option>
     <option value="tx_indexedsearch_modfunc1">Indexed search</option>
</select>
Example:

 
   # Disables the item "Hit Statistics":
 mod.web_info.menu.function {
   tx_cms_webinfo_hits = 0
}
\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:22:\"web_func.menu.function\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:292:\"Web > Functions module
 
 
Option tags:

 
<select name="SET[function]">
     <option value="tx_funcwizards_webfunc">Wizards</option>
</select>\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:17:\"web_func.menu.wiz\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:862:\"Web > Functions module, Wizards sub module
This is the 2nd-level Function Menu in the Web > Functions module. Instead of the "function" key of the main menu it just uses the key "wiz" instead.
 
 
Option tags:

 
<select name="SET[wiz]">
     <option value="tx_wizardcrpages_webfunc_2">Create multiple pages</option>
     <option value="tx_wizardsortpages_webfunc_2">Sort pages</option>
</select>
Example:

 
   # Disables the sub-item "Create multiple pages":
 mod.web_func.menu.wiz {
   tx_wizardcrpages_webfunc_2 = 0
}
\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:20:\"web_ts.menu.function\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:843:\"Web > Template module
 
 
 
Option tags:

 
<select name="SET[function]">
     <option value="tx_tstemplateceditor">Constant Editor</option>
     <option value="tx_tstemplateinfo">Info/Modify</option>
     <option value="tx_tstemplateobjbrowser">TypoScript Object Browser</option>
     <option value="tx_tstemplateanalyzer">Template Analyzer</option>
     <option value="tx_tstemplatestyler_modfunc1">CSS Styler</option>
</select>\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:23:\"user_task.menu.function\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:1146:\"User > Task Center
This is slightly different because the Task Center does not provide a selector box function menu. But behind the scene it uses the same functionality of saving "states" and therefore you can also blind items in the Task Center.
There is one tricky thing thought: The Task Center is not depending on a page in the page tree! So you either have to set default Page TSconfig or User TSconfig to blind options here!
 
 
 
Keys are:

 
tx_sysnotepad = Quick Notetx_taskcenterrecent = Recent Pagestx_taskcenterrootlist = Web>List module / roottx_taskcentermodules = Pluginstx_sysaction = Actionstx_systodos = Tasks
 
Example:

Set this as User TSconfig:
 
   # Task Center configuration:
 mod.user_task.menu.function {
     # Disable "Recent Pages" display:
   tx_taskcenterrecent = 0
     # Disable "Action" list
   tx_sysaction = 0
}
\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}}}',''),(19,6356713,'ef29a11397049df8d64b160558d05e89','','page:mod.SHARED; beuser:mod.SHARED','a:1:{s:4:\"rows\";a:3:{i:0;a:6:{s:8:\"property\";s:11:\"colPos_list\";s:8:\"datatype\";s:51:\"(list of integers, blank = don't do anything.)\";s:11:\"description\";s:841:\"This option lets you specify which columns of tt_content elements should be displayed in the 'Columns' view of the modules, in particular Web>Page.
By default there are four columns, Left, Normal, Right, Border. However most websites use only the Normal column, maybe another also. In that case the remaining columns are not needed. By this option you can specify exactly which of the columns you want to display.
Each column has a number which ultimately comes from the configuration of the table tt_content, field 'colPos' found in the tables.php file. This is the values of the four default columns:
Left: 1
Normal: 0
Right: 2
 Border: 3
 
Example:

This results in only the Normal and Border column being displayed:
 
 mod.SHARED.colPos_list = 0,3\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:20:\"defaultLanguageLabel\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:166:\"Alternative label for "Default" when language labels are shown in the interface.
 
Used on Web>List, Web>Page and TemplaVoilas page module.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:19:\"defaultLanguageFlag\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:117:\"Flag icon filename from gfx/flags/ for default language
 
User in Web>List and TemplaVoila page module.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(20,6356713,'4bce98e2b4a7c289073897b4dbc86601','','page:mod.web_layout; beuser:mod.web_layout','a:1:{s:4:\"rows\";a:12:{i:0;a:6:{s:8:\"property\";s:22:\"tt_content.colPos_list\";s:8:\"datatype\";s:51:\"(list of integers, blank = don't do anything.)\";s:11:\"description\";s:288:\"See mod.SHARED.colPos_list for details.
If non-blank, this list will override the one set by mod.SHARED.colPos_list.
 
Example:

This results in only the Normal and Border column being displayed:
 
 mod.web_layout.tt_content.colPos_list = 0,3\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:21:\"tt_content.fieldOrder\";s:8:\"datatype\";s:41:\"list of field names from tt_content table\";s:11:\"description\";s:646:\"This allows you to specify (and thereby overrule) the preferred order of the fieldnames of the "Quick Edit" editing forms of the tt_content table (Content Elements). Just specify the list of fields, separated by comma. Then these fields will be listed first and all remaining fields thereafter in their original order.
 
Example:

This results in the 'Text' field and thereafter 'Header' field being display as the very first fields instead of the 'Type' field.
 
 mod.web_layout.tt_content {
   fieldOrder = bodytext, header
}
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:17:\"editFieldsAtATime\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:305:\"Specifies the number of subsequent content elements to load in the editform when clicking the editicon of a content element in the 'Columns' view of the module.
 
Example:

 
 mod.web_layout {
   editFieldsAtATime = 2
}
\";s:7:\"default\";s:1:\"1\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:19:\"noCreateRecordsLink\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:85:\"If set, the link in the bottom of the page, "Create new record", is hidden.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:11:\"QEisDefault\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:108:\"If set, then the QuickEditor is the first element in the Function Menu in the top of the menu in Web>Page\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:16:\"disableSearchBox\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:40:\"Disables the search box in Columns view.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:17:\"disableBigButtons\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:141:\"Disables the large buttons in top of the Columns view.
 
These are the buttons that are hidden by this option:
 
 \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:15:\"disableAdvanced\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:133:\"Disables the clear cache advanced function in the bottom of the page in the module, including the "Create new record" link.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:30:\"disableNewContentElementWizard\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:142:\"Disables the fact that the new-content-element icons links to the content element wizard and not directly to a blank “NEW” form.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:20:\"defaultLanguageLabel\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:156:\"Alternative label for "Default" when language labels are shown in the interface.
 
Overrides the same property from mod.SHARED if set. \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:14:\"defLangBinding\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:521:\"If set, translations of content elements are bound to the default record in the display. This means that within each column with content elements any translation found for exactly the shown default content element will be shown in the language column next to.
 
This display mode should be used depending on how the frontend is configured to display localization. The frontend must display localized pages by selecting the default content elements and for each one overlay with a possible translation if found.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:18:\"disableIconToolbar\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:95:\"Disables the topmost icon toolbar with the "view"-Icon and the icon
toolbar below.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(21,6356713,'2f1769c34fe68445a2679c113ab252c3','','page:mod.web_list; beuser:mod.web_list','a:1:{s:4:\"rows\";a:10:{i:0;a:6:{s:8:\"property\";s:19:\"noCreateRecordsLink\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:219:\"If set, the link in the bottom of the page, "Create new record", is hidden.
 
Example:

 
 mod.web_list {
   noCreateRecordsLink = 1
}
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:17:\"alternateBgColors\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:274:\"If set, the background colors of elements will alternate.
 
Example:

 
 mod.web_list {
   alternateBgColors = 1
}

The result is alternating background colors for each element:
 
 \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:22:\"disableSingleTableView\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:199:\"If set, then the links on the table titles which shows a single table listing only will not be available (including sorting links on columns titles, because these links jumps to the table-only view).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:25:\"listOnlyInSingleTableView\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:500:\"If set, then records will be listed only when the single table view is enabled. This is very practical for pages containing many records from many tables!
 
Example:

 
 mod.web_list {
   listOnlyInSingleTableView = 1
}

The result will be that records from tables are listed only in the single-table mode and the default view will just show number of table records in page and the table description if available:
 \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:10:\"hideTables\";s:8:\"datatype\";s:19:\"list of table names\";s:11:\"description\";s:54:\"Hide these tables in record listings (comma-separated)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:16:\"allowedNewTables\";s:8:\"datatype\";s:25:\"list of tablenames\";s:11:\"description\";s:669:\"If this list is set, then only tables listed here will have a link to “create new” in the page and subpages.
 
This also affects "db_new.php" (the display of “Create new record”)
 Note: Technically records can be created (eg. by copying/moving), so this is "pseudo security". The point is to reduce the number of options for new records visually.
 
Example:

 
 mod.web_list {
   allowedNewTables = pages, tt_news
}

Only pages and tt_news table elements will be linked to in the New record screen:
 
 \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:10:\"newWizards\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:177:\"If set, then the new-link over the control panel of the pages and tt_content listings in the List module will link to the wizards and not create a record in the top of the list.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:38:\"showClipControlPanelsDespiteOfCMlayers\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:237:\"If set, then the control- and clipboard panels of the module is shown even if the context-popups (ClickMenu) are available. Normally the control- and clipboard panels are disabled (unless extended mode is set) in order to save bandwidth.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:71:\"newPageWiz.overrideWithExtension
newContentWiz.overrideWithExtension\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:363:\"If set to an extension key, (eg. “templavoila”) then the “mod1/index.php” file of that extension will be used for creating new elements on the page. "newContentWiz" will likewise use the "mod1/db_new_content_el.php" for creating new content elements.
 
Also see “options.overridePageModule”\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:14:\"clickTitleMode\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:337:\"Keyword which defines what happens when a user clicks the title in the list.
 
Default is that pages will go one level down while other records have no link at all.
 
Keywords:
 edit = Edits record
 info = Shows information
 show = Shows page/content element in frontend\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(22,6356713,'2c0faa1efede00c1315123808e0536ef','','page:mod.web_view; beuser:mod.web_view','a:1:{s:4:\"rows\";a:1:{i:0;a:6:{s:8:\"property\";s:4:\"type\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:314:\"Enter the value of the &type parameter passed to the webpage.
 
Example:

By this configuration frontend pages will be shown with "index.php?id=123&type=1" from the Web > View module:
 
 mod.web_view {
   type = 1
}
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(23,6356713,'14bf6725234188138476fdcb63eaba70','','beuser:mod.tools_em','a:1:{s:4:\"rows\";a:1:{i:0;a:6:{s:8:\"property\";s:14:\"allowTVlisting\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:350:\"If set the Technical and Validation listings are available in the EM. Those will evaluate ALL available extensions and that can take many seconds (up to 30) depending on number of extensions.
 
Example:

 
 mod.tools_em.allowTVlisting = 1
Enables these options in the Extension Manager:
 
 \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(24,6356713,'b6ee1f8429c301026c90ac1561f84770','','page:mod.xMOD_alt_doc; beuser:mod.xMOD_alt_doc','a:1:{s:4:\"rows\";a:2:{i:0;a:6:{s:8:\"property\";s:18:\"disableDocSelector\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:393:\"If set, the document selector is disabled
 
Example:

 
 mod.xMOD_alt_doc {
   disableDocSelector = 1
   disableCacheSelector = 1
}

The result is that both the document and cache action selector is hidden in the form page:
 
 
(The interesting part is what is missing...)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:20:\"disableCacheSelector\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:89:\"If set, the cache/save/close selector is disabled.
 
See example above.
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(25,6356713,'dc552e3c78a7a59de68ad59044c36468','','page:TCEMAIN','a:1:{s:4:\"rows\";a:8:{i:0;a:6:{s:8:\"property\";s:35:\"table.[tablename]
default\";s:8:\"datatype\";s:19:\"->TCEMAIN_tables\";s:11:\"description\";s:23:\"Options for each table.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:41:\"permissions.userid
permissions.groupid\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:861:\"Hardcodes the default owner Backend User / Group UID of new and copied pages.
 
(The default owner is the backend user that creates / copies the record. The default user group is the "main group" of the backend user - the group in the very top of the users group-list.)
 
Example:

 
 TCEMAIN {
     # Owner be_users UID for new pages:
   permissions.userid = 2
     # Owner be_groups UID for new pages:
   permissions.groupid = 3
}

Backend User with UID 2 is "test" and the Backend Group with UID 3 is "test_group". With the configuration above a new page would be created with this user/group setting instead of the defaults:
 
 \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:62:\"permissions.user
permissions.group
permissions.everybody\";s:8:\"datatype\";s:24:\"list of string/int[0-31]\";s:11:\"description\";s:1415:\"Default permissions set for owner-user, owner-group and everybody.
 
Keylist: show,edit,delete,new,editcontent
Alternatively you can specify an integer from 0 to 31 indicating which bits corresponding to the keylist should be set. (Bits in keylist: show=1,edit=2,delete=4,new=8,editcontent=16)
 
Defaults from $TYPO3_CONF_VARS:
"user" => "show,edit,delete,new,editcontent",
“group" => "show,edit,new,editcontent",
"everybody" => ""
 
Example:

 
 TCEMAIN.permissions {
     # User can do anything (default):
   user = 31
     # Group can do anything
     # (normally "delete" is disabled)
   group = 31
     # Everybody can at least see the page
     # (normally everybody can do nothing)
   everybody = show
}

The page "Test (copy 3)" was created with the settings above for permissions. Compared to the two other pages created with default permissions you can see the effect: The Backend Group can now also delete the page by default and Everybody has read access:
 
 \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:13:\"clearCacheCmd\";s:8:\"datatype\";s:61:\"List of values (integers, "all", "pages")\";s:11:\"description\";s:563:\"This can allow you to have the cache for additional pages cleared when saving to some page or branch of the page tree.
 
Examples:

 
   # Will clear the cache for page ID 12 and 23
   # when saving a record in this page:
 TCEMAIN.clearCacheCmd = 12,23
 
   # Will clear all pages cache:
 TCEMAIN.clearCacheCmd = pages
 
   # Will clear ALL cache:
 TCEMAIN.clearCacheCmd = all\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:30:\"clearCache_pageSiblingChildren\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:204:\"If set, then children of all siblings of a page being edited will have the page cache cleared.
(Default is that when a page record is edited, the cache for itself and siblings (same level) is cleared.)\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:26:\"clearCache_pageGrandParent\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:86:\"If set, then the grand parent of a page being edited will have the page cache cleared.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:18:\"clearCache_disable\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:189:\"If set, then the automatic clearing of page cache when records are edited etc. is disabled. This also disables the significance of the two "clearCache_page*" options listed above.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:18:\"translateToMessage\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:486:\"Defines the string that will be prepended to every field value if you copy an element to another language version.
 
The special string “%s" will be replaced with the language title.
Default ist "Translate to [language title]:".
 
Example:

 
 TCEMAIN {
     # Set a German label:
   translateToMessage = Bitte in "%s" übersetzen:
}
\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}}}',''),(26,6356713,'bdedb7b326ecbf571a94829143391fa3','','page:TCEMAIN.default/TCEMAIN.table.(tablename)/->TCEMAIN_tables','a:1:{s:4:\"rows\";a:3:{i:0;a:6:{s:8:\"property\";s:18:\"history.maxAgeDays\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:155:\"The number of days elements are in the history at most. Takes precedence over keepEntries.
Default is 7 days. Range 0-200. Zero turns the magAgeDays of.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:20:\"disablePrependAtCopy\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:1182:\"Disables the “prependAtCopy” feature (if configured for table in $TCA)
 
(The word "prepend" is misguiding - the "(copy)" label is appended to (put after) the record title! Sorry for that mistake, it isn't the only time I have made that.)
 
Example:

 
 TCEMAIN.table.pages {
     # Pages will NOT have "(copy)" appended:
   disablePrependAtCopy = 1
     # Pages will NOT be hidden upon copy:
   disableHideAtCopy = 1
}

These settings means that a page copied (say, the last page in this tree, labeled "Test") will neither have "(copy X)" appended nor be hidden.
This effect is shown in the first sub page here, labeled "Test". It appears exactly like the third page that was copied.
The page in the middle, labeled "Test (copy 3)" is the default mode where the page is hidden and the "(copy X)" suffix is added if another page with the same named existed already.
 
 \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:17:\"disableHideAtCopy\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:151:\"Disables the “hideAtCopy” feature (if configured for table in $TCA)
 
For example, see "disablePrependAtCopy" above.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}}}',''),(27,6356713,'635aff2d727b50d7cdaaaf6a4144318e','','page:TCEFORM','a:1:{s:4:\"rows\";a:2:{i:0;a:6:{s:8:\"property\";s:90:\"[tablename].[field]
[tablename].[field].types.[type]\";s:8:\"datatype\";s:20:\"->TCEFORM_confObj\";s:11:\"description\";s:459:\"These objects contain additional configuration of the TCEFORM interface. For the properties available, refer to the table below. This is a description of how you can customize in general and override for specific types.
 
TCEFORM.[tablename].[field] - configures the field in TCEFORM for all types.
 
TCEFORM.[tablename].[field].types.[type] - configures the field in TCEFORM in case the 'type'-value of the field matches type.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:53:\"[tablename].[field].config.[key]\";s:8:\"datatype\";s:14:\"string / array\";s:11:\"description\";s:783:\"This setting allows to override TCA field configuration and offers a flexible opportunity to reuse tables and TCA definitions but adept it to individual demands. So this will influence configuration settings in $TCA[<tablename>]['columns'][<field>]['config'][<key>].
 
Depending on the $TCA type of the field, the allowed keys are:
 input - size, max
 text - cols, rows, wrap
 check - cols, showIfRTE
 select - size, autoSizeMax, maxitems, minitems
 group - size, autoSizeMax, max_size, show_thumbs, maxitems, minitems
 inline - appearance, foreign_label, foreign_selector, foreign_unique, maxitems, minitems, size, autoSizeMax, symmetric_label\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}}}',''),(28,6356713,'aa7f13fe687c77a191a431405d3f9631','','page:TCEFORM.(tablename).(field)/TCEFORM.(tablename).(field).types.(type)','a:1:{s:4:\"rows\";a:12:{i:0;a:6:{s:8:\"property\";s:8:\"disabled\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:248:\"If set, the field is not rendered.
 
Example:

 
 TCEFORM.pages.title {
     # You cannot edit the Page title field now:
   disabled = 1
}
\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:11:\"removeItems\";s:8:\"datatype\";s:14:\"list of values\";s:11:\"description\";s:378:\"(applies to select-types only)
 

This removes the items from the list which has a value found in this comma list of values.
 
Example:

 
 TCEFORM.pages.doktype {
     # Remove the "Recycler" and "Spacer" page type options:
   removeItems = 199, 255
}\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:20:\"addItems.[itemValue]\";s:8:\"datatype\";s:18:\"string (label, LS)\";s:11:\"description\";s:935:\"(applies to select-types only)
 

This will add elements to the list. Notice that the added elements might be removed if the selector represents records. In that case only still existing records will be preserved.
 
Example:

 
 TCEFORM.pages.doktype {
     # Creates a new page type option:
   addItems.123 = New Page type!
 
     # Creates yet a page type with "locallang" title:
   addItems.124 = LLL:EXT:lang/locallang_tca.php:title
}

This example extends the options for Page types with two new items:
 
 
 Warning: This example shows the principle of adding adhoc-items to a selector box in TYPO3 but you should not add new page types or Content Element types this way!\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:29:\"disableNoMatchingValueElement\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:771:\"(applies to select-types only)
 

If set, the element "CURRENT VALUE IS NOT AVAILABLE" will not be added to the list.
 
Example:

 
If a selector box value is not available among the options in the box the default behavior of TYPO3 is to preserve the value and show a label that warns about this special state:
 
 
Setting this option disables that behavior:
 
 TCEFORM.pages.doktype {
     # "CURRENT VALUE IS NOT ..." label will never show up:
   disableNoMatchingValueElement = 1
}

... and the selector box will default to the first element in the selector box:
 
 \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:21:\"noMatchingValue_label\";s:8:\"datatype\";s:11:\"string (LS)\";s:11:\"description\";s:564:\"(applies to select-types only)
 

Allows for an alternative label the “noMatchingValue” element.
You can insert the placeholder "%s" to insert the value.
If you supply a blank value the label will be blank.
 
Example:

 
 TCEFORM.pages.doktype {
     # Alternative "CURRENT VALUE IS NOT ..." label:
   noMatchingValue_label = VALUE "%s" was not available!
}
The result will be:
 
 \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:22:\"altLabels.[item_value]\";s:8:\"datatype\";s:11:\"string (LS)\";s:11:\"description\";s:727:\"(applies to select-types only)
 

This allows you to enter alternative labels for the items in the list.
 
Example:

 
 TCEFORM.pages.doktype {
     # Setting alternative labels:
   altLabels.1 = STANDARD page type
   altLabels.2 = ADVANCED page type
   altLabels.254 = System Folder (for various elements)
     # Sets the default labels for Recycler (via "locallang"):
   altLabels.255 = LLL:EXT:lang/locallang_tca.php:doktype.I.2
}

Result will be:
 
 \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:16:\"PAGE_TSCONFIG_ID\";s:8:\"datatype\";s:7:\"integer\";s:11:\"description\";s:293:\"(applies to select-types with foreign table)
 

When the select-types are used with foreign-table the where-query has four markers (see description of $TCA in the “Inside TYPO3” document.) The value of three of these markers may be set from Page TSconfig.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:20:\"PAGE_TSCONFIG_IDLIST\";s:8:\"datatype\";s:22:\"comma list of integers\";s:11:\"description\";s:81:\"(applies to select-types with foreign table)
 

See above\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:17:\"PAGE_TSCONFIG_STR\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:81:\"(applies to select-types with foreign table)
 

See above\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:19:\"itemsProcFunc.[...]\";s:8:\"datatype\";s:8:\"(custom)\";s:11:\"description\";s:192:\"(applies to select-types with itemsProcFunc)
 

The properties of this key is passed on to the itemsProcFunc in the parameter array by the key “TSconfig”.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:18:\"RTEfullScreenWidth\";s:8:\"datatype\";s:6:\"int+/%\";s:11:\"description\";s:273:\"(applies for RTE text fields only with the RTE wizard configured)
 

The width of the RTE full screen display. If nothing is set, the whole width is used which means “100%”. If you set an integer value, that indicates the pixels width.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:15:\"linkTitleToSelf\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:870:\"(all fields)
 

If set, then the title of the field in the forms links to alt_doc.php editing ONLY that field.
Works for existing records only - not new records.
 
Extra property:

.returnUrl = boolean; if set, then the return URL is also set.
 
Example:

 
 TCEFORM.pages.title {
     # The label for the "title" field will link itself
   linkTitleToSelf = 1
     # From the form with "title", return to full form:
   linkTitleToSelf.returnUrl = 1
}

The result is that the label for the title field will be a link:
 
 
Clicking the link brings you to a form where only this field is shown:
 
 \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}}}',''),(29,6356713,'7a924c59af67c619fd51493947aa7abb','','page:TSFE','a:1:{s:4:\"rows\";a:2:{i:0;a:6:{s:8:\"property\";s:23:\"jumpUrl_transferSession\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:977:\"If set, the jumpUrl redirection to the URL will be prepended with a parameter that transfers the current fe_users session to that URL. This URL should be the TYPO3 frontend in the same database, just at another domain (else it makes no sense).
 
You can implement it in your own links if you like. This is how you do:
You must send the parameter 'FE_SESSION_KEY' as GET or POST. The parameter looks like this: [fe_user-session-id]-[a hash made to prevent misuse]
The parameter can be calculated like this:
 
 $param = '&FE_SESSION_KEY='.rawurlencode(
    $GLOBALS['TSFE']->fe_user->id.'-'.
    md5(
      $GLOBALS['TSFE']->fe_user->id.'/'.
      $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']
   )
);\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:9:\"constants\";s:8:\"datatype\";s:40:\"[TypoScript Frontend Constants defaults]\";s:11:\"description\";s:1728:\"Defaults for TypoScript Template constants!
 
This features allows you to pass some amount of information (in the form of TypoScript Template constants) to the frontend.
The specific use of this should be information which you want to configure for both frontend and backend. For instance you could have a backend module which should act in a certain way depending on in which branch of the page tree it operates. The change of behavior is set by Page TSconfig as always but since you need the same setting applied somewhere in the frontend you don't want the redundancy of specifying the value twice. In such a case you can use this feature.
 
Example:

 
 TSFE.constants.websiteConfig.id = 123
 
In the TypoScript templates you can now insert this constant as {$websiteConfig.id}
 
 
 
In the backend module (in the Web main module) you can reach the value by a few codelines like these:
 
 $PageTSconfig =
     t3lib_BEfunc::getPagesTSconfig($this->pObj->id);
 $websiteID =
     $PageTSconfig['TSFE.']['constants.']['websiteConfig.']['id'];
 Notice: In the frontend the setting of default constants will only apply to a branch of the tree if a template record is found on that page (or if a template record is set for “next level”). In other words: If you want the Page TSconfig constant defaults to affect only a certain branch of the page tree, make sure to create a template record (a blank one will do) on the page that carries the Page TSconfig information.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(30,7389802,'562ee021929de249706534bf02f731ff','','tsref:(datatypes)','a:1:{s:4:\"rows\";a:34:{i:0;a:6:{s:8:\"property\";s:11:\"<tag>\";s:8:\"datatype\";s:43:\"<BODY bgcolor="red">\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:5:\"align\";s:8:\"datatype\";s:12:\"right\";s:11:\"description\";s:73:\"right / left / center
Decides alignment, typically in HTML-tags\";s:7:\"default\";s:4:\"left\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:7:\"VHalign\";s:8:\"datatype\";s:67:\"Hori.align = right and Vert.align = center:
r , c
\";s:11:\"description\";s:97:\"r/c/l , t/c/b
Horizontal (right, center, left) , Vertical align (top / center / bottom)\";s:7:\"default\";s:5:\"l , t\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:8:\"resource\";s:8:\"datatype\";s:116:\"From the resourcefield:
toplogo*.gif
 
Reference to filesystem:

fileadmin/picture.gif\";s:11:\"description\";s:603:\"1) A reference to a file from the resource-field in the template.
You can write the exact filename or you can include an asterisk (*) as wildcard.
It's recommended to include a "*" before the fileextension (see example to the left). This will ensure that the file is still referenced correct even if the template is copied and the file will have it's name prepended with numbers!!
 2) If the value contains a "/" it's expected to be a reference (absolute or relative) to a file on the file-system instead of the resource-field. No support for wildcards.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:11:\"imgResource\";s:8:\"datatype\";s:204:\"Here "file" is an imgResource:
file = toplogo*.gif
file.width = 200
 
GIFBUILDER:
file = GIFBUILDER
file {
    ... (GIFBUILDER-properties here)
}\";s:11:\"description\";s:371:\"1) A "resource" (see above) + imgResource-properties (see example to the left and object-reference below)
Filetypes can be anything among the allowed types defined in the configuration variable $TYPO3_CONF_VARS["GFX"]["imagefile_ext"] (localconf.php). Standard is pdf,gif,jpg,jpeg,tif,bmp,ai,pcx,tga,png.
 
2) GIFBUILDER-object\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:9:\"HTML-code\";s:8:\"datatype\";s:43:\"<B>Some text in bold</B>\";s:11:\"description\";s:14:\"pure HTML-code\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:6:\"target\";s:8:\"datatype\";s:46:\"_top
_blank

content
\";s:11:\"description\";s:121:\"target in <A>-tag.
This is normally the same value as the name of the root-level object that defines the frame.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:14:\"imageExtension\";s:8:\"datatype\";s:46:\"jpg
web(gif or jpg ..)
\";s:11:\"description\";s:388:\"Image extensions can be anything among the allowed types defined in the global variable $TYPO3_CONF_VARS["GFX"]["imagefile_ext"] (localconf.php). Standard is pdf,gif,jpg,jpeg,tif,bmp,ai,pcx,tga,png.
 The value "web" is special. This will just ensure that an image is converted to a web imageformat (gif or jpg) if it happens not to be already!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:6:\"degree\";s:8:\"datatype\";s:13:\" \";s:11:\"description\";s:19:\"-90 to 90, integers\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:13:\"posint / int+\";s:8:\"datatype\";s:13:\" \";s:11:\"description\";s:16:\"Positive integer\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:3:\"int\";s:8:\"datatype\";s:13:\" \";s:11:\"description\";s:115:\"integer
(sometimes used generally though another type would have been more appropriate, like "pixels")\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:20:\"str / string / value\";s:8:\"datatype\";s:13:\" \";s:11:\"description\";s:114:\"string.
(sometimes used generally though another type would have been more appropriate, like "align")\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:7:\"boolean\";s:8:\"datatype\";s:8:\"1\";s:11:\"description\";s:65:\"boolean
non-empty strings (but not zero) are "true"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:8:\"rotation\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:29:\"integer, degrees from 0 - 360\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:7:\"x,y,w,h\";s:8:\"datatype\";s:16:\"10,10,5,5\";s:11:\"description\";s:77:\"x,y is the offset from the upper left corner.
w,h is the width and height\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:10:\"HTML-color\";s:8:\"datatype\";s:29:\"red
#ffeecc
\";s:11:\"description\";s:633:\"HTML-color codes:
 
Black = "#000000"   
Silver = "#C0C0C0"   
Gray = "#808080"   
White = "#FFFFFF"   
Maroon = "#800000"   
Red = "#FF0000"   
Purple = "#800080"   
Fuchsia = "#FF00FF"   
Green = "#008000"
Lime = "#00FF00"
Olive = "#808000"
Yellow = "#FFFF00"
Navy = "#000080"
Blue = "#0000FF"
Teal = "#008080"
Aqua = "#00FFFF" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:12:\"GraphicColor\";s:8:\"datatype\";s:166:\"red
#ffeecc

255,0,255

 

Extra:

red : *0.8

#ffeecc : +16

 
\";s:11:\"description\";s:399:\"The color can be given as HTML-colors or as a comma-seperated list of RGB-values (integers)
You can add an extra parameter that will modify the color mathematically:
Syntax:
[colordef] : [modifier]
where modifier can be and integer which is added/subtracted to the three RGB-channels or a floatingpoint with an "*" before, which will then multiply the values with that factor.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:7:\"page_id\";s:8:\"datatype\";s:24:\"this
34
\";s:11:\"description\";s:54:\"A page id (int) or "this" (=current page id)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:6:\"pixels\";s:8:\"datatype\";s:10:\"345\";s:11:\"description\";s:14:\"pixel-distance\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:19;a:6:{s:8:\"property\";s:4:\"list\";s:8:\"datatype\";s:23:\"item,item2,item3\";s:11:\"description\";s:14:\"list of values\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:20;a:6:{s:8:\"property\";s:7:\"margins\";s:8:\"datatype\";s:108:\"This sets leftmargin to 10 and bottom-margin to 5. Top and right is not set (zero)
10,0,0,5
\";s:11:\"description\";s:35:\"l,t,r,b
left, top, right, bottom\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:21;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:145:\"This will cause the value to be wrapped in a font-tag coloring the value red:
<font color="red"> | </font>
\";s:11:\"description\";s:156:\"<...> | </...>
Used to wrap something. The part on the left and right of the vertical line is placed on the left and right side of the value.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:22;a:6:{s:8:\"property\";s:8:\"linkWrap\";s:8:\"datatype\";s:118:\"This will make a link to the root-level of a website:
<A HREF="?id={0}"> | </A>
\";s:11:\"description\";s:351:\"<.. {x}.> | </...>
{x}; x is an integer (0-9) and points to a key in the PHP-array rootLine. The key is equal to the level the current page is on measured relatively to the root of the website.
If the key exists the uid of the level that key pointed to is inserted instead of {x}.
Thus we can insert page_ids from previous levels.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:23;a:6:{s:8:\"property\";s:4:\"case\";s:8:\"datatype\";s:12:\"upper\";s:11:\"description\";s:56:\""upper" / "lower"
Case-conversion\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:24;a:6:{s:8:\"property\";s:5:\"space\";s:8:\"datatype\";s:12:\"5 | 5\";s:11:\"description\";s:89:\""before | after"
Used for content and sets space "before | after".\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:25;a:6:{s:8:\"property\";s:9:\"date-conf\";s:8:\"datatype\";s:36:\"d-m-y(dd-mm-yy format)\";s:11:\"description\";s:931:\"See PHP function Date()!
 
a - "am" or "pm"
A - "AM" or "PM"
d - day of the month, numeric, 2 digits (with leading zeros)
D - day of the week, textual, 3 letters; i.e. "Fri"
F - month, textual, long; i.e. "January"
h - hour, numeric, 12 hour format
H - hour, numeric, 24 hour format
i - minutes, numeric
j - day of the month, numeric, without leading zeros
l (lowercase 'L') - day of the week, textual, long; i.e. "Friday"
m - month, numeric
M - month, textual, 3 letters; i.e. "Jan"
s - seconds, numeric
S - English ordinal suffix, textual, 2 characters; i.e. "th", "nd"
U - seconds since the epoch
Y - year, numeric, 4 digits
w - day of the week, numeric, 0 represents Sunday
y - year, numeric, 2 digits
z - day of the year, numeric; i.e. "299"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:26;a:6:{s:8:\"property\";s:13:\"strftime-conf\";s:8:\"datatype\";s:122:\"Date "DD-MM-YY" =
%e:%m:%y

Time "HH:MM:SS" =
%H:%M:%S

or just
%T
\";s:11:\"description\";s:2273:\"%a - abbreviated weekday name according to the current locale
%A - full weekday name according to the current locale
%b - abbreviated month name according to the current locale
%B - full month name according to the current locale
%c - preferred date and time representation for the current locale
%C - century number (the year divided by 100 and truncated to an integer, range 00 to 99)
%d - day of the month as a decimal number (range 00 to 31)
%D - same as %m/%d/%y
%e - day of the month as a decimal number, a single digit is preceded by a space (range ' 1' to '31')

%h - same as %b
%H - hour as a decimal number using a 24-hour clock (range 00 to 23)

%I - hour as a decimal number using a 12-hour clock (range 01 to 12)
%j - day of the year as a decimal number (range 001 to 366)
%m - month as a decimal number (range 01 to 12)

%M - minute as a decimal number

%n - newline character
%p - either `am' or `pm' according to the given time value, or the corresponding strings for the current locale
%r - time in a.m. and p.m. notation
%R - time in 24 hour notation
%S - second as a decimal number

%t - tab character
%T - current time, equal to %H:%M:%S
%u - weekday as a decimal number [1,7], with 1 representing Monday
%U - week number of the current year as a decimal number, starting with the first Sunday as the first day of the first week
%V - The ISO 8601:1988 week number of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the current year, and with Monday as the first day of the week.
%W - week number of the current year as a decimal number, starting with the first Monday as the first day of the first week
%w - day of the week as a decimal, Sunday being 0
%x - preferred date representation for the current locale without the time
%X - preferred time representation for the current locale without the date
%y - year as a decimal number without a century (range 00 to 99)

%Y - year as a decimal number including the century
%Z - time zone or name or abbreviation
%% - a literal `%' character \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:27;a:6:{s:8:\"property\";s:9:\"UNIX-time\";s:8:\"datatype\";s:55:\"Seconds to 07/04 2000 23:58:
955144722
\";s:11:\"description\";s:25:\"Seconds since 1/1 1970...\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:28;a:6:{s:8:\"property\";s:4:\"path\";s:8:\"datatype\";s:23:\"fileadmin/stuff/\";s:11:\"description\";s:53:\"path relative to the directory from which we operate.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:29;a:6:{s:8:\"property\";s:23:\"<tag>-data\";s:8:\"datatype\";s:13:\" \";s:11:\"description\";s:89:\"Example:
<frameset>-data: row

could be '150,*'\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:30;a:6:{s:8:\"property\";s:25:\"<tag>-params\";s:8:\"datatype\";s:13:\" \";s:11:\"description\";s:128:\"Example:
<frameset>-params

could be 'border="0" framespacing="0"'\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:31;a:6:{s:8:\"property\";s:7:\"getText\";s:8:\"datatype\";s:2094:\"get content from the $cObj->data-array[header]:
= field : header

get content from the $cObj->parameters-array[color]:

= parameters : color

get content from the $GLOBALS["TSFE"]->register[color]:

= register : color

get the title of the page on the first level of the rootline:

= leveltitle : 1

get the title of the page on the level right below the current page AND if that is not present, walt to the bottom of the rootline until there's a title:

= leveltitle : -2 , slide

get the id of the root-page of the website (level zero)

= leveluid : 0

Gets the value of the user defined field “user_myExtField” in the root line (requires additional config in TYPO3_CONF_VARS to include field!)

= levelfield : -1 , user_myExtField , slide

get the env var HTTP_REFERER:

= getenv : HTTP_REFERER

get the env variable $HTTP_COOKIE_VARS[some_cookie]:

= global : HTTP_COOKIE_VARS | some_cookie

get the current time formatted dd-mm-yy:

= date : d-m-y

get the current page-title:

= page : title

get the current value:

= current : 1

get input value from query string, (&stuff=)
= GPvar : stuff

get input value from query string, (&stuff[key]=)
= GPvar : stuff | key

get the current id
= TSFE : id

get the value of the header of record with uid 234 from table tt_content:
= DB : tt_content:234:header

Gets the title of the page right before the start of the current website:

= fullRootLine : -1, title

Returns localized label for logout button

= LLL:EXT:css_styled_content/pi1/locallang.x:login.logout

Outputs the current root-line visually in HTML:

= debug : rootLine

Gets path to file relative file to siteroot possibly placed in an extension:

path:EXT:ie7/js/ie7-standard.js
\";s:11:\"description\";s:4383:\"This returns a value from somewhere in PHP-array, defined by the type. The syntax is "type : pointer"
 
 field : [fieldname from the current $cObj->data-array in the cObj.]
As default the $cObj->data-array is $GLOBALS["TSFE"]->page (record of the current page!)
In TMENU: $cObj->data is set to the page-record for each menuitem.
In CONTENT/RECORDS $cObj->data is set to the actual record
In GIFBUILDER $cObj->data is set to the data GIFBUILDER is supplied with.
  [fieldname from the current $cObj->parameters-array in the cObj.]
See ->parseFunc!
 register : [fieldname from the $GLOBALS["TSFE"]->register]
See cObject "LOAD_REGISTER"
 leveltitle, leveluid, levelmedia: [levelTitle, uid or media in rootLine, 0- , negative = from behind, “ , slide” parameter forces a walk to the bottom of the rootline until there's a “true” value to return. Useful with levelmedia.]
 levelfield: Like “leveltitle” et al. but where the second parameter is the rootLine field you want to fetch. Syntax: [pointer, integer], [fieldname], [“slide”]
 global : [GLOBAL-var, split with | if you want to get from an array! DEPRECATED, use GPvar, TSFE or getenv]
 date : [date-conf]
 page : [current page record]
 current : 1 (gets 'current' value)
level : 1 (gets the rootline level of the current page)

 GPvar: Value from GET or POST method. Use this instead of global
 TSFE: Value from TSFE global main object
 getenv: Value from environment vars
 getIndpEnv: Value from t3lib_div::getIndpEnv()
 DB: Value from database, syntax is [tablename] : [uid] : [field]. Any record from a table in TCA can be selected here. Only marked-deleted records does not return a value here.
 fullRootLine : This gets the title “1. page before” in a page tree like the one below provided we are are the page “Here you are!” (or “Site root”) and this TypoScript is in the template with root at “Site root”. Red numbers indicate what values of keynumber would point to:
- Page tree root   -2
    |- 1. page before   -1
       |- Site root (root template here!)   0
          |- Here you are! 1
 
 LLL: Reference to a locallang (php or xml) label. Reference consists of [fileref]:[labelkey]
 path: path to a file, possibly placed in an extension, returns empty if the file doesn't exist.
 cObj: [internal variable from list: “parentRecordNumber”]: For CONTENT and RECORDS cObjects that are returned
by a select query, this returns the row number (1,2,3,...) of the current cObject record.
 debug: Returns HTML formated content of PHP variable defined by keyword. Available keys are “rootLine”, “fullRootLine”, “data”
--------------------

Getting array/object elements.

You can fetch the value of an array/object by splitting it with a pipe “|”.Example: TSFE:fe_user|user|username
Getting more values.

By separating the value of getText with "//" (double slash) you let getText fetch the first value. If it appears empty ("" or zero) the next value is fetched and so on. Example:
= field:header // field:title // field:uid
This gets "title" if "header" is empty. If "title" is also empty it gets field "uid"
 fullRootLine :
Getting a value from the rootline (TSFE->rootLine) going all the way to the root of the page tree.
[keynumber, fieldname, “slide”]

Keynumber is relative to the current site root, so negative numbers refer to subsequent levels below the site root. Fieldname is the name of the datafield to get. For “slide”, see levelmedia type above.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:32;a:6:{s:8:\"property\";s:3:\"dir\";s:8:\"datatype\";s:251:\" returns a list of all pdf, gif and jpf-filer from fileadmin/files/ sorted by their name reversely and with the full path (with "fileadmin/files/" prepended)
 fileadmin/files/ | pdf,gif,jpg | name | r | true\";s:11:\"description\";s:380:\"[path relative to the webroot of the site] | [list of valid extensions] | [sorting: name, size, ext, date] | [reverse: "r"] | [return full path: boolean
Files matching is returned in a comma-separated string.
Note:

 The value of config-option "lockFilePath" must equal the first part of the path. Thereby the path is locked to that folder.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:33;a:6:{s:8:\"property\";s:13:\"function-name\";s:8:\"datatype\";s:107:\"Function:
user_reverseString

Method in class:
user_stringReversing->reverseString
\";s:11:\"description\";s:759:\"Indicates a function or method in a class to call. See more information at the USER cObject.
Depending on implementation the class or function name (but not the method name) should probably be prefixed with “user_”. This can be changed in the TYPO3_CONF_VARS config though. Also the function / method is normally called with 2 parameters, typ. $conf (TS config) and $content (some content to be processed and returned)
Also if you call a method in a class, it is checked (when using the USER/USER_INT objects) whether a class with the same name, but prefixed with “ux_” is present and if so, this class is instantiated instead. See “Inside TYPO3” document for more information on extending the classes in TYPO3!\";s:7:\"default\";s:13:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(31,7389802,'dd3620dfffa9b5fa5da8d430c83cae46','','tsref:->stdWrap','a:1:{s:4:\"rows\";a:79:{i:0;a:6:{s:8:\"property\";s:16:\"Get data:\";s:8:\"datatype\";N;s:11:\"description\";N;s:7:\"default\";N;s:12:\"column_count\";i:1;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:19:\"setContentToCurrent\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:63:\"Sets the current value to the incoming content of the function.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:10:\"setCurrent\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:141:\"Sets the "current"-value. This is normally set from some outside routine, so be careful with this. But it might be handy to do this\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:4:\"lang\";s:8:\"datatype\";s:29:\"Array of language keys\";s:11:\"description\";s:465:\"This is used to define optional language specific values.
If the global language key set by the ->config property .language is found in this array, then this value is used instead of the default input value to stdWrap.
 
Example:

config.language = de
page.10 = TEXT
page.10.value = I am a Berliner!
page.10.lang.de = Ich bin ein Berliner!
 
Output will be “Ich bin...” instead of “I am...”\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:4:\"data\";s:8:\"datatype\";s:7:\"getText\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:5:\"field\";s:8:\"datatype\";s:16:\"fieldname\";s:11:\"description\";s:564:\"Sets the content to the value $cObj->data[field]
 
 Example: Set content to the value of field "title": ".field = title"
$cObj->data changes. See the description for the data type "getText"/field!
 

 Note: You can also divide fieldnames by “//”. Say, you set “nav_title // title” as the value, then the content from the field nav_title will be returned unless it is a blank string, in which case the title-field's value is returned.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:7:\"current\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:66:\"Sets the content to the "current"-value (see ->split)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:7:\"cObject\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:35:\"Loads content from a content-object\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:7:\"numRows\";s:8:\"datatype\";s:12:\"->numRows\";s:11:\"description\";s:52:\"Returns the number of rows resulting from the select\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:8:\"filelist\";s:8:\"datatype\";s:12:\"dir /stdWrap\";s:11:\"description\";s:442:\"Reads a directory and returns a list of files.
The value is exploded by "|" into parameters:
1: The path
2: comma-list of allowed extensions (no spaces between); if empty all extensions goes.
3: sorting: name, size, ext, date, mdate (modification date)
4: reverse: Set to "r" if you want a reversed sorting
5: fullpath_flag: If set, the filelist is returned with complete paths, and not just the filename\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:11:\"preUserFunc\";s:8:\"datatype\";s:13:\"function-name\";s:11:\"description\";s:168:\"Calling a PHP-function or method in a class, passing the current content to the function as first parameter and any properties as second parameter.
See .postUserFunc\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:29:\"Override / Conditions:\";s:8:\"datatype\";N;s:11:\"description\";N;s:7:\"default\";N;s:12:\"column_count\";i:1;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:8:\"override\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:117:\"if "override" returns something else than "" or zero (trimmed), the content is loaded with this! \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:17:\"preIfEmptyListNum\";s:8:\"datatype\";s:30:\"(as "listNum" below)\";s:11:\"description\";s:30:\"(as "listNum" below)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:7:\"ifEmpty\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:131:\"if the content is empty (trimmed) at this point, the content is loaded with "ifEmpty". Zeros are treated as empty values!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:7:\"ifBlank\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:65:\"Same as "ifEmpty" but the check is done using strlen().\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:7:\"listNum\";s:8:\"datatype\";s:34:\"int
+calc
+"last"\";s:11:\"description\";s:727:\"Explodes the content with "," (comma) and the content is set to the item[value].
 

 Special keyword: "last" is set to the last element of the array!
 

 .splitChar (string):
Defines the string used to explode the value. If splitChar is an integer, the character with that number is used (eg. "10" to split lines...).

Default: “," (comma)

 .stdWrap (stdWrap properties):
stdWrap properties of the listNum...

 

Examples:

We have a value of "item 1, item 2, item 3, item 4":
This would return "item 3":
.listNum = last - 1\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:4:\"trim\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:52:\"PHP-function trim(); Removes whitespace around value\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:34:\"Recursive call to stdWrap function\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:19;a:6:{s:8:\"property\";s:8:\"required\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:291:\"This flag requires the content to be set to some value after any content-import and treatment that might have happend now (data, field, current, listNum, trim). Zero's is NOT regarded as empty! Use "if" instead!
If the content i empty, "" is returned immediately.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:20;a:6:{s:8:\"property\";s:2:\"if\";s:8:\"datatype\";s:7:\"->if\";s:11:\"description\";s:72:\"If the if-object returns false, stdWrap returns "" immediately\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:21;a:6:{s:8:\"property\";s:13:\"fieldRequired\";s:8:\"datatype\";s:16:\"fieldname\";s:11:\"description\";s:31:\"value in this field MUST be set\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:22;a:6:{s:8:\"property\";s:18:\"Parse data:\";s:8:\"datatype\";N;s:11:\"description\";N;s:7:\"default\";N;s:12:\"column_count\";i:1;s:16:\"is_propertyTable\";i:1;}i:23;a:6:{s:8:\"property\";s:6:\"csConv\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:131:\"Convert the charset of the string from the charset given as value to the current rendering charset of the frontend (renderCharset).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:24;a:6:{s:8:\"property\";s:9:\"parseFunc\";s:8:\"datatype\";s:38:\"object path reference / ->parseFunc\";s:11:\"description\";s:529:\"Processing instructions for the content.
 Notice: If you enter a string as value this will be taken as a reference to an object path globally in the TypoScript object tree. This will be the basis configuration for parseFunc merged with any properties you add here. It works exactly like references does for content elements.
 
Example:

parseFunc = < lib.parseFunc_RTE
parseFunc.tags.myTag = TEXT
parseFunc.tags.myTag.value = This will be inserted when &lt;myTag&gt; is found!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:25;a:6:{s:8:\"property\";s:10:\"HTMLparser\";s:8:\"datatype\";s:25:\"boolean / ->HTMLparser\";s:11:\"description\";s:220:\"This object allows you to parse the HTML-content and make all kinds of advanced filterings on the content.
Value must be set and properties are those of ->HTMLparser.
(See adminguide for ->HTMLparser options)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:26;a:6:{s:8:\"property\";s:5:\"split\";s:8:\"datatype\";s:10:\"->split\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:27;a:6:{s:8:\"property\";s:10:\"prioriCalc\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:661:\"Calculation of the value using operators -+*/%^ plus respects priority to + and - operators and parenthesis levels ().
. (period) is decimal delimiter.
Returns a doublevalue.
If .prioriCalc is set to “intval” an integer is returned.
There is no errorchecking and division by zero or other invalid values may generate strange results. Also you use a proper syntax because future modifications to the function used may allow for more operators and features.
 
Examples:

100%7 = 2
-5*-4 = 20
+6^2 = 36
6 ^(1+1) = 36
-5*-4+6^2-100%7 = 54
-5 * (-4+6) ^ 2 - 100%7 = 98
-5 * ((-4+6) ^ 2) - 100%7 = -22\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:28;a:6:{s:8:\"property\";s:4:\"char\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:94:\"Content is set to the chr(value).
PHP: $content=chr(intval($conf["char"]);\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:29;a:6:{s:8:\"property\";s:6:\"intval\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:77:\"PHP function intval(); Returns an integer.
PHP: $content=intval($content);\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:30;a:6:{s:8:\"property\";s:4:\"date\";s:8:\"datatype\";s:9:\"date-conf\";s:11:\"description\";s:256:\"The content should be data-type "UNIX-time". Returns the content formatted as a date.
$content=Date($conf["date"], $content);
 
 Example where a timestamp is imported:
.value.field = tstamp
.value.date = \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:31;a:6:{s:8:\"property\";s:8:\"strftime\";s:8:\"datatype\";s:20:\"strftime-conf\";s:11:\"description\";s:424:\"Exactly like "date" above. See the PHP-manual (strftime) for the codes, or datatype "strftime-conf".
This formatting is useful if the locale is set in advance in the CONFIG-object. See this.
 
Properties:
 .charset : Can be set to the charset of the output string if you need to convert it to renderCharset. Default is to take the intelligently guessed charset from t3lib_cs.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:32;a:6:{s:8:\"property\";s:3:\"age\";s:8:\"datatype\";s:17:\"boolean or string\";s:11:\"description\";s:666:\"If enabled with a "1" (number, integer) the content is seen as a date (UNIX-time) and the difference from present time and the content-time is returned as one of these four variations:
"xx min" or "xx hrs" or "xx days" or "xx yrs"
The limits between which layout is used are 60 minutes, 24 hours, 365 days,
 
NOTE:

If you set this property with a non-integer, it's used to format the four units. This is the default value:
" min| hrs| days| yrs"
 
Set another string if you want to change the units. You may include the "-signs. They are removed anyway.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:33;a:6:{s:8:\"property\";s:4:\"case\";s:8:\"datatype\";s:4:\"case\";s:11:\"description\";s:76:\"Converts case
 
Uses "renderCharset" for the operation.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:34;a:6:{s:8:\"property\";s:5:\"bytes\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:401:\"Will format the input (an integer) as bytes: bytes, kb, mb
 
If you add a value for the property “labels” you can alter the default suffixes. Labels for bytes, kilo, mega and giga are separated by vertical bar (|) and possibly encapsulated in "". Eg: " | K| M| G" (which is the default value)
Thus:
 
bytes.labels = “ | K| M| G”\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:35;a:6:{s:8:\"property\";s:9:\"substring\";s:8:\"datatype\";s:10:\"[p1], [p2]\";s:11:\"description\";s:168:\"Returns the substring with [p1] and [p2] send as the 2nd and 3rd parameter to the PHP substring function.
 
Uses "renderCharset" for the operation.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:36;a:6:{s:8:\"property\";s:13:\"removeBadHTML\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:118:\"Removes "bad" HTML code based on a pattern that filters away HTML that is considered dangerous for XSS bugs.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:37;a:6:{s:8:\"property\";s:9:\"stripHtml\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:21:\"Strips all html-tags.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:38;a:6:{s:8:\"property\";s:4:\"crop\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:831:\"Crops the content to a certain length
Syntax: +/- (chars) = from left / from right | [string] | [boolean: keep whole words]
 
 Examples:
 20 | ...    => max 20 characters. If more, the value will be truncated to first 20 chars and prepended with "..."
 -20 | ... => max 20 characters. If more, the value will be truncated to last 20 chars and appended with "..."
 20 | ... | 1 => max 20 characters. If more, the value will be truncated to last 20 chars and appended with "...". If the division is in the middle of a word, the remains of that word is removed.

 

Uses "renderCharset" for the operation.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:39;a:6:{s:8:\"property\";s:12:\"rawUrlEncode\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:54:\"Passes the content through rawurlencode()-PHP-function\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:40;a:6:{s:8:\"property\";s:16:\"htmlSpecialChars\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:177:\"Passes the content through htmlspecialchars()-PHP-function
Additional property “.preserveEntities” will preserve entities so only non-entity chars are affected.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:41;a:6:{s:8:\"property\";s:11:\"doubleBrTag\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:55:\"All double-line-breaks are substituted with this value.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:42;a:6:{s:8:\"property\";s:2:\"br\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:62:\"PHP function nl2br(); Converts linebreaks to <br />-tags\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:43;a:6:{s:8:\"property\";s:5:\"brTag\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:77:\" All ASCII-codes of "10" (CR) is substituted with value\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:44;a:6:{s:8:\"property\";s:11:\"encapsLines\";s:8:\"datatype\";s:16:\"->encapsLines\";s:11:\"description\";s:115:\"Lets you split the content by chr(10) and proces each line independently. Used to format content made with the RTE.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:45;a:6:{s:8:\"property\";s:8:\"keywords\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:149:\"splits the content by characters "," ";" and chr(10) (return), trims each value and returns a comma-separated list of the values.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:46;a:6:{s:8:\"property\";s:9:\"innerWrap\";s:8:\"datatype\";s:13:\"wrap /stdWrap\";s:11:\"description\";s:17:\"Wraps the content\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:47;a:6:{s:8:\"property\";s:10:\"innerWrap2\";s:8:\"datatype\";s:13:\"wrap /stdWrap\";s:11:\"description\";s:74:\"same as .innerWrap (but watch the order in which they are executed)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:48;a:6:{s:8:\"property\";s:7:\"fontTag\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:49;a:6:{s:8:\"property\";s:9:\"addParams\";s:8:\"datatype\";s:14:\"->addParams\";s:11:\"description\";s:74:\"Lets you add tag-parameters to the content if the content is a tag!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:50;a:6:{s:8:\"property\";s:9:\"textStyle\";s:8:\"datatype\";s:14:\"->textStyle\";s:11:\"description\";s:26:\"Wraps content in font-tags\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:51;a:6:{s:8:\"property\";s:10:\"tableStyle\";s:8:\"datatype\";s:15:\"->tableStyle\";s:11:\"description\";s:29:\"Wraps content with table-tags\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:52;a:6:{s:8:\"property\";s:8:\"filelink\";s:8:\"datatype\";s:13:\"->filelink\";s:11:\"description\";s:37:\"Used to make lists of links to files.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:53;a:6:{s:8:\"property\";s:10:\"preCObject\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:30:\"cObject prepended the content \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:54;a:6:{s:8:\"property\";s:11:\"postCObject\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:28:\"cObject appended the content\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:55;a:6:{s:8:\"property\";s:9:\"wrapAlign\";s:8:\"datatype\";s:14:\"align /stdWrap\";s:11:\"description\";s:109:\"Wraps content with <div style=text-align:[value];”> | </div> if align is set\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:56;a:6:{s:8:\"property\";s:8:\"typolink\";s:8:\"datatype\";s:13:\"->typolink\";s:11:\"description\";s:33:\"Wraps the content with a link-tag\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:57;a:6:{s:8:\"property\";s:14:\"TCAselectItem.\";s:8:\"datatype\";s:26:\"Array of properties\";s:11:\"description\";s:446:\"Resolves a comma seperated list of values into the TCA item representation.
 
 .table (string): The Table to look up
 .field (string): The field to resolve
 .delimiter (string): Delimiter for concatenating multiple elements.
 
 Notice: Currently this works only with TCA fields of type “select” which are not database relations.
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:58;a:6:{s:8:\"property\";s:11:\"spaceBefore\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:69:\"Pixels space before. Done with a clear-gif; <img ...><BR>\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:59;a:6:{s:8:\"property\";s:10:\"spaceAfter\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:68:\"Pixels space after. Done with a clear-gif; <img ...><BR>\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:60;a:6:{s:8:\"property\";s:5:\"space\";s:8:\"datatype\";s:5:\"space\";s:11:\"description\";s:260:\"[spaceBefore]   |   [spaceAfter]
 
Additional property:

.useDiv = 1
If set, a clear gif is not used by rather a <div> tag with a style-attribute setting the height. (Affects spaceBefore and spaceAfter as well).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:61;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:17:\"wrap /+.splitChar\";s:11:\"description\";s:104:\".splitChar defines an alternative splitting character (default is “|” - the vertical line)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:62;a:6:{s:8:\"property\";s:10:\"noTrimWrap\";s:8:\"datatype\";s:24:\""special" wrap\";s:11:\"description\";s:292:\"This wraps the content with the values val1 and val2 in the example below - including surrounding whitespace! - without trimming the values. Note that this kind of wrap requires a "|" character to begin and end the wrap.
 
Example:

| val1 | val2 |\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:63;a:6:{s:8:\"property\";s:5:\"wrap2\";s:8:\"datatype\";s:17:\"wrap /+.splitChar\";s:11:\"description\";s:69:\"same as .wrap (but watch the order in which they are executed)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:64;a:6:{s:8:\"property\";s:8:\"dataWrap\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:336:\"The content is parsed for sections of {...} and the content of {...} is of the type getText and substituted with the result of getText.
 
Example:

This should result in a font-tag where the fontsize is decided by the global variable "size":
<font size="{global : size}"> | </font>\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:65;a:6:{s:8:\"property\";s:7:\"prepend\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:37:\"cObject prepended to content (before)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:66;a:6:{s:8:\"property\";s:6:\"append\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:35:\"cObject appended to content (after)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:67;a:6:{s:8:\"property\";s:5:\"wrap3\";s:8:\"datatype\";s:17:\"wrap /+.splitChar\";s:11:\"description\";s:69:\"same as .wrap (but watch the order in which they are executed)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:68;a:6:{s:8:\"property\";s:9:\"outerWrap\";s:8:\"datatype\";s:13:\"wrap /stdWrap\";s:11:\"description\";s:33:\"Wraps the complete content\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:69;a:6:{s:8:\"property\";s:10:\"insertData\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:205:\"If set, then the content string is parsed like .dataWrap above.
 
Example:

Displays the page title:
10 = TEXT
10.value = This is the page title: {page:title}
10.insertData = 1\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:70;a:6:{s:8:\"property\";s:10:\"offsetWrap\";s:8:\"datatype\";s:3:\"x,y\";s:11:\"description\";s:387:\"This wraps the input in a table with columns to the left and top that offsets the content by the values of x,y. Based on the cObject OTABLE.
 
.tableParams / .tdParams /stdWrap

- used to manipulate tableParams/tdParams (default width=99%) of the offset. Default: See OTABLE.
 
.stdWrap

- stdWrap properties wrapping the offsetWrap'ed output\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:71;a:6:{s:8:\"property\";s:12:\"postUserFunc\";s:8:\"datatype\";s:13:\"function-name\";s:11:\"description\";s:871:\" Calling a PHP-function or method in a class, passing the current content to the function as first parameter and any properties as second parameter. Please see the description of the cObject USER for in-depth information.
 
Example:

You can paste this example directly into a new template record.
 
page = PAGE
page.typeNum=0
includeLibs.something = media/scripts/example_callfunction.php
 
page.10 = TEXT
page.10 {
   value = Hello World
   postUserFunc = user_reverseString
   postUserFunc.uppercase = 1
}
 
page.20 = TEXT
page.20 {
   value = Hello World
   postUserFunc = user_various->reverseString
   postUserFunc.uppercase = 1
   postUserFunc.typolink = 11
}\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:72;a:6:{s:8:\"property\";s:15:\"postUserFuncInt\";s:8:\"datatype\";s:13:\"function-name\";s:11:\"description\";s:347:\"Calling a PHP-function or method in a class, passing the current content to the function as first parameter and any properties as second parameter. The result will be rendered non-cached, outside the main page-rendering. Please see the description of the cObject USER_INT and PHP_SCRIPT_INT for in-depth information.
Supplied by Jens Ellerbrock\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:73;a:6:{s:8:\"property\";s:13:\"prefixComment\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:462:\"Prefixes content with a HTML comment with the second part of input string (divided by "|") where first part is an integer telling how many trailing tabs to put before the comment on a new line.
The content is parsed through insertData.
 
Example:

prefixComment = 2 | CONTENT ELEMENT, uid:{field:uid}/{field:CType}
 
Will indent the comment with 1 tab (and the next line with 2+1 tabs)
(Added in TYPO3 >3.6.0RC1)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:74;a:6:{s:8:\"property\";s:9:\"editIcons\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:1795:\"If not empty, then insert an icon linking to the typo3/alt_doc.php with some parameters to build and backend user edit form for certain fields.
The value of this property is a list of fields from a table to edit. It's assumed that the current record of the cObj is the record to be edited.
Syntax: optional tablename : comma list of fieldnames[list of pallette-field names separated by | ]
 

 .beforeLastTag (1,0,-1): If set (1), the icon will be inserted before the last HTML tag in the content. If -1 the icon will be prepended to the content. If zero (0) the icon is appended in the end of the content.
 
 .styleAttribute (string): Adds a style-attribute to the icon image with this value. For instance you can set “position:absolute” if you want a non-destructive insertion of the icon. Notice: For general styling all edit icons has the class “frontEndEditIcons” which can be addressed from the stylesheet of the site.
 
.iconTitle (string): The title attribute of the image tag.

 
 .iconImg (HTML): Alternative HTML code instead of the default icon shown. Can be used to set another icon for editing (for instance a red dot or otherwise... :-)
 
Example:

This will insert an edit icon which links to a form where the header and bodytext fields are displayed and made available for editing (provided the user has access!).
editIcons = tt_content : header, bodytext
 
Or this line that puts the header_align and date field into a “palette” which means they are displayed on a single line below the header field. This saves some space.
editIcons = header[header_align|date], bodytext
 \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:75;a:6:{s:8:\"property\";s:9:\"editPanel\";s:8:\"datatype\";s:19:\"boolean / editPanel\";s:11:\"description\";s:22:\"See cObject EDITPANEL.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:76;a:6:{s:8:\"property\";s:5:\"debug\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:231:\"Prints content with HTMLSpecialChars() and <PRE></PRE>: Usefull for debugging which value stdWrap actually ends up with, if you're constructing a website with TypoScript.
Should be used under construction only.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:77;a:6:{s:8:\"property\";s:9:\"debugFunc\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:196:\"Prints the content directly to browser with the debug() function.
Should be used under construction only.
Set to value “2” the content will be printed in a table - looks nicer.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:78;a:6:{s:8:\"property\";s:9:\"debugData\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:160:\"Prints the current data-array, $cObj->data, directly to browser. This is where ".field" gets data from.
Should be used under construction only. \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(32,7389802,'a86e19eef308f8779c6e1c720defaacb','','tsref:->imgResource','a:1:{s:4:\"rows\";a:17:{i:0;a:6:{s:8:\"property\";s:3:\"ext\";s:8:\"datatype\";s:23:\"imageExtension /stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:3:\"web\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:5:\"width\";s:8:\"datatype\";s:15:\"pixels /stdWrap\";s:11:\"description\";s:1321:\"If both the width and the heigth are set and one of the numbers is appended by an "m", the proportions will be preserved and thus width/height are treated as maximum dimensions for the image. The image will be scaled to fit into width/height rectangle.
 
If both the width and the heigth are set and at least one of the numbers is appended by a "c", cropscaling will be enabled. This means that the proportions will be preserved and the image will be scaled to fit around a rectangle with width/height dimensions. Then, a centered portion from inside of the image (size defined by width/height) will be cut out.
The "c" can have a percentage value (-100 ... +100) after it, which defines how much the cropping will be moved off the center to the border.
 
Notice that you can only use “m” or “c” at the same time!
 
Examples:

This crops 120x80px from the center of the scaled image:
.width = 120c.height = 80c
 
This crops 100x100px; from landscape-images at the left and portrait-images centered:
.width = 100c-100.height = 100c
 
This crops 100x100px; from landscape-images a bit right of the center and portrait-images a bit upper than centered:
.width = 100c+30
.height = 100c-25\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:6:\"height\";s:8:\"datatype\";s:15:\"pixels /stdWrap\";s:11:\"description\";s:26:\"see “.width”\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:6:\"params\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:78:\"ImageMagick command-line:
fx. "-rotate 90" or "-negate"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:6:\"sample\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:124:\"If set, -sample is used to scale images instead of -geometry. Sample does not use antialiasing and is therefore much faster.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:19:\"alternativeTempPath\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:116:\"Enter an alternative path to use for temp images. Must be found in the list in TYPO3_CONF_VARS[FE][allowedTempPaths]\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:5:\"frame\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:90:\"Chooses which frame in an gif-animation or pdf-file.
"" = first frame (zero)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:6:\"import\";s:8:\"datatype\";s:13:\"path /stdWrap\";s:11:\"description\";s:301:\" value should be set to the path of the file
with stdWrap you get the filename from the data-array
 
Example:

This returns the first image in the field "image" from the data-array:
.import = uploads/pics/
.import.field = image
.import.listNum = 0\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:4:\"maxW\";s:8:\"datatype\";s:15:\"pixels /stdWrap\";s:11:\"description\";s:9:\"Max width\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:4:\"maxH\";s:8:\"datatype\";s:15:\"pixels /stdWrap\";s:11:\"description\";s:10:\"Max height\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:4:\"minW\";s:8:\"datatype\";s:6:\"pixels\";s:11:\"description\";s:31:\"Min width (overrules maxW/maxH)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:4:\"minH\";s:8:\"datatype\";s:6:\"pixels\";s:11:\"description\";s:32:\"Min height (overrules maxW/maxH)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:45:\"Masking:
(Black hides, white shows)\";s:8:\"datatype\";N;s:11:\"description\";N;s:7:\"default\";N;s:12:\"column_count\";i:1;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:6:\"m.mask\";s:8:\"datatype\";s:11:\"imgResource\";s:11:\"description\";s:262:\"The mask by which the image is masked onto "m.bgImg". Both "m.mask" and "m.bgImg" is scaled to fit the size of the imgResource image!
 NOTE: Both "m.mask" and "m.bgImg" must be valid images.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:7:\"m.bgImg\";s:8:\"datatype\";s:11:\"imgResource\";s:11:\"description\";s:88:\" NOTE: Both "m.mask" and "m.bgImg" must be valid images.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:11:\"m.bottomImg\";s:8:\"datatype\";s:11:\"imgResource\";s:11:\"description\";s:430:\"An image masked by "m.bottomImg_mask" onto "m.bgImg" before the imgResources is masked by "m.mask".
Both "m.bottomImg" and "m.bottomImg_mask" is scaled to fit the size of the imgResource image!
This is most often used to create an underlay for the imgResource.
 NOTE: Both "m.bottomImg" and "m.bottomImg_mask" must be valid images.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:16:\"m.bottomImg_mask\";s:8:\"datatype\";s:11:\"imgResource\";s:11:\"description\";s:116:\"(optional)
 NOTE: Both "m.bottomImg" and "m.bottomImg_mask" must be valid images.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(33,7389802,'995f8106dda949b01ff8cc2cc0da016c','','tsref:->imageLinkWrap','a:1:{s:4:\"rows\";a:16:{i:0;a:6:{s:8:\"property\";s:5:\"width\";s:8:\"datatype\";s:12:\"int (1-1000)\";s:11:\"description\";s:134:\"If you add "m" to either the width or height, the image will be held in proportions and width/height works as max-dimensions\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:6:\"height\";s:8:\"datatype\";s:12:\"int (1-1000)\";s:11:\"description\";s:22:\"see ".width"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:7:\"effects\";s:8:\"datatype\";s:66:\" see GIFBUILDER / effects. (from stdgraphics-library) \";s:11:\"description\";s:55:\"Example:
gamma=1,3 | sharpen=80 | solarize=70\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:6:\"sample\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:124:\"If set, -sample is used to scale images instead of -geometry. Sample does not use antialiasing and is therefore much faster.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:19:\"alternativeTempPath\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:116:\"Enter an alternative path to use for temp images. Must be found in the list in TYPO3_CONF_VARS[FE][allowedTempPaths]\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:5:\"title\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:35:\"page title of the new window (HTML)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:7:\"bodyTag\";s:8:\"datatype\";s:11:\"<tag>\";s:11:\"description\";s:26:\"Body tag of the new window\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:56:\"Wrap of the image, which is output between the body-tags\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:6:\"target\";s:8:\"datatype\";s:21:\"<A>-data:target\";s:11:\"description\";s:42:\"NOTE: Only if ".JSwindow" is set\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:8:\"JSwindow\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:88:\"The image will be opened in a new window which is fitted to the dimensions of the image!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:15:\"JSwindow.expand\";s:8:\"datatype\";s:3:\"x,y\";s:11:\"description\";s:42:\"x and y is added to the window dimensions.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:18:\"JSwindow.newWindow\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:39:\"Each picture will open in a new window!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:15:\"JSwindow.altUrl\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:99:\"If this returns anything, the URL shown in the JS-window is NOT showpic.php but the url given here!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:31:\"JSwindow.altUrl_noDefaultParams\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:159:\"If this is set, the image parameters are not appended to the altUrl
automatically. This is useful if you want to create them with a userfunction
instead.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:8:\"typolink\";s:8:\"datatype\";s:13:\"->typolink\";s:11:\"description\";s:63:\"NOTE: This overrides the imageLinkWrap if it returns anything!!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:6:\"enable\";s:8:\"datatype\";s:16:\"boolean /stdWrap\";s:11:\"description\";s:49:\"The image is linked ONLY if this is true!!\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(34,7389802,'8354e493f67a8b31615797f35c761ce3','','tsref:->numRows','a:1:{s:4:\"rows\";a:2:{i:0;a:6:{s:8:\"property\";s:5:\"table\";s:8:\"datatype\";s:9:\"tablename\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:6:\"select\";s:8:\"datatype\";s:11:\"->select\";s:11:\"description\";s:142:\"Select query for the operation.
 
The property “selectFields” is overridden internally with “count(*)”.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(35,7389802,'232474bb912dfb37279eda0d54a3cebe','','tsref:->select','a:1:{s:4:\"rows\";a:11:{i:0;a:6:{s:8:\"property\";s:9:\"uidInList\";s:8:\"datatype\";s:22:\"list of page_id\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:9:\"pidInList\";s:8:\"datatype\";s:37:\" list of page_id /stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:4:\"this\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:7:\"orderBy\";s:8:\"datatype\";s:18:\"SQL-orderBy\";s:11:\"description\";s:60:\"without "order by"! Eg. "sorting, title"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:7:\"groupBy\";s:8:\"datatype\";s:18:\"SQL-groupBy\";s:11:\"description\";s:51:\"without "group by"! Eg. "CType"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:3:\"max\";s:8:\"datatype\";s:35:\"int
+calc
+"total"\";s:11:\"description\";s:95:\"max records
 
Special keyword: "total" is substituted with count(*)
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:5:\"begin\";s:8:\"datatype\";s:36:\"int
+calc
+"total"\";s:11:\"description\";s:134:\"begin with record number value
 

 Special keyword: "total" is substituted with count(*)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:5:\"where\";s:8:\"datatype\";s:16:\"SQL-where\";s:11:\"description\";s:98:\"without "where"!, Eg. " (title LIKE '%SOMETHING%' AND NOT doktype) "\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:8:\"andWhere\";s:8:\"datatype\";s:31:\" SQL-where /stdWrap\";s:11:\"description\";s:54:\"without "AND"!, Eg. "NOT doktype".\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:13:\"languageField\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:327:\"If set, this points to the field in the record which holds a reference to a record in sys_language table. And if set, the records returned by the select-function will be selected only if the value of this field matches the $GLOBALS[“TSFE”]->sys_language_uid (which is set by the config.sys_language_uid option)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:12:\"selectFields\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:54:\"List of fields to select, or “count(*)”.\";s:7:\"default\";s:1:\"*\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:29:\"join
leftjoin
rightjoin\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:77:\"Enter tablename for JOIN , LEFT OUTER JOIN and RIGHT OUTER JOIN respectively.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(36,7389802,'d31c5c1d83f5f71ea314f95fa18982b3','','tsref:->split','a:1:{s:4:\"rows\";a:7:{i:0;a:6:{s:8:\"property\";s:5:\"token\";s:8:\"datatype\";s:12:\"str /stdWrap\";s:11:\"description\";s:51:\"string or character (token) used to split the value\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:3:\"max\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:20:\"max number of splits\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:3:\"min\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:21:\"min number of splits.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:9:\"returnKey\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:87:\"Instead of parsing the split result, just return this element of the index immediately.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:7:\"cObjNum\";s:8:\"datatype\";s:30:\"cObjNum
+optionSplit\";s:11:\"description\";s:120:\"This is a pointer the array of this object ("1,2,3,4"), that should treat the items, resulting from the split.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:7:\"1,2,3,4\";s:8:\"datatype\";s:20:\"->CARRAY /stdWrap\";s:11:\"description\";s:537:\"The object that should treat the value.
NOTE: The "current"-value is set to the value of current item, when the objects are called. See "stdWrap" / current.

 

Example (stdWrap used):

1.current = 1
1.wrap = <B> | </B>
 
Example (CARRAY used):

1 {
   10 = TEXT
   10.current = 1
   10.wrap = <B> | </B>
   20 = CLEARGIF
   20.height = 20
}\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:21:\"wrap
+optionSplit\";s:11:\"description\";s:29:\"Defines a wrap for each item.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(37,7389802,'c3abe7b3e50e8c5a3ec49c6fc37e7c6c','','tsref:->if','a:1:{s:4:\"rows\";a:10:{i:0;a:6:{s:8:\"property\";s:6:\"isTrue\";s:8:\"datatype\";s:12:\"str /stdWrap\";s:11:\"description\";s:70:\"If the content is "true".... (not empty string and not zero)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:7:\"isFalse\";s:8:\"datatype\";s:12:\"str /stdWrap\";s:11:\"description\";s:54:\"If the content is "false"... (empty or zero)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:10:\"isPositive\";s:8:\"datatype\";s:22:\"int /stdWrap
+ calc\";s:11:\"description\";s:40:\"returns false if content is not positive\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:13:\"isGreaterThan\";s:8:\"datatype\";s:14:\"value /stdWrap\";s:11:\"description\";s:63:\"returns false if content is not greater than ".value"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:10:\"isLessThan\";s:8:\"datatype\";s:14:\"value /stdWrap\";s:11:\"description\";s:60:\"returns false if content is not less than ".value"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:6:\"equals\";s:8:\"datatype\";s:14:\"value /stdWrap\";s:11:\"description\";s:58:\"returns false if content does not equal ".value"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:8:\"isInList\";s:8:\"datatype\";s:14:\"value /stdWrap\";s:11:\"description\";s:152:\"returns false if content is not in the comma-separated list ".value".
The list in ".value" may not have spaces between elements!!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:5:\"value\";s:8:\"datatype\";s:14:\"value /stdWrap\";s:11:\"description\";s:56:\""value" (the comparison value mentioned above)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:6:\"negate\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:125:\"This negates the result just before it exits. So if anything above returns true the overall returns ends up returning false!!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:12:\"directReturn\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:120:\"If this property exists the true/false of this value is returned. Could be used to set true/false by TypoScript constant\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(38,7389802,'8d5bffcf7ab541700c652a5edf894713','','tsref:->typolink','a:1:{s:4:\"rows\";a:15:{i:0;a:6:{s:8:\"property\";s:9:\"extTarget\";s:8:\"datatype\";s:15:\"target /stdWrap\";s:11:\"description\";s:30:\"target used for external links\";s:7:\"default\";s:4:\"_top\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:6:\"target\";s:8:\"datatype\";s:15:\"target /stdWrap\";s:11:\"description\";s:30:\"target used for internal links\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:8:\"no_cache\";s:8:\"datatype\";s:16:\"boolean /stdWrap\";s:11:\"description\";s:56:\"Adds a "&no_cache=1"-parameter to the link\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:12:\"useCacheHash\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:532:\"If set, the additionalParams list is exploded and calculated into a hashstring appended to the url, like “&cHash=ae83fd7s87”. When the caching mechanism sees this value, it calculates the same value on the server based on incoming values in HTTP_GET_VARS, excluding id,type,no_cache,ftu,cHash,MP values. If the incoming cHash value matches the calculated value, the page may be cached based on this.
The [SYS][encryptionKey] is included in the hash in order to make it unique for the server and non-predictable.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:16:\"additionalParams\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:556:\"This is parameters that are added to the end of the url. This must be code ready to insert after the last parameter.
 
Example:

'&print=1'
'&sword_list[]=word1&sword_list[]=word2'
 
Applications:

This is very useful when linking to pages from a searchresult. The searchwords are stored in the register-key SWORD_PARAMS and can be insert directly like this:
.additionalParams.data = register:SWORD_PARAMS
 
 NOTE: This is only active for internal links!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:14:\"addQueryString\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:884:\"Add the QUERY_STRING to the start of the link. Notice that this does not check for any duplicate parameters! This is not a problem (only the last parameter of the same name will be applied), but enable "config.uniqueLinkVars" if you still don't like it.
 
 .method: If set to to GET or POST then then the parsed query arguments (GET or POST data) will be used. This settings are useful if you use URL processing extensions like Real URL, which translate part of the path into query arguments.
It's also possible to get both, POST and GET data, on setting this to
"POST,GET" or "GET,POST". The last method in this sequence takes
precedence and overwrites the parts that are also present for the first
method.
 
 .exclude: List of query arguments to exclude from the link (eg L or cHash).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:16:\"Wraps the links.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:14:\"ATagBeforeWrap\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:91:\"If set, the link is first wrapped with ".wrap" and then the <A>-tag.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:9:\"parameter\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:4199:\"This is the data, that ->typolink uses to create the link. The value is trimmed and if it's empty, ->typolink returns the input value untouched.
 
 NOTE: If used from parseFunc, this value should be imported by:
typolink.parameter.data = parameters : allParams
 
Examples:

Internal links:
integers (51): creates a link to page with uid = 51
filerefs (fileadmin/somedir/thedoc.html): creates a link to the file on the local server.
strings (some_alias): creates a link to the page with alias = "some_alias"
 
External links:
email-adresses (name@email.com): creates a link to the email-addr.
domains (www.domain.com): creates link to http://-page
 
The input is parsed like this:

First the parameter is splitted by character-space. This provides a way to pass more parameters. See "target" below here.
If a "@" is in the string, it's an email
If a period (.) is in the string AND if the period (.) is found before a slash (/) is found OR if a doubleslash is found, then it's a URL
If a slash (/) is found, it's a filereference. If the file/directory does not exist on the server, the link is NOT made!
 
Now the input can be an alias or page-id. If the input is an integer it's a page-id, if it's two comma separated integers, it's a id/type pair, else it's an alias. For page-id's or aliases you can prepend a "#" mark with a number indication tt_content record number on the page to jump to! (if .section-property is present, it overrides this).
If you insert only "#234" where "234" is the tt_content record number, it links to the current page-id
Notice: The parameter can contain a keyword that hands over link generation to an external function. See example below this table!

 

Target

Target is normally defined by the "extTarget" and "target" properties of typolink. But you may override this target by adding the new target after the parameter separated by a whitespace. Thus the target becomes the second parameter.
If the “Target” parameter is set to the “-” character, then it's the same as no target passed to the function. This feature enables you to still pass a class as third parameter and title as fourth parameter without setting the target also.
 
Open in windows with fixed dimensions (JavaScript)

It is possible to open the link in a window opened by JavaScript (with “window.open”). For this, just set the target value to “123x456” where 123 is the window width and 456 is the window height. You can also specify additional parameters to the function by entering them separated from the width and height with a colon “:”. For instance “230x450:resizable=0,location=1” will disable resizing of the window and enable the location bar.
Also see property “JSwindow”.
 
Class

If you specify a third parameter separated by whitespace in the parameter value this becomes the class-parameter of the link. This class parameter is inserted in the link-tag before any values from .ATagParams which means this class value will override any class value set in ATagParams (at least for MSIE). If set to “-”, then it's the same as no class passed to the function. This feature enables you to still pass a title as fourth parameter without setting the class also.
 
Title

The title attribute is normally specified via .ATagParams or directly via the .title property. But you may override this value by adding the desired title as the fourth parameter (parameters separated by whitespace) to typolink.
 
Examples of multiparameters:

Consider this .parameter value passed to this function:
 
51 _blank blueLink
 
 This would result in a link approx like this:
 
<A href=”?id=51” target=”_blank” class=”blueLink”>\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:5:\"title\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:38:\"Sets the title parameter of the A-tag.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:15:\"JSwindow_params\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:170:\"Preset values for opening the window. This example lists almost all possible attributes:
status=1,menubar=1,scrollbars=1,resizable=1,location=1,directories=1,toolbar=1\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:10:\"returnLast\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:263:\"If set to "url" then it will return the URL of the link ($this->lastTypoLinkUrl)
If set to "target" it will return the target of the link.
So, in these two cases you will not get the value wrapped but the url or target value returned!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:7:\"section\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:221:\"If this value is present, it's prepended with a "#" and placed after any internal url to another page in TYPO3.
This is used create a link, which jumps from one page directly the section on another page.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:10:\"ATagParams\";s:8:\"datatype\";s:38:\" <A>-params /stdWrap\";s:11:\"description\";s:81:\"Additional parameters
 
Example:

class=”board”\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:8:\"userFunc\";s:8:\"datatype\";s:13:\"function-name\";s:11:\"description\";s:954:\"This passes the link-data compiled by the typolink function to a user-defined function for final manipulation.
The $content variable passed to the user-function (first parameter) is an array with the keys “TYPE”, “TAG”, “url”, “targetParams” and “aTagParams”.
TYPE is an indication of link-kind: mailto, url, file, page
TAG is the full <A>-tag as generated and ready from the typolink function.
The latter three is combined into the 'TAG' value after this formula:
 
<a href="'.$finalTagParts['url'].'"'.
            $finalTagParts['targetParams'].
            $finalTagParts['aTagParams'].'>
 
The userfunction must return an <A>-tag.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(39,7389802,'80780565cc3f65439bc9a712a1a05942','','tsref:->textStyle','a:1:{s:4:\"rows\";a:11:{i:0;a:6:{s:8:\"property\";s:11:\"align.field\";s:8:\"datatype\";s:5:\"align\";s:11:\"description\";s:46:\"Set to fieldname from the $cObj->data-array\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:30:\"face.field
 
 \";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:200:\"Set to fieldname from the $cObj->data-array
 
[1] = "Times New Roman";
[2] = "Verdana,Arial,Helvetica,Sans serif";
[3] = "Arial,Helvetica,Sans serif";\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:12:\"face.default\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:24:\"[default] = User defined\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:30:\"size.field
 
 \";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:144:\"Set to fieldname from the $cObj->data-array
 
[1] = 1;
[2] = 2;
[3] = 3;
[10] = "+1";
[11] = "-1";\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:12:\"size.default\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:24:\"[default] = User defined\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:41:\"color.field
 
 
 \";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:112:\"Set to fieldname from the $cObj->data-array
 
See "content.php" for the colors available\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:13:\"color.default\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:24:\"[default] = User defined\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:18:\"color.1
color.2\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:22:\"[1],[2] = User defined\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:16:\"properties.field\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:249:\"Set to fieldname from the $cObj->data-array
 
The property values goes like this:
bit 0: <B>
bit 1: <I>
bit 2: <U>
bit 3: (uppercase)
 
Thus a value of 5 would result in bold and underlined text\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:18:\"properties.default\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:88:\"[default] = User defined (This value will be used whenever ".field" is false!)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:7:\"altWrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:268:\"If this value is set, the wrapping with a font-tag based on font,size and color is NOT done. Rather the element is wrapped with this value.
Use it to assign a stylesheet by setting this value to eg.
 
<div class=”text”> | </div>\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(40,7389802,'5117f2da4a9bf819b7f78f176d3ede8e','','tsref:->encapsLines','a:1:{s:4:\"rows\";a:9:{i:0;a:6:{s:8:\"property\";s:13:\"encapsTagList\";s:8:\"datatype\";s:15:\"list of strings\";s:11:\"description\";s:374:\"List of tags which qualify as encapsulating tags. Must be lowercase.
 
Example:

encapsTagList = div, p
 
This setting will recognize the red line below as encapsulated lines:
 
First line of text
Some <div>text</div>
<p>Some text</p>
<div>Some text</div>
<B>Some text</B>\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:25:\"remapTag.[tagname]\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:440:\"Enter a new tag name here if you wish the tagname of any encapsulation to be unified to a single tag name.
 
For instance, setting this value to “remapTags.P=DIV” would convert:
 
 <p>Some text</p>
<div>Some text</div>
 
to
 
 <div>Some text</div>
<div>Some text</div>
 
([tagname] is in uppercase.)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:30:\"addAttributes.[tagname]\";s:8:\"datatype\";s:16:\"array of strings\";s:11:\"description\";s:554:\"Attributes to set in the encapsulation tag.
 

Example:

addAttributes.P {
   style=padding-bottom:0px; margin-top:1px; margin-bottom:1px;
   align=center
}
 
([tagname] is in uppercase.)
 
.setOnly =
exists : This will set the value ONLY if the property does not already exist
blank : This will set the value ONLY if the property does not already exist OR is blank (“”)
 
Default is to always override/set the attributes value.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:14:\"removeWrapping\";s:8:\"datatype\";s:6:\"boolen\";s:11:\"description\";s:391:\"If set, then all existing wrapping will be removed.
 
This:
 
First line of text
Some <div>text</div>
<p>Some text</p>
<div>Some text</div>
<B>Some text</B>
 
becomes this:
 
First line of text
Some <div>text</div>
Some text
Some text
<B>Some text</B>\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:19:\"wrapNonWrappedLines\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:304:\"Wrapping for non-encapsulated lines
 
Example:

.wrapNonWrappedLines = <P>|</P>
 
This:
 
First line of text
<p>Some text</p>
 
becomes this:
 
<P>First line of text</P>
<p>Some text</p>\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:16:\"innerStdWrap_all\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:73:\"Wraps the content inside all lines, whether they are encapsulated or not.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:35:\"encapsLinesStdWrap.[tagname]\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:87:\"Wraps the content inside all encapsulated lines.
([tagname] is in uppercase.)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:12:\"defaultAlign\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:156:\"If set, this value is set as the default “align” value of the wrapping tags, both from .encapsTagList, .bypassEncapsTagList and .nonWrappedTag\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:13:\"nonWrappedTag\";s:8:\"datatype\";s:7:\"tagname\";s:11:\"description\";s:343:\"For all non-wrapped lines, you can set here which tag it should be wrapped in. Example would be “P”. This is an alternative to .wrapNonWrappedLines and has the advantage that it's attributes are set by .addAttributes as well as defaultAlign. Thus you can easier match the wrapping tags used for nonwrapped and wrapped lines.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(41,7389802,'1678f0ea79537a75222cb478bbf92623','','tsref:->tableStyle','a:1:{s:4:\"rows\";a:7:{i:0;a:6:{s:8:\"property\";s:5:\"align\";s:8:\"datatype\";s:14:\"align /stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:6:\"border\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:11:\"cellspacing\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:11:\"cellpadding\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:11:\"color.field\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:46:\"Set to fieldname from the $cObj->data-array\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:35:\"color.default
color.1
color.2\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:42:\"[default],[1],[2] = User defined
 \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:6:\"params\";s:8:\"datatype\";s:20:\"<TABLE>-params\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(42,7389802,'91a86be2eb43c2534b3785464471e0c3','','tsref:->addParams','a:1:{s:4:\"rows\";a:2:{i:0;a:6:{s:8:\"property\";s:7:\"_offset\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:143:\"Use this to define which tag you want to manipulate.
1 is the first tag in the input, 2 is the second, -1 is the last, -2 is the second last\";s:7:\"default\";s:1:\"1\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:25:\"(array of strings)\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:284:\"This defines the content of each added property to the tag.
If there is a tag-property with this name already (case-sensitive!) that property will be overridden!
If the returned value is a blank string (but not zero!) then the existing (if any) property will not be overridden.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(43,7389802,'f7e884f75020be6aeaf62ddc5e89bce0','','tsref:->filelink','a:1:{s:4:\"rows\";a:17:{i:0;a:6:{s:8:\"property\";s:4:\"path\";s:8:\"datatype\";s:13:\"path /stdWrap\";s:11:\"description\";s:45:\"Example:
"uploads/media/"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:4:\"icon\";s:8:\"datatype\";s:16:\"boolean /stdWrap\";s:11:\"description\";s:27:\"Set if icon should be shown\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:19:\"icon_image_ext_list\";s:8:\"datatype\";s:30:\"list of imageextensions\";s:11:\"description\";s:74:\"This is the extensions that should render as thumbsnails instead of icons.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:11:\"iconCObject\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:164:\"Enter a cObject to use alternatively for the icons, eg. IMAGE type.
If this is set, it'll substitute the use of the thumbs-script for display of thumbnails.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:9:\"icon_link\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:33:\"If the icon should be linked also\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:12:\"labelStdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:177:\"stdWrap options for the label (by default the label is the filename) before being wrapped with the A-tags.
Use this to eg. import another label from a database field or such.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:16:\"Wraps the links.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:14:\"ATagBeforeWrap\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:91:\"If set, the link is first wrapped with ".wrap" and then the <A>-tag.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:4:\"file\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:97:\"stdWrap of the label (by default the label is the filename) after having been wrapped with A-tag!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:4:\"size\";s:8:\"datatype\";s:16:\"boolean /stdWrap\";s:11:\"description\";s:27:\"Set if size should be shown\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:7:\"jumpurl\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:949:\"Decides if the link should call the script with the jumpurl paramter in order to register any clicks in the stat.
This has the advantage that any clicks on the file will register in the stat.
The disadvantage is, that users cant right-click and select "Save Target As" in the browser.
 

Properties:

.secure (boolean)If set, then the file pointed to by jumpurl is NOT redirected to, but rather it's read from the file and returned with a correct header. This option adds a hash and locationData to the url and there MUST be access to the record in order to download the file. If the fileposition on the server is furthermore secured by a .htaccess file preventing ANY access, you've got secure download here!
 
.secure.mimeTypes (list of mimetypes, syntax [ext] = [mimetype]
 
Example:

.secure = 1
.secure.mimeTypes = pdf=application/pdf, doc=application/msword\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:6:\"target\";s:8:\"datatype\";s:6:\"target\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:10:\"ATagParams\";s:8:\"datatype\";s:38:\" <A>-params /stdWrap\";s:11:\"description\";s:81:\"Additional parameters
 
Example:

class=”board”\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:22:\"removePrependedNumbers\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:90:\"if set, any 2-digit prepended numbers (“eg _23”) in the filename is removed.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:20:\"altText
titleText\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:212:\"For icons (image made with "iconCObject" must have their own properties)
 
If no titltext is specified, it will use the alttext insteadIf no alttext is specified, it will use an empty alttext\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:11:\"longdescURL\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:189:\"For icons (image made with "iconCObject" must have their own properties)
 
"longdesc" attribute (URL pointing to document with extensive details about image).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(44,7389802,'ce1240f8c0d72bb639611ea407625c88','','tsref:->parseFunc','a:1:{s:4:\"rows\";a:13:{i:0;a:6:{s:8:\"property\";s:15:\"externalBlocks \";s:8:\"datatype\";s:28:\"list of tagnames/+properties\";s:11:\"description\";s:3527:\"This allows you to pre-split the content passed to parseFunc so that only content outside the blocks with the given tags is parsed.
Extra properties:

 .[tagname] {
   callRecursive = [boolean]; If set, the content of the block is directed into parseFunc again. Otherwise the content is just passed through with no other processing than stdWrap (see below)
   callRecursive.dontWrapSelf = [boolean]; If set, the tags of the block is not wrapped around the content returned from parseFunc.
   callRecursive.alternativeWrap = Alternative wrapping instead of the original tags.
   callRecursive.tagStdWrap = ->stdWrap processing of the block-tags.
   stdWrap = ->stdWrap processing of the whole block (regardless of whether callRecursive was set.)
   stripNLprev = [boolean]; Strips off last linebreak of the previous outside block
   stripNLnext = [boolean]; Strips off first linebreak of the next outside block
   stripNL = [boolean]: Does both of the above.
 
    = [boolean]; If set, then the content is expected to be a table and every table-cell is traversed.
    # Below, default is all cells and 1,2,3... overrides for specific cols.
    {
      callRecursive = [boolean]; The content is parsed through current parseFunc
       stdWrap = ->stdWrap processing of the content in the cell
       tagStdWrap = -> The <TD> tag is processed by ->stdWrap
    }
    HTMLtableCells.addChr10BetweenParagraphs = [boolean]; If set, then all </P><P> appearances will have a chr(10) inserted between them
}
 
Example:

This example is used to split regular bodytext content so that tables and blockquotes in the bodytext are processed correctly. The blockquotes are passed into parseFunc again (recursively) and further their top/bottom margins are set to 0 (so no apparent linebreaks are seen)
The tables are also displayed with a number of properties of the cells overridden.
tt_content.text.20.parseFunc.externalBlocks {
   blockquote.callRecursive=1
   blockquote.callRecursive.tagStdWrap.HTMLparser = 1
   blockquote.callRecursive.tagStdWrap.HTMLparser {
     tags.blockquote.fixAttrib.style.list = margin-bottom:0;margin-top:0;
     tags.blockquote.fixAttrib.style.always=1
   }
   blockquote.stripNLprev=1
   blockquote.stripNLnext=1
 
   table.stripNL=1
   table.stdWrap.HTMLparser = 1
   table.stdWrap.HTMLparser {
     tags.table.overrideAttribs = border=0 cellpadding=2 cellspacing=1 style="margin-top:10px; margin-bottom:10px;"
     tags.tr.allowedAttribs=0
     tags.td.overrideAttribs = valign=top bgcolor="#eeeeee" style="font-family : Verdana, Geneva, Arial, Helvetica, sans-serif;font-size : 10px;"
   }
}\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:9:\"constants\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:346:\"The toplevel-defined constants will be substituted in the text. The constant-name is wrapped in "###".
 
Example:

constants.EMAIL = email@email.com
(NOTE: This is toplevel TypoScript!)
All cases of the string ###EMAIL### will be substituted in the text. The constants are defined as a toplevel object. \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:5:\"short\";s:8:\"datatype\";s:23:\"array of strings\";s:11:\"description\";s:346:\"Like constants above, but local.
 
Example:

This substitutes all occurencies of “T3” with “TYPO3 CMS” and “T3web” with a link to typo3.com.
short {
   T3 = TYPO3 CMS
   T3web = <a href=”http://typo3.com”>typo3</a>
}\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:16:\"plainTextStdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:52:\"This is stdWrap properties for all non-tag content. \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:8:\"userFunc\";s:8:\"datatype\";s:13:\"function name\";s:11:\"description\";s:185:\"This passes the non-tag content to a function of your own choice. Similar to eg. .postUserFunc in stdWrap.
Remember the function name must possibly be prepended “user_”\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:17:\"nonTypoTagStdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:250:\"Like .plainTextStdWrap. Difference:
.plainTextStdWrap works an ALL non-tag pieces in the text. .nonTypoTagStdWrap is post processing of all text (including tags) between special TypoTags (unless .breakoutTypoTagContent is not set for the TypoTag)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:18:\"nonTypoTagUserFunc\";s:8:\"datatype\";s:13:\"function name\";s:11:\"description\";s:276:\"Like .userFunc. Differences is (like nonTypoTagStdWrap) that this is post processing of all content pieces around TypoTags while .userFunc processes all non-tag content. (Notice: .breakoutTypoTagContent must be set for the TypoTag if it's excluded from nonTypoTagContent)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:5:\"sword\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:203:\"Marks up any words from the GET-method send array sword_list[] in the text. The word MUST be at least two characters long!
 NOTE: works only with $GLOBALS["TSFE"]->no_cache==1\";s:7:\"default\";s:48:\"<font color="red">|</font>\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:9:\"makelinks\";s:8:\"datatype\";s:24:\"boolean / ->makelinks\";s:11:\"description\";s:115:\"Convert webadresses prefixed with "http://" and mail-adresses prefixed with "mailto:" to links.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:4:\"tags\";s:8:\"datatype\";s:16:\"->tags\";s:11:\"description\";s:80:\"Here you can define custom tags that will parse the content to something.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:9:\"allowTags\";s:8:\"datatype\";s:15:\"list of strings\";s:11:\"description\";s:125:\"List of tags, which are allowed to exist in code!
Highest priority: If a tag is found in allowTags, denyTags is ignored!!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:8:\"denyTags\";s:8:\"datatype\";s:15:\"list of strings\";s:11:\"description\";s:388:\"List of tags, which may NOT exist in code! (use "*" for all.)
Lowest priority: If a tag is NOT found in allowTags, denyTags is checked. If denyTags is not "*" and the tag is not found in the list, the tag may exist!
 
Example:

This allows <B>, <I>, <A> and <IMG> -tags to exist
.allowTags = b,i,a,img
.denyTags = *\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:2:\"if\";s:8:\"datatype\";s:7:\"->if\";s:11:\"description\";s:85:\"if "if" returns false the input value is not parsed, but returned directly.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(45,7389802,'87d6057bd7b0beb18019a72c170a32fa','','tsref:->makelinks','a:1:{s:4:\"rows\";a:8:{i:0;a:6:{s:8:\"property\";s:14:\"http.extTarget\";s:8:\"datatype\";s:6:\"target\";s:11:\"description\";s:22:\"The target of the link\";s:7:\"default\";s:4:\"_top\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:9:\"http.wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:20:\"wrap around the link\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:19:\"http.ATagBeforeWrap\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:83:\"If set, the link is first wrapped with http.wrap and then the <A>-tag.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:9:\"http.keep\";s:8:\"datatype\";s:66:\"list: "scheme","path","query"\";s:11:\"description\";s:381:\"As default the link-text will be the full domain-name of the link.
 
 Examples:
http://www.webaddress.rld/test/doc.php?id=3
"": www.webaddress.rld
"scheme": http://www.webaddress.rld
"scheme,path": http://www.webaddress.rld/test/doc.php
"scheme,path,query": http://www.webaddress.rld/test/doc.php?id=3\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:15:\"http.ATagParams\";s:8:\"datatype\";s:38:\" <A>-params /stdWrap\";s:11:\"description\";s:81:\"Additional parameters
 
Example:

class=”board”\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:11:\"mailto.wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:20:\"wrap around the link\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:21:\"mailto.ATagBeforeWrap\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:85:\"If set, the link is first wrapped with mailto.wrap and then the <A>-tag.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:17:\"mailto.ATagParams\";s:8:\"datatype\";s:38:\" <A>-params /stdWrap\";s:11:\"description\";s:81:\"Additional parameters
 
Example:

class=”board”\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(46,7389802,'a465bb5ed515df37786b15b6049198e8','','tsref:->tags','a:1:{s:4:\"rows\";a:1:{i:0;a:6:{s:8:\"property\";s:15:\"Array...\";s:8:\"datatype\";s:58:\"cObject +stripNL
+ breakoutTypoTagContent
\";s:11:\"description\";s:1226:\"Every entry in the Array... corresponds to a tag, that will be parsed. The elements MUST be in lowercase.
Every entry must be set to a content-object.
"current" is set to the content of the tag, eg <TAG>content</TAG>: here "current" is set to "content".
Parameters:

Parameters of the tag is set in $cObj->parameters (key is lowercased):
<TAG COLOR="red">content</TAG>
=> $cObj->parameters[color] = red
Special added properties to the content-object:

$cObj->parameters[allParams]: this is automatically set to the whole parameter-string of the tag, eg ' color="red"'
[cObject].stripNL: is a boolean option, which tells parseFunc that NewLines before and after content of the tag should be stripped.
[cObject].breakoutTypoTagContent: is a boolean option, which tells parseFunc that this block of content is breaking up the nonTypoTag content and that the content after this must be re-wrapped.
 
Examples:

tags.bold = TEXT
tags.bold {
   current = 1
   wrap = <B> | </B>
}
tags.bold.stripNL = 1\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(47,7389802,'eb48183e6181b87770ebe8ae2364c70d','','page:->HTMLparser; tsref:->HTMLparser','a:1:{s:4:\"rows\";a:10:{i:0;a:6:{s:8:\"property\";s:9:\"allowTags\";s:8:\"datatype\";s:12:\"list of tags\";s:11:\"description\";s:20:\"Default allowed tags\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:14:\"tags.[tagname]\";s:8:\"datatype\";s:28:\"boolean/->HTMLparser_tags\";s:11:\"description\";s:212:\"Either set this property to 0 or 1 to allow or deny the tag. If you enter ->HTMLparser_tags properties, those will automatically overrule this option, thus it's not needed then.
[tagname] in lowercase.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:12:\"localNesting\";s:8:\"datatype\";s:42:\"list of tags, must be among preserved tags\";s:11:\"description\";s:100:\"List of tags (among the already set tags), which will be forced to have the nesting-flag set to true\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:13:\"globalNesting\";s:8:\"datatype\";s:6:\"(ibid)\";s:11:\"description\";s:118:\"List of tags (among the already set tags), which will be forced to have the nesting-flag set to “global”\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:15:\"rmTagIfNoAttrib\";s:8:\"datatype\";s:6:\"(ibid)\";s:11:\"description\";s:103:\"List of tags (among the already set tags), which will be forced to have the rmTagIfNoAttrib set to true\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:8:\"noAttrib\";s:8:\"datatype\";s:6:\"(ibid)\";s:11:\"description\";s:154:\"List of tags (among the already set tags), which will be forced to have the allowedAttribs value set to zero (which means, all attributes will be removed.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:10:\"removeTags\";s:8:\"datatype\";s:6:\"(ibid)\";s:11:\"description\";s:95:\"List of tags (among the already set tags), which will be configured so they are surely removed.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:18:\"keepNonMatchedTags\";s:8:\"datatype\";s:33:\"boolean / “protect”\";s:11:\"description\";s:328:\"If set (true=1), then all tags are kept regardless of tags present as keys in $tags-array.
If "protect", then the preserved tags have their <> converted to &lt; and &gt;
Default is to REMOVE all tags, which are not specifically assigned to be allowed! So you might probably want to set this value!\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:16:\"htmlSpecialChars\";s:8:\"datatype\";s:14:\"-1 / 0 / 1 / 2\";s:11:\"description\";s:538:\"This regards all content which is NOT tags:
“0” means “disabled” - nothing is done
“1” means the content outside tags is htmlspecialchar()'ed (PHP-function which converts &”<> to &...;)
“2” is the same as “1” but entities like “&amp;” or “&#234” are untouched.
“-1” does the opposite of “1” - converts &lt; to <, &gt; to >, &quot; to “ etc.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:14:\"xhtml_cleaning\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:167:\"Cleans up the content for XHTML compliance. Still slightly experimental and supports only some clean up operations (like convertion tags and attributes to lower case).\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}}}',''),(48,7389802,'0adbed858831d26590fb2051a38b06d1','','page:->HTMLparser_tags; tsref:->HTMLparser_tags','a:1:{s:4:\"rows\";a:19:{i:0;a:6:{s:8:\"property\";s:15:\"overrideAttribs\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:60:\"If set, this string is preset as the attributes of the tag. \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:14:\"allowedAttribs\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:156:\"'0' (zero) = no attributes allowed, '[commalist of attributes]' = only allowed attributes. If blank/not set, all attributes are allowed.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:31:\" fixAttrib.[attribute].set\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:40:\"Force the attribute value to this value.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:33:\" fixAttrib.[attribute].unset\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:37:\" If set, the attribute is unset.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:35:\" fixAttrib.[attribute].default\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:100:\"If no attribute exists by this name, this value is set as default value (if this value is not blank)\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:34:\" fixAttrib.[attribute].always\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:95:\"If set, the attribute is always processed. Normally an attribute is processed only if it exists\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:144:\" fixAttrib.[attribute].trim
 fixAttrib.[attribute].intval
 fixAttrib.[attribute].upper
 fixAttrib.[attribute].lower\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:87:\"If any of these keys are set, the value is passed through the respective PHP-functions.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:33:\" fixAttrib.[attribute].range\";s:8:\"datatype\";s:12:\"[low],[high]\";s:11:\"description\";s:23:\"Setting integer range. \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:32:\" fixAttrib.[attribute].list\";s:8:\"datatype\";s:23:\"list of values, trimmed\";s:11:\"description\";s:84:\"Attribute value must be in this list. If not, the value is set to the first element.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:41:\" fixAttrib.[attribute].removeIfFalse\";s:8:\"datatype\";s:36:\"boolean/”blank” string\";s:11:\"description\";s:203:\"If set, then the attribute is removed if it is "false". If this value is set to "blank" then the value must be a blank string (that means a "zero" value will not be removed)\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:42:\" fixAttrib.[attribute].removeIfEquals\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:70:\"If the attribute value matches the value set here, then it is removed.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:45:\" fixAttrib.[attribute].casesensitiveComp\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:113:\"If set, the comparison in .removeIfEquals and .list will be case-sensitive. At this point, it's insensitive.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:46:\" fixAttrib.[attribute].prefixLocalAnchors\";s:8:\"datatype\";s:7:\"integer\";s:11:\"description\";s:473:\"If the first char is a “#” character (anchor of fx. <a> tags) this will prefix either a relative or absolute path.
If the value is “1” you will get the absolute path (t3lib_div::getIndpEnv('TYPO3_REQUEST_URL'))
If the value is “2” you will get the relative path (stripping of t3lib_div::getIndpEnv('TYPO3_SITE_URL'))
 
Example:

 
...fixAttrib.href.prefixLocalAnchors = 1\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:45:\" fixAttrib.[attribute].prefixRelPathWith\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:314:\"If the value of the attribute seems to be a relative URL (no scheme like “http” and no “/” as first char) then that value of this property will be prefixed the attribute.
 
Example:

 
...fixAttrib.src.prefixRelPathWith = http://192.168.230.3/typo3/32/dummy/\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:36:\" fixAttrib.[attribute].userFunc\";s:8:\"datatype\";s:18:\"function reference\";s:11:\"description\";s:145:\"User function for processing of the attribute.
 
Example:

 
...fixAttrib.href.userFunc = tx_realurl->test_urlProc\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:7:\"protect\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:62:\"If set, the tag <> is converted to &lt; and &gt;\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:5:\"remap\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:47:\"If set, the tagname is remapped to this tagname\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:15:\"rmTagIfNoAttrib\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:69:\"If set, then the tag is removed if no attributes happend to be there.\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:7:\"nesting\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:624:\"If set true, then this tag must have starting and ending tags in the correct order. Any tags not in this order will be discarded. Thus '</B><B><I></B></I></B>' will be converted to '<B><I></B></I>'.
Is the value "global" then true nesting in relation to other tags marked for "global" nesting control is preserved. This means that if <B> and <I> are set for global nesting then this string '</B><B><I></B></I></B>' is converted to '<B></B>'\";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}}}',''),(49,7389802,'2bcf41f3a27a1da90a09ebdf3a40f315','','tsref:(TLO)','a:1:{s:4:\"rows\";a:10:{i:0;a:6:{s:8:\"property\";s:5:\"types\";s:8:\"datatype\";s:8:\"readonly\";s:11:\"description\";s:59:\"Types (internal)
type=99 reserved for plaintext display \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:9:\"resources\";s:8:\"datatype\";s:8:\"readonly\";s:11:\"description\";s:28:\"Resources in list (internal)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:9:\"sitetitle\";s:8:\"datatype\";s:8:\"readonly\";s:11:\"description\";s:20:\"SiteTitle (internal)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:6:\"config\";s:8:\"datatype\";s:11:\"->CONFIG\";s:11:\"description\";s:135:\"Global configuration.
These values are stored with cached pages which means they are also accessible when retrieving a cached page.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:9:\"constants\";s:8:\"datatype\";s:14:\"->CONSTANTS\";s:11:\"description\";s:183:\"Site-specific constants, eg. a general email-adresse. These constants may be substituted in the text throughout the pages. The substitution is done by parseFunc. (Option: constants=1)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:6:\"FEData\";s:8:\"datatype\";s:19:\"->FE_DATA\";s:11:\"description\";s:105:\"Here you can configure how data submitted from the front-end should be processed, which script and so on.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:11:\"includeLibs\";s:8:\"datatype\";s:23:\"Array of strings\";s:11:\"description\";s:160:\"With this you can include php-files with function libraries for use in your includescript in TYPO3.
Please see the PAGE-object, which has the same property.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:101:\"Other reserved TLO's:
 
plugin
tt_*
temp
styles
lib
_GIFBUILDER\";s:8:\"datatype\";s:13:\" \";s:11:\"description\";s:872:\"These toplevel object names are reserved. That means you can risk static_templates to use them:
“plugin” is used for rendering of special content like boards, ecommerce solutions, guestbooks and so on. Normally set from static_templates. Please see separate description below!
“tt_*”, eg tt_content (from “content (default)”) is used to render content from tables.
“temp” and “styles” are used for conde-libraries you can copy during parse-time, but they are not saved with the template in cache. "temp" / "styles" are unset before the template is cached! Therefore use these names to store temporary data.
“lib” can be used for a “library” of code, you can reference in TypoScript (unlike “styles” which is unset)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:3:\"...\";s:8:\"datatype\";s:4:\"PAGE\";s:11:\"description\";s:469:\"Start a new page
 
Example:

page = PAGE
page.typeNum = 1
 
Guidelines:

Good, general PAGE object names to use are such as:
 page for the main page with content
 frameset, frameset2 for framesets.
 top, left, menu, right, bottom, border for top and menu frames etc.
This is just recommandations. Especially the name 'page' for the content bearing page is very common.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:3:\"...\";s:8:\"datatype\";s:17:\"(whatever)\";s:11:\"description\";s:368:\"If a toplevel-object is not a PAGE-object it could be used as a temporary repository for setup. In this case you should use the "temp" or "styles" objects.
"tt_..." is normally used to define the setup of content-records. Eg. "tt_content" would be used for the tt_content-table as default. See the "CONTENT"-cObject\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(50,7389802,'270df189982a4482d7b570baa95cba05','','tsref:plugin','a:1:{s:4:\"rows\";a:5:{i:0;a:6:{s:8:\"property\";s:15:\"userFunc\";s:8:\"datatype\";s:13:\" \";s:11:\"description\";s:67:\"Property setting up the USER / USER_INT object of the plugin\";s:7:\"default\";s:13:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:18:\"includeLibs\";s:8:\"datatype\";s:13:\" \";s:11:\"description\";s:67:\"Property setting up the USER / USER_INT object of the plugin\";s:7:\"default\";s:13:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:18:\"_CSS_DEFAULT_STYLE\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:331:\"Use this to have some default CSS styles inserted in the header section of the document. Most likely this will provide a default acceptable display from the plugin, but should ideally be cleared and moved to an external stylesheet.
This value is for all plugins read by the pagegen script when making the header of the document.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:28:\"_DEFAULT_PI_VARS.[piVar-key]\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:206:\"Allows you to set default values of the piVars array which most plugins are using (and should use) for data exchange with themselves.
This works only if the plugin calls $this->pi_setPiVarDefaults().\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:34:\"_LOCAL_LANG.[lang-key].[label-key]\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:68:\"Can be used to override the default locallang labels for the plugin.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(51,7389802,'f98a9e5726c62fb08803c31cac589abb','','tsref:config/->CONFIG','a:1:{s:4:\"rows\";a:109:{i:0;a:6:{s:8:\"property\";s:8:\"linkVars\";s:8:\"datatype\";s:4:\"list\";s:11:\"description\";s:1097:\"HTTP_GET_VARS, which should be passed on with links in TYPO3. This is compiled into a string stored in $GLOBALS["TSFE"]->linkVars
 
The values are rawurlencoded in PHP.
 
You can specify a range of valid values by appending a () after each value. If this range does not match, the variable won't be appended to links. This is very important to prevent that the cache system gets flooded with forged values.
 
The range may containing one of these values:
 [a]-[b] - A range of allowed integer values
 int - Only integer values are allowed
 [a]|[b]|[c] - A list of allowed strings (whitespaces will be remove',''),(52,7389802,'61a507730523bd733941819140f8811b','','tsref:constants','a:1:{s:4:\"rows\";a:1:{i:0;a:6:{s:8:\"property\";s:15:\"Array...\";s:8:\"datatype\";s:13:\"string\";s:11:\"description\";s:232:\"Constants.
 
Examples:

.EMAIL = email@email.com
Now if parseFunc anywhere is configured with constants=1 then all cases of the string ###EMAIL### will be substituted in the text.
see ->parseFunc\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(53,7389802,'7032add39bae490a73f4ce839844c001','','tsref:(page)','a:1:{s:4:\"rows\";a:27:{i:0;a:6:{s:8:\"property\";s:7:\"typeNum\";s:8:\"datatype\";s:17:\"typeNumber\";s:11:\"description\";s:221:\"This decides the the typeId of the page. The value defaults to 0 for the first
found PAGE object, but it MUST be set and be unique as soon you use more than one such object (watch this if you use frames on your page)!\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:10:\"1,2,3,4...\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:42:\"Wraps the content of the the cObject array\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:63:\"Wraps the content of the the cObject array with stdWrap options\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:14:\"bodyTagCObject\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:78:\"This is default bodytag overridden by “.bodyTag” if that is set.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:7:\"bodyTag\";s:8:\"datatype\";s:11:\"<tag>\";s:11:\"description\";s:93:\"Bodytag on the page
 
Example:

<body bgcolor="{$bgCol}">\";s:7:\"default\";s:40:\"<body bgcolor="#FFFFFF">\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:7:\"headTag\";s:8:\"datatype\";s:11:\"<tag>\";s:11:\"description\";s:35:\"Head-tag if alternatives are wanted\";s:7:\"default\";s:12:\"<head>\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:14:\"bodyTagMargins\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:373:\"margins in the bodytag.
 
Property:

.useCSS = 1 (boolean) - will set a “BODY {margin: ...}” line in the in-document style declaration - for XHTML compliance.
 
Example:

value 4
adds leftmargin="4" topmargin="4" marginwidth="4" marginheight="4" to the bodyTag.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:10:\"bodyTagAdd\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:48:\"This content is added to the end of the bodyTag.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:5:\"bgImg\";s:8:\"datatype\";s:11:\"imgResource\";s:11:\"description\";s:74:\"Background image on the page. This is automatically added to the body-tag.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:8:\"frameSet\";s:8:\"datatype\";s:13:\"->FRAMESET\";s:11:\"description\";s:76:\"if any properties is set to this property, the page is made into a frameset.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:4:\"meta\";s:8:\"datatype\";s:9:\"->META\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:12:\"shortcutIcon\";s:8:\"datatype\";s:8:\"resource\";s:11:\"description\";s:339:\"Favicon of the page. Create a reference to an icon here!
Browsers that support favicons display them in the browser's address bar, next to the site's name in lists of bookmarks, and next to the page's title in a Tabbed Document Interface.
 
Note:

This must be a valid ".ico"-file (iconfile)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:10:\"headerData\";s:8:\"datatype\";s:11:\"->CARRAY\";s:11:\"description\";s:149:\"Inserts content in the header-section. Could be JavaScripts, meta-tags, other stylesheet references.
Is inserted after all the style-definitions.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:6:\"config\";s:8:\"datatype\";s:11:\"->CONFIG\";s:11:\"description\";s:108:\"configuration for the page. Any entries override the same entries in the toplevel-object "config".\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:17:\"includeJS.[array]\";s:8:\"datatype\";s:8:\"resource\";s:11:\"description\";s:537:\"Inserts one or more (Java)Scripts in <script> tags.
 
The file definition must be a valid "resource" datatype, otherwise nothing is inserted.
 
Each file has optional properties:
 .style - setting the MIME type of the script (default: text/javascript)
 
Example:

includeJS {
   file1 = fileadmin/helloworld.js
   file1.type = application/x-javascript
   file2 = javascript_uploaded_to_template*.js
}\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:11:\"includeLibs\";s:8:\"datatype\";s:23:\"array of strings\";s:11:\"description\";s:902:\"With this you may include php-files. This does the same as "includeLibrary" in ->CONFIG but this can include more than one file. These files are included after the file of includeLibrary.
 
NOTE:

The toplevel object "includeLibs" and the scripts defined with this property is added to each other. Script-keys (that is the "array of strings"-value, like below "ts_address") from this property of the page overrides any scripts-keys from the toplevel "includeLibs" property!
The script-filenames are of the datatype "resource".
 
Example:

includeLibs.ts_address = lib_filename.php
includeLibs.ts_shop = lib_filename.php
 
Please do not use the prefix shown above ("ts_") as this will probably be used by the standard TYPO3 libraries that will appear in the future. \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:40:\" 
CSS Stylesheets:
\";s:8:\"datatype\";N;s:11:\"description\";N;s:7:\"default\";N;s:12:\"column_count\";i:1;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:10:\"stylesheet\";s:8:\"datatype\";s:8:\"resource\";s:11:\"description\";s:139:\"Inserts a stylesheet in the <HEAD>-section of the page;
<link rel="stylesheet" href="[resource]">
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:19;a:6:{s:8:\"property\";s:18:\"includeCSS.[array]\";s:8:\"datatype\";s:8:\"resource\";s:11:\"description\";s:962:\"Inserts a stylesheet (just like the .stylesheet property) by allows to setting up more than a single stylesheet, because you can enter files in an array.
 
The file definition must be a valid "resource" datatype, otherwise nothing is inserted.
 
Each file has optional properties:
 .media - setting the media attribute of the <style> tag.
 .title - setting the title of the <style> tag.
 .alternate - If set (boolean) then the rel-attribute will be "alternate stylesheet"
 .import - If set (boolean) then the @import way of including a stylesheet is used instead of <link>
 
Example:

includeCSS {
   file1 = fileadmin/mystylesheet1.css
   file2 = stylesheet_uploaded_to_template*.css
   file2.title = High contrast
   file2.media = print
}\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:20;a:6:{s:8:\"property\";s:15:\"CSS_inlineStyle\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:95:\"This value is just passed on as inline css (in-document css encapsulated in <style>-tags)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:21;a:6:{s:8:\"property\";s:20:\"insertClassesFromRTE\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:470:\"If set, the classes for the Rich Text Editor configured in Page TSconfig is inserted in as the first thing in the Style-section right after the setting of the stylesheet.
 
 .add_mainStyleOverrideDefs = [* / list of tags ] - will add all the “RTE.default. mainStyleOverride_add” - tags configured as well.
 
Might be deprecated soon. Most likely the RTE should be configured by the stylesheet instead. Stay tuned...
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:22;a:6:{s:8:\"property\";s:15:\"noLinkUnderline\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:111:\"Disables link-underlining. Uses in-document stylesheet.
 
Deprecated. Use stylesheet instead.
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:23;a:6:{s:8:\"property\";s:5:\"hover\";s:8:\"datatype\";s:10:\"HTML-color\";s:11:\"description\";s:147:\"The color of a link when the mouse moves over it! (only MSIE). Uses in-document stylesheet.
 
Deprecated. Use stylesheet instead.
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:24;a:6:{s:8:\"property\";s:10:\"hoverStyle\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:189:\"Additional style information to the hover-color.
 
Example:

page.hoverStyle = font: bold; text-decoration: none;
 
Deprecated. Use stylesheet instead.
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:25;a:6:{s:8:\"property\";s:15:\"smallFormFields\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:396:\"Renders formfields like textarea, input and select-boxes small with "verdana size 1" font.
Uses in-document stylesheet.
 
Tip:

Use this together with the config-option "compensateFieldWidth" set to "0.6" for netscape-browsers in order to render the small form fields in the same width!
 
Deprecated. Use stylesheet instead.
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:26;a:6:{s:8:\"property\";s:16:\"adminPanelStyles\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:44:\"Will include CSS styles for the Admin Panel.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(54,7389802,'abe1a9b50d108f34d9b6348126ca6a7b','','tsref:FEData','a:1:{s:4:\"rows\";a:1:{i:0;a:6:{s:8:\"property\";s:26:\"array of tableNames\";s:8:\"datatype\";s:13:\"->FE_TABLE\";s:11:\"description\";s:13:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(55,7389802,'885e0cbd1482e884cb0583019453c414','','tsref:FEData.(tablename)/->FE_TABLE','a:1:{s:4:\"rows\";a:9:{i:0;a:6:{s:8:\"property\";s:15:\"default.[field]\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:446:\"This property is in charge of which default-values is used for the table:
 
Example:

This defines the default values used for new records. These values will be overridden with any value submitted instead (as long as the submitted fields are allowed due to "allowNew")
default {
   subject = This is the default subject value!
   hidden = 1
   parent = 0
}\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:16:\"allowNew.[field]\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:641:\"This property is in charge of which fields that may be written from the frontend.
 
Example:

This defines that subject is a field, that may be submitted from the frontend. If a value is not submitted, subject is filled with the default value (see above).
The field "hidden" on the other hand cannot be changed from the frontend. "hidden" will gain the value from the default definition (see above). If fields are set to "0" (zero) it's the same as if they were not defined in this array.
 
allowNew {
   subject = 1
   hidden = 0
}\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:17:\"allowEdit.[field]\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:221:\"Same as above ("allowNew") but this controls which fields that may be written in case of an update of a record (and not a new submission)
Please pay attension to the property below! ("overrideEdit")\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:20:\"overrideEdit.[field]\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:479:\"This works like default-values above but is values inserted after the submitted values has beed processed. This means that opposite to default-values overwritten by the submitted values, these values override the submitted values.
 
Example:

In this case overrideEdit secures that if a user updates his record (if he "own" it) the "hidden"-field will be set no matter what.
 
overrideEdit {
   hidden = 1
}\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:12:\"userIdColumn\";s:8:\"datatype\";s:14:\"string (field)\";s:11:\"description\";s:197:\"This is a string that points to the column of a record where the user-id of the current fe_user should be inserted. This fe_user-uid is inserted/updated both by "new" and "edit"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:13:\"autoInsertPID\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:195:\"Works with new records: Insert automatically the PID of the page, where the submitted data is sent to. Any "pid" supplied from the submitted data will override. This is for convenience.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:13:\"processScript\";s:8:\"datatype\";s:8:\"resource\";s:11:\"description\";s:567:\"Include-script to be used for processing of incoming data to the table. The script is included from a function in the class tslib_fetce
This is the really important option, because whether or not you are going to utilize the "cleaning"/"authorization" features of the properties above depend on how you write your script to process data and put it in the database.
A very good example is to look at "media/scripts/guest_submit.inc", included from static_template "plugin.tt_guest" (Used for the default guestbook feature)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:9:\"separator\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:94:\"Separator character used when the submitted data is an array from eg. a multiple selector box.\";s:7:\"default\";s:19:\"chr(10) (linebreak)\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:15:\"doublePostCheck\";s:8:\"datatype\";s:18:\"string (fieldname)\";s:11:\"description\";s:344:\"Specifies a fieldname (integer) into which an integer-hash compiled of the submitted data is inserted. If the field is set, then submissions are checked whether another record with this value already exists. If so, the record is NOT inserted, because it's expected to be a “double post” (posting the same data more than once)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(56,7389802,'dfb38a4b542a66ea9ca4c51cc1e8c454','','tsref:(page).frameSet/->FRAMESET','a:1:{s:4:\"rows\";a:4:{i:0;a:6:{s:8:\"property\";s:10:\"1,2,3,4...\";s:8:\"datatype\";s:8:\"frameObj\";s:11:\"description\";s:45:\"Configuration of frames and nested framesets.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:4:\"cols\";s:8:\"datatype\";s:26:\"<frameset>-data:cols\";s:11:\"description\";s:4:\"Cols\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:4:\"rows\";s:8:\"datatype\";s:26:\"<frameset>-data:rows\";s:11:\"description\";s:4:\"Rows\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:6:\"params\";s:8:\"datatype\";s:23:\"<frameset>-params\";s:11:\"description\";s:93:\"Example:
border="0" framespacing="0" frameborder="NO"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(57,7389802,'88d7c4b86d5cebdad2b438b0538b48d3','','tsref:(page).frameSet.(number)/->FRAMESET.(number)','a:1:{s:4:\"rows\";a:5:{i:0;a:6:{s:8:\"property\";s:3:\"obj\";s:8:\"datatype\";s:38:\"pointer to toplevel object-name\";s:11:\"description\";s:130:\"toplevel object-name of a PAGE / FRAMESET
 
Example:

"left", "page", "frameset"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:7:\"options\";s:8:\"datatype\";s:21:\"url-parameters\";s:11:\"description\";s:199:\"Example:
print=1&othervar=anotherthing
would add '&print=1&othervar=anotherthing' to the ".src"-content (if not ".src" is set manually!!)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:6:\"params\";s:8:\"datatype\";s:20:\"<frame>-params\";s:11:\"description\";s:81:\"Example:
scrolling="AUTO" noresize frameborder="NO"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:4:\"name\";s:8:\"datatype\";s:23:\"<frame>-data:name\";s:11:\"description\";s:133:\"Manually set name of frame
 
 NOTE: Is set automatically and should not be overridden under normal conditions!\";s:7:\"default\";s:25:\"value of ".obj"\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:3:\"src\";s:8:\"datatype\";s:22:\"<frame>-data:src\";s:11:\"description\";s:140:\"Manually set the src of the frame
 
 NOTE: Is set automatically and should not be overridden under normal conditions!\";s:7:\"default\";s:33:\"could be index.php?$id&$type \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(58,7389802,'c123846d335b06bc44b284ee8c7a8ea0','','tsref:->META','a:1:{s:4:\"rows\";a:1:{i:0;a:6:{s:8:\"property\";s:15:\"Array...\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:495:\"Metatags
If value is empty (after trimming) the metatag is not generated.
If the "key" (eg. "REFRESH" or "DESCRIPTION") is "REFRESH" (caseinsensitive), then the "http-equiv"-attribute is used in the metatag instead of "name".
 
Examples:

.REFRESH = [sec]; [url, leave blank for same page]
.DESCRIPTION = This is the description of the content in this document
.KEYWORDS = This is the keywords...\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(59,7389802,'e8c6be7a5c4bf207221e5b5d5a6441a4','','tsref:->CARRAY','a:1:{s:4:\"rows\";a:4:{i:0;a:6:{s:8:\"property\";s:10:\"1,2,3,4...\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:182:\"This is a numerical "array" of content-objects (cObjects). The order by which you specific the objects is not important as the array will be sorted before it's parsed!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:29:\"Occational properties:\";s:8:\"datatype\";N;s:11:\"description\";N;s:7:\"default\";N;s:12:\"column_count\";i:1;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:23:\"(stdWrap properties...)\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:474:\" NOTE: This applies ONLY if "CARRAY /stdWrap" is set to be data type
If you specify any non-integer properties to a CARRAY, stdWrap will be invoked with all properties of the CARRAY.
 
Example:

This will return '<B>This will be rendered before "10"testing</B>'
10 = TEXT
10.value = testing
5 = HTML
5.value = This will be rendered before "10"
wrap = <B> |</B>\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:10:\"(TDParams)\";s:8:\"datatype\";s:17:\"<TD>-params\";s:11:\"description\";s:217:\" NOTE: This applies ONLY if "CARRAY +TDParams" is set to be data type
This property is used only in some cases where CARRAY is used. Please look out for a note about that in the various cases.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(60,7389802,'90abbeca518fabd3ec8944e62fd200b7','','tsref:(cObject).HTML','a:1:{s:4:\"rows\";a:1:{i:0;a:6:{s:8:\"property\";s:5:\"value\";s:8:\"datatype\";s:13:\"HTML /stdWrap\";s:11:\"description\";s:14:\"Raw HTML-code.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(61,7389802,'03fe46bb8628f60fec5859bf75fa5f75','','tsref:(cObject).TEXT','a:1:{s:4:\"rows\";a:2:{i:0;a:6:{s:8:\"property\";s:5:\"value\";s:8:\"datatype\";s:5:\"value\";s:11:\"description\";s:34:\"text, wrap with stdWrap properties\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:30:\"(stdWrap properties...)\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(62,7389802,'571d18366e15bc9b1ce2cd4ef7da8ff5','','tsref:(cObject).COA/(cObject).COA_INT/(cObject).COBJ_ARRAY','a:1:{s:4:\"rows\";a:5:{i:0;a:6:{s:8:\"property\";s:10:\"1,2,3,4...\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:2:\"if\";s:8:\"datatype\";s:7:\"->if\";s:11:\"description\";s:55:\"if "if" returns false the COA is NOT rendered\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:11:\"includeLibs\";s:8:\"datatype\";s:29:\" list of resource\";s:11:\"description\";s:380:\"(This property is used only if the object is COA_INT!, See introduction.)
This is a comma-separated list of resources that are included as PHP-scripts (with include_once() function) if this script is included.
This is possible to do because any include-files will be known before the scripts are included. That's not the case with the regular PHP_SCRIPT cObject.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(63,7389802,'3918801c03952a7fde07c4afd3faa80a','','tsref:(cObject).FILE','a:1:{s:4:\"rows\";a:5:{i:0;a:6:{s:8:\"property\";s:4:\"file\";s:8:\"datatype\";s:8:\"resource\";s:11:\"description\";s:217:\"If the resource is jpg,gif,jpeg,png the image is inserted as an image-tag. Al other formats is read and inserted into the HTML-code.
The maximum filesize of documents to be read is set to 1024 kb internally!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:8:\"linkWrap\";s:8:\"datatype\";s:8:\"linkWrap\";s:11:\"description\";s:26:\"(before ".wrap")\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:20:\"altText
titleText\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:165:\"For <img> output only!
 
If no titltext is specified, it will use the alttext insteadIf no alttext is specified, it will use an empty alttext\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:11:\"longdescURL\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:149:\"For <img> output only!
 

"longdesc" attribute (URL pointing to document with extensive details about image).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(64,7389802,'45effe326c7d351875eb76178430f63f','','tsref:(cObject).IMAGE','a:1:{s:4:\"rows\";a:10:{i:0;a:6:{s:8:\"property\";s:4:\"file\";s:8:\"datatype\";s:11:\"imgResource\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:6:\"params\";s:8:\"datatype\";s:18:\"<IMG>-params\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:6:\"border\";s:8:\"datatype\";s:7:\"integer\";s:11:\"description\";s:63:\"Value of the “border” attribute of the image tag.\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:43:\"altText
titleText
 
(alttext)\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:273:\"If no titltext is specified, it will use the alttext insteadIf no alttext is specified, it will use an empty alttext
 
("alttext" is the old spelling of this attribute. It will be used only if "altText" does not specify a value or properties)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:11:\"longdescURL\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:93:\""longdesc" attribute (URL pointing to document with extensive details about image).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:8:\"linkWrap\";s:8:\"datatype\";s:8:\"linkWrap\";s:11:\"description\";s:26:\"(before ".wrap")\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:13:\"imageLinkWrap\";s:8:\"datatype\";s:30:\"boolean/
->imageLinkWrap\";s:11:\"description\";s:122:\" NOTE: ONLY active if linkWrap is NOT set and file is NOT GIFBUILDER (as it works with the original imagefile)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:2:\"if\";s:8:\"datatype\";s:7:\"->if\";s:11:\"description\";s:55:\"if "if" returns false the image is not shown!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(65,7389802,'a2140130f94da8de59d956354896d9bf','','tsref:(cObject).IMG_RESOURCE','a:1:{s:4:\"rows\";a:2:{i:0;a:6:{s:8:\"property\";s:4:\"file\";s:8:\"datatype\";s:11:\"imgResource\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(66,7389802,'698298181be68b56fd0361e9da1a114f','','tsref:(cObject).CLEARGIF','a:1:{s:4:\"rows\";a:3:{i:0;a:6:{s:8:\"property\";s:6:\"height\";s:8:\"datatype\";s:45:\" <img>-data:height /stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:1:\"1\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:5:\"width\";s:8:\"datatype\";s:44:\" <img>-data:width /stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:1:\"1\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:18:\" | <BR>\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(67,7389802,'0f2fee21aca2929d02f2ede163104d2b','','tsref:(cObject).CONTENT','a:1:{s:4:\"rows\";a:6:{i:0;a:6:{s:8:\"property\";s:6:\"select\";s:8:\"datatype\";s:11:\"->select\";s:11:\"description\";s:30:\"The SQL-statement is set here!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:5:\"table\";s:8:\"datatype\";s:16:\"tableName\";s:11:\"description\";s:320:\"The table, the content should come from.
In standard-configurations this will be "tt_content"
 NOTE: Only tables allowed are “pages” or tables prefixed with one of these: “tt_”, “tx_”, “ttx_”, “fe_”, “user_”\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:9:\"renderObj\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:16:\"< [tablename]\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:5:\"slide\";s:8:\"datatype\";s:7:\"integer\";s:11:\"description\";s:1001:\"If set and no content element is found by the select command, then the rootLine will be traversed back until some content is found.
 
Possible values are “-1” (slide back up to the siteroot), “1” (only the current level) and “2” (up from one level back).
 
Use -1 in combination with collect.
 
 .collect (integer): If set, all content elements found on current and parent pages will be collected. Otherwise, the sliding would stop after the first hit. Set this value to the amount of levels to collect on, or use “-1” to collect up to the siteroot.
 .collectFuzzy (boolean): Only useful in collect mode. If no content elements have been found for the specified depth in collect mode, traverse further until at least one match has occurred.
 .collectReverse (boolean): Change order of elements in collect mode. If set, elements of the current page will be on the bottom.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:31:\"Wrap the whole content-story...\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(68,7389802,'fda9a1413332096fac6ed5a6f0f8ce90','','tsref:(cObject).RECORDS','a:1:{s:4:\"rows\";a:5:{i:0;a:6:{s:8:\"property\";s:6:\"source\";s:8:\"datatype\";s:34:\" records-list /stdWrap\";s:11:\"description\";s:126:\"List of record-id's, optionally with appended table-names.
 
Example:

tt_content_34, 45, tt_links_56\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:6:\"tables\";s:8:\"datatype\";s:21:\"list of tables\";s:11:\"description\";s:456:\"List of accepted tables. If any items in the ".source"-list is not prepended with a tablename, the first table in this list is assumed to be the table for such records.
Also tablenames configured in .conf is allowed.
 
Example:

tables = tt_content, tt_address, tt_links
conf.tx_myexttable = TEXT
conf.tx_myexttable.value = Hello world
 
This adds the tables tt_content, tt_address, tt_links, tx_myexttable\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:23:\"conf.[tablename]\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:62:\"Config-array which renders records from table tablename\";s:7:\"default\";s:131:\"If this is NOT defined, the rendering of the records is done with the toplevel-object [tablename] - just like the cObject, CONTENT!\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:12:\"dontCheckPid\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:141:\"Normally a record cannot be selected, if it's parent page (pid) is not accessible for the website user. This option disables that check.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(69,7389802,'58494541fb84e7f9f04a7222619963cf','','tsref:(cObject).HMENU','a:1:{s:4:\"rows\";a:16:{i:0;a:6:{s:8:\"property\";s:16:\"(1 / 2 / 3 /...)\";s:8:\"datatype\";s:7:\"menuObj\";s:11:\"description\";s:260:\"Required!
Defines which menuObj that should render the menuitems on the various levels.
1 is the first level, 2 is the second level, 3 is the third level, 4 is ....
 
Example:

temp.sidemenu = HMENU
temp.sidemenu.1 = GMENU \";s:7:\"default\";s:15:\" (no menu)\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:10:\"entryLevel\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:358:\"Defines at which level in the rootLine, the menu should start.
Default is "0" which gives us a menu of the very first pages on the site.
If the value is < 0, entryLevel is chosen from "behind" in the rootLine. Thus "-1" is a menu with items from the outermost level, "-2" is the level before the outermost...\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:7:\"special\";s:8:\"datatype\";s:163:\""directory" / "list" / "updated" / "browse" / "rootline" / "keywords" / “language”\";s:11:\"description\";s:26:\"(See separate table below)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:13:\"special.value\";s:8:\"datatype\";s:45:\" list of page-uid's /stdWrap\";s:11:\"description\";s:9:\"See above\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:8:\"minItems\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:364:\"The minimum items in the menu. If the number of pages does not reach this level, a dummy-page with the title "..." and uid=[currentpage_id] is inserted.
 
 Notice: Affects all sub menus as well. To set the value for each menu level individually, set the properties in the menu objects (see “Common properties” table).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:8:\"maxItems\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:165:\"The maximum items in the menu. More items will be ignored.
 
 Notice: Affects all sub menus as well. (See “minItems” for notice)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:5:\"begin\";s:8:\"datatype\";s:9:\"int +calc\";s:11:\"description\";s:290:\"The first item in the menu.
 
Example:

This results in a menu, where the first two items are skipped starting with item number 3:
   begin = 3
 
 Notice: Affects all sub menus as well. (See “minItems” for notice)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:14:\"excludeUidList\";s:8:\"datatype\";s:11:\"list of int\";s:11:\"description\";s:372:\"This is a list of page uid's to exclude when the select statement is done. Comma-separated. You may add “current” to the list to exclude the current page.
 
Example:

The pages with these uid-number will NOT be within the menu!! Additionally the current page is always excluded too.
   excludeUidList = 34,2,current\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:15:\"excludeDoktypes\";s:8:\"datatype\";s:16:\"list of integers\";s:11:\"description\";s:193:\"Enter the list of page document types (doktype) to exclude from menus. By default pages that are “not in menu” (5) are excluded and those marked for backend user access only (6). \";s:7:\"default\";s:3:\"5,6\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:16:\"includeNotInMenu\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:272:\"If set, pages with type “Not in menu” will be included in menus.
The number “5” will simply be removed from the current dok-type list (which is by default “5,6” but can be changed by “excludeDoktypes”, see above).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:19:\"alwaysActivePIDlist\";s:8:\"datatype\";s:16:\"list of integers\";s:11:\"description\";s:145:\"This is a list of page UID numbers that will always be regarded as active menu items and thereby automatically opened regardless of the rootline.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:11:\"protectLvar\";s:8:\"datatype\";s:17:\"boolean / keyword\";s:11:\"description\";s:1242:\"If set, then for each page in the menu it will be checked if an Alternative Page Language record for the language defined in "config.sys_language_uid" (typically defined via &L) exists for the page. If that is not the case and the pages “Localization settings” have the “Hide page if no translation for current language exists” flag set, then the menu item will link to a non accessible page that will yield an error page to the user. Setting this option will prevent that situation by simply adding “&L=0” for such pages, meaning that they will switch to the default language rather than keeping the current language.
The check is only carried out if a translation is requested ("config.sys_language_uid" is not zero).
 
Keyword: “all”

When set to “all” the same check is carried out but it will not look if “Hide page if no translation for current language exists” is set - it always reverts to default language if no translation is found.
 
For these options to make sense, they should only be used when “config.sys_language_mode” is not set to “content_fallback”.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:14:\"addQueryString\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:113:\"see typolink.addQueryString
 
 Notice: This works only for special=language.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:2:\"if\";s:8:\"datatype\";s:7:\"->if\";s:11:\"description\";s:58:\"If "if" returns false, the menu is not generated\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(70,7389802,'cd830eb4ea8346e958afc812a860ed75','','tsref:(cObject).HMENU.special','a:1:{s:4:\"rows\";a:9:{i:0;a:6:{s:8:\"property\";s:9:\"directory\";s:8:\"datatype\";s:304:\"This will generate a menu of all pages with pid = 35 and pid = 56.
   20 = HMENU
   20.special = directory
   20.special.value = 35, 56
 
If .value is not set, the default pid is the current page.
 
Support for Mount Pages: Yes.\";s:11:\"description\";s:6:\" \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:4:\"list\";s:8:\"datatype\";s:308:\"This will generate a menu with the two pages (uid=35 and uid=36) listed:
   20 = HMENU
   20.special = list
   20.special.value = 35, 56
 
If .value is not set, the default uid is the .entryLevel uid.
 
Support for Mount Pages: Yes.\";s:11:\"description\";s:6:\" \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:7:\"updated\";s:8:\"datatype\";s:2753:\"This will generate a menu of the most recently updated pages from the branches in the tree starting with the uid's (uid=35 and uid=36) listed. Furthermore the field "tstamp" is used (default is SYS_LASTCHANGED) and the treedepth is 2 levels. Also there will be shown a maximum of 8 pages and they must have been updated within the last three days (3600*24*3):
   20 = HMENU
   20.special = updated
   20.special.value = 35, 56
   20.special {
     mode = tstamp
     depth = 2
     maxAge = 3600*24*3
     limit = 8
   }
 
 Ordering is by default done in reverse order (desc) with the field specified by “mode” , but setting “alternativeSortingField” for the menu object (eg GMENU, see later) will override that.
Properties "mode", "depth", "maxAge" and "limit" is only used with special="updated".
 mode: Which field in the pages-table to use. Default is "SYS_LASTCHANGED" (which is updated when a page is generated to the youngest tstamp of the records on the page), "manual" or “lastUpdated” will use the field "lastUpdated" (set manually in the page-record) and "tstamp" will use the "tstamp"-field of the pagerecord, which is set automatically when the record is changed. "crdate" will use "crdate"-field of the pagerecord. “starttime” will use the starttime field.
Fields with zero value is not selected anyway.
 depth: By default (if the value is not an integer) the depth is 20 levels. The range is 1-20. A depth of 1 means only the start id, depth of 2 means start-id + first level. NOTE: depth is relative to beginAtLevel.
 beginAtLevel: Integer. Determines starting level for the pagetrees generated based on .value and .depth. Zero is default and includes the start id. 1=starts with the first row of subpages, 2=starts with the second row of subpages. Depth is relative to this starting point.
 maxAge: Seconds+calc. Pages with update-dates older than currenttime minus this number of seconds will not be shown in the menu no matter what. Default is "not used". You may use +-*/ for calculations.
 limit: Max number of items in the menu. Default is 10, max is 100.
 excludeNoSearchPages: Boolean. If set, pages marked "No search" is not included into special-menus.
 
Support for Mount Pages: Yes.\";s:11:\"description\";s:6:\" \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:8:\"rootline\";s:8:\"datatype\";s:888:\"Creates a menu with pages from the "rootline" (see earlier in this reference)
 .range = [begin-level] | [end-level] (same way as you reference the .entryLevel for HMENU)
 .target_[0-x] targets
 
This...
 
page.2 = HMENU
page.2.special = rootline
page.2.special.range = 1|-2
page.2.special.targets.3 = page
page.2.1 = TMENU
page.2.1.target = _top
page.2.1.wrap = <HR> | <HR>
page.2.1.NO {
   linkWrap = | >
}
 
... creates a menu like this:
Page level 1 > Page level 2 > Page level 3 > Page level 4 >

(The menu starts at level 1 and does NOT link to the current page (-2 is the level before). Further all pages on level 3 will have "page" as target and all other "_top")
 
Support for Mount Pages: Yes.\";s:11:\"description\";s:6:\" \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:6:\"browse\";s:8:\"datatype\";s:3477:\"This kind of menu is built of items given by a list from the property ".item". Each element in the list (sep. by "|") is either a reserved itemname (see list) with a predefined function or a userdefined name which you can assign a link to any page. Note that the current page cannot be the root-page of a site.
 
Support for Mount Pages: No!
 .items ( "|" separated list of "itemnames")
 .[itemnames].target (target) - optional/alternative target of the item
 .[itemnames].uid (uid of page) - optional/alternative page-uid to link to
 .[itemnames].fields.[fieldname] (string) - override field "fieldname" in pagerecord.
 .items.prevnextToSection (boolean) - if set, the "prev" and "next" navigation will jump to the next section when it reaches the end of pages in the current section
 .value (page-uid) - default is current page id. Seldomly you might want to override this value with another page-uid which will then act as the basepoint for the menu and the predefined items.
 Ordering is by default done in reverse order (desc) with the field specified by “mode” , but setting “alternativeSortingField” for the menu object (eg GMENU, see later) will override that.
 

Reserved itemnames:

 next / prev : links to next page / previous page. Next and previous pages are from the same "pid" as the current page id (or "value") - that is the next item in a menu with the current page. Also referred to as current level.
If ".prevnextToSection" is set then next/prev will link to the first page of next section / last page of previous section.
 nextsection / prevsection : links to next section / previous section. A section is defined as the subpages of a page on the same level as the parent (pid) page of the current page. Will not work if parent page of current page is the root page of the site.
 nextsection_last | prevsection_last: Where nextsection/prevsection links to the first page in a section, these links to the last pages. If there is only one page in the section that will be both first and last. Will not work if parent page of current page is the root page of the site.
 first / last : First / Last page on current level. If there is only one page on the current level that page will be both first and last.
 up : Links to the parent (pid) page of the current page. (up 1 level) Will always be available
 index : Links to the parent of the parent page of the current page (up 2 levels). May not be available if that page is out of the rootline.
 
 Examples:

If id=20 is current page then:
21= prev and first, 19 = next, 18 = last, 17 = up, 1=index, 10 = nextsection, 11 = nextsection_last
prevsection and prevsection_last is not present because id=3 has no subpages!
 
TypoScript (only "browse"-part, needs also TMENU/GMENU):

xxx = HMENU
xxx.special = browse
xxx.special {
   items = index|up|next|prev
   items.prevnextToSection = 1
   index.target = _blank
   index.fields.title = INDEX
   index.uid = 8
}\";s:11:\"description\";s:6:\" \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:8:\"keywords\";s:8:\"datatype\";s:1741:\"Makes a menu of pages with one or more keywords also found on the current page.
 .value = page for which keywords to find similar pages.
 .mode: Which field in the pages-table to use for sorting. Default is "SYS_LASTCHANGED" (which is updated when a page is generated to the youngest tstamp of the records on the page), "manual" or “lastUpdated” will use the field "lastUpdated" (set manually in the page-record) and "tstamp" will use the "tstamp"-field of the pagerecord, which is set automatically when the record is changed. "crdate" will use "crdate"-field of the pagerecord. “starttime” will use the starttime field.
 .entryLevel = where in the rootline the search begins. Standard rootline syntax (-x to x)
 .depth, .limit, .excludeNoSearchPages, .beginAtLevel (like "updated" menu)
.setKeywords (/stdWrap) = lets you define the keywords manually by defining them as a commaseparated list. If this property is defined, it overrides the default, which is the keywords of the current page.

 .keywordsField = defines the field in the pages-table in which to search for the keywords. Default is the fieldname “keyword”. No check is done to see if the field you enter here exists, so enter an existing field, OK?!
 .keywordsField.sourceField = defines the field from the current page from which to take the keywords being matched. The default is “keyword”. (Notice that “.keywordsField” is only setting the page-record field to search in !)
 
Support for Mount Pages: Yes.\";s:11:\"description\";s:6:\" \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:8:\"language\";s:8:\"datatype\";s:2678:\"Creates a language selector menu. Typically this is made as a menu with flags for each language a page is translated to and when the user clicks any element the same page id is hit but with a change to the “&L” parameter in the URL.
 
The “language” type will create menu items based on the current page record but with the language record for each language overlaid if available. The items all link to the current page id and only “&L” is changed.
 
Item states:

When “TSFE->sys_language_uid” matches the sys_language uid for an element the state is set to “ACT”, otherwise “NO”. However, if a page is not available due to the pages “Localization settings” (which can disable translations) or if no Alternative Page Language record was found (can be disabled with “.normalWhenNoLanguage”, see below) the state is set to “USERDEF1” for non-active items and “USERDEF2” for active items. So in total there are four states to create designs for. It is recommended to disable the link on menu items rendered with “USERDEF1” and “USERDEF2” in this case since they are disabled exactly because a page in that language does not exist and might even issue an error if tried accessed (depending on site configuration).
 
 .value = comma list of sys_language uids to construct the menu with. The number of elements in this list determines the number of menu items.
 .normalWhenNoLanguage = boolean, which if set will render the button for a language as a non-disabled button even if no translation is found for the language.
 
Example:

Creates a language menu with flags (notice that some lines break):
 
 
 
 
lib.langMenu = HMENU
lib.langMenu.special = language
lib.langMenu.special.value = 0,1,2
lib.langMenu.1 = GMENU
lib.langMenu.1.NO {
   XY = [5.w]+4, [5.h]+4
   backColor = white
   5 = IMAGE
   5.file = media/flags/flag_uk.gif || media/flags/flag_fr.gif || media/flags/flag_es.gif
   5.offset = 2,2
}
 
lib.langMenu.1.ACT < lib.langMenu.1.NO
lib.langMenu.1.ACT=1
lib.langMenu.1.ACT.backColor = black
 
lib.langMenu.1.USERDEF1 < lib.langMenu.1.NO
lib.langMenu.1.USERDEF1=1
lib.langMenu.1.USERDEF1.5.file = media/flags/flag_uk_d.gif || media/flags/flag_fr_d.gif || media/flags/flag_es_d.gif
lib.langMenu.1.USERDEF1.noLink = 1\";s:11:\"description\";s:6:\" \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:11:\"userdefined\";s:8:\"datatype\";s:2231:\"Lets you write your own little PHP-script that generates the array of menuitems.
 .file [resource] = filename of the php-file to include. (Just like cObject PHP_SCRIPT)
 .[any other key] = your own variables to your script. They are all accessible in the array $conf in your script
 
Howto:

You must populate an array called $menuItemsArray with page-records of the menuitems you want to be in the menu.
It goes like this:
 
$menuItemsArray[] = pageRow1;
$menuItemsArray[] = pageRow2;
$menuItemsArray[] = pageRow3;
...
 
A “pageRow” is a record from the table “pages” with all fields selected (SELECT * FROM...)
If you create fake page rows, make sure to add at least “title” and “uid” field values.
 
Notice:

If you work with mount-points you can set the MP param which should be set for the page by setting the internal field “_MP_PARAM” in the page-record (xxx-xxx).
 
Overriding URLs:

You can also use the internal field "_OVERRIDE_HREF" to set a custom href-value (eg. "http://www.typo3.org") which will in any case be used rather than a link to the page that the page otherwise might represent. If you use "_OVERRIDE_HREF" then "_OVERRIDE_TARGET" can be used to override the target value as well (See example below).
 
Other reserved keys:

“_ADD_GETVARS” can be used to add get parameters to the URL, eg. “&L=xxx”.
“_SAFE” can be used to protect the element to make sure it is not filtered out for any reason.
 
Creating submenus:

You can create submenus for the next level easily by just adding an array of menu items in the internal field "_SUB_MENU" (See example below).
 
Presetting element state

If you would like to preset an element to be recognized as a SPC, IFSUB, ACT, CUR or USR mode item, you can do so by specifying one of these values in the key “ITEM_STATE” of the page record. This setting will override the natural state-evaluation.\";s:11:\"description\";s:6:\" \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:12:\"userfunction\";s:8:\"datatype\";s:184:\"Calls a user function/method in class which should (as with “userdefined” above) return an array with page records for the menu.
 .userFunc = function-name\";s:11:\"description\";s:6:\" \";s:7:\"default\";N;s:12:\"column_count\";i:3;s:16:\"is_propertyTable\";i:1;}}}',''),(71,7389802,'51fb0254a54165c4bb95358367ae0aec','','tsref:(cObject).CTABLE','a:1:{s:4:\"rows\";a:9:{i:0;a:6:{s:8:\"property\";s:6:\"offset\";s:8:\"datatype\";s:3:\"x,y\";s:11:\"description\";s:29:\"Offset from upper left corner\";s:7:\"default\";s:11:\"0,0 = intet\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:2:\"tm\";s:8:\"datatype\";s:21:\"->CARRAY +TDParams\";s:11:\"description\";s:7:\"topMenu\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:2:\"lm\";s:8:\"datatype\";s:21:\"->CARRAY +TDParams\";s:11:\"description\";s:8:\"leftMenu\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:2:\"rm\";s:8:\"datatype\";s:21:\"->CARRAY +TDParams\";s:11:\"description\";s:9:\"rightMenu\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:2:\"bm\";s:8:\"datatype\";s:21:\"->CARRAY +TDParams\";s:11:\"description\";s:10:\"bottomMenu\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:1:\"c\";s:8:\"datatype\";s:21:\"->CARRAY +TDParams\";s:11:\"description\";s:13:\"content-cell \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:8:\"cMargins\";s:8:\"datatype\";s:7:\"margins\";s:11:\"description\";s:46:\"Distance around the content-cell "c"\";s:7:\"default\";s:7:\"0,0,0,0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:6:\"cWidth\";s:8:\"datatype\";s:6:\"pixels\";s:11:\"description\";s:39:\"Width of the content-cell "c"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:11:\"tableParams\";s:8:\"datatype\";s:20:\"<TABLE>-params\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:36:\"border=0 cellspacing=0 cellpadding=0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(72,7389802,'d15fe4c25a73d14a1233602ae5c00aeb','','tsref:(cObject).OTABLE','a:1:{s:4:\"rows\";a:3:{i:0;a:6:{s:8:\"property\";s:6:\"offset\";s:8:\"datatype\";s:3:\"x,y\";s:11:\"description\";s:334:\"Offset from upper left corner
 
Note:

Actually the datatype is “x,y,r,b,w,h”:
x,y is offset from upperleft corner
r,b is offset (margin) to right and bottom
w is the required width of the content field
h is the required height of the content field
 
All measures is in pixels.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:10:\"1,2,3,4...\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:11:\"tableParams\";s:8:\"datatype\";s:20:\"<TABLE>-params\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:36:\"border=0 cellspacing=0 cellpadding=0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(73,7389802,'ac73d41309997ef5db797e0ac823c30f','','tsref:(cObject).COLUMNS','a:1:{s:4:\"rows\";a:12:{i:0;a:6:{s:8:\"property\";s:11:\"tableParams\";s:8:\"datatype\";s:20:\"<TABLE>-params\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:36:\"border=0 cellspacing=0 cellpadding=0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:8:\"TDparams\";s:8:\"datatype\";s:17:\"<TD>-params\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:10:\"valign=top\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:4:\"rows\";s:8:\"datatype\";s:17:\"int (Range: 2-20)\";s:11:\"description\";s:34:\"The number of rows in the columns.\";s:7:\"default\";s:1:\"2\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:10:\"totalWidth\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:35:\"The total-width of the columns+gaps\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:8:\"gapWidth\";s:8:\"datatype\";s:28:\"int /stdWrap
+optionSplit\";s:11:\"description\";s:48:\"Width of the gap between columns.
0 = no gap\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:8:\"gapBgCol\";s:8:\"datatype\";s:35:\"HTML-color /stdWrap
+optionSplit\";s:11:\"description\";s:39:\"background-color for the gap-tablecells\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:16:\"gapLineThickness\";s:8:\"datatype\";s:28:\"int /stdWrap
+optionSplit\";s:11:\"description\";s:72:\"lineThickness of the dividerline in the gap between cells
0 = no line\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:10:\"gapLineCol\";s:8:\"datatype\";s:35:\"HTML-color /stdWrap
+optionSplit\";s:11:\"description\";s:10:\"Line color\";s:7:\"default\";s:5:\"black\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:29:\"[column-number]
1,2,3,4...\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:44:\"This is the content-object for each column!!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:5:\"after\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:50:\"This is a cObject placed after the columns-table!!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:2:\"if\";s:8:\"datatype\";s:7:\"->if\";s:11:\"description\";s:61:\"if "if" returns false the columns are not rendered!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(74,7389802,'735744d82b01f1ae8ee357b35a445a18','','tsref:(cObject).HRULER','a:1:{s:4:\"rows\";a:6:{i:0;a:6:{s:8:\"property\";s:13:\"lineThickness\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:11:\"Range: 1-50\";s:7:\"default\";s:1:\"1\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:9:\"lineColor\";s:8:\"datatype\";s:10:\"HTML-color\";s:11:\"description\";s:23:\"The color of the ruler.\";s:7:\"default\";s:5:\"black\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:9:\"spaceLeft\";s:8:\"datatype\";s:6:\"pixels\";s:11:\"description\";s:35:\"space before the line (to the left)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:10:\"spaceRight\";s:8:\"datatype\";s:6:\"pixels\";s:11:\"description\";s:35:\"space after the line (to the right)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:10:\"tableWidth\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:63:\"Width of the ruler (“width” attribute in a table)\";s:7:\"default\";s:3:\"99%\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(75,7389802,'99c88493b5fbff11087e84f8b0caf05e','','tsref:(cObject).IMGTEXT','a:1:{s:4:\"rows\";a:36:{i:0;a:6:{s:8:\"property\";s:4:\"text\";s:8:\"datatype\";s:20:\"->CARRAY /stdWrap\";s:11:\"description\";s:82:\"Use this to import / generate the content, that should flow around the imageblock.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:7:\"textPos\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:352:\"Textposition:
bit[0-2]: 000 = centre, 001 = right, 010 = left
bit[3-5]: 000 = over, 001 = under, 010 text
 
0 - Above: Centre
1 - Above: Right
2 - Above: Left
8 - Below: Centre
9 - Below: Right
10 - Below: Left
17 - In Text: Right
18 - In Text: Left
25 - In Text: Right (no wrap)
26 - In Text: Left (no wrap)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:10:\"textMargin\";s:8:\"datatype\";s:15:\"pixels /stdWrap\";s:11:\"description\";s:40:\"margin between the image and the content\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:20:\"textMargin_outOfText\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:337:\"If set, the textMargin space will still be inserted even if the image is placed above or below the text.
This flag is only for a kind of backwards compatibility because this "feature" was recently considered a bug and thus corrected. So if anyone has depended on this way things are done, you can compensate with this flag.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:7:\"imgList\";s:8:\"datatype\";s:40:\" list of imagefiles /stdWrap\";s:11:\"description\";s:176:\"list of images from ".imgPath"
 
Example:

This imports the list of images from tt_content's image-field
"imgList.field = image"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:7:\"imgPath\";s:8:\"datatype\";s:13:\"path /stdWrap\";s:11:\"description\";s:76:\"Path to the images
 
Example:

"uploads/pics/"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:6:\"imgMax\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:20:\"max number of images\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:8:\"imgStart\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:45:\"start with image-number ".imgStart"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:9:\"imgObjNum\";s:8:\"datatype\";s:35:\" imgObjNum +optionSplit\";s:11:\"description\";s:410:\"Here you define, which IMAGE-cObjects from the array "1,2,3,4..." in this object that should render the images.
"current" is set to the image-filename.
 
Example:

"imgObjNum = 1 |*||*| 2":
This would render the first two images with "1. ..." and the last image with "2. ...", provided that the ".imgList" contains 3 images.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:7:\"1,2,3,4\";s:8:\"datatype\";s:20:\"->IMAGE (cObject)\";s:11:\"description\";s:323:\"Rendering of the images
The register "IMAGE_NUM" is set with the number of image being rendered for each rendering of a image-object. Starting with zero.
The image-object should not be of type GIFBUILDER!
 
Important:

"file.import.current = 1" fetches the name of the images! \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:7:\"caption\";s:8:\"datatype\";s:20:\"->CARRAY /stdWrap\";s:11:\"description\";s:7:\"Caption\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:12:\"captionAlign\";s:8:\"datatype\";s:14:\"align /stdWrap\";s:11:\"description\";s:17:\"Caption alignment\";s:7:\"default\";s:30:\"default = ".textPos"\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:12:\"captionSplit\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:379:\"If this is set, the caption text is split by the character (or string) from ".token" , and every item is displayed under an image each in the image block.
.token = (string /stdWrap) Character to split the caption elements (default is chr(10))
.cObject = cObject, used to fetch the caption for the split
.stdWrap = stdWrap properties used to render the caption.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:20:\"altText
titleText\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:215:\"Default altText/titleText if no alternatives are provided by the ->IMAGE cObjects
 
If no titltext is specified, it will use the alttext insteadIf no alttext is specified, it will use an empty alttext\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:11:\"longdescURL\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:186:\"Default longdescURL if no alternatives are provided by the ->IMAGE cObjects
 
"longdesc" attribute (URL pointing to document with extensive details about image).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:6:\"border\";s:8:\"datatype\";s:17:\"boolean /stdWrap \";s:11:\"description\";s:48:\"If true, a border i generated around the images.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:9:\"borderCol\";s:8:\"datatype\";s:32:\" HTML-color /stdWrap\";s:11:\"description\";s:50:\"Color of the border, if ".border" is set\";s:7:\"default\";s:5:\"black\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:11:\"borderThick\";s:8:\"datatype\";s:15:\"pixels /stdWrap\";s:11:\"description\";s:39:\"Width of the border around the pictures\";s:7:\"default\";s:1:\"1\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:4:\"cols\";s:8:\"datatype\";s:13:\"int /stdWrap \";s:11:\"description\";s:7:\"Columns\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:19;a:6:{s:8:\"property\";s:4:\"rows\";s:8:\"datatype\";s:13:\"int /stdWrap \";s:11:\"description\";s:44:\"Rows (higher priority thab "cols")\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:20;a:6:{s:8:\"property\";s:6:\"noRows\";s:8:\"datatype\";s:16:\"boolean /stdWrap\";s:11:\"description\";s:145:\"If set, the rows are not divided by a table-rows. Thus images are more nicely shown if the height differs a lot (normally the width is the same!)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:21;a:6:{s:8:\"property\";s:6:\"noCols\";s:8:\"datatype\";s:16:\"boolean /stdWrap\";s:11:\"description\";s:208:\"If set, the columns are not made in the table. The images are all put in one row separated by a clear giffile to space them apart.
If noRows is set, noCols will be unset. They cannot be set simultaneously.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:22;a:6:{s:8:\"property\";s:8:\"colSpace\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:21:\"space between columns\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:23;a:6:{s:8:\"property\";s:8:\"rowSpace\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:18:\"space between rows\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:24;a:6:{s:8:\"property\";s:15:\"spaceBelowAbove\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:101:\"Pixelsspace between content an images when position of image is above or belox text (but not in text)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:25;a:6:{s:8:\"property\";s:12:\"tableStdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:85:\"This passes the final <table> code for the image block to the stdWrap function.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:26;a:6:{s:8:\"property\";s:4:\"maxW\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:195:\"max width of the image-table.
This will scale images not in the right size! Takes the number of columns into account!
 
 NOTE: Works ONLY if IMAGE-obj is NOT GIFBUILDER\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:27;a:6:{s:8:\"property\";s:10:\"maxWInText\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:269:\"max width of the image-table, if the text is wrapped around the image-table (on the left or right side).
This will scale images not in the right size! Takes the number of columns into account!
 
 NOTE: Works ONLY if IMAGE-obj is NOT GIFBUILDER\";s:7:\"default\";s:11:\"50% of maxW\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:28;a:6:{s:8:\"property\";s:6:\"equalH\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:655:\"If this value is greater than zero, it will secure that images in a row has the same height. The width will be calculated.
If the total width of the images raise above the "maxW"-value of the table the height for each image will be scaled down equally so that the images still have the same height but is within the limits of the totalWidth.
Please note that this value will override the properties "width", "maxH", "maxW", "minW", "minH" of the IMAGE-objects generating the images. Furthermore it will override the "noRows"-property and generate a table with no columns instead!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:29;a:6:{s:8:\"property\";s:12:\"colRelations\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:629:\"This value defines the width-relations of the images in the columns of IMGTEXT. The syntax is "[int] : [int] : [int] : ..." for each column. If there are more imagecolumns than figures in this value, it's ignored. If the relation between two of these figures exceeds 10, this function is ignore.
It works only fully if all images are downscaled by their maxW-definition.
 
Example:

If 6 images are placed in three columns and their width's are high enough to be forcibly scaled, this value will scale the images in the to be eg. 100, 200 and 300 pixels from left to right
1 : 2 : 3\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:30;a:6:{s:8:\"property\";s:17:\"image_compression\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:996:\"Image Compression:
0= Default
1= Dont change! (removes all parameters for the image_object!!)
(adds gif-extension and color-reduction command)
10= GIF/256
11= GIF/128
12= GIF/64
13= GIF/32
14= GIF/16
15= GIF/8
(adds jpg-extension and quality command)
20= IM: -quality 100
21= IM: -quality 90 <=> Photoshop 60     (JPG/Very High)
22= IM: -quality 80    (JPG/High)
23= IM: -quality 70
24= IM: -quality 60 <=> Photoshop 30   (JPG/Medium)
25= IM: -quality 50
26= IM: -quality 40 (JPG/Low)
27= IM: -quality 30 <=> Photoshop 10
28= IM: -quality 20   (JPG/Very Low)
 
The default ImageMagick quality seems to be 75. This equals Photoshop quality 45. Images compressed with ImageMagick with the same visual quality as a Photoshop-compressed image seems to be largely 50% greater in size!!
 
 NOTE: Works ONLY if IMAGE-obj is NOT GIFBUILDER\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:31;a:6:{s:8:\"property\";s:13:\"image_effects\";s:8:\"datatype\";s:12:\"int /stdWrap\";s:11:\"description\";s:548:\"Adds these commands to the parameteres for the scaling. This function has no effect if "image_compression" above is set to 1!!
 
1 => "-rotate 90",
2 => "-rotate 270",
3 => "-rotate 180",
10 => "-colorspace GRAY",
11 => "-sharpen 70",
20 => "-normalize",
23 => "-contrast",
25 => "-gamma 1.3",
26 => "-gamma 0.8"
 
 NOTE: Works ONLY if IMAGE-obj is NOT GIFBUILDER\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:32;a:6:{s:8:\"property\";s:12:\"image_frames\";s:8:\"datatype\";s:35:\"Array
+ .key /stdWrap
 \";s:11:\"description\";s:1175:\"Frames:
.key points to the frame used.
 
".image_frames.x" is imgResource-mask (".m")properties which will override to the [imgResource].m properties of the imageObjects. This is used to mask the images into a frame. See how it's done in the default configuration and IMGTEXT in the static_template-table.
 
Example:

1 {
   mask = media/uploads/darkroom1_mask.jpg
   bgImg = GIFBUILDER
   bgImg {
     XY = 100,100
     backColor = {$bgCol}
   }
   bottomImg = GIFBUILDER
   bottomImg {
     XY = 100,100
     backColor = black
   }
   bottomImg_mask = media/uploads/darkroom1_bottom.jpg
}
 
 NOTE: This cancels the jpg-quality settings sent as ordinary ".params" to the imgResource. In addition the output of this operation will always be jpg or gif!
 NOTE: Works ONLY if IMAGE-obj is NOT GIFBUILDER\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:33;a:6:{s:8:\"property\";s:9:\"editIcons\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:23:\"(See stdWrap.editIcons)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:34;a:6:{s:8:\"property\";s:23:\"noStretchAndMarginCells\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:279:\"If set (1), the cells used to add left and right margins plus stretch out the table will not be added. You will loose the ability to set margins for the object if entered “in text”. So it's not recommended, but it has been requested by some people for reasons.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:35;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(76,7389802,'7831f428e4ab5909c05af00f0f34071e','','tsref:(cObject).CASE','a:1:{s:4:\"rows\";a:6:{i:0;a:6:{s:8:\"property\";s:10:\"setCurrent\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:36:\"Sets the "current"-value. \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:3:\"key\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:12:\"This is the \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:7:\"default\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:15:\"Array...\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:2:\"if\";s:8:\"datatype\";s:7:\"->if\";s:11:\"description\";s:51:\"if "if" returns false nothing is returned\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(77,7389802,'11559da8560e5a25a5d94dc2ababdc78','','tsref:(cObject).LOAD_REGISTER','a:1:{s:4:\"rows\";a:1:{i:0;a:6:{s:8:\"property\";s:38:\"Array...
[fieldname]
\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:347:\"Example:
(This sets "contentWidth", "label" and "head")
 
page.27 = LOAD_REGISTER
page.27 {
   contentWidth = 500
 
   label.field = header
 
   head = some text
   head.wrap = <B> | </B>
}\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(78,7389802,'d6df84910bc06faaa29868176f91b324','','tsref:(cObject).FORM','a:1:{s:4:\"rows\";a:38:{i:0;a:6:{s:8:\"property\";s:4:\"data\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:102:\"This is the data that sets up the form. See above.
"||" can be used instead of linebreaks\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:9:\"dataArray\";s:8:\"datatype\";s:31:\"[array of form elements]\";s:11:\"description\";s:2835:\"This is an alternative way to define the form-fields. Instead of using the syntax with vertical separator bars suggested by the .data property, you can define the elements in regular TypoScript style arrays.
.dataArray is added to the input in .data if any.
Every entry in the dataArray is numeric and has three main properties, label, type, value and required. 'label' and 'value' has stdWrap properties.
There is an alternative property to .value, which is .valueArray. This is also an array in the same style with numeric entries which has properties label, value and selected. 'label' has stdWrap properties.
 
Example:

   dataArray {
     10.label = Name:
     10.type = name=input
     10.value = [Enter name]
     10.required = 1
     20.label = Eyecolor
     20.type = eyecolor=select
     20.valueArray {
       10.label = Blue
       10.value = 1
       20.label = Red
       20.value = 2
       20.selected = 1
     }
     40.type = submit=submit
     40.value = Submit
   }
 
 
This is the same as this line in the .data property:
 
Name: | *name=input | [Enter name]
Eyecolor: | eyecolor=select | Blue=1, *Red=2
| submit=submit | Submit
 
 Why do it this way?
Inserting an email-field after the name field would be like this:
   dataArray {
     15.label = Email:
     15.type = input
     15.value =
     15.specialEval = EMAIL
   }
 
 Or translating the form to danish (setting config.language to 'dk'):
 
   dataArray {
     10.label.lang.dk = Navn:
     10.value.lang.dk = [Indtast dit navn]
     20.label.lang.dk = Øjenfarve
     20.valueArray {
       10.label.lang.dk = Blå
       20.label.lang.dk = Rød
     }
     40.value.lang.dk = Send
   }
 \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:9:\"radioWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:33:\"Wraps the labels for radiobuttons\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:4:\"type\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:742:\"Type (action="" of the form):
 
 Integer: this is regarded to be a page in TYPO3
 String: this is regarded to be a normal URL (eg. "formmail.php" or "fe_tce_db.php")
 Empty: the current page is chosen.
 
 NOTE: If type is integer/empty the form will be submitted to a page in TYPO3 and if this page has a value for target/no_cache, then this will be used instead of the default target/no_cache below.
 
 NOTE: If the redirect-value is set, the redirect-target overrides the target set by the action-url
 
 NOTE: May be overridden by the property override feature of the formdata (see above)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:6:\"target\";s:8:\"datatype\";s:6:\"target\";s:11:\"description\";s:28:\"Default target of the form. \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:6:\"method\";s:8:\"datatype\";s:11:\"form-method\";s:11:\"description\";s:23:\"Example:
GET\";s:7:\"default\";s:4:\"POST\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:8:\"no_cache\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:23:\"Default no_cache-option\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:13:\"noValueInsert\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:434:\"By default values that are submitted to the same page (and thereby same form, eg. at searchforms) are re-inserted in the form instead of any default-data that might be set up.
This, however, applies ONLY if the "no_cache=1" is set! (a page being cached may not include user-specific defaults in the fields of course...)
If you set this flag, "noValueInsert", the content will always be the default content.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:20:\"compensateFieldWidth\";s:8:\"datatype\";s:6:\"double\";s:11:\"description\";s:85:\"Overriding option to the config-value of the same name. See "CONFIG" above.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:12:\"locationData\";s:8:\"datatype\";s:16:\"boolean / string\";s:11:\"description\";s:1479:\"If this value is true, then a hidden-field called "locationData" is added to the form. This field wil be loaded with a value like this:
[page id]:[current record table]:[current record id]
For example, if a formfield is inserted on page with uid = "100", as a page-content item from the table "tt_content" with id "120", then the value would be "100:tt_content:120".
The value is use by eg. the cObject SEARCHRESULT. If the value $GLOBALS["HTTP_POST_VARS"]["locationData"] is detected here, the search is done as if it was performed on this page! This is very usefull if you want a search functionality implemented on a page with the "stype" field set to "L1" which means that the search is carried out from the first level in the rootline.
Suppose you want the search to submit to a dedicated searchpage where ever. This page will then know - because of locationData - that the search was submittet from another place on the website.
If "locationData" is not only true but also set to "HTTP_POST_VARS" then the value will insert the content of $GLOBALS["HTTP_POST_VARS"]["locationData"] instead of the true location data of the page. This should be done with search-fields as this will carry the initial searching start point with.
 NOTE: May be overridden by the property override feature of the formdata (see above)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:8:\"redirect\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:372:\"URL to redirect to (generates the hidden field "redirect")
 
 Integer: this is regarded to be a page in TYPO3
 String: this is regarded to be a normal url
 Empty; the current page is chosen.
 
 NOTE: If this value is set the target of this overriddes the target of the "type".\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:9:\"recipient\";s:8:\"datatype\";s:38:\" (list of) string /stdWrap\";s:11:\"description\";s:89:\"Email recipient of the formmail content (generates the hiddenfield "recipient")\";s:7:\"default\";s:8:\"No email\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:8:\"goodMess\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:184:\"Message for the formevaluation function in case of correctly filled form.
 
 NOTE: May be overridden by the property override feature of the formdata (see above)\";s:7:\"default\";s:10:\"No message\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:7:\"badMess\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:238:\"Prefixed Message for the formevaluation in case of missing required fields.
This message is shown above the list of fields.
 
 NOTE: May be overridden by the property override feature of the formdata (see above)\";s:7:\"default\";s:10:\"No message\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:9:\"emailMess\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:180:\"Message if a field evaluated to be an email adresse did not validate.
 
 NOTE: May be overridden by the property override feature of the formdata (see above)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:5:\"image\";s:8:\"datatype\";s:20:\"->IMAGE (cObject)\";s:11:\"description\";s:171:\"If this is a valid image the submitbutton is rendered as this image!!
 
 NOTE: CurrentValue is set to the caption-label before generating the image.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:6:\"layout\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:471:\"This defines how the label and the field are placed towards each other.
 
Example:

This substitutes the "###FIELD###" with the field data and the "###LABEL###' with labeldata.
 
<tr><td>###FIELD###</td><td> ###LABEL###</td></tr>
 
You can also use the marker ###COMMENT### which is ALSO the label value inserted, but wrapped in .commentWrap stdWrap-properties (see below)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:9:\"fieldWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:23:\"Field: Wraps the fields\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:9:\"labelWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:23:\"Labels: Wraps the label\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:19;a:6:{s:8:\"property\";s:11:\"commentWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:52:\"Comments: Wrap for comments IF you use ###COMMENT###\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:20;a:6:{s:8:\"property\";s:3:\"REQ\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:58:\"Defines if required-fields should be checked and marked up\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:21;a:6:{s:8:\"property\";s:13:\"REQ.fieldWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:47:\"Field: Wraps the fields, but for reuired fields\";s:7:\"default\";s:34:\"the "fieldWrap"-property\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:22;a:6:{s:8:\"property\";s:13:\"REQ.labelWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:47:\"Labels: Wraps the label, but for reuired fields\";s:7:\"default\";s:34:\"the "labelWrap"-property\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:23;a:6:{s:8:\"property\";s:10:\"REQ.layout\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:60:\"The same as "layout" above, but for reuired fields\";s:7:\"default\";s:31:\"the "layout"-property\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:24;a:6:{s:8:\"property\";s:14:\"COMMENT.layout\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:32:\"Alternative layout for comments.\";s:7:\"default\";s:31:\"the "layout"-property\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:25;a:6:{s:8:\"property\";s:12:\"CHECK.layout\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:33:\"Alternative layout for checkboxes\";s:7:\"default\";s:31:\"the "layout"-property\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:26;a:6:{s:8:\"property\";s:12:\"RADIO.layout\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:35:\"Alternative layout for radiobuttons\";s:7:\"default\";s:31:\"the "layout"-property\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:27;a:6:{s:8:\"property\";s:12:\"LABEL.layout\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:34:\"Alternative layout for label types\";s:7:\"default\";s:31:\"the "layout"-property\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:28;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:46:\"Wraps the hole form (before formtags is added)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:29;a:6:{s:8:\"property\";s:12:\"hiddenFields\";s:8:\"datatype\";s:18:\"[array of cObject]\";s:11:\"description\";s:221:\"Used to set hiddenFields from TS.
 
Example:

hiddenFields.pid = TEXT
hiddenFields.pid.value = 2
 
This makes a hidden-field with the name “pid” and value “2”.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:30;a:6:{s:8:\"property\";s:6:\"params\";s:8:\"datatype\";s:27:\"form-element tag parameters\";s:11:\"description\";s:288:\"Extra parameters to form elements
 
Example:

params = style=”width:200px;”
params.textarea = style=”width:300px;”
params.check =
 
This sets the default to 200 px width, but excludes check-boxes and sets textareas to 300.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:31;a:6:{s:8:\"property\";s:13:\"wrapFieldName\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:222:\"This wraps the fieldnames before they are applied to the form-field tags.
 
Example:

If value is then the fieldname "email" would be wrapped to this value: tx_myextension[input][email]\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:32;a:6:{s:8:\"property\";s:10:\"noWrapAttr\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:281:\"If this value is true then all wrap attributes of textarea elements are suppressed. This is needed for XHTML-compliancy.
 
The wrap attributes can also be disabled on a per-field basis by using the special keyword "disabled" as the value of the wrap attribute.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:33;a:6:{s:8:\"property\";s:15:\"arrayReturnMode\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:217:\"If set, the <form> tags and the form content will be returned in an array as separate elements including other pratical values. This mode is for use in extensions where the array return value can be more useful.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:34;a:6:{s:8:\"property\";s:13:\"accessibility\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:461:\"If set, then the form will be compliant with accessibility guidelines (XHTML compliant). This includes:
 
label string will be wrapped in <label for="formname[fieldname-hash]"> ... </label>
All form elements will have an id-attribute carrying the formname with the md5-hashed fieldname appended
 
 Notice: In TYPO3 4.0 and later, CSS Styled Content is configured to produce accessible forms by default.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:35;a:6:{s:8:\"property\";s:8:\"formName\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:125:\"An alternative name for this form. Default will be a unique (random) hash.
 
<form name=”...”>\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:36;a:6:{s:8:\"property\";s:11:\"fieldPrefix\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:255:\"Alternative prefix for the name of the fields in this form. Otherwise, all fields are prefixed with the form name (either a unique hash or the name set in the “formName” property). If set to “0”, there will be no prefix at all.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:37;a:6:{s:8:\"property\";s:17:\"dontMd5FieldNames\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:272:\"The IDs generated for all elements in a form are md5 hashes from the fieldname. Setting this to true will disable this behaviour and use a cleaned fieldname, prefixed with the form name as the ID, instead.
This can be useful to style specifically named fields with CSS.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(79,7389802,'06d8abccf0aba6b413150e9c100f4bd4','','tsref:(cObject).SEARCHRESULT','a:1:{s:4:\"rows\";a:15:{i:0;a:6:{s:8:\"property\";s:11:\"allowedCols\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:120:\"List (separated by ":") of allowed table-cols.
 
Example:

pages.title:tt_content.bodytext\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:6:\"layout\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:368:\"This defines how the search content is shown.
 
Example:

This substitutes the following fields:
###RANGELOW###:The low result range, eg. "1"
###RANGEHIGH###:The high result range, eg. "10"
###TOTAL###:The total results
###RESULT###:The result itself
 ###NEXT###:The next-button
###PREV###:The prev-button\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:4:\"next\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:126:\"This cObject will be wrapped by a link to the next searchresult. This is the code substituting the "###NEXT###"-mark\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:4:\"prev\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:126:\"This cObject will be wrapped by a link to the prev searchresult. This is the code substituting the "###PREV###"-mark\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:6:\"target\";s:8:\"datatype\";s:6:\"target\";s:11:\"description\";s:27:\"target til next/prev links!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:5:\"range\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:32:\"The number of results at a time!\";s:7:\"default\";s:2:\"20\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:9:\"renderObj\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:325:\"the cObject to render the searchresults
$cObj->data array is set to the resulting record from the search.
Please note, that in all fields are named [tablename]_[fieldnam]. Thus the pagetitle is in the field "pages_title".
Apart from this, these fields from the pages-table are also present:
 uid\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:10:\"renderWrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:9:\"resultObj\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:56:\"the cObject prepended in the search results returns rows\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:11:\"noResultObj\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:50:\"the cObject used if the search results in no rows.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:9:\"noOrderBy\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:87:\"If this is set, the result is NOT sorted after lastUpdated, tstamp for the pages-table.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:25:\"Wrap the whole content...\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:25:\"Wrap the whole content...\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:22:\"addExtUrlsAndShortCuts\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:408:\"If set, then the doktypes 3 and 4 (External URLS and Shortcuts) are added to the doktypes being searched.
However at this point in time, no pages will be select if they do not have at least one tt_content record on them! That is because the pages and tt_content (or other) table is joined. So there must at least one occurance of a tt_content element on a External URL / Shortcut page for them to show up.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:25:\"languageField.[2nd table]\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:202:\"Setting a field name to filter language on. This works like the “languageField” setting in ->select
 
Example:

 
languageField.tt_content = sys_language_uid\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(80,7389802,'4a24c3602d0800d7feacc6759c6dbf21','','tsref:(cObject).USER/(cObject).USER_INT','a:1:{s:4:\"rows\";a:2:{i:0;a:6:{s:8:\"property\";s:15:\"userFunc\";s:8:\"datatype\";s:13:\"function-name\";s:11:\"description\";s:862:\"The name of the function. If you specify the name with a '->' in, it's intepreted as a call to a method in a class.
 Two parameters are sent: A content variable (which is empty in this case, but not when used from stdWrap function .postUserFunc and .preUserFunc) and the second parameter is an array with the properties of this cObject if any.
 
Example:

This TypoScript will display all content element headers of a page in reversed order. Please take a look in media/scripts/example_callfunction.php!!
(Also demonstrated on the testsite, page
 
page = PAGE
page.typeNum=0
includeLibs.something = media/scripts/example_callfunction.php
 
page.30 = USER
page.30 {
   userFunc = user_various->listContentRecordsOnPage
   reverseOrder = 1
}\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:11:\"includeLibs\";s:8:\"datatype\";s:29:\" list of resource\";s:11:\"description\";s:372:\"(This property applies only if the object is created as USER_INT)
This is a comma-separated list of resources that are included as PHP-scripts (with include_once() function) if this script is included.
This is possible to do because any include-files will be known before the scripts are included. That's not the case with the regular PHP_SCRIPT cObject.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(81,7389802,'58679d0408b0f09f69cb93e0634e69c9','','tsref:(cObject).PHP_SCRIPT','a:1:{s:4:\"rows\";a:1:{i:0;a:6:{s:8:\"property\";s:11:\"file\";s:8:\"datatype\";s:8:\"resource\";s:11:\"description\";s:972:\"File that will be included. This file must be valid PHP-code! It's included with "include()";
 
Directions:

 1) All content must be put into $content. No output must be echo'ed out!
 
 2) Call $GLOBALS["TSFE"]->set_no_cache(), if you want to disable caching of the page. Set this during development! And set it, if the content you create may not be cached.
 
 NOTE: If you have a parsing error in your include script the $GLOBALS["TSFE"]->set_no_cache() function is NOT executed and thereby does not disable caching. Upon a parse-error you must manually clear the page-cache after you have corrected your error!
 3) the array $conf contains the configuration for the PHP_SCRIPT cObject. Try debug($conf) to see the content printed out for debugging!
See later in this manual for an introduction to writing your own PHP include-scripts.
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(82,7389802,'6307a490ae08c78efdc8a3ceb92bfde6','','tsref:(cObject).PHP_SCRIPT_INT','a:1:{s:4:\"rows\";a:2:{i:0;a:6:{s:8:\"property\";s:11:\"file\";s:8:\"datatype\";s:8:\"resource\";s:11:\"description\";s:2109:\"File that will be included. This file must be valid PHP-code! It's included with "include()";
 
Purpose:

 This basically works like PHP_SCRIPT. But the vital difference is that inserting a PHP_SCRIPT_INT (internal opposed to external, see below) merely inserts a divider-string in the code and then serializes the current cObj and puts it in the $GLOBALS["TSFE"]->config[“INTincScript”]-array. This array is saved with the cached page-content.
Now, the point is, that including a script like this lets you avoid disabling pagecaching. The reason is that the cached page contains the divider string and when a “static” page is fetched from cache, it's divided by that string and the dynamic content object is inserted.
This is the compromise option of all three PHP_SCRIPT-cObjects, because the page-data is all cached, but still the pagegen.php script is included, which initializes all the classes, objects and so. What you gain here is an environment for your script almost exactly the same as PHP_SCRIPT because your script is called from inside a class tslib_cObj object. You can work with all functions of the tslib_cObj-class. But still all the “static” pagecontent is only generated once, cached and only your script is dynamically rendered.
 
Rules:

- calls to $GLOBALS["TSFE"]->set_no_cache() and $GLOBALS["TSFE"]->set_cache_timeout_default() makes no sense in this situation.
- parsing errors does not interfere with caching
- Be aware that certain global variables may not be set as usual and be available as usual when working in this mode. Most scripts should work out-of-the-box with this option though.
- Dependence and use of LOAD_REGISTER is fragile because the PHP_SCRIPT_INT is not rendered until after the cached content and due to this changed order of events, use of LOAD_REGISTER may not work.
- You can not nest PHP_SCRIPT_INT and PHP_SCRIPT_EXT in PHP_SCRIPT_INT. You may nest PHP_SCRIPT cObjects though.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:11:\"includeLibs\";s:8:\"datatype\";s:29:\" list of resource\";s:11:\"description\";s:296:\"This is a comma-separated list of resources that are included as PHP-scripts (with include_once() function) if this script is included.
This is possible to do because any include-files will be known before the scripts are included. That's not the case with the regular PHP_SCRIPT cObject.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(83,7389802,'dede7a11cddf475e1eaf0a9116291157','','tsref:(cObject).PHP_SCRIPT_EXT','a:1:{s:4:\"rows\";a:2:{i:0;a:6:{s:8:\"property\";s:11:\"file\";s:8:\"datatype\";s:8:\"resource\";s:11:\"description\";s:1472:\"File that will be included. This file must be valid PHP-code! It's included with "include()";
 
Purpose:

 This works like PHP_SCRIPT_INT, because a divider string is also inserted in the content for this kind of include-script. But the difference is that the content is divided as the very last thing before it's output to the browser.
This basically means that PHP_SCRIPT_EXT (external, because it's included in the global space in index_ts.php file!!) can output data directly with echo-statements!
This is a very “raw” version of PHP_SCRIPT because it's not included from inside an object and you have only very few standard functions from TYPO3 to call.
This is the fastest option of all three PHP_SCRIPT-cObjects, because the page-data is all cached and your dynamic content is generated by a raw php-script
 
Rules:

- All content can be either 1) echo'ed out directly, or 2) returned in $content.
- calls to $GLOBALS["TSFE"]->set_no_cache() and $GLOBALS["TSFE"]->set_cache_timeout_default() makes no sense in this situation.
- parsing errors does not interfere with caching
- In the global name-space, the array $REC contains the current record when the file was “inserted” on the page, and $CONF-array contains the configuration for the script.
- Don't mess with the global vars named $EXTiS_* \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:11:\"includeLibs\";s:8:\"datatype\";s:29:\" list of resource\";s:11:\"description\";s:296:\"This is a comma-separated list of resources that are included as PHP-scripts (with include_once() function) if this script is included.
This is possible to do because any include-files will be known before the scripts are included. That's not the case with the regular PHP_SCRIPT cObject.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(84,7389802,'36fc199c62fb88c0a813769e3de9adc9','','tsref:(cObject).TEMPLATE','a:1:{s:4:\"rows\";a:9:{i:0;a:6:{s:8:\"property\";s:8:\"template\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:84:\" This must be loaded with the template-code. If not the object returns nothing.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:8:\"subparts\";s:8:\"datatype\";s:30:\"Array... of
cObject\";s:11:\"description\";s:1253:\"This is an array of subpart-markers (case-sensitive).
A subpart is defined by two markers in the template. The markers must be wrapped by "###" on both sides. You may insert the subpart-markers inside HTML-comment-tags!!
 
Example:

subparts {
   HELLO = TEXT
   HELLO.value = En subpart er blevet erstattet!!
}
 
In the templates:
<!-- start of subpart: ###HELLO### -->
This is the HTML.code, that will be loaded in the register and replaced with the result...
<!-- end ###HELLO### -->
 
NOTE:

Before the content-objects of each subpart is generated, all subparts in the array are extracted and loaded into the register so that you can load them from there later on.
The register-key for each subparts code is "SUBPART_[theSubpartkey]".
In addition the current-value is loaded with the content of each subpart just before the cObject for the subpart is parsed. That makes it quite easy to load the subpart of the cObject (eg: ".current=1")
Eg. this subpart above has the register-key "SUBPART_HELLO".
This is valid ONLY if the property .nonCachedSubst is not set! (see below)
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:13:\"relPathPrefix\";s:8:\"datatype\";s:26:\"string / properties\";s:11:\"description\";s:757:\"Finds all relative references (eg. to images or stylesheets) and prefixes this value.
If you specify properties (uppercase) these will match HTML tags and specify alternative paths for them. See example below.
If the property is named "style" it will set alternative path for the "url()" wrapper that may be in <style> sections.
 
Example:

page.10 = TEMPLATEpage.10 { template = FILE template.file = fileadmin/template.html relPathPrefix = fileadmin/
   relPathPrefix.IMG = fileadmin/img/}
 
Inthis example all relative paths found are prefixed "fileadmin/" unless it was the src attribute of an img tag in which case the path prefixed is "fileadmin/img/"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:5:\"marks\";s:8:\"datatype\";s:30:\"Array... of
cObject\";s:11:\"description\";s:451:\"This is an array of marks-markers (case-sensitive).
A mark is defined by one markers in the template. The marker must be wrapped by "###" on both sides. Opposite to subparts, you may NOT insert the subpart-markers inside HTML-comment-tags! (They will not be removed).
Marks are substituted bya str_replace-function. The subparts loaded in the register is available also to the cObjects of markers (only if .nonCachedSubst is not set!).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:5:\"wraps\";s:8:\"datatype\";s:30:\"Array... of
cObject\";s:11:\"description\";s:487:\"This is an array of wraps-markers (case-sensitive).
This is shown best by an example:
Example:

subparts {
   MYLINK = TEXT
   MYLINK.value = <A href=”#”> | </A>
}
 
In the template:
This is <!--###MYLINK###-->a link to my<!--###MYLINK###--> page!
 
In this example the MYLINK subpart will be substituted by the wrap which is the content returned by the MYLINK cObject.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:13:\"workOnSubpart\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:204:\"This is an optional definition of a subpart, that we decide to work on. In other words; if you define this value that subpart is extracted from the template and is the basis for this whole templateobject.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:10:\"markerWrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:235:\"This is the wrap the markers is wrapped with. The default value is ### | ### resulting in the markers to be presented as ###[marker_key]###.
Any whitespace around the wrap-items is stripped before they are set around the marker_key.\";s:7:\"default\";s:9:\"### | ###\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:20:\"substMarksSeparately\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:431:\"If set, then marks are substituted in the content AFTER the substitution of subparts and wraps.
Normally marks are not substituted inside of subparts and wraps when you are using the default cached mode of the TEMPLATE cObject. That is a problem if you have marks inside of subparts! But setting this flag will make the marker-substitution a non-cached, subsequent process.
Another solution is to turn of caching, see below.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:14:\"nonCachedSubst\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:711:\"If set, then the substitution mode of this cObject is totally different. Normally the raw template is read and divided into the sections denoted by the marks, subparts and wraps keys. The good thing is high speed, because this “pre-parsed” template is cached. The bad thing is that templates that depends on incremental substition (where the order of substition is important) will not work so well.
By setting this flag, markers are first substituted by str_replace in the template - one by one. Then the subparts are substituted one by one. And finally the wraps one by one.
Obviously you loose the ability to refer to other parts in the template with the register-keys as described above. \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(85,7389802,'9e45ae1e8e57e33a34339154486c9e40','','tsref:(cObject).MULTIMEDIA','a:1:{s:4:\"rows\";a:3:{i:0;a:6:{s:8:\"property\";s:4:\"file\";s:8:\"datatype\";s:17:\"resource /stdWrap\";s:11:\"description\";s:213:\"The multimedia file. Types are:
txt, html, htm:Inserted directly
class:Java-applet
swf:Flash animation
swa, dcr:ShockWave Animation
wav,au:Sound
avi,mov,asf,mpg,wmv:Movies (AVI, QuickTime, MPEG4)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:6:\"params\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:351:\"This is parameters for the multimedia-objects. Use this to enter stuff like with and height:
 
Example:

width=200
height=300
 
... will generate a tag like '<embed .... width="200" height="300">'
height=
 
An empty string will remove the parameter from the embed-tag\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(86,7389802,'71d45380d5c1507c11c46fa7b95d72fa','','tsref:(cObject).EDITPANEL','a:1:{s:4:\"rows\";a:11:{i:0;a:6:{s:8:\"property\";s:5:\"label\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:123:\"Title for the panel. You can insert the record title with %s
 
Example:

Section: <B>%s</B>\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:5:\"allow\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:356:\"Define which functions are accessible. Further this list may be reduced, if the BE_USER does not have permission to perform the action
Values should be listed separated by comma. This is the options you can choose between:
toolbar,edit,new,delete,move,hide
(toolbar is a general list of icons regarding the page, so use this for pagerecords only)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:18:\"newRecordFromTable\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:98:\"Will display a panel for creation of new element (in the top of list) on the page from that table.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:14:\"newRecordInPid\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:70:\"Define a page ID where new records (except new pages) will be created.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:4:\"line\";s:8:\"datatype\";s:13:\"boolean / int\";s:11:\"description\";s:120:\"If set, a black line will appear after the panel. This value will indicate the distance from the black line to the panel\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:18:\"edit.displayRecord\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:67:\"If set, then the record edited is displayed above the editing form.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:14:\"onlyCurrentPid\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:99:\"If set, only records with a pid matching the current id (TSFE->id) will be shown with the panel.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:9:\"innerWrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:20:\"Wraps the edit panel\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:9:\"outerWrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:67:\"Wraps the whole edit panel including the black line (if configured)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:13:\"previewBorder\";s:8:\"datatype\";s:14:\"boolean / int \";s:11:\"description\";s:157:\"If set, the hidden/starttime/endtime/fe_user elements which are previewed will have a border around.
The integer value denotes the thickness of the border\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:73:\"previewBorder.innerWrap
previewBorder.outerWrap
previewBorder.color\";s:8:\"datatype\";s:17:\"wrap / HTML color\";s:11:\"description\";s:271:\" innerWrap wraps the content elements (including the icons) inside the preview border (an HTML table).
 
 outerWrap wraps the whole content element including the border.
 
 color denotes the color of the border.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(87,7389802,'92d229100f79be75aed1bd3d7f60373d','','tsref:_GIFBUILDER.charRangeMap','a:1:{s:4:\"rows\";a:4:{i:0;a:6:{s:8:\"property\";s:8:\"[array] \";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:1003:\"Basename of font file to match for this configuration. Notice that only the filename of the font file is used - the path is stripped off. This is done to make matching easier and avoid problems when font files might move to other locations in extensions etc.
 
So if you use the font file “EXT:myext/fonts/arial.ttf” or “t3lib/fonts/arial.ttf” both of them will match with this configuration.
 
The key:

The value of the array key will be the key used when forcing the configuration into “splitRendering” configuration of the individual GIFBUILDER objects. In the example below the key is “123”.
Notice; If the key is already found in the local GIFBUILDER configuration the content of that key is respected and not overridden. Thus you can make local configurations which override the global setting.
 
Example:

_GIFBUILDER.charRangeMap {
   123 = arial.ttf
....\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:21:\"[array].charMapConfig\";s:8:\"datatype\";s:43:\"TEXT / splitRendering.[array] configuration\";s:11:\"description\";s:879:\"splitRendering configuration to set. See GIFBUILDER TEXT object for details.
 
Example:

 
_GIFBUILDER.charRangeMap {
   123 = arial.ttf
   123 {
     charMapConfig {
       fontFile = t3lib/fonts/vera.ttf

       value = -65

       fontSize = 45

     }

     fontSizeMultiplicator = 2.3
   }
}
 
This example configuration shows that GIFBUILDER TEXT objects with font faces matching “arial.ttf” will have a splitConfiguration that uses “t3lib/fonts/vera.ttf” for all characters that fall below/equal to 65 in Unicode value.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:29:\"[array].fontSizeMultiplicator\";s:8:\"datatype\";s:6:\"double\";s:11:\"description\";s:193:\"If set, this will take the font size of the TEXT GIFBUILDER object and multiply with this amount (xx.xx) and override the “fontSize” property inside “charMapConfig”.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:29:\"[array].pixelSpaceFontSizeRef\";s:8:\"datatype\";s:6:\"double\";s:11:\"description\";s:1377:\"If set, this will multiply the four [x/y]Space[Before/After] properties of split rendering with the relationship between the fontsize and this value.
In other words; Since pixel space may vary depending on the font size used you can simply specify by this value at what fontsize the pixel space settings are optimized and for other fontsizes this will automatically be adjusted according to this font size.
 
Example:

_GIFBUILDER.charRangeMap {
   123 = arial.ttf
   123 {
     charMapConfig {
       fontFile = t3lib/fonts/vera.ttf
       value = 48-57
       color = green
       xSpaceBefore = 3
       xSpaceAfter = 3

     }
     pixelSpaceFontSizeRef = 24
   }
}
 
In this example xSpaceBefore and xSpaceAfter will be “3” when the font size is 24. If this configuration is used on a GIFBUILDER TEXT object where the font size is only 16 the spacing values will be corrected by “16/24”, effectively reducing the pixelspace to “2” in that case.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(88,7389802,'07c97ef7ff913a09f3d43365e693254c','','tsref:->GIFBUILDER','a:1:{s:4:\"rows\";a:12:{i:0;a:6:{s:8:\"property\";s:10:\"1,2,3,4...\";s:8:\"datatype\";s:32:\"GifBuilderObj
+ .if (->if)\";s:11:\"description\";s:205:\".if (->if) is a property of all gifbuilder-objects. If the property is present and NOT set, the object is NOT rendered! This corresponds to the functionallity of ".if" of the stdWrap-function.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:2:\"XY\";s:8:\"datatype\";s:9:\"x,y +calc\";s:11:\"description\";s:22:\"Size of the gif-file. \";s:7:\"default\";s:6:\"100,20\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:6:\"format\";s:8:\"datatype\";s:33:\""gif" / "jpg"\";s:11:\"description\";s:61:\"Output type.
"jpg"/"jpeg" = jpg-image\";s:7:\"default\";s:3:\"gif\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:12:\"reduceColors\";s:8:\"datatype\";s:14:\"posint (1-255)\";s:11:\"description\";s:41:\"Reduce the number of colors (if gif-file)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:21:\"transparentBackground\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:287:\"Set this flag to render the background transparent. TYPO3 makes the color found at position 0,0 of the image (upper left corner) transparent.
If you render text you should leave the niceText option OFF as the result with probably be more precise without the niceText antialiasing hack\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:16:\"transparentColor\";s:8:\"datatype\";s:31:\" HTMLColor /stdWrap\";s:11:\"description\";s:451:\"Specify a color that should be transparent
 
Example-values:

#ffffcc
red
255,255,127
 
Option:

transparentColor.closest = 1
This will allow for the closest color to be matched instead. You may need this if you image is not garanteed "clean".
 
 NOTE: You may experience that this doesn't work if you use reduceColors-option or render text with niceText-option.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:7:\"quality\";s:8:\"datatype\";s:15:\"posint (10-100)\";s:11:\"description\";s:51:\"JPG-quality (if “.format” = jpg/jpeg)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:9:\"backColor\";s:8:\"datatype\";s:25:\"GraphicColor
/stdWrap\";s:11:\"description\";s:28:\"Background color for the gif\";s:7:\"default\";s:5:\"white\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:6:\"offset\";s:8:\"datatype\";s:9:\"x,y +calc\";s:11:\"description\";s:30:\"Offset all objects on the gif.\";s:7:\"default\";s:3:\"0,0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:8:\"workArea\";s:8:\"datatype\";s:14:\"x,y,w,h + calc\";s:11:\"description\";s:253:\"Define the workarea on the giffile. All the GifBuilderObj's will see this as the dimensions of the gif-file regarding alignment, overlaying of images an so on. Only will TEXT-objects exceeding the boundaries of the workarea print outside this area.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:8:\"maxWidth\";s:8:\"datatype\";s:6:\"pixels\";s:11:\"description\";s:25:\"Maximal width of gif-file\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:9:\"maxHeight\";s:8:\"datatype\";s:6:\"pixels\";s:11:\"description\";s:26:\"Maximal heigth of gif-file\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(89,7389802,'39e45fa8cdd66301847431223c33177b','','tsref:->GIFBUILDER.(GBObj).TEXT','a:1:{s:4:\"rows\";a:22:{i:0;a:6:{s:8:\"property\";s:4:\"text\";s:8:\"datatype\";s:7:\"stdWrap\";s:11:\"description\";s:220:\"This is text text-string on the gif-file. The item is rendered only if this string is not empty.
The cObj->data-array is loaded with the page-record, if for example the GIFBUILDER-object is used by GMENU or IMGMENU\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:13:\"textMaxLength\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:115:\"The maximum length of the text. This is just a natural break that prevents incidental rendering of very long texts!\";s:7:\"default\";s:3:\"100\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:8:\"maxWidth\";s:8:\"datatype\";s:6:\"pixels\";s:11:\"description\";s:261:\"Sets the maximum width in pixels, the text must be. Reduces the fontSize if the text does not fit within this width.
 
Does not support setting alternative fontSizes in splitRendering options.
 
(By Rene Fritz <r.fritz@colorcube.de>)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:14:\"doNotStripHTML\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:104:\"If set, HTML-tags in the string inserted are NOT removed. Any other way HTML-code is removed by default!\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:8:\"fontSize\";s:8:\"datatype\";s:6:\"posint\";s:11:\"description\";s:9:\"Font size\";s:7:\"default\";s:2:\"12\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:9:\"fontColor\";s:8:\"datatype\";s:21:\"GraphicColor /stdWrap\";s:11:\"description\";s:10:\"Font color\";s:7:\"default\";s:5:\"black\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:8:\"fontFile\";s:8:\"datatype\";s:8:\"resource\";s:11:\"description\";s:42:\"Font face (truetype font you can upload!!)\";s:7:\"default\";s:20:\"Nimbus (Arial-clone)\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:5:\"angle\";s:8:\"datatype\";s:6:\"degree\";s:11:\"description\";s:116:\"Rotation degrees of the text.
 
 NOTE: Angle is not available if spacing/wordSpacing is set.\";s:7:\"default\";s:22:\"0
Range: -90 til 90\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:5:\"align\";s:8:\"datatype\";s:5:\"align\";s:11:\"description\";s:21:\"Alignment of the text\";s:7:\"default\";s:4:\"left\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:6:\"offset\";s:8:\"datatype\";s:9:\"x,y +calc\";s:11:\"description\";s:18:\"Offset of the text\";s:7:\"default\";s:3:\"0,0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:9:\"antiAlias\";s:8:\"datatype\";s:7:\"Boolean\";s:11:\"description\";s:151:\"FreeType antialiasing. Notice, the default mode is "on"!
 
 Note: This option is not available if .niceText is enabled\";s:7:\"default\";s:1:\"1\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:10:\"iterations\";s:8:\"datatype\";s:6:\"posint\";s:11:\"description\";s:191:\"How many times the text should be "printed" onto it self. This will add the effect of bold text.
 
 Note: This option is not available if .niceText is enabled\";s:7:\"default\";s:1:\"1\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:7:\"spacing\";s:8:\"datatype\";s:6:\"posint\";s:11:\"description\";s:53:\"Pixel-distance between letters. This may render ugly!\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:11:\"wordSpacing\";s:8:\"datatype\";s:6:\"posint\";s:11:\"description\";s:29:\"Pixel-distance between words.\";s:7:\"default\";s:24:\"= ".spacing"*2\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:4:\"hide\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:163:\"If this is true, the text is NOT printed.
This feature may be used if you need a shadow-object to base a shadow on the text, but do not want the text to print.\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:16:\"hideButCreateMap\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:230:\"If this option is set, the text will not be rendered. Shadows and emboss will, though, so don't apply these!! But this feature is also meant only to enable a text to generate the imageMap coordinates without rendering itself.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:6:\"emboss\";s:8:\"datatype\";s:24:\"GifBuilderObj->EMBOSS\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:6:\"shadow\";s:8:\"datatype\";s:24:\"GifBuilderObj->SHADOW\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:7:\"outline\";s:8:\"datatype\";s:25:\"GifBuilderObj->OUTLINE\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:19;a:6:{s:8:\"property\";s:6:\"imgMap\";s:8:\"datatype\";s:111:\"->IMGMAP
 
->stdWrap properties for "altText" and "titleText" in this case\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:20;a:6:{s:8:\"property\";s:8:\"niceText\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:1004:\"This is a very popular feature that helps to render small letters much nicer than the freetype library can normally do. But it also loads the system very much!
The principle of this function is to create a black/white giffile in twice or more times the size of the actual gif-file and then print the text onto this is a scaled dimension. Afterwards ImageMagick (IM) scales down the mask and masks the font color down on the original gif-file through the temporary mask.
The fact that the font is actually rendered in the double size and scaled down adds a more homogenous shape to the lettes. Some fonts are more critical than others though. If you do not need the quality, then don't use the function.
 
Some properties:

.before = IM-params before scale
.after = IM-params after scale
.sharpen = sharpen-value for the mask (after scaling), integer 0-99 (this enables you to make the text crisper if it's too blurred!)
.scaleFactor = scaling-factor, int 2-5\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:21;a:6:{s:8:\"property\";s:80:\"splitRendering.compX
splitRendering.compY
splitRendering.[array]
 \";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:2838:\"Split the rendering of a string into separate processes with individual configurations. By this method a certain range of characters can be rendered with another font face or size. This is very useful if you want to use separate fonts for strings where you have latin characters combined with eg. Japanese and there is a separate font file for each.
You can also render keywords in another font/size/color.
 
Properties:

splitRendering.compX = Additional pixelspace between parts, x direction
splitRendering.compY = Additional pixelspace between parts, y direction
splitRendering.[array] = [charRange, highlightWord]
splitRendering.[array] {
   fontFile = Alternative font file for this rendering
   fontSize = Alternative font size for this rendering
   color = Alternative color for this rendering, works ONLY without “niceText”
   xSpaceBefore = x-Space before this part
   xSpaceAfter = x-Space after this part
   ySpaceBefore = y-Space before this part
   ySpaceAfter =
}
 
Keyword: charRange

splitRendering.[array].value = Commaseparated list of character ranges (eg. “100-200”) given as Unicode character numbers. The list accepts optional starting and ending points, eg. “ - 200” or “ 200 -” and single values, eg. “65, 66, 67”
 
Keyword: highlightWord

splitRendering.[array].value = Word to highlight, makes a case sensitive search for this.
 
Limitations:

The pixelcompensation values are not corrected for scale factor used with niceText. Basically this means that when niceText is used, these values will have only the half effect.
When word spacing is used the “highlightWord” mode doesn't work.
The color override works only without “niceText”.
 
Example:

   10.splitRendering.compX = 2
   10.splitRendering.compY = -2
   10.splitRendering.10 = charRange
   10.splitRendering.10 {
     value = 200-380 , 65, 66
     fontSize = 50
     fontFile = t3lib/fonts/nimbus.ttf
     xSpaceBefore = 30
   }
   10.splitRendering.20 = highlightWord
   10.splitRendering.20 {
     value = TheWord
     color = red
   }\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(90,7389802,'5be8c3b8974e916b9d679e1daf164057','','tsref:->GIFBUILDER.(GBObj).SHADOW','a:1:{s:4:\"rows\";a:6:{i:0;a:6:{s:8:\"property\";s:10:\"textObjNum\";s:8:\"datatype\";s:7:\"pos-int\";s:11:\"description\";s:309:\"Must point to the TEXT-object if these shadow-properties are not properties to a TEXT-object directly ("stand-alone-shadow"). Then the shadow needs to know which TEXT-object it should be a shadow of!
If - on the other hand - the shadow is a property to a text-object, this property is not needed.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:6:\"offset\";s:8:\"datatype\";s:3:\"x,y\";s:11:\"description\";s:13:\"Shadow offset\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:5:\"color\";s:8:\"datatype\";s:12:\"GraphicColor\";s:11:\"description\";s:12:\"Shadow color\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:4:\"blur\";s:8:\"datatype\";s:13:\"posint (1-99)\";s:11:\"description\";s:389:\"Blurring of the shadow. Above 40 only values of 40,50,60,70,80,90 means something.
 
 NOTE: Unfortunately the blurring capabilities of ImageMagick is not very mature in the version 4.2.9. This is addressed in the later version 5.2.0 where a gaussian blur-function is added. BUT as we do cannot use the latest ImageMagick development yet, this is not utilized so far.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:7:\"opacity\";s:8:\"datatype\";s:14:\"posint (1-100)\";s:11:\"description\";s:97:\"Opacity (transparency^-1)
100% opacity = 0% transparency). Only active with a value for blur.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:9:\"intensity\";s:8:\"datatype\";s:13:\"posint(0-100)\";s:11:\"description\";s:148:\"How "massive" the shadow is. This value can - if it has a high value combined with a blurred shadow - create a kind of soft-edged outline.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(91,7389802,'effa3a1bd581c80efddf4f9370a21358','','tsref:->GIFBUILDER.(GBObj).EMBOSS','a:1:{s:4:\"rows\";a:7:{i:0;a:6:{s:8:\"property\";s:10:\"textObjNum\";s:8:\"datatype\";s:7:\"pos-int\";s:11:\"description\";s:309:\"Must point to the TEXT-object if these shadow-properties are not properties to a TEXT-object directly ("stand-alone-shadow"). Then the shadow needs to know which TEXT-object it should be a shadow of!
If - on the other hand - the shadow is a property to a text-object, this property is not needed.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:6:\"offset\";s:8:\"datatype\";s:3:\"x,y\";s:11:\"description\";s:20:\"Offset of the emboss\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:9:\"highColor\";s:8:\"datatype\";s:12:\"GraphicColor\";s:11:\"description\";s:18:\"Upper border-color\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:8:\"lowColor\";s:8:\"datatype\";s:12:\"GraphicColor\";s:11:\"description\";s:18:\"lower border-color\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:4:\"blur\";s:8:\"datatype\";s:13:\"posint (1-99)\";s:11:\"description\";s:82:\"Blurring of the shadow. Above 40 only values of 40,50,60,70,80,90 means something.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:7:\"opacity\";s:8:\"datatype\";s:14:\"posint (1-100)\";s:11:\"description\";s:97:\"Opacity (transparency^-1)
100% opacity = 0% transparency). Only active with a value for blur.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:9:\"intensity\";s:8:\"datatype\";s:13:\"posint(0-100)\";s:11:\"description\";s:148:\"How "massive" the emboss is. This value can - if it has a high value combined with a blurred shadow - create a kind of soft-edged outline.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(92,7389802,'51a763b66d4511f3e4e5216bc300f7db','','tsref:->GIFBUILDER.(GBObj).OUTLINE','a:1:{s:4:\"rows\";a:3:{i:0;a:6:{s:8:\"property\";s:10:\"textObjNum\";s:8:\"datatype\";s:7:\"pos-int\";s:11:\"description\";s:309:\"Must point to the TEXT-object if these shadow-properties are not properties to a TEXT-object directly ("stand-alone-shadow"). Then the shadow needs to know which TEXT-object it should be a shadow of!
If - on the other hand - the shadow is a property to a text-object, this property is not needed.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:9:\"thickness\";s:8:\"datatype\";s:3:\"x,y\";s:11:\"description\";s:38:\"Thickness in each direction, range 1-2\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:5:\"color\";s:8:\"datatype\";s:12:\"GraphicColor\";s:11:\"description\";s:13:\"Outline color\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(93,7389802,'8ff83c2335d4b0a2170dbe5180c449a0','','tsref:->GIFBUILDER.(GBObj).BOX','a:1:{s:4:\"rows\";a:3:{i:0;a:6:{s:8:\"property\";s:10:\"dimensions\";s:8:\"datatype\";s:13:\"x,y,w,h +calc\";s:11:\"description\";s:164:\"Dimensions of a filled box.
x,y    is the offset.
w,h    is the dimensions. Dimensions of 1 will result in 1-pixel wide lines!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:5:\"color\";s:8:\"datatype\";s:12:\"GraphicColor\";s:11:\"description\";s:10:\"fill-color\";s:7:\"default\";s:5:\"black\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:5:\"align\";s:8:\"datatype\";s:7:\"VHalign\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(94,7389802,'2cb1f22d527579954a79b8a61bde9821','','tsref:->GIFBUILDER.(GBObj).IMAGE','a:1:{s:4:\"rows\";a:5:{i:0;a:6:{s:8:\"property\";s:4:\"file\";s:8:\"datatype\";s:11:\"imgResource\";s:11:\"description\";s:13:\"The imagefile\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:6:\"offset\";s:8:\"datatype\";s:9:\"x,y +calc\";s:11:\"description\";s:7:\"Offset \";s:7:\"default\";s:3:\"0,0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:4:\"tile\";s:8:\"datatype\";s:3:\"x,y\";s:11:\"description\";s:93:\"tile x,y times.
Maximum times is 20 each direction. If you need more, use a larger image.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:5:\"align\";s:8:\"datatype\";s:7:\"VHalign\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:4:\"mask\";s:8:\"datatype\";s:11:\"imgResource\";s:11:\"description\";s:38:\"Optional mask-image for the imagefile.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(95,7389802,'929383b3d8d54785cc1039680ff99cc1','','tsref:->GIFBUILDER.(GBObj).EFFECT','a:1:{s:4:\"rows\";a:16:{i:0;a:6:{s:8:\"property\";s:5:\"gamma\";s:8:\"datatype\";s:9:\"0.5 - 3.0\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:4:\"blur\";s:8:\"datatype\";s:4:\"1-99\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:7:\"sharpen\";s:8:\"datatype\";s:4:\"1-99\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:8:\"solarize\";s:8:\"datatype\";s:4:\"0-99\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:5:\"swirl\";s:8:\"datatype\";s:5:\"0-100\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:4:\"wave\";s:8:\"datatype\";s:15:\"ampli , length \";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:8:\"charcoal\";s:8:\"datatype\";s:5:\"0-100\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:4:\"gray\";s:8:\"datatype\";s:1:\"-\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:4:\"edge\";s:8:\"datatype\";s:4:\"0-99\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:6:\"emboss\";s:8:\"datatype\";s:1:\"-\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:4:\"flip\";s:8:\"datatype\";s:1:\"-\";s:11:\"description\";s:17:\"Vertical flipping\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:4:\"flop\";s:8:\"datatype\";s:1:\"-\";s:11:\"description\";s:19:\"Horizontal flipping\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:6:\"rotate\";s:8:\"datatype\";s:5:\"0-360\";s:11:\"description\";s:8:\"Rotation\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:6:\"colors\";s:8:\"datatype\";s:5:\"2-255\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:5:\"shear\";s:8:\"datatype\";s:8:\"-90 - 90\";s:11:\"description\";s:19:\"Horizontal shearing\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:6:\"invert\";s:8:\"datatype\";s:1:\"-\";s:11:\"description\";s:17:\"invert the colors\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(96,7389802,'2f2fcb9c4842398cd5db95ab70b149e1','','tsref:->GIFBUILDER.(GBObj).WORKAREA','a:1:{s:4:\"rows\";a:2:{i:0;a:6:{s:8:\"property\";s:3:\"set\";s:8:\"datatype\";s:14:\"x,y,w,h + calc\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:5:\"clear\";s:8:\"datatype\";s:7:\"(isset)\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(97,7389802,'5508b16c314c5d90493806f1d5ca4cf3','','tsref:->GIFBUILDER.(GBObj).CROP','a:1:{s:4:\"rows\";a:3:{i:0;a:6:{s:8:\"property\";s:9:\"backColor\";s:8:\"datatype\";s:12:\"GraphicColor\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:22:\"The original backColor\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:5:\"align\";s:8:\"datatype\";s:7:\"VHalign\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:4:\"crop\";s:8:\"datatype\";s:14:\"x,y,v,h + calc\";s:11:\"description\";s:58:\"x,y is offset of the crop-frame,
v,h is the dimensions\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(98,7389802,'ba6305e366aaa4b52244519082a733b0','','tsref:->GIFBUILDER.(GBObj).SCALE','a:1:{s:4:\"rows\";a:3:{i:0;a:6:{s:8:\"property\";s:5:\"width\";s:8:\"datatype\";s:13:\"pixels + calc\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:6:\"height\";s:8:\"datatype\";s:13:\"pixels + calc\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:6:\"params\";s:8:\"datatype\";s:17:\"ImageMagickParams\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(99,7389802,'bf3aab4abf7599f8a3e05707afd7b9fc','','tsref:->GIFBUILDER.(GBObj).ADJUST','a:1:{s:4:\"rows\";a:3:{i:0;a:6:{s:8:\"property\";s:11:\"inputLevels\";s:8:\"datatype\";s:8:\"low,high\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:12:\"outputLevels\";s:8:\"datatype\";s:9:\"low, high\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:10:\"autoLevels\";s:8:\"datatype\";s:1:\"-\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(100,7389802,'c647a6f7686f2a20dfc6fcea63b02c18','','tsref:->IMGMAP','a:1:{s:4:\"rows\";a:6:{i:0;a:6:{s:8:\"property\";s:3:\"url\";s:8:\"datatype\";s:3:\"url\";s:11:\"description\";s:11:\"url to link\";s:7:\"default\";s:47:\"For IMGMENU menu objects provided automatically\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:6:\"target\";s:8:\"datatype\";s:6:\"target\";s:11:\"description\";s:15:\"target for link\";s:7:\"default\";s:47:\"For IMGMENU menu objects provided automatically\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:6:\"noBlur\";s:8:\"datatype\";s:7:\"Boolean\";s:11:\"description\";s:192:\"Normally graphical links are "blurred" if the browser is MSIE. This removes the ugly box around a link.
If this property is set, the link is NOT blurred with "onFocus".\";s:7:\"default\";s:47:\"For IMGMENU menu objects provided automatically\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:7:\"explode\";s:8:\"datatype\";s:3:\"x,y\";s:11:\"description\";s:146:\"This "explodes" or "implodes" the image-map. Useful to let the hot area cover a little more than just the letters of the text.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:7:\"altText\";s:8:\"datatype\";s:6:\"atring\";s:11:\"description\";s:121:\"Value of the alt-attribute.
 
(Used from TEXT Gifbuilding objects, this has stdWrap properties. Otherwise not)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:9:\"titleText\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:123:\"Value of the title attribute.
 
(Used from TEXT Gifbuilding objects, this has stdWrap properties. Otherwise not)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(101,7389802,'5c576ef57f313263731885ee7eb93387','','tsref:(cObject).HMENU.(mObj)','a:1:{s:4:\"rows\";a:14:{i:0;a:6:{s:8:\"property\";s:12:\"sectionIndex\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:11:\"(see below)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:23:\"alternativeSortingField\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:517:\"Normally the menuitems are sorted by the fields "sorting" in the pages- and tt_content-table. Here you can enter a list of fields that is used in the SQL- "ORDER BY" statement instead.
 
Examples (for "pages" table):

alternativeSortingField = title desc
(This will render the menu in reversed alphabetical order)
 
 LIMITATIONS:
This property works with normal menus, sectionsIndex menus and special-menus of type "directory".\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:8:\"minItems\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:212:\"The minimum items in the menu. If the number of pages does not reach this level, a dummy-page with the title "..." and uid=[currentpage_id] is inserted.
 
Takes precedence over HMENU.minItems\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:8:\"maxItems\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:108:\"The maximum items in the menu. More items will be ignored.
 
Takes precedence over HMENU.maxItems\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:5:\"begin\";s:8:\"datatype\";s:9:\"int +calc\";s:11:\"description\";s:230:\"The first item in the menu.
 
Example:

This results in a menu, where the first two items are skipped starting with item number 3:
   begin = 3
 
Takes precedence over HMENU.begin\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:8:\"JSWindow\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:441:\"If set, the links of the menu-items will open by JavaScript in a pop-up window.
 
.newWindow boolean, that lets every menuitem open in its own window opposite to opening in the same window for each click.

 
 .params is the list of parameters sent to the JavaScript open-window function, eg:
width=200,height=300,status=0,menubar=0
 
 NOTE: Does not work with JSMENU's\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:13:\"imgNamePrefix\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:76:\"prefix for the imagenames. This prefix is appended with the uid of the page.\";s:7:\"default\";s:15:\""img"\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:16:\"imgNameNotRandom\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:373:\"If set, the image names of menuitems is not randomly assigned. Usefull switch if you're manipulating these images with some external JavaScript
 
 NOTE: Don't set this if you're working with a menu with sectionIndex! In that case you need special unique names of items based on something else than the uid of the parent page of course!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:13:\"debugItemConf\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:160:\"Outputs (by the debug()-function) the configuration arrays for each menuitem. Useful to debug optionSplit things and such...
Applies to GMENU, TMENU, IMGMENU\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:10:\"overrideId\";s:8:\"datatype\";s:17:\"integer (page-id)\";s:11:\"description\";s:393:\"If set, then all links in the menu will point to this pageid. Instead the real uid of the page is sent by the parameter "&real_uid=[uid]".
This feature is smart, if you have inserted a menu from somewhere else, perhaps a shared menu, but wants the menuitems to call the same page, which then generates a proper output based on the real_uid.
Applies to GMENU, TMENU, IMGMENU\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:9:\"addParams\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:174:\"Additional parameter for the menu-links.
 
Example:

"&some_var=some%20value"
Must be rawurlencoded.
Applies to GMENU, TMENU, IMGMENU\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:25:\"showAccessRestrictedPages\";s:8:\"datatype\";s:48:\"integer (page id) / keyword “NONE”\";s:11:\"description\";s:1182:\"If set, pages in the menu will include pages with frontend user group access enabled. However the page is of course not accessible and therefore the URL in the menu will be linked to the page with the ID of this value. On that page you could put a login form or other message.
If the value is “NONE” the link will not be changed and the site will perform page-not-found handling when clicked (which can be used to capture the event and act accordingly of course).
 
Properties:

.addParam = Additional parameter for the URL, which can hold two markers; ###RETURN_URL### which will be substituted with the link the page would have had if it had been accessible and ###PAGE_ID### holding the page id of the page coming from (could be used to look up which fe_groups was required for access.
 
Example:

showAccessRestrictedPages = 22
showAccessRestrictedPages.addParams = &return_url=###RETURN_URL###&pageId=###PAGE_ID###
 
The example will link access restricted menu items to page id 22 with the return URL in the GET var “return_url” and the page id in the GET var “pageId”.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:17:\"itemArrayProcFunc\";s:8:\"datatype\";s:13:\"function-name\";s:11:\"description\";s:690:\"The first variable passed to this function is the “menuArr” array with the menuitems as they are collected based on the type of menu.
You're free to manipulate or add to this array as you like. Just remember to return the array again!
 
Note:

.parentObj property is hardcoded to be a reference to the calling tslib_menu object. Here you'll find eg. ->id to be the uid of the menu item generating a submenu and such.
 
Presetting element state

You can override element states like SPC, IFSUB, ACT, CUR or USR by setting the key ITEM_STATE in the page records. See cObject HMENU/special=userdefined for more information.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:18:\"submenuObjSuffixes\";s:8:\"datatype\";s:22:\"string
+optionSplit\";s:11:\"description\";s:1805:\"Defines a suffix for alternative sub-level menu objects. Useful to create special submenus depending on their parent menu element. See example below.
 
Example:

This example will generate a menu where the menu objects for the second level will differ depending on the number of the first level item for which the submenu is rendered. The second level objects used are “2” (the default), “2a” and “2b” (the alternatives). Which of them is used is defined by “1.submenuObjSuffixes” which has the configuration “a |*| |*| b”. This configuration means that the first menu element will use configuration “2a” and the last will use “2b” while anything in between will use “2” (no suffix applied)
 
page.200 = HMENU
page.200 {
   1 = TMENU
   1.wrap = <div style="width:200px; border: 1px solid;">|</div>
   1.expAll = 1
   1.submenuObjSuffixes = a |*| |*| b
   1.NO.allWrap = <b>|</b><br/>
 
   2 = TMENU
   2.NO.allWrap = <div style="background:red;">|</div>
 
   2a = TMENU
   2a.NO.allWrap = <div style="background:yellow;">|</div>
 
   2b = TMENU
   2b.NO.allWrap = <div style="background:green;">|</div>
}
 
The result can be seen in the image below (applied on the testsite package):
 
 
 
Applies to GMENU, TMENU, GMENU_LAYERS, TMENU_LAYERS and GMENU_FOLDOUT on >= 2nd level in a menu.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(102,7389802,'2c8d1fb6db707d441cd5769786710a19','','tsref:(cObject).HMENU.(mObj_itemStates)','a:1:{s:4:\"rows\";a:10:{i:0;a:6:{s:8:\"property\";s:2:\"NO\";s:8:\"datatype\";s:18:\"Boolean / (config)\";s:11:\"description\";s:524:\"The default “Normal” state rendering of Item. This is required for all menus.
If you specify properties for the “NO” property you do not have to set it “1”. Otherwise with no properties setting “NO=1” will render the menu anyways (for TMENU this may make sense).
 
The simplest menu TYPO3 can generate is then:
 
page.20 = HMENU
page.20.1 = TMENU
page.20.1.NO = 1
 
That will be pure <a> tags wrapped around page titles.\";s:7:\"default\";s:1:\"1\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:16:\"IFSUB
IFSUBRO\";s:8:\"datatype\";s:18:\"Boolean / (config)\";s:11:\"description\";s:54:\"Enable/Configuration for menu items which has subpages\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:12:\"ACT
ACTRO\";s:8:\"datatype\";s:18:\"Boolean / (config)\";s:11:\"description\";s:67:\"Enable/Configuration for menu items which are found in the rootLine\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:22:\"ACTIFSUB
ACTIFSUBRO\";s:8:\"datatype\";s:18:\"Boolean / (config)\";s:11:\"description\";s:84:\"Enable/Configuration for menu items which are found in the rootLine and has subpages\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:12:\"CUR
CURRO\";s:8:\"datatype\";s:18:\"Boolean / (config)\";s:11:\"description\";s:69:\"Enable/Configuration for a menu item if the item is the current page.\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:22:\"CURIFSUB
CURIFSUBRO\";s:8:\"datatype\";s:18:\"Boolean / (config)\";s:11:\"description\";s:86:\"Enable/Configuration for a menu item if the item is the current page and has subpages.\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:12:\"USR
USRRO\";s:8:\"datatype\";s:18:\"Boolean / (config)\";s:11:\"description\";s:96:\"Enable/Configuration for menu items which are access restricted pages that a user has access to.\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:3:\"SPC\";s:8:\"datatype\";s:18:\"Boolean / (config)\";s:11:\"description\";s:295:\"Enable/Configuration for 'Spacer' pages.
Spacers are pages of the doktype "Spacer". These are not viewable pages but "placeholders" which can be used to divide menuitems.
 
 Note: Rollovers doesn't work with spacers, if you use GMENU!\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:22:\"USERDEF1
USERDEF1RO\";s:8:\"datatype\";s:18:\"Boolean / (config)\";s:11:\"description\";s:280:\"Userdefined, see .itemArrayProcFunc for details on how to use this.
You can set the ITEM_STATE values USERDEF1 and USERDEF2 (+...RO) from a script/userfunction processing the menu item array. See HMENU/special=userdefined or the property .itemArrayProcFunc of the menu objects.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:22:\"USERDEF2
USERDEF2RO\";s:8:\"datatype\";s:18:\"Boolean / (config)\";s:11:\"description\";s:11:\"(See above)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(103,7389802,'397a0804fc8ada0e121f0a17e8bf8dd4','','tsref:(cObject).HMENU.(mObj).GMENU','a:1:{s:4:\"rows\";a:21:{i:0;a:6:{s:8:\"property\";s:2:\"RO\";s:8:\"datatype\";s:7:\"Boolean\";s:11:\"description\";s:159:\"RollOver configuration enabled / disabled.
If this is true, RO becomes a GIFBUILDER-object defining the layout of the menuitem when the mouse rolls over it\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:6:\"expAll\";s:8:\"datatype\";s:7:\"Boolean\";s:11:\"description\";s:252:\"If this is true, the menu will always show the menu on the level underneath the menuitem. This corresponds to a situation where a user has clicked a menuitem and the menu folds out the next level. This can enable that to happen on all items as default.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:8:\"collapse\";s:8:\"datatype\";s:7:\"Boolean\";s:11:\"description\";s:116:\"If set, "active" menuitems that has expanded the next level on the menu will now collapse that menu again.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:9:\"accessKey\";s:8:\"datatype\";s:7:\"Boolean\";s:11:\"description\";s:44:\"If set access-keys are set on the menu-links\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:6:\"noBlur\";s:8:\"datatype\";s:7:\"Boolean\";s:11:\"description\";s:222:\"Normally graphical links are "blurred" if the browser is MSIE. Blurring removes the ugly box around a clicked link.
If this property is set, the link is NOT blurred (browser-default) with "onFocus".\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:6:\"target\";s:8:\"datatype\";s:6:\"target\";s:11:\"description\";s:23:\"Target of the menulinks\";s:7:\"default\";s:4:\"self\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:14:\"forceTypeValue\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:151:\"If set, the &type parameter of the link is forced to this value regardless of target. Overrides the global equivalent in 'config' if set.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:328:\"Wraps the whole item using stdWrap
 
Example:

2 = TMENU
2 {
   stdWrap.dataWrap = <ul class=”{register :
      parentProperty}”> | </ul>
   NO {
     ...
   }
}\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:43:\"Wraps only if there were items in the menu!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:11:\"applyTotalH\";s:8:\"datatype\";s:20:\"objNumsList (offset)\";s:11:\"description\";s:498:\"This adds the total height of the previously generated menuitems to the offset of the GifBuilderObj's mentioned in this list.
 
Example:

This is useful it you want to create a menu with individual items but a common background image that extends to the whole area behind the menu. Then you should setup the background image in each GIFBUILDER-object and include the object-number in this list.
Look at the implementation in static_template "styles.gmenu.bug"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:11:\"applyTotalW\";s:8:\"datatype\";s:20:\"objNumsList (offset)\";s:11:\"description\";s:129:\"This adds the total width of the previously generated menuitems to the offset of the GifBuilderObj's mentioned in this list.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:3:\"min\";s:8:\"datatype\";s:13:\"x,y (calcInt)\";s:11:\"description\";s:54:\"Forces the menu as a whole to these minimum dimensions\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:3:\"max\";s:8:\"datatype\";s:13:\"x,y (calcInt)\";s:11:\"description\";s:54:\"Forces the menu as a whole to these maximum dimensions\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:15:\"useLargestItemX\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:81:\"If set, then the width of all menuitems will be equal to the largest of them all.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:15:\"useLargestItemY\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:82:\"If set, then the height of all menuitems will be equal to the largest of them all.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:11:\"distributeX\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:219:\"If set, the total width of all the menuitems will be equal to this number of pixels by adding/subtracting an equal amount of pixels to each menu items width.
Will overrule any setting for ".useLargestItemX"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:11:\"distributeY\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:221:\"If set, the total height of all the menuitems will be equal to this number of pixels by adding/subtracting an equal amount of pixels to each menu items height.
Will overrule any setting for ".useLargestItemY"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:20:\"removeObjectsOfDummy\";s:8:\"datatype\";s:11:\"objNumsList\";s:11:\"description\";s:259:\"If the menu is forced to a certain minimum dimension, this is a list of objects in the gifbuilder-object that is removed for this last item. This is important to do if the menuitems has elements that should only be applied if the item is actually a menuitem!!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:14:\"disableAltText\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:116:\"If set, the alt-parameter of the images are not set. You can do it manually by “imgParams” (see below)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:19;a:6:{s:8:\"property\";s:9:\"IProcFunc\";s:8:\"datatype\";s:13:\"function-name\";s:11:\"description\";s:339:\"The internal array “I” is passed to this function and expected returned as well. Subsequent to this function call the menu item is compiled by implode()'ing the array $I[parts] in the passed array. Thus you may modify this if you need to.
See example on the testsite and in media/scripts/example_itemArrayProcFunc.php\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:20;a:6:{s:8:\"property\";s:73:\"[Common Item States, see above]
+ rollover version for all, except SPC\";s:8:\"datatype\";s:59:\"->GIFBUILDER
+ Additional properties! See table below\";s:11:\"description\";s:572:\"This is the GIFBUILDER-options for each category of menuitem that can be generated.
 
 NOTE: For the GMENU series you can also define the RollOver configuration for the item states. This means that you define the GIFBUILDER object for the 'Active' state by ACT and the RollOver GIFBUILDER object for the 'Active' state by ACTRO.
This pattern goes for ALL the states except the SPC state.
 
SPECIAL:

The ->OptionSplit function is run on the whole GIFBUILDER-configuration before the items are generated.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(104,7389802,'1bbf6acf6082debc2080c0087b00e44b','','tsref:(cObject).HMENU.(mObj).GMENU.(itemState)','a:1:{s:4:\"rows\";a:11:{i:0;a:6:{s:8:\"property\";s:6:\"noLink\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:31:\"If set, the item is NOT linked!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:9:\"imgParams\";s:8:\"datatype\";s:6:\"params\";s:11:\"description\";s:34:\"Parameters for the <img>-tag\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:9:\"altTarget\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:67:\"Alternative target which overrides the target defined for the GMENU\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:14:\"altImgResource\";s:8:\"datatype\";s:10:\"imgResouce\";s:11:\"description\";s:109:\"Defines an alternative image to use. If an image returns here, it will override any GIFBUILDER configuration.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:10:\"ATagParams\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:21:\"Additional parameters\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:9:\"ATagTitle\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:68:\"which defines the title attribute of the a-tag. (See TMENUITEM also)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:16:\"additionalParams\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:175:\"Define parameters that are added to the end of the URL. This must be code ready to insert after the last parameter.
 
For details, see typolink->additionalParams\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:21:\"Wrap of the menu item\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:7:\"allWrap\";s:8:\"datatype\";s:13:\"wrap /stdWrap\";s:11:\"description\";s:20:\"Wraps the whole item\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:16:\"subst_elementUid\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:66:\"If set, "{elementUid}" is substituted with the item uid.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:10:\"allStdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:25:\"stdWrap of the whole item\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(105,7389802,'de8dd1a479d93f1a2b3b6339f8b3bcc6','','tsref:(cObject).HMENU.(mObj).GMENU_LAYERS, (cObject).HMENU.(mObj).TMENU_LAYERS','a:1:{s:4:\"rows\";a:23:{i:0;a:6:{s:8:\"property\";s:10:\"layerStyle\";s:8:\"datatype\";s:22:\"<DIV>-tag params\";s:11:\"description\";s:176:\"Parameters for the <DIV>-layer-tags in the HTML-document. You might probably not need change this.
 
Example:

position:absolute; VISIBILITY: hidden; \";s:7:\"default\";s:39:\"position:absolute; visibility: hidden; \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:12:\"lockPosition\";s:8:\"datatype\";s:44:\""x" / "y" / ""\";s:11:\"description\";s:438:\"If this is set to "x" or "y" the menu on the layers is locked and does not follow the mouse-cursor (which it does if this is not set).
"x" or "y" defines respectively that the summed width (x) or height (y) is added to the x or y offset of the menu. That means that you should set this value to "x" if you have a horizontal GMENU_LAYERS and to "y" if you have a verical menu.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:15:\"dontFollowMouse\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:422:\"If set and lockPosition is blank (so that the menu layer follows the mouse) then the menu will NOT follow the mouse but still it will appear where the mouse cursor hit the trigger-element. Usefull if you don't know the exact positions of elements.
 
 Warning: You should not set displayActiveOnLoad for menus with this feature enabled (because the absolute position of the layer is not known).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:19:\"lockPosition_adjust\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:153:\"A number which is added to the width/height of the menuitems in order to compensate for eg. hspace or other things between the images in the GMENU_LAYERS\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:20:\"lockPosition_addSelf\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:308:\"Normally the width and height of the items (+lockPosition_adjust) are summed up after the item has been rendered. This is good if the direction of the menulayers is right- og downwards.
But if you use directionLeft/directionUp, you might want to add the width of the items before.
If so, set this flag.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:10:\"xPosOffset\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:154:\"The offset of the menu from the point where it's "activated" (if lockPosition is false) / from topleft page corner (if lockPosition is set)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:10:\"yPosOffset\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:34:\"As above, but for the y-dimension.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:9:\"topOffset\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:210:\"The offset of menuitems from top of browser. Should be set rather than defining it in the .layerStyle property. Must be set in order to use directionUp.
Used with either lockPosition=x or xPosOffset defined.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:10:\"leftOffset\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:220:\"The offset of menuitems from left border of browser. Should be set rather than defining it in the .layerStyle property. Must be set in order to use directionLeft.
Used with either lockPosition=y or yPosOffset defined.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:15:\"blankStrEqFalse\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:308:\"If set, then the properties topOffset,leftOffset, xPosOffset, yPosOffset are considered “blank” if they are really blank strings - not just “zero”. You should enable this if you wish to be able to work with zero offsets. This is typically the case if you use relative positioning.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:13:\"directionLeft\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:292:\"Set this, if you want the items to be right-aligned (pop's out towards the left).
Does not work with Opera at this time because I don't know how to make Opera read the width of each layer.
If you set the width of the menu-layers in .layerStyles this might work no matter what.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:11:\"directionUp\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:99:\"Set this, if you want the items to be bottom-aligned (pop's out upwards instead of downwards).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:13:\"setFixedWidth\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:926:\"For GMENU_LAYERS the width and heights of the element is normally known from the graphical item. For TMENU_LAYERS this cannot be known in the same way. Therefore you can use .setFixedWidth and .setFixedHeight to set these values to a number you find reasonable. Of course this may be blasted by the browsers rendering if the font gets out of proportions etc.
Alternatively you may want to use the property “relativeToTriggerItem” which will position your menu layers relative to the item you roll over. This has some drawbacks though. A middle solution is to use a menu with lockPosition set to blank and dontFollowMouse set to true. Then you need only specify either an x or y coordinate to follow and the item will appear where the mouse hits the element.
 Notice: Active if value is NOT a blank str. Setting this value to zero means that no width is calculated for the items in GMENU_LAYERS.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:14:\"setFixedHeight\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:56:\"See “setFixedWidth”. Same, but for height.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:13:\"bordersWithin\";s:8:\"datatype\";s:11:\"l,t,r,b,l,t\";s:11:\"description\";s:172:\"Keep borders of the layer within these limits in pixels. Zero is 'not set'
(Syntax: List of integers, evaluated clockwise: Left, Top, Right, Bottom, Left, Top)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:19:\"displayActiveOnLoad\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:605:\"If set, the submenu-layer of the active menuitem is opened at page-load. If .freezeMouseover is also set and there is RO defined for the main menu items, the menuitem belonging to the displayed submenu is also shown.
 
Properties:

.onlyOnLoad (boolean)
If set, then the display of the active item will happen only when the page is loaded. The display will not be restored on mouseout of other items.
 
Warning: If you are cascading GMENU_LAYER objects make sure that all elements before this element (for which you set this attribute) also has this attribute set!
\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:15:\"freezeMouseover\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:297:\"If set, any mouseout effect of main menuitems is removed not on roll-out but when another element is rolled over (or the layer is hidden/default layer restored)
 
Properties:

.alwaysKeep (boolean)
If set, the freezed element will always stay, even if the submenu is hidden.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:19:\"hideMenuWhenNotOver\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:267:\"If set (> 1) then the menu will hide it self whenever a user moves the cursor away from the menu. The value of this parameter determines the width (pixels) of the zone around the element until the mousepointer is considered to be far enough away to hide the layer.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:13:\"hideMenuTimer\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:106:\"This is the number of milliseconds to wait before the submenu will disappear if hideMenuWhenNotOver is set\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:19;a:6:{s:8:\"property\";s:17:\"dontHideOnMouseUp\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:140:\"If set, the menu will not hide it's layers when the mouse botton is clicked. Usefull if your menuitems loads the pages in another frame\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:20;a:6:{s:8:\"property\";s:13:\"layer_menu_id\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:209:\"If you want to specifically name a menu on a page. Probably you don't need that!
 
 Warning: Don't use underscore and special characters in this string. Stick to alpha-numeric.\";s:7:\"default\";s:26:\"[random 6 char hashstring]\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:21;a:6:{s:8:\"property\";s:21:\"relativeToTriggerItem\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:1246:\"This allows you to position the menu layers relative to the item that triggers it. However you should be aware of the following facts:
This does not work with Netscape 4 - the position of the trigger layer will be calculated to zero and thus the offset for all menu layers will be 0,0 + your values.
This feature will wrap the menu item in some <div>-tags right before the whole item is wrapped by the .wrap code (for GMENU_LAYERS) or .allWrap (for TMENU_LAYERS). The bottom line of this is: 1) If your menu is horizontal, always wrap your menu items in a table so linebreaks does not appear because of the <div>-tags and 2) make sure the wrapping of the table cell is done with the .wrap/.allWrap properties respectively.
Works only effectively on the first xMENU_LAYER in a cascade. For succeeding xMENU_LAYERS items please use “relativeToParentLayer”.
If set, properties xPosOffset, yPosOffset and lockPosition* are not functional (properties directionLeft, directionUp, topOffset and leftOffset are still active)

 

Additional Properties:

 .addWidth = Adds the width of the trigger element
 .addHeight = Adds the height of the trigger element\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:22;a:6:{s:8:\"property\";s:21:\"relativeToParentLayer\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:556:\"If set, then the layer will be positioned relative to the previous layer (parent) in a cascaded series of xMENU_LAYERS. Basically the relative position of the parent layer is just added to the offset of the current menu.
 
 Warning: This property makes sense only if there really is a previous GMENU_LAYER to get position from! So you must have a cascaded menu!
 
Additional Properties:

 .addWidth = Adds the width of the parent layer
 .addHeight = Adds the height of the parent layer\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(106,7389802,'cc7479b256282161af55c3137ffe98ec','','tsref:(cObject).HMENU.(mObj).GMENU_FOLDOUT','a:1:{s:4:\"rows\";a:17:{i:0;a:6:{s:8:\"property\";s:17:\"dontLinkIfSubmenu\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:110:\"If set, items that has a submenu is not linked. Items without a submenu are always linked in the regular ways.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:9:\"foldTimer\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:53:\"The timeout in the animation, these are milliseconds.\";s:7:\"default\";s:2:\"40\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:9:\"foldSpeed\";s:8:\"datatype\";s:16:\"int, range 1-100\";s:11:\"description\";s:58:\"How many steps in an animation? Choose 1 for no animation.\";s:7:\"default\";s:1:\"1\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:10:\"stayFolded\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:49:\"Stay open when you click a new toplink? (Level 1)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:12:\"bottomHeight\";s:8:\"datatype\";s:11:\"int, pixels\";s:11:\"description\";s:147:\"Sets the height of the bottom layer. Is important if the bottomlayer contains either content or a background color: Else the layer will be clipped.\";s:7:\"default\";s:3:\"100\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:9:\"menuWidth\";s:8:\"datatype\";s:11:\"int, pixels\";s:11:\"description\";s:174:\"Width of the whole menu main layer. Important to set, especially for the bottomlayer as it is clipped by this value. Always try to set this to the width in pixels of the menu\";s:7:\"default\";s:3:\"170\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:10:\"menuHeight\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:60:\"Height of the whole menulayer. Seems to be not so important.\";s:7:\"default\";s:3:\"400\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:13:\"subMenuOffset\";s:8:\"datatype\";s:3:\"x,y\";s:11:\"description\";s:159:\"Offset of the submenu for each menuitem. This is important because if you don't set this value the items will appear ontop of their “parent”\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:10:\"menuOffset\";s:8:\"datatype\";s:3:\"x,y\";s:11:\"description\";s:64:\"Offset of the menu main layer on the page. From upperleft corner\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:13:\"menuBackColor\";s:8:\"datatype\";s:10:\"HTML-color\";s:11:\"description\";s:158:\"Background color behind menu. If not set, transparent (which will not work very well in case .foldSpeed is set to something else than 1. But see for yourself)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:15:\"dontWrapInTable\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:482:\"By default every menuitem on the first level is wrapped in a table:
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0><TR><TD>
[menu item HTML here..]
</TD></TR></TABLE>
Doing this ensures that the layers renders equally in the supported browsers. However you might need to disable that which is what you can do by setting this flag.
 Note: Using <TBODY> in this tables seems to break Netscape 4+\";s:7:\"default\";s:1:\"0\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:13:\"bottomContent\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:62:\"Content for the bottom layer that covers the end of the menu. \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:12:\"adjustItemsH\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:211:\"Adjusts the height calculation of the menulayers of the first level (called Top)
 
Example:

-10
 
This value will substract 10 pixels from the height of the layer in calculations.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:15:\"adjustSubItemsH\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:104:\"Adjusts the height calculation of the menulayers of the second level (subitems, called Sub)
See above\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:19:\"arrowNO
arrowACT\";s:8:\"datatype\";s:11:\"imgResource\";s:11:\"description\";s:407:\"If both arrowNO and arrowACT is defined and valid imgResources then these images are use as “traditional arrows” that indicates whether an item is expanded (active) or not.
NO is normal, ACT is expanded
The image is inserted just before the menuitem. If you want to change the position, put the marker ###ARROW_IMAGE### into the wrap of the item and the image will be put there instead.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:14:\"arrowImgParams\";s:8:\"datatype\";s:18:\"<img> params\";s:11:\"description\";s:80:\"Parameters to the arrow-image.
 
Example:

hspace=5 vspace=7\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:19:\"displayActiveOnLoad\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:71:\"If set, then the active menu items will fold out “onLoad”\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(107,7389802,'bec5811d03462a9bb1c8e461c032d461','','tsref:(cObject).HMENU.(mObj).TMENU','a:1:{s:4:\"rows\";a:10:{i:0;a:6:{s:8:\"property\";s:6:\"expAll\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:252:\"If this is true, the menu will always show the menu on the level underneath the menuitem. This corresponds to a situation where a user has clicked a menuitem and the menu folds out the next level. This can enable that to happen on all items as default.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:8:\"collapse\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:116:\"If set, "active" menuitems that has expanded the next level on the menu will now collapse that menu again.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:9:\"accessKey\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:44:\"If set access-keys are set on the menu-links\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:6:\"noBlur\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:212:\"Normally links are "blurred" if the browser is MSIE. Blurring removes the ugly box around a clicked link.
If this property is set, the link is NOT blurred (browser-default) with "onFocus".\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:6:\"target\";s:8:\"datatype\";s:6:\"target\";s:11:\"description\";s:23:\"Target of the menulinks\";s:7:\"default\";s:4:\"self\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:14:\"forceTypeValue\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:89:\"If set, the &type parameter of the link is forced to this value regardless of target.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:87:\"Wraps the whole item using stdWrap
 
 Example: see GMENU.stdWrap\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:43:\"Wraps only if there were items in the menu!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:9:\"IProcFunc\";s:8:\"datatype\";s:13:\"function-name\";s:11:\"description\";s:339:\"The internal array “I” is passed to this function and expected returned as well. Subsequent to this function call the menu item is compiled by implode()'ing the array $I[parts] in the passed array. Thus you may modify this if you need to.
See example on the testsite and in media/scripts/example_itemArrayProcFunc.php\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:31:\"[Common Item States, see above]\";s:8:\"datatype\";s:14:\"->TMENUITEM\";s:11:\"description\";s:221:\"This is the TMENUITEM-options for each category of menuitem that can be generated.
 
SPECIAL:

The ->OptionSplit function is run on the whole GIFBUILDER-configuration before the items are generated.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(108,7389802,'6741d93da8500fc90e7237a7a0cf9479','','tsref:(cObject).HMENU.(mObj).TMENUITEM','a:1:{s:4:\"rows\";a:23:{i:0;a:6:{s:8:\"property\";s:7:\"allWrap\";s:8:\"datatype\";s:13:\"wrap /stdWrap\";s:11:\"description\";s:20:\"Wraps the whole item\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:15:\"wrapItemAndSub \";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:56:\"Wraps the whole item and any submenu concatenated to it.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:16:\"subst_elementUid\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:301:\"If set, all appearances of the string '{elementUid}' in the total element html-code (after wrapped in .allWrap} is substituted with the uid number of the menu item.
This is useful if you want to insert an identification code in the HTML in order to manipulate properties with JavaScript.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:12:\"RO_chBgColor\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:1411:\"If property RO is set (see below) then you can set this property to a certain set of parameters which will allow you to change the background color of eg. the tablecell when the mouse rolls over you text-link.
 
Syntax:

[over-color] | [out-color] | [id-prefix]
 
Example:

page = PAGE
page.typeNum = 0
page.10 = HMENU
page.10.wrap = <table border=1>|</table>
page.10.1 = TMENU
page.10.1.NO {
   allWrap = <tr><td valign=top id="1tmenu{elementUid}" style="background:#eeeeee;">|</td></tr>
   subst_elementUid = 1
   RO_chBgColor = #cccccc | #eeeeee | 1tmenu
   RO = 1
}
 
This example will start out with the table cells in #eeeeee and change them to #cccccc (and back) when rolled over. The “1tmenu” string is a unique id for the menu items. You may not need it (unless the same menu items are more than once on a page), but the important thing is that the id of the table cell has the exact same label before the {elementUid} (red marks). The other important thing is that you DO set a default background color for the cell with the style-attribute (blue marking). If you do not, Mozilla browsers will behave a little strange by not capturing the mouseout event the first time it's triggered. \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:6:\"before\";s:8:\"datatype\";s:13:\"HTML /stdWrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:9:\"beforeImg\";s:8:\"datatype\";s:11:\"imgResource\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:18:\"beforeImgTagParams\";s:8:\"datatype\";s:18:\"<img>-params\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:13:\"beforeImgLink\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:68:\"If set, this image is linked with the same <A> tag as the text\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:11:\"beforeROImg\";s:8:\"datatype\";s:11:\"imgResource\";s:11:\"description\";s:99:\"If set, ".beforeImg" and ".beforeROImg" is expected to create a rollOver-pair. \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:10:\"beforeWrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:40:\"wrap around the ".before"-code\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:8:\"linkWrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:7:\"stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:26:\"stdWrap to the link-text! \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:14:\"ATagBeforeWrap\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:10:\"ATagParams\";s:8:\"datatype\";s:38:\" <A>-params /stdWrap\";s:11:\"description\";s:81:\"Additional parameters
 
Example:

class=”board”\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:9:\"ATagTitle\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:280:\"Allows you to specify the "title" attribute of the <a> tag around the menu item.
 
Example:

ATagTitle.field = abstract // description
 
This would use the abstract or description field for the <a title=""> attribute.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:16:\"additionalParams\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:175:\"Define parameters that are added to the end of the URL. This must be code ready to insert after the last parameter.
 
For details, see typolink->additionalParams\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:11:\"doNotLinkIt\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:43:\"if set, the linktext are not linked at all!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:13:\"doNotShowLink\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:62:\"if set, the text will not be shown at all (smart with spacers)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:8:\"stdWrap2\";s:8:\"datatype\";s:13:\"wrap /stdWrap\";s:11:\"description\";s:127:\"stdWrap to the total link-text and ATag. (Notice that the plain default value passed to stdWrap function is “|“.)\";s:7:\"default\";s:8:\" | \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:19;a:6:{s:8:\"property\";s:2:\"RO\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:41:\"if set, rollOver is enabled for this link\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:20;a:6:{s:8:\"property\";s:8:\"after...\";s:8:\"datatype\";s:7:\"[mixed]\";s:11:\"description\";s:233:\"The series of “before...” properties are duplicated to “after...” properties as well. The only difference is that the output generated by the .after.... properties are placed after the link and not before.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:21;a:6:{s:8:\"property\";s:9:\"altTarget\";s:8:\"datatype\";s:6:\"target\";s:11:\"description\";s:70:\"Alternative target overriding the target property of the TMENU if set.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:22;a:6:{s:8:\"property\";s:10:\"allStdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:25:\"stdWrap of the whole item\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(109,7389802,'0ab0ced808e0b089231bd8b12ab07fca','','tsref:(cObject).HMENU.(mObj).IMGMENU','a:1:{s:4:\"rows\";a:10:{i:0;a:6:{s:8:\"property\";s:6:\"target\";s:8:\"datatype\";s:6:\"target\";s:11:\"description\";s:23:\"Target of the menulinks\";s:7:\"default\";s:4:\"self\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:14:\"forceTypeValue\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:89:\"If set, the &type parameter of the link is forced to this value regardless of target.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:6:\"noBlur\";s:8:\"datatype\";s:7:\"Boolean\";s:11:\"description\";s:222:\"Normally graphical links are "blurred" if the browser is MSIE. Blurring removes the ugly box around a clicked link.
If this property is set, the link is NOT blurred (browser-default) with "onFocus".\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:6:\"params\";s:8:\"datatype\";s:18:\"<img>-params\";s:11:\"description\";s:6:\" \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:4:\"main\";s:8:\"datatype\";s:15:\"->GIFBUILDER\";s:11:\"description\";s:75:\"Main configuration of the image-map! This defines the "underlay"!\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:9:\"dWorkArea\";s:8:\"datatype\";s:13:\"offset + calc\";s:11:\"description\";s:78:\"Main offset of the GIFBUILDER-items (also called the "distribution")\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:31:\"[Common Item States, see above]\";s:8:\"datatype\";s:30:\"->IMGMENUITEM
+ .distrib\";s:11:\"description\";s:1359:\"This is the TMENUITEM-options for each category of menuitem that can be generated.
 
SPECIAL:

The ->OptionSplit function is run on the whole GIFBUILDER-configuration before the items are generated.
 
 .distrib is (x,y,v,h +calc) of the distribution of the menuitems. This provides a way to space each item from the other. The codes "textX" and "textY" can be used for the width (X) and height (Y) dimension of each link.
This works by adding a WORKAREA-GifBuilderObj between each of the IMGMENUITEM ("subset" of a GIFBUILDER-object) and this workarea defines where the text should be printed. As such the "x,y" defines the offset the next item will have (this should be the width of the previous in many cases!) and "v,h" defines the dimensions of the current item.
Consider this example taken from the static_template "template: MM":
     NO.distrib = textX+10, 0, textX+10, textY+5
In the future TypoScript may provide better ways to position GIFBUILDER-objects on the image-maps!
 
 ImgMap is automatically used on the links! (that is the ".imgMap" property of the text-objects in the GIFBUILDER-objects is set automatically, unless is allready set.)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:12:\"imgMapExtras\";s:8:\"datatype\";s:20:\"<area...>-tags\";s:11:\"description\";s:43:\"Extra <area...>tags for the image-map\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:21:\"debugRenumberedObject\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:104:\"if set, the final GIFBUILDER object configuration is output in order for you to debug your configuration\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(110,7389802,'cdccc471d5b78c74bb04998ced50107c','','tsref:(cObject).HMENU.(mObj).IMGMENUITEM','a:1:{s:4:\"rows\";a:1:{i:0;a:6:{s:8:\"property\";s:10:\"1,2,3,4...\";s:8:\"datatype\";s:18:\"->GifBuilderObj\";s:11:\"description\";s:2298:\"NOTE:
The way a imagemap is made is this; All IMGMENUITEMS are included in one big Gifbuilderobj (and renumbered!!). Because of this, Gifbuilderobjects on the next level will not be able to access the data of each menuitem.
Also the feature of using [##.w] and [##.h] with +calc is currently not supported by IMGMENUITEMs.
Therefore all IMAGE-objects on the first level is checked; if "file" or "mask" for any IMAGE-objects are set to "GIFBUILDER", the Gifbuilder-object is parsed to see if any TEXT-objects are present and if so, the TEXT-object is "checked" - which means, that the stdWrap-function is called at a time where the $cObj->data-array is set to the actual menuitem.
In the example below, the text of each menuitem is rendered by letting the title be rendered on a mask instead of directly on the image. Please observe that the "NO.10"-object is present in order for the image-map coordinates to be generated!!
 
   NO.6 = IMAGE
   NO.6.file = masked_pencolor*.gif
   NO.6.mask = GIFBUILDER
   NO.6.mask {
     XY = 500, 200
     backColor = black
     10 = TEXT
     10 {
       text.field = title
       fontFile = fileadmin/fonts/caflisch.ttf
       fontSize = 34
       fontColor = white
       angle = 15
       offset = 48,110
     }
     20 = EFFECT
     20.value = blur=80
   }
   NO.10 = TEXT
   NO.10 {
     text.field = title
     fontFile = fileadmin/fonts/caflisch.ttf
     fontSize = 34
     angle = 15
     offset = 48,110
     hideButCreateMap = 1
   }\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(111,7389802,'2cdd9060dcb2633b93d2a58448f1323e','','tsref:(cObject).HMENU.(mObj).JSMENU','a:1:{s:4:\"rows\";a:9:{i:0;a:6:{s:8:\"property\";s:6:\"levels\";s:8:\"datatype\";s:8:\"int, 1-5\";s:11:\"description\";s:25:\"How many levels there are\";s:7:\"default\";s:1:\"1\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:8:\"menuName\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:111:\"JavaScript menu name.
If you have more than one JSMENU on the page, you should set this value for each one.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:6:\"target\";s:8:\"datatype\";s:6:\"target\";s:11:\"description\";s:32:\"Decides target of the menu-links\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:14:\"forceTypeValue\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:89:\"If set, the &type parameter of the link is forced to this value regardless of target.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:10:\"1,2,3,4...\";s:8:\"datatype\";s:10:\"JSMENUITEM\";s:11:\"description\";s:13:\"levels-config\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:30:\"wrap around the selector-boxes\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:13:\"wrapAfterTags\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:66:\"wrap around the selector-boxes with wrap and form-tags og JS-code.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:17:\"firstLabelGeneral\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:71:\"General firstlabel. May be overridden by the one set in each JSMENUITEM\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:3:\"SPC\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:46:\"If set, spacer can go into the menu, else not.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(112,7389802,'52b4fd3e8e7b15fb48cd362b5fc056cd','','tsref:(cObject).HMENU.(mObj).JSMENUITEM','a:1:{s:4:\"rows\";a:9:{i:0;a:6:{s:8:\"property\";s:6:\"noLink\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:407:\"Normally the selection of a menu item in the selector box will update the selector on the next level (if there is a next level) and if there are no items for that selector (because there were no subpages), then the link jumps to the page of itself.
If this flag is set, however, no menuitems in the selector box will ever link to anything. Only update the content of the next selector box on next level.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:10:\"alwaysLink\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:100:\"If set an item in the menu selector will always link. This takes precedence over "noLink".\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:10:\"showFi rst\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:62:\"if set, the first link will be shown when the menu is updated.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:10:\"showActive\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:53:\"if set, the active level will be selected, if present\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:4:\"wrap\";s:8:\"datatype\";s:4:\"wrap\";s:11:\"description\";s:21:\"wraps the selectorbox\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:5:\"width\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:61:\"Initial width of the boxes set by a number of _ (underscores)\";s:7:\"default\";s:2:\"14\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:8:\"elements\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:98:\"Initial number of elements in the menu. This is of course overruled by the actual menu item texts.\";s:7:\"default\";s:1:\"5\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:16:\"additionalParams\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:145:\"Additional parameters to the <select> box. Eg, you could set the width with a style-parameter like this:
style="width: 200px;"\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:10:\"firstLabel\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:48:\"Firt label in top of the menu (default is blank)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(113,7389802,'d5d05a1da766c8752918259cd571b75f','','tsref:(script).fe_adminLib','a:1:{s:4:\"rows\";a:31:{i:0;a:6:{s:8:\"property\";s:12:\"templateFile\";s:8:\"datatype\";s:8:\"resource\";s:11:\"description\";s:67:\"The template file, see examples in media/scripts/fe_user_admin.tmpl\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:15:\"templateContent\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:78:\"Alternatively you can set this property directly to the value of the template.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:5:\"table\";s:8:\"datatype\";s:9:\"tablename\";s:11:\"description\";s:289:\"The table to edit.
Notice: The ultimate lsit of fields allowed to be edited for the table is defined in TCA with the key ["feInterface"]["fe_admin_fieldList"] for each table in question. For an example, see the table definition for fe_users which is a good example.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:10:\"defaultCmd\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:86:\"Defines which action should be default (if &cmd= is not set when calling the page)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:17:\"clearCacheOfPages\";s:8:\"datatype\";s:25:\"[list of integers]\";s:11:\"description\";s:114:\"This is a list of page-ids for which to clear the cache on any successfull operation be it EDIT, CREATE og DELETE.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:5:\"debug\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:86:\"If set, debug information will be output from fe_adminLib which helps to track errors.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:15:\"Actions:\";s:8:\"datatype\";N;s:11:\"description\";N;s:7:\"default\";N;s:12:\"column_count\";i:1;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:5:\"edit \";s:8:\"datatype\";s:21:\"boolean /actionObject\";s:11:\"description\";s:1880:\"If set, editing is basically allowed.
But you need to specify:
 
 .fields (list of fieldnames) which determines the fields allowed for editing. Every field in this list must be found as well in the ["feInterface"]["fe_admin_fieldList"] found in the TCA array which ultimately determines which fields can be edited by the fe_adminLib.
 

 .overrideValues.[fieldname] (value string) defines values for specific fields which will override ANY input from the form. Overriding values happens after the outside values has been parsed by the .parseValues-property of fe_adminLib but before the evaluation by .required and .evalValues below. For example this may be useful if you wish to hide a record which is being edited, because you want to preview it first.
 

 .required (list of fieldnames, subset of .fields) which determines which fields are required to return a true value. The valid fields entered here will have the subpart ###SUB_REQUIRED_FIELD_[fieldname]### removed from the templates if they evaluates to being true and thereby OK. See below for information about this subpart.
 

 .evalValues.[fieldname] (list of eval-codes) defines specific evaluation forms for the individual fiels of the form. See below.
 

 .preview (boolean) will enable the form submitted to be previewed first. This requires a template for preview to be found in the template file. See below for subpart marker names.
 

 .menuLockPid (boolean will force the menu of editable items to be locked to the .pid (edit only)
 

 .userFunc_afterSave (function-name) is called after the record is saved. The content passed is an array with the current (and previous) record in.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:7:\"create \";s:8:\"datatype\";s:21:\"boolean /actionObject\";s:11:\"description\";s:443:\"The same as .edit above except where otherwise stated.
Plus there is these additional properties:
 

 .noSpecialLoginForm (boolean) - if set, fe_adminLib does NOT look for the subpart marker TEMPLATE_CREATE_LOGIN but always for TEMPLATE_CREATE
 

 .defaultValues.[fieldname] (value string); Like .overrideValues but this sets the default values the first time the form is displayed.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:6:\"delete\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:218:\"Whether or not records may be deleted. Still regular authentication (ownership or email authCode) is required. Setting the var “preview” lets you make a delete-preview before actually deleting the record.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:8:\"infomail\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:374:\"Infomails are plaintext mails based on templates found in the template file. They may be used for such as sending a forgotten password to a user, but what goes into the infomail is totally up to your design of the template.
Normally you may have only a default infomail (infomail.default) for instance for sending the password. But you can use other keys also. See below.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:14:\"infomail.[key]\";s:8:\"datatype\";s:38:\"(configuration of infomail properties)\";s:11:\"description\";s:619:\"In order to make fe_adminLib send an infomail, you must specify these vars in your GET vars or HTML-form.
 
 fetch - if integer, it searches for the uid being the value of 'fetch'. If not, it searches for the email-field (defined by a property of fe_adminLib, see below).
 
 key - points to the infomail.[key] configuration to use
 

Properties:

 .dontLockPid (boolean) - selects only records from the .pid of fe_adminLib.
 .label (string) - The suffix for the markers, see 'Email Markers' beneath.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:8:\"setfixed\";s:8:\"datatype\";s:19:\"boolean /properties\";s:11:\"description\";s:3167:\"Allows set-fixed input, probably coming from a link in an infomail or notification mail.
Syntax:

 
 .[fixkey].[fieldname] = fieldvalue - is used to setup a setfixed-link insertable in the infomail by the SYS_SETFIXED_*-markers. See above (setfixed-property of fe_adminLib).
Special fixkey 'DELETE' is just a boolean.
 
 .userFunc_afterSave (function-name) is called after the record is saved. The content passed is an array with the current (and previous) record in.
 
Concept:

The 'setfixed' concept is best explained by describing a typical scenario - in fact the most common situation of its use:
Imagine you have some users submitting information on your website. But before that information enters the database, you would like to moderate it - simply preview it and then either delete it or approve it. In the 'create' configuration of fe_adminLib, you set up the hidden field of the record to be overridden to 1. Thus the record is hidden by default. Then you configure a setfixed-fixkey to set the hidden field to 0. This set up generates a list of parameters for use in an URL and those parameters are finally inserted by a corresponding marker in the email template. The link includes all necessary authentication to perform the change of values and thus a single click on that link is enough to change the field values. So this will - by a single click of a link in a notification mail sent to an admin - enable the record! Or of course a similar link with a cmd=delete link will delete it...
There is a special “fieldname” you can use, which is '_FIELDLIST” and that lets you specify a list of fields in the record to base the auth-code on. If nothing is specifyed the md5-hash is based on the whole record which means that any changes will disable the setfixed link. If on the other hand, you set _FIELDLIST = uid,pid then that record will be editable as long as the uid and pid values are intact.
Example:

This is a common configuration of the email-properties with a simple setfixed setting:
   email.from = kasper@typo3.com
   email.fromName = Kasper Skårhøj
   email.admin = kasper@typo3.com
   setfixed.approve {
     hidden = 0
     _FIELDLIST = uid,pid
   }
   setfixed.DELETE = 1
   setfixed.DELETE._FIELDLIST = uid
 
Now, if you insert this marker in your email template
 
   ###SYS_SETFIXED_approve###
 
if will get substituted with something like these parameters:
 
&cmd=setfixed&rU=9&fD[hidden]=0&aC=5c403d90
 
Now, all you need is to point that to the correct url (where fe_adminLib is invoked!), eg:
 
###THIS_URL######FORM_URL######SYS_SETFIXED_approve###
 
and for deletion:
 
...###SYS_SETFIXED_DELETE###\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:13:\"Others\";s:8:\"datatype\";N;s:11:\"description\";N;s:7:\"default\";N;s:12:\"column_count\";i:1;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:15:\"authcodeFields \";s:8:\"datatype\";s:23:\"[list of fields]\";s:11:\"description\";s:1352:\"Comma separated list of fields to base the authCode generation on. Basically this list would include “uid” only in most cases. If the list includes more fields, you should be aware that the authCode will change when the value of that field changes. And then the user will have to re-send an email to himself with a new code.
 
 .addKey (string) adds the string to the md5-hash of the authCode. Just enter any random string here. Point is that people from outside doesn't know this code and therefore are not able to reconstruct the md5-hash solely based on the uid
 
 .addDate (date-config) You can use this to make the code time-disabled. Say if you enter “d-m-Y” here as value, the code will work until midnight and then a new code will be valid.
 
 .codeLength (int) Defines how long the authentication code should be. Default is 8 characters.
In any case TYPO3_CONF_VARS[SYS][encryptionKey] is prepended.
 
Advice:

If you want to generate authCodes compatible with the standard authCodes (used by the direct mailer by t3lib_div::stdAuthCode()), please set TYPO3_CONF_VARS[SYS][encryptionKey] to a unique and secret key (like you should in any case) and add “uid” as authcodeField ONLY. This is secure enough.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:5:\"email\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:558:\" .from (string, email) Defines the sender email address of mails sent out
 
 .fromName (string) Defines the name of the sender. If set, this will be used on the form NAME <EMAIL>
 
.admin

 
 .field (string/integer) Defines the fieldname of the record where the email address to send to is found. If the field content happens to be an integer, this is assumed to be the uid of the fe_user owning the record and the email address of that user is fetched for the purpose instead.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:3:\"pid\";s:8:\"datatype\";s:4:\"int+\";s:11:\"description\";s:42:\"The pid in which to store/get the records.\";s:7:\"default\";s:12:\"Current page\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:14:\"fe_userOwnSelf\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:361:\"If set, fe_users created by this module has their fe_cruser_id-field set to their own uid which means they 'own' their own record and can thus edit their own data.
All other tables which has a fe_cruser_id field configured in the 'ctrl' section of their $TCA-configuration will automatically get this field set to the current fe_user id.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:15:\"fe_userEditSelf\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:102:\"If set, fe_users - regardless of whether they own themselves or not - will be allowed to edit himself.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:19;a:6:{s:8:\"property\";s:13:\"allowedGroups\";s:8:\"datatype\";s:18:\"[list of integers]\";s:11:\"description\";s:141:\"List of fe_groups uid numbers which are allowed to edit the records through this form. Normally only the owner fe_user is allowed to do that.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:20;a:6:{s:8:\"property\";s:8:\"evalFunc\";s:8:\"datatype\";s:13:\"function-name\";s:11:\"description\";s:280:\"Function by which you can manipulate the dataArray before it's saved.
The dataArray is passed to the function as $content and MUST be returned again from the function.
The property “parentObj” is a hardcoded reference to the fe_adminLib object.
 \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:21;a:6:{s:8:\"property\";s:7:\"formurl\";s:8:\"datatype\";s:13:\"->typolink\";s:11:\"description\";s:66:\"Contains typolink properties for the URL (action tag) of the form.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:22;a:6:{s:8:\"property\";s:19:\"parseValues.[field]\";s:8:\"datatype\";s:20:\"[list of parseCodes]\";s:11:\"description\";s:1510:\"ParseCodes:
 int - returns the integer value of the input
 lower - returns lowercase version of the input
 upper - returns uppercase version of the input
 nospace - strips all space
 alpha, num, alphanum, alphanum_x - only alphabetic (a-z) and/or numeric chars. alphanum_x also allows _ and -
 trim - trims whitespace in the ends of the string
 setEmptyIfAbsent - will make sure the field is set to empty if the value is not submitted. This ensures a field to be updated an is handy with checkboxes
 random[x] - Returns a random number between 0 and x
 files[semicolon-list(!) of extensions, none=all][maxsize in kb, none=no limit] - Defining the field to hold files. See below for details!
 multiple - Set this, if the input comes from a multiple-selector box (remember to add ...[] to the fieldname so the values come in an array!)
 checkArray - Set this, if you want several checkboxes to set bits in a single field. In that case you must prepend every checkbox with [x] where x is the bitnumber to set starting with zero. The default values of the checkbox form elements must be false.
 uniqueHashInt[semicolon-list(!) of other fields] - This makes a unique hash (32 bit integer) of the content in the specified fields. The values of those fields are first converted to lowercase and only alphanum chars are preserved. \";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:23;a:6:{s:8:\"property\";s:20:\"userFunc_updateArray\";s:8:\"datatype\";s:13:\"function-name\";s:11:\"description\";s:148:\"Points to a user function which will have the value-array passed to it before the value array is used to construct the update-JavaScript statements.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:24;a:6:{s:8:\"property\";s:29:\"evalErrors.[field].[evalCode]\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:165:\"This lets you specify the error messages inserted in the ###EVAL_ERROR_FIELD_[fieldname]### markers upon an evaluation error.
See description of evaluation below.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:25;a:6:{s:8:\"property\";s:22:\"cObjects.[marker_name]\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:389:\"This is cObjects you can insert by markers in the template.
 
Example:

Say, you set up a cObject like this:
 
cObject.myHeader = TEXT
cObject.myHeader.value = This is my header
 
then you can include this cObject in most of the templates through a marker named ###CE_myHeader### or ###PCE_myHeader### (see below for details on the difference).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:26;a:6:{s:8:\"property\";s:5:\"wrap1\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:225:\"Global Wrap 1. This will be splitted into the markers ###GW1B### and ###GW1E###. Don't change the input value by the settings, only wrap it in something.
 
Example:

wrap1.wrap = <b> |</B>\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:27;a:6:{s:8:\"property\";s:5:\"wrap2\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:25:\"Global Wrap 2 (see above)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:28;a:6:{s:8:\"property\";s:6:\"color1\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:43:\"Value for ###GC1### marker (Global color 1)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:29;a:6:{s:8:\"property\";s:6:\"color2\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:43:\"Value for ###GC2### marker (Global color 2)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:30;a:6:{s:8:\"property\";s:6:\"color3\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:43:\"Value for ###GC3### marker (Global color 3)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(114,7389802,'63743e1b082d6f7bcb449ddeb484466e','','tsref:(script).fe_adminLib.evalErrors.(field).(evalCode)','a:1:{s:4:\"rows\";a:8:{i:0;a:6:{s:8:\"property\";s:12:\"uniqueGlobal\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:149:\"This requires the value of the field to be globally unique, which means it must not exist in the same field of any other record in the current table.\";s:7:\"default\";N;s:12:\"column_count\";i:2;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:11:\"uniqueLocal\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:193:\"This is like uniqueGlobal, but the value is required to be unique only in the PID of the record. Thus if two records has different pid values, they may have the same value of this field.\";s:7:\"default\";N;s:12:\"column_count\";i:2;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:5:\"twice\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:349:\"This requires the value of the field to match the value of a secondary field name [fieldname]_again sent in the incoming formdata. THis is useful for entering password. Then if your password field is name “user_pass” then you simple add a second field name “user_pass_again” and then set the 'twice' eval code. \";s:7:\"default\";N;s:12:\"column_count\";i:2;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:5:\"email\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:91:\"Requires the field value to be an email address at least on the form [name]@*[domain].[tld]\";s:7:\"default\";N;s:12:\"column_count\";i:2;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:8:\"required\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:70:\"Just simple required (trimmed value). 0 (zero) will evaluate to false!\";s:7:\"default\";N;s:12:\"column_count\";i:2;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:17:\"atLeast
atMost\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:142:\"Specifies a minimum / maximum of characters to enter in the fields.
 Example, that requires at least 5 characters: atleast [5] \";s:7:\"default\";N;s:12:\"column_count\";i:2;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:8:\"inBranch\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:320:\"inBranch requires the value (typically of a pid-field) to be among a list of page-id's (pid's) specified with the inBranch parameters. The parameters are given like [root_pid; depth; beginAt]
 Example, which will return a list of pids one level deep from page 4 (included): inBranch [4;1]\";s:7:\"default\";N;s:12:\"column_count\";i:2;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:10:\"unsetEmpty\";s:8:\"datatype\";s:6:\" \";s:11:\"description\";s:196:\"This evaluation does not result in any error code. Only it simply unsets the field if the value of the field is empty. Thus it'll not override any current value if the field value is not set.\";s:7:\"default\";N;s:12:\"column_count\";i:2;s:16:\"is_propertyTable\";i:1;}}}',''),(115,7389802,'63839135a1a4b8831ae951b0be3e42e0','','tsref:(script).tipafriend','a:1:{s:4:\"rows\";a:10:{i:0;a:6:{s:8:\"property\";s:12:\"templateFile\";s:8:\"datatype\";s:8:\"resource\";s:11:\"description\";s:88:\"The template-file.
See example in 'media/scripts/tipafriend_template.tmpl'\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:4:\"code\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:53:\"Code to define, what the script does. Case sensitive.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:11:\"defaultCode\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:110:\"The default code (see above) if the value is empty. By default it's not set and a help screen will appear\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:5:\"wrap1\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:225:\"Global Wrap 1. This will be splitted into the markers ###GW1B### and ###GW1E###. Don't change the input value by the settings, only wrap it in something.
 
Example:

wrap1.wrap = <B> |</B>\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:5:\"wrap2\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:25:\"Global Wrap 2 (see above)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:6:\"color1\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:43:\"Value for ###GC1### marker (Global color 1)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:6:\"color2\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:43:\"Value for ###GC2### marker (Global color 2)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:6:\"color3\";s:8:\"datatype\";s:15:\"string /stdWrap\";s:11:\"description\";s:43:\"Value for ###GC3### marker (Global color 3)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:8:\"typolink\";s:8:\"datatype\";s:13:\"->typolink\";s:11:\"description\";s:129:\"TypoLink configuration for the TIPLINK to the TIPFORM page. .additionalParams is added the parameter “&tipUrl=”\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:8:\"htmlmail\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:92:\"If set, the page is fetched as HTML and send in HTML (a plain text version is sent as well).\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(116,7389802,'824b1ba31d52dfeb00b9afbcb7790c9b','','tsref:(script).plaintextLib','a:1:{s:4:\"rows\";a:28:{i:0;a:6:{s:8:\"property\";s:7:\"siteUrl\";s:8:\"datatype\";s:3:\"url\";s:11:\"description\";s:16:\"Url of the site.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:13:\"defaultOutput\";s:8:\"datatype\";s:16:\"untrimmed string\";s:11:\"description\";s:40:\"Default output if CType is not rendered.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:14:\"uploads.header\";s:8:\"datatype\";s:16:\"untrimmed string\";s:11:\"description\";s:18:\"Header for uploads\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:13:\"images.header\";s:8:\"datatype\";s:16:\"untrimmed string\";s:11:\"description\";s:17:\"Header for images\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:20:\"images.captionHeader\";s:8:\"datatype\";s:16:\"untrimmed string\";s:11:\"description\";s:24:\"Header for imagecaptions\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:17:\"images.linkPrefix\";s:8:\"datatype\";s:16:\"untrimmed string\";s:11:\"description\";s:22:\"Prefix for image-links\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:14:\".header\";s:8:\"datatype\";N;s:11:\"description\";N;s:7:\"default\";N;s:12:\"column_count\";i:1;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:11:\"defaultType\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:28:\"Which type to use as default\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:4:\"date\";s:8:\"datatype\";s:11:\"date-config\";s:11:\"description\";s:15:\"For header date\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:10:\"datePrefix\";s:8:\"datatype\";s:16:\"untrimmed string\";s:11:\"description\";s:22:\"Prefix for header date\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:10:\"linkPrefix\";s:8:\"datatype\";s:16:\"untrimmed string\";s:11:\"description\";s:23:\"Prefix for header links\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:16:\"[1-5].preLineLen\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:28:\"Lenght of line before header\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:17:\"[1-5].postLineLen\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:27:\"Lenght of line after header\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:13;a:6:{s:8:\"property\";s:15:\"[1-5].preBlanks\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:35:\"Number of blank lines before header\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:14;a:6:{s:8:\"property\";s:16:\"[1-5].postBlanks\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:34:\"Number of blank lines after header\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:15;a:6:{s:8:\"property\";s:13:\"[1-5].stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:15:\"for header text\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:16;a:6:{s:8:\"property\";s:17:\"[1-5].preLineChar\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:21:\"Character to pre-line\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:17;a:6:{s:8:\"property\";s:18:\"[1-5].postLineChar\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:22:\"Character to post-line\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:18;a:6:{s:8:\"property\";s:19:\"[1-5].preLineBlanks\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:49:\"Number of blank lines between header and pre-line\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:19;a:6:{s:8:\"property\";s:20:\"[1-5].postLineBlanks\";s:8:\"datatype\";s:3:\"int\";s:11:\"description\";s:50:\"Number of blank lines between header and post-line\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:20;a:6:{s:8:\"property\";s:16:\"[1-5].autonumber\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:111:\"If set, a number is prepended every header. The number corresponds to the content element number in the select.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:21;a:6:{s:8:\"property\";s:12:\"[1-5].prefix\";s:8:\"datatype\";s:16:\"untrimmed string\";s:11:\"description\";s:20:\"Header string prefix\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:22;a:6:{s:8:\"property\";s:23:\"bulletlist.[0-3].bullet\";s:8:\"datatype\";s:16:\"untrimmed string\";s:11:\"description\";s:36:\"Bullet for bullet list, layout [0-3]\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:23;a:6:{s:8:\"property\";s:26:\"bulletlist.[0-3].secondRow\";s:8:\"datatype\";s:16:\"untrimmed string\";s:11:\"description\";s:65:\"If set, this is used for lines on the second row of bullet-lists.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:24;a:6:{s:8:\"property\";s:4:\"menu\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:137:\"cObject to render menu. The output is stripped for tags and the links is extracted. Further all <BR> chars are converted to chr(10)\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:25;a:6:{s:8:\"property\";s:8:\"shortcut\";s:8:\"datatype\";s:7:\"cObject\";s:11:\"description\";s:129:\"cObject to render other elements. See config below which simply uses this object to render more tt_content elements as plaintext.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:26;a:6:{s:8:\"property\";s:16:\"bodytext.stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:48:\"stdWrap for body-text. See config example below.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:27;a:6:{s:8:\"property\";s:8:\"userProc\";s:8:\"datatype\";s:13:\"function-name\";s:11:\"description\";s:199:\"Lets you proces the output of each content element before it finally is returned. Property “parentObj” of the conf-array holds a references to the plainText object calling the function.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''),(117,9021659,'f6d94840515a9e43422f184482e42e5c','','tsref:plugin.tx_indexedsearch','a:1:{s:4:\"rows\";a:13:{i:0;a:6:{s:8:\"property\";s:12:\"templateFile\";s:8:\"datatype\";s:8:\"resource\";s:11:\"description\";s:67:\"The template file, see examples in typo3/sysext/indexed_search/pi/.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:1;a:6:{s:8:\"property\";s:21:\"show.forbiddenRecords\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:131:\"Explicitely display search hits although the visitor has no access to it.
Notice: This behavior was different in TYPO3 < 4.0.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:2;a:6:{s:8:\"property\";s:17:\"show.resultNumber\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:96:\"Display the numbers of search results.
Notice: This behavior was different in TYPO3 < 4.0.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:3;a:6:{s:8:\"property\";s:23:\"show.advancedSearchLink\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:45:\"Display the link to the advanced search page.\";s:7:\"default\";s:1:\"1\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:4;a:6:{s:8:\"property\";s:18:\"search.rootPidList\";s:8:\"datatype\";s:11:\"list of int\";s:11:\"description\";s:514:\"A list of integer which should be root-pages to search from. Thus you can search multiple branches of the page tree by setting this property to a list of page id numbers.
If this value is set to less than zero (eg. -1) searching will happen in ALL of the page tree with no regard to branches at all.
 
Notice that by “root-page” we mean a website root defined by
a TypoScript Template! If you just want to search in branches of your site, use the possibility of searching in levels.\";s:7:\"default\";s:24:\"The current root-page id\";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:5;a:6:{s:8:\"property\";s:32:\"search.detect_sys_domain_records\";s:8:\"datatype\";s:7:\"boolean\";s:11:\"description\";s:86:\"If set, then the search results are linked to the proper domains where they are found.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:6;a:6:{s:8:\"property\";s:39:\"search.detect_sys_domain_records.target\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:25:\"Target for external URLs.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:7;a:6:{s:8:\"property\";s:16:\"search.mediaList\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:53:\"Restrict the file type list when searching for files.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:8;a:6:{s:8:\"property\";s:30:\"search.defaultFreeIndexUidList\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:136:\"List of Indexing Configuration Uids to show as categories in search form. The order determines the order displayed in the search result.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:9;a:6:{s:8:\"property\";s:15:\"specConfs.[pid]\";s:8:\"datatype\";s:1:\"-\";s:11:\"description\";s:967:\"“specConfs” is an array of objects with properties that can customize certain behaviours of the display of a result row depending on it's position in the rootline. For instance you can define that all results which links to pages in a branch from page id 123 should have another page icon displayed. Of you can add a suffix to the class names so you can style that section differently.
 
Examples:

If a page “Contact” is found in a search for “address” and that “Contact” page is in the rootline “Frontpage [ID=23] > About us [ID=45] > Contact [ID=77]” then you should set the pid value to either “77” or “45”. If “45” then all subpages including the “About us” page will have similar configuration.
If the pid value is set to 0 (zero) it will apply to all pages.
 
Please see the options below.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:10;a:6:{s:8:\"property\";s:24:\"specConfs.[pid].pageIcon\";s:8:\"datatype\";s:18:\"->IMAGE cObject\";s:11:\"description\";s:22:\"Alternative page icon.\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:11;a:6:{s:8:\"property\";s:25:\"specConfs.[pid].CSSsuffix\";s:8:\"datatype\";s:6:\"string\";s:11:\"description\";s:332:\"A string that will be appended to the class-names of all the class-attributes used within the result row presentation. The prefix will be like this:
 
Example:

If “...CSSsuffix = doc” then eg. the class name “tx-indexedsearch-title” will be “tx-indexedsearch-title-doc”\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}i:12;a:6:{s:8:\"property\";s:14:\"whatis_stdWrap\";s:8:\"datatype\";s:12:\"->stdWrap\";s:11:\"description\";s:40:\"Parse input through the stdWrap function\";s:7:\"default\";s:6:\" \";s:12:\"column_count\";i:4;s:16:\"is_propertyTable\";i:1;}}}',''); +/*!40000 ALTER TABLE static_tsconfig_help ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_be_shortcuts` +-- + +DROP TABLE IF EXISTS sys_be_shortcuts; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_be_shortcuts ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + userid int(11) unsigned NOT NULL DEFAULT '0', + module_name varchar(255) DEFAULT NULL, + url text, + description varchar(255) DEFAULT NULL, + sorting int(11) NOT NULL DEFAULT '0', + sc_group tinyint(4) NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY `event` (userid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_be_shortcuts` +-- + +LOCK TABLES sys_be_shortcuts WRITE; +/*!40000 ALTER TABLE sys_be_shortcuts DISABLE KEYS */; +INSERT INTO sys_be_shortcuts (uid, userid, module_name, url, description, sorting, sc_group) VALUES (1,7,'web_layout|','/typo3/sysext/cms/layout/db_layout.php?&id=4&edit_record=&pointer=&new_unique_uid=&search_field=&search_levels=&showLimit=&SET[tt_board]=0&SET[tt_address]=0&SET[tt_links]=0&SET[tt_calender]=0&SET[tt_products]=0&SET[tt_content_showHidden]=&SET[showPalettes]=&SET[showDescriptions]=&SET[disableRTE]=&SET[function]=1&SET[language]=0','Text mit Bild 1',1258305385,0); +/*!40000 ALTER TABLE sys_be_shortcuts ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_domain` +-- + +DROP TABLE IF EXISTS sys_domain; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_domain ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + pid int(11) unsigned NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + crdate int(11) unsigned NOT NULL DEFAULT '0', + cruser_id int(11) unsigned NOT NULL DEFAULT '0', + hidden tinyint(4) unsigned NOT NULL DEFAULT '0', + domainName varchar(80) DEFAULT NULL, + redirectTo varchar(255) NOT NULL DEFAULT '', + redirectHttpStatusCode int(4) unsigned NOT NULL DEFAULT '301', + sorting int(10) unsigned NOT NULL DEFAULT '0', + prepend_params int(10) NOT NULL DEFAULT '0', + forced tinyint(3) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY parent (pid), + KEY tx_realurl (domainName,hidden) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_domain` +-- + +LOCK TABLES sys_domain WRITE; +/*!40000 ALTER TABLE sys_domain DISABLE KEYS */; +/*!40000 ALTER TABLE sys_domain ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_filemounts` +-- + +DROP TABLE IF EXISTS sys_filemounts; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_filemounts ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + pid int(11) unsigned NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + title varchar(30) DEFAULT NULL, + path varchar(120) DEFAULT NULL, + base tinyint(4) unsigned NOT NULL DEFAULT '0', + hidden tinyint(3) unsigned NOT NULL DEFAULT '0', + deleted tinyint(1) unsigned NOT NULL DEFAULT '0', + sorting int(11) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY parent (pid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_filemounts` +-- + +LOCK TABLES sys_filemounts WRITE; +/*!40000 ALTER TABLE sys_filemounts DISABLE KEYS */; +INSERT INTO sys_filemounts (uid, pid, tstamp, title, path, base, hidden, deleted, sorting) VALUES (1,0,1258381157,'News','user_upload/news/',1,0,0,0),(2,0,1258381173,'Images','user_upload/images/',1,0,0,0),(3,0,1258381204,'Documents','user_upload/documents/',1,0,0,0); +/*!40000 ALTER TABLE sys_filemounts ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_history` +-- + +DROP TABLE IF EXISTS sys_history; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_history ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + sys_log_uid int(11) NOT NULL DEFAULT '0', + history_data mediumtext, + fieldlist text, + recuid int(11) NOT NULL DEFAULT '0', + tablename varchar(255) DEFAULT NULL, + tstamp int(11) NOT NULL DEFAULT '0', + history_files mediumtext, + `snapshot` tinyint(4) NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY recordident_1 (tablename,recuid), + KEY recordident_2 (tablename,tstamp), + KEY sys_log_uid (sys_log_uid) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_history` +-- + +LOCK TABLES sys_history WRITE; +/*!40000 ALTER TABLE sys_history DISABLE KEYS */; +/*!40000 ALTER TABLE sys_history ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_language` +-- + +DROP TABLE IF EXISTS sys_language; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_language ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + pid int(11) unsigned NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + hidden tinyint(4) unsigned NOT NULL DEFAULT '0', + title varchar(80) DEFAULT NULL, + flag varchar(20) DEFAULT NULL, + static_lang_isocode int(11) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY parent (pid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_language` +-- + +LOCK TABLES sys_language WRITE; +/*!40000 ALTER TABLE sys_language DISABLE KEYS */; +INSERT INTO sys_language (uid, pid, tstamp, hidden, title, flag, static_lang_isocode) VALUES (1,0,1277119475,0,'Dansk','dk',0); +/*!40000 ALTER TABLE sys_language ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_lockedrecords` +-- + +DROP TABLE IF EXISTS sys_lockedrecords; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_lockedrecords ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + userid int(11) unsigned NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + record_table varchar(255) DEFAULT NULL, + record_uid int(11) NOT NULL DEFAULT '0', + record_pid int(11) NOT NULL DEFAULT '0', + username varchar(50) DEFAULT NULL, + feuserid int(11) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY `event` (userid,tstamp) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_lockedrecords` +-- + +LOCK TABLES sys_lockedrecords WRITE; +/*!40000 ALTER TABLE sys_lockedrecords DISABLE KEYS */; +/*!40000 ALTER TABLE sys_lockedrecords ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_log` +-- + +DROP TABLE IF EXISTS sys_log; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_log ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + userid int(11) unsigned NOT NULL DEFAULT '0', + `action` tinyint(4) unsigned NOT NULL DEFAULT '0', + recuid int(11) unsigned NOT NULL DEFAULT '0', + tablename varchar(255) DEFAULT NULL, + recpid int(11) NOT NULL DEFAULT '0', + error tinyint(4) unsigned NOT NULL DEFAULT '0', + details text NOT NULL, + tstamp int(11) unsigned NOT NULL DEFAULT '0', + `type` tinyint(3) unsigned NOT NULL DEFAULT '0', + details_nr tinyint(3) unsigned NOT NULL DEFAULT '0', + IP varchar(39) DEFAULT NULL, + log_data varchar(255) DEFAULT NULL, + event_pid int(11) NOT NULL DEFAULT '-1', + workspace int(11) NOT NULL DEFAULT '0', + NEWid varchar(20) DEFAULT NULL, + PRIMARY KEY (uid), + KEY `event` (userid,event_pid), + KEY recuidIdx (recuid,uid) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_log` +-- + +LOCK TABLES sys_log WRITE; +/*!40000 ALTER TABLE sys_log DISABLE KEYS */; +/*!40000 ALTER TABLE sys_log ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_news` +-- + +DROP TABLE IF EXISTS sys_news; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_news ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + pid int(11) unsigned NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + crdate int(11) unsigned NOT NULL DEFAULT '0', + cruser_id int(11) unsigned NOT NULL DEFAULT '0', + deleted tinyint(3) unsigned NOT NULL DEFAULT '0', + hidden tinyint(4) unsigned NOT NULL DEFAULT '0', + starttime int(11) unsigned NOT NULL DEFAULT '0', + endtime int(11) unsigned NOT NULL DEFAULT '0', + title varchar(255) DEFAULT NULL, + content mediumtext, + PRIMARY KEY (uid), + KEY parent (pid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_news` +-- + +LOCK TABLES sys_news WRITE; +/*!40000 ALTER TABLE sys_news DISABLE KEYS */; +INSERT INTO sys_news (uid, pid, tstamp, crdate, cruser_id, deleted, hidden, starttime, endtime, title, content) VALUES (1,0,1287577563,1287577563,1,0,0,0,0,'Welcome to TYPO3','Explore the different roles. Login with one of the following usernames and the password that you choose during the installation routine:\r\n\r\nHave fun!'),(2,0,1287579123,1287577560,1,0,0,0,0,'Important Messages','You can edit the Important Messages shown on the Login screen very easily: As admin, just edit the records of type System News which are stored in the root folder.'); +/*!40000 ALTER TABLE sys_news ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_note` +-- + +DROP TABLE IF EXISTS sys_note; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_note ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + pid int(11) unsigned NOT NULL DEFAULT '0', + deleted tinyint(3) unsigned NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + crdate int(11) unsigned NOT NULL DEFAULT '0', + cruser int(11) unsigned NOT NULL DEFAULT '0', + author varchar(80) DEFAULT NULL, + email varchar(80) DEFAULT NULL, + `subject` varchar(255) DEFAULT NULL, + message text, + personal tinyint(3) unsigned NOT NULL DEFAULT '0', + category tinyint(3) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY parent (pid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_note` +-- + +LOCK TABLES sys_note WRITE; +/*!40000 ALTER TABLE sys_note DISABLE KEYS */; +/*!40000 ALTER TABLE sys_note ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_preview` +-- + +DROP TABLE IF EXISTS sys_preview; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_preview ( + keyword varchar(32) NOT NULL DEFAULT '', + tstamp int(11) NOT NULL DEFAULT '0', + endtime int(11) NOT NULL DEFAULT '0', + config text, + PRIMARY KEY (keyword) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_preview` +-- + +LOCK TABLES sys_preview WRITE; +/*!40000 ALTER TABLE sys_preview DISABLE KEYS */; +/*!40000 ALTER TABLE sys_preview ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_refindex` +-- + +DROP TABLE IF EXISTS sys_refindex; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_refindex ( + `hash` varchar(32) NOT NULL DEFAULT '', + tablename varchar(255) DEFAULT NULL, + recuid int(11) NOT NULL DEFAULT '0', + field varchar(40) DEFAULT NULL, + flexpointer varchar(255) DEFAULT NULL, + softref_key varchar(30) DEFAULT NULL, + softref_id varchar(40) DEFAULT NULL, + sorting int(11) NOT NULL DEFAULT '0', + deleted tinyint(1) NOT NULL DEFAULT '0', + ref_table varchar(255) DEFAULT NULL, + ref_uid int(11) NOT NULL DEFAULT '0', + ref_string varchar(200) DEFAULT NULL, + PRIMARY KEY (`hash`), + KEY lookup_rec (tablename,recuid), + KEY lookup_uid (ref_table,ref_uid), + KEY lookup_string (ref_string) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_refindex` +-- + +LOCK TABLES sys_refindex WRITE; +/*!40000 ALTER TABLE sys_refindex DISABLE KEYS */; +/*!40000 ALTER TABLE sys_refindex ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_registry` +-- + +DROP TABLE IF EXISTS sys_registry; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_registry ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + entry_namespace varchar(128) DEFAULT NULL, + entry_key varchar(128) DEFAULT NULL, + entry_value blob, + PRIMARY KEY (uid), + UNIQUE KEY entry_identifier (entry_namespace,entry_key) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_registry` +-- + +LOCK TABLES sys_registry WRITE; +/*!40000 ALTER TABLE sys_registry DISABLE KEYS */; +/*!40000 ALTER TABLE sys_registry ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_template` +-- + +DROP TABLE IF EXISTS sys_template; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_template ( + uid int(11) NOT NULL AUTO_INCREMENT, + pid int(11) NOT NULL DEFAULT '0', + t3ver_oid int(11) NOT NULL DEFAULT '0', + t3ver_id int(11) NOT NULL DEFAULT '0', + t3ver_wsid int(11) NOT NULL DEFAULT '0', + t3ver_label varchar(255) DEFAULT NULL, + t3ver_state tinyint(4) NOT NULL DEFAULT '0', + t3ver_stage int(11) NOT NULL DEFAULT '0', + t3ver_count int(11) NOT NULL DEFAULT '0', + t3ver_tstamp int(11) NOT NULL DEFAULT '0', + t3_origuid int(11) NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + sorting int(11) unsigned NOT NULL DEFAULT '0', + crdate int(11) unsigned NOT NULL DEFAULT '0', + cruser_id int(11) unsigned NOT NULL DEFAULT '0', + title varchar(255) DEFAULT NULL, + sitetitle varchar(255) DEFAULT NULL, + hidden tinyint(4) unsigned NOT NULL DEFAULT '0', + starttime int(11) unsigned NOT NULL DEFAULT '0', + endtime int(11) unsigned NOT NULL DEFAULT '0', + root tinyint(4) unsigned NOT NULL DEFAULT '0', + clear tinyint(4) unsigned NOT NULL DEFAULT '0', + include_static_file text, + constants text, + config text, + editorcfg text, + resources text, + nextLevel varchar(5) DEFAULT NULL, + description text, + basedOn tinytext, + deleted tinyint(3) unsigned NOT NULL DEFAULT '0', + includeStaticAfterBasedOn tinyint(4) unsigned NOT NULL DEFAULT '0', + static_file_mode tinyint(4) unsigned NOT NULL DEFAULT '0', + tx_impexp_origuid int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY t3ver_oid (t3ver_oid,t3ver_wsid), + KEY parent (pid,deleted,hidden,sorting), + KEY tx_realurl (root,hidden) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_template` +-- + +LOCK TABLES sys_template WRITE; +/*!40000 ALTER TABLE sys_template DISABLE KEYS */; +INSERT INTO sys_template (uid, pid, t3ver_oid, t3ver_id, t3ver_wsid, t3ver_label, t3ver_state, t3ver_stage, t3ver_count, t3ver_tstamp, t3_origuid, tstamp, sorting, crdate, cruser_id, title, sitetitle, hidden, starttime, endtime, root, clear, include_static_file, constants, config, editorcfg, resources, nextLevel, description, basedOn, deleted, includeStaticAfterBasedOn, static_file_mode, tx_impexp_origuid) VALUES (1,1,0,0,0,'',0,0,0,0,0,1290503626,256,1257766279,1,'Introduction Package','Introduction Package',0,0,0,1,3,'','','','','','','This is the Introduction Package template.\r\n\r\nFor each website you need a Typoscript template on the ROOT level. For better maintenance, all Typoscript has been put into the folder \'Typoscript Templates\'. The only thing this template does is calling the ROOT template.','50',0,0,0,1),(53,9,0,0,0,'',0,0,0,0,0,1276890936,512,1258319661,4,'plugin.automaketemplate','',0,0,0,0,0,'','','# Configuring the Auto-Parser for main template:\r\n\r\nplugin.tx_automaketemplate_pi1 {\r\n\r\n # Read the template file\r\n content = FILE\r\n content.file = {$filepaths.templates}{$plugin.tx_automaketemplate_pi1.templatefile}\r\n\r\n elements {\r\n BODY.all = 1\r\n BODY.all.subpartMarker = DOCUMENT_BODY\r\n HEAD.all = 1\r\n HEAD.all.subpartMarker = DOCUMENT_HEADER\r\n \r\n # Configure which HTML-tags should be made replacable by subparts\r\n DIV.id.navigationFirstLevelMenu = 1\r\n DIV.id.navigationSecondLevelMenu = 1\r\n DIV.id.topMenu = 1\r\n DIV.id.languageMenu = 1\r\n DIV.id.breadcrumb = 1\r\n\r\n DIV.id.siteTitle = 1\r\n DIV.id.searchBox = 1\r\n DIV.id.footerContent = 1\r\n\r\n DIV.id.mainContent = 1\r\n DIV.id.secondaryContent = 1\r\n DIV.id.navigationContent = 1\r\n \r\n H1.all = 1\r\n \r\n # Remove some tags from HTML head section (because TYPO3 will add these dynamically)\r\n HEAD.rmTagSections = title,meta,link\r\n }\r\n\r\n # Prefix all relative paths in the HTML template with this value\r\n #relPathPrefix = {$filepaths.templates}\r\n}\r\n','','','','The AUTOMAKETEMPLATE template\r\n\r\nThe automaketemplate parser reads the HTML template files, extracts the markers for content, and replaces them with the content assigned to these markers.','',0,0,0,0),(59,11,0,0,0,'',0,0,0,0,0,1258568494,1536,1258458592,4,'lib.sitetitle','',0,0,0,0,0,'','','lib.sitetitle = TEXT\r\nlib.sitetitle {\r\n \r\n # Copy the value from the top level object sitetitle\r\n # You can change the site title in the Sitetitle field of the ROOT typoscript template\r\n value < sitetitle\r\n \r\n # Wrap a link to the home page around the sitetitle\r\n typolink.parameter = {$contentpage.homeID}\r\n} \r\n','','','','The SITE TITLE template\r\n\r\nBuilding block for the site title','',0,0,0,0),(60,11,0,0,0,'',0,0,0,0,0,1278361173,1024,1258460317,4,'lib.searchbox','',0,0,0,0,0,'','','# Create the searchbox in TypoScript, so we can easily include in on every page\r\nlib.searchbox = COA\r\n\r\n# Make the searchbox remember the search term on the search result page\r\n[globalVar = TSFE:id = 17]\r\nlib.searchbox = COA_INT\r\n[global]\r\n\r\nlib.searchbox {\r\n stdWrap.prefixComment = 2 | lib.searchbox\r\n 10 = TEXT\r\n 10.typolink.parameter = {$plugin.tx_indexedsearch.searchpageID}\r\n 10.typolink.returnLast = url\r\n 10.wrap =
\r\n 20 = COA\r\n 20 {\r\n 10 = TEXT\r\n 10.data = GP : tx_indexedsearch |sword\r\n 10.htmlSpecialChars = 1 \r\n 10.wrap = \r\n 20 = COA\r\n 20 {\r\n 10 = TEXT\r\n 10.value = \r\n 20 = TEXT\r\n 20.value = \r\n 30 = TEXT\r\n 30.value = \r\n }\r\n }\r\n \r\n wrap = |
\r\n}\r\n ','','','','The SEARCHBOX template\r\n\r\nA building block for a searchform','',0,0,0,0),(61,13,0,0,0,'',0,0,0,0,0,1280228398,38,1258463526,4,'menu.breadcrumb','',0,0,0,0,0,'','','# For the breadcrumb cObject we use a HMENU of the type \'rootline\'\r\nmenu.breadcrumb = COA\r\nmenu.breadcrumb {\r\n 10 = HMENU\r\n 10 {\r\n # Select HMENU type \'special.rootline\'\r\n special = rootline\r\n \r\n # Traverse the pagetree starting at the rootpage (0) and ending at the current page (-1)\r\n special.range = 0|-1\r\n \r\n # Pages which are excluded from the regular menus should still be shown in the breadcrumb\r\n includeNotInMenu = 1\r\n \r\n # This menu has only 1 level since this is a rootline-menu\r\n 1 = TMENU\r\n 1 {\r\n # Remove the ancient onfocus=\"blurLink(this);\" from link tags\r\n noBlur = 1\r\n \r\n # Append spaces and >> to normal linked breadcrumb items\r\n NO.allWrap = | » \r\n NO.stdWrap.htmlSpecialChars = 1\r\n }\r\n }\r\n}\r\n\r\n# This condition checks whether a news article will be shown in single view\r\n[globalVar = GP:tx_ttnews|tt_news > 0] && [globalVar = TSFE:id = {$plugin.tt_news.singlePid}]\r\n\r\nmenu.breadcrumb {\r\n # Render the current page as the normal state (linked) because we\'ll append the title of the news article\r\n 10.1 {\r\n CUR = 1\r\n CUR < .NO\r\n }\r\n \r\n # Append the title of the news item. Using this example, the breadcrumb can be exented with\r\n # any other thinkable kind of data and logic\r\n 20 = RECORDS\r\n 20 {\r\n dontCheckPid = 1\r\n tables = tt_news\r\n source.data = GP:tx_ttnews|tt_news\r\n source.intval = 1\r\n conf.tt_news = TEXT\r\n conf.tt_news.field = title\r\n wrap = |\r\n }\r\n}\r\n# Else configure the breadcrumb for normal cases when no news article is shown\r\n[else]\r\n\r\nmenu.breadcrumb {\r\n 10.1 {\r\n # Add alternative, unlinked configuration for current page, which is always the last item in\r\n # the breadcrumb\r\n CUR = 1\r\n CUR.stdWrap.htmlSpecialChars = 1\r\n CUR.allWrap = |\r\n \r\n # Do not wrap a link around this item\r\n CUR.doNotLinkIt = 1\r\n }\r\n}\r\n\r\n[global]\r\n','','','','The BREADCRUMB template\r\n\r\nTyposcript for producing a breadcrumb.','',0,0,0,0),(3,14,0,0,0,'',0,0,0,0,0,1276357485,128,1258294829,3,'page.includeCSS','',0,0,0,0,0,'','','page.includeCSS {\r\n 10 = {$filepaths.css}stylesheet.css\r\n 10 {\r\n media = all\r\n }\r\n 20 = {$filepaths.css}print.css\r\n 20 {\r\n media = print\r\n }\r\n}\r\n\r\n# Condition to add specific stylesheet for the frontpage only \r\n[globalVar = TSFE:id = 6] \r\npage.includeCSS {\r\n 30 = {$filepaths.css}frontpage.css\r\n 30 {\r\n media = all\r\n }\r\n}\r\n[end] \r\n\r\n# Condition to add extra CSS for Internet Explorer 6\r\n[browser = msie] && [version =< 7]\r\npage.includeCSS {\r\n 9999 = {$filepaths.css}msie6.css\r\n 9999 {\r\n media = screen\r\n }\r\n}\r\n[global]','','','','The CSS template.\r\n\r\nIncludes all necessarry Cascading Style Sheets by referring to the file on the server and configuring the media type.\r\n\r\nSpecial condition for including extra CSS file for Internet Explorer. ','',0,0,0,46),(4,14,0,0,0,'',0,0,0,0,0,1280239107,64,1258294829,3,'page.headerData','',0,0,0,0,0,'','','page.headerData {\r\n 10 = TEMPLATE\r\n 10 {\r\n template =< plugin.tx_automaketemplate_pi1\r\n workOnSubpart = DOCUMENT_HEADER\r\n }\r\n 20 = TEXT\r\n 20.value = \r\n}','','','','The PAGE HEADERDATA template. \r\n\r\nAll config.headerData contents goes in here. This could be almost everything that belongs in the , but does not have any configuration like page.config, page.includeCSS or page.includeJS or needs special configuration, like dynamic handling.','',0,0,0,52),(5,14,0,0,0,'',0,0,0,0,0,1280239382,32,1258294829,3,'page.meta','',0,0,0,0,0,'','','page.meta {\r\n # Use the meta tag \'description\' from the constants as default value\r\n # If the meta field description in the page properties is filled, then this will override the default.\r\n description = {$plugin.meta.description}\r\n description.override.field = description\r\n \r\n author = {$plugin.meta.author}\r\n author.override.field = author\r\n \r\n keywords = {$plugin.meta.keywords}\r\n keywords.override.field = keywords\r\n \r\n robots.value = {$plugin.meta.robots}\r\n revisit = {$plugin.meta.revisit}\r\n copyright = {$plugin.meta.copyright}\r\n}\r\n','','','','The META template. \r\n\r\nConfigures meta information for the website. It\'s possible this template remains empty because most of the information is handled by constants, which are not allowed here. Constant settings belong to the root.','',0,0,0,40),(6,14,0,0,0,'',0,0,0,0,0,1280255270,16,1258294829,3,'page.config','',0,0,0,0,0,'','','config {\r\n // Administrator settings\r\n admPanel = {$config.adminPanel}\r\n debug = {$config.debug}\r\n \r\n doctype = xhtml_trans\r\n\r\n // Character sets\r\n renderCharset = utf-8\r\n metaCharset = utf-8\r\n\r\n // Cache settings\r\n cache_period = 43200\r\n sendCacheHeaders = 1\r\n \r\n // URL Settings\r\n tx_realurl_enable = 1\r\n simulateStaticDocuments = 0\r\n\r\n // Language Settings\r\n uniqueLinkVars = 1\r\n linkVars = L(1)\r\n sys_language_uid = 0\r\n sys_language_overlay = 1\r\n sys_language_mode = content_fallback\r\n language = en\r\n locale_all = en_US.UTF-8\r\n htmlTag_langKey = en\r\n \r\n // Link settings\r\n absRefPrefix = {$config.absRefPrefix}/\r\n prefixLocalAnchors = all\r\n \r\n // Remove targets from links\r\n intTarget =\r\n extTarget =\r\n\r\n // Indexed Search\r\n index_enable = 1\r\n index_externals = 1\r\n\r\n // Code cleaning\r\n disablePrefixComment = 1\r\n \r\n // Move default CSS and JS to external file \r\n removeDefaultJS = external\r\n inlineStyle2TempFile = 1\r\n\r\n // Protect mail addresses from spamming\r\n spamProtectEmailAddresses = -3\r\n spamProtectEmailAddresses_atSubst = @remove-this.\r\n\r\n // Comment in the tag\r\n headerComment (\r\n This TYPO3 introduction package has been started at T3UXW09\r\n \r\n ===\r\n )\r\n}\r\n\r\n# Set baseURL setting for http or https\r\nconfig.baseURL = http://{$config.domain}/\r\n[globalString = IENV:TYPO3_SITE_URL=https://{$config.domain}/]\r\nconfig.baseURL = https://{$config.domain}/\r\n[global]\r\n\r\n// Condition to switch the doctype and xml prologue\r\n[browser = msie] && [version = <7]\r\nconfig {\r\n doctypeSwitch = 1\r\n}\r\n[global]\r\n\r\n// Condition to set language according to L POST/GET variable\r\n[globalVar = GP:L = 1]\r\nconfig {\r\n htmlTag_langKey = da\r\n sys_language_uid = 1\r\n language = da\r\n locale_all = da_DK\r\n}\r\n[global]','','','','The PAGE CONFIG template. \r\n\r\nOnly page.config settings are done here, like character sets, url and language. ','',0,0,0,39),(7,14,0,0,0,'Auto-created for WS #-1',0,0,0,0,38,1276891086,8,1258294829,3,'page','',0,0,0,0,0,'','','# Make the PAGE object\r\npage = PAGE\r\npage {\r\n # Regular pages always have typeNum = 0\r\n typeNum = 0\r\n \r\n # Add the icon that will appear in front of the url in the browser\r\n # This icon will also be used for the bookmark menu in browsers\r\n shortcutIcon = {$filepaths.images}favicon.ico\r\n \r\n # Add class to bodytag to select which columns will be used in the HTML template\r\n # Labels for the values used in this field are defined in the TSconfig field of the root page of the website\r\n bodyTagCObject = CASE\r\n bodyTagCObject {\r\n # The value of the CASE object will depend on the value of the layout field in the page records\r\n key.field = layout\r\n \r\n # Define the default value\r\n default = TEXT\r\n default.value = \r\n \r\n # Copy the default value to 0\r\n 0 < .default\r\n \r\n # Add different values for cases 1, 2 and 3\r\n 1 = TEXT\r\n 1.wrap = \r\n 1.value = hideRightColumn\r\n \r\n 2 < .1\r\n 2.value = hideLeftColumn\r\n \r\n 3 < .1\r\n 3.value = hideRightAndLeftColumn\r\n }\r\n \r\n # Add a TEMPLATE object to the page\r\n # We use the template autoparser extension to easily replace parts of the HTML template by dynamic TypoScript objects\r\n 10 = TEMPLATE\r\n 10 {\r\n # Use the HTML template from the automake template plugin\r\n template =< plugin.tx_automaketemplate_pi1\r\n \r\n # Use the subpart\r\n workOnSubpart = DOCUMENT_BODY\r\n \r\n # Link content and page blocks to id\'s that have been enabled in the\r\n # automaketemplate template in the extension_configuration sysfolder\r\n subparts { \r\n # Insert menu\'s from lib-objects into the appropriate subparts\r\n navigationFirstLevelMenu < menu.firstlevel\r\n navigationSecondLevelMenu < menu.secondlevel\r\n topMenu < menu.top\r\n languageMenu < menu.language\r\n breadcrumb < menu.breadcrumb\r\n\r\n # Insert various TypoScript lib objects into the appropriate subparts of the template\r\n siteTitle < lib.sitetitle\r\n searchBox < lib.searchbox\r\n footerContent < lib.footer\r\n\r\n # Insert content as already constructed in TypoScript objects into subparts\r\n mainContent < lib.content\r\n secondaryContent < lib.contentright\r\n navigationContent < lib.contentleft\r\n }\r\n }\r\n}\r\n','','','','The PAGE OBJECT template. \r\n\r\nTells the PAGE object to use the parsed HTML template from the automaketemplate extension.\r\n','',0,0,0,38),(8,14,0,0,0,'',0,0,0,0,0,1280237741,4,1258294829,3,'root_page','',0,0,0,0,0,'','plugin.meta.includeGlobal = 0\r\nplugin.meta.language = ','','','','','The PAGE ROOT template. \r\n\r\nThis template will be called by the GLOBAL MASTER ROOT template. \r\nIt reads the templates for the page, like page setup, config and header data.\r\n\r\nIn this template record are only other template records included.','7,6,5,4,3',0,0,0,34),(10,13,0,0,0,'',0,0,0,0,0,1258566099,128,1258294829,3,'menu.firstlevel','',0,0,0,0,0,'','','# Start with copying our default menu configuration so we don\'t have to repeat our selves (except in the explanation, didn\'t I already mention this?) ;-)\r\nmenu.firstlevel < menu\r\nmenu.firstlevel {\r\n # Since this is the top-level menu, we start this menu at the root level of the website\r\n entryLevel = 0\r\n}\r\n','','','','The FIRST LEVEL MENU template.\r\n\r\nConfiguration for the menu of the first level of pages. It inherits the MAIN MENU template and has some small modifications on top of it, in this case the setting of the entryLevel.','',0,0,0,43),(14,13,0,0,0,'',0,0,0,0,0,1260552309,8,1258294829,3,'menu_defaults','',0,0,0,0,0,'','','menu = HMENU\r\nmenu {\r\n \r\n 1 = TMENU\r\n 1 {\r\n wrap = \r\n \r\n # Always unfold all sub-levels of the menu\r\n expAll = 1\r\n\r\n # Remove the (old) default behaviour which adds onfocus=\"blurLink(this);\" to all links\r\n noBlur = 1\r\n \r\n # Define the normal state (not active, not selected) of menu items\r\n # Using NO=1 to activate normal state is not necessary, but useful when copying \r\n NO = 1\r\n NO {\r\n # Use the page title field the title property on the A-tag, but only if the navigation title is set\r\n ATagTitle {\r\n field = title\r\n fieldRequired = nav_title\r\n }\r\n \r\n # Use the option-split feature to generate a different wrap for the last item on a level of the menu\r\n # The last item on each level gets class=\"last\" added for CSS styling purposes.\r\n #\r\n # See the TSref documentation for details about option split and other features:\r\n # http://typo3.org/documentation/document-library/references/doc_core_tsref/current/\r\n wrapItemAndSub =
  • |
  • |*|
  • |
  • |*|
  • |
  • \r\n \r\n # HTML-encode special characters according to the PHP-function htmlSpecialChars\r\n stdWrap.htmlSpecialChars = 1\r\n }\r\n \r\n # Copy properties of normal to active state, and then add a CSS class for styling\r\n ACT < .NO\r\n ACT {\r\n ATagParams = class=\"active\"\r\n }\r\n\r\n # Copy properties of normal to current state, and then add a CSS class for styling\r\n CUR < .NO\r\n CUR {\r\n ATagParams = class=\"selected\"\r\n }\r\n }\r\n}','','','','The MENU template.\r\n\r\nConfiguration for default menu, which can be used with small modifications for other menu\'s, without writing the whole menu configuration all over again for all kinds of menu\'s.','',0,0,0,41),(55,13,0,0,0,'',0,0,0,0,10,1258565791,68,1258385418,4,'menu.top','',0,0,0,0,0,'','','# Copy basic menu object from TS template \'menu\' so we don\'t have to repeat all that\r\nmenu.top < menu\r\nmenu.top {\r\n # Also show pages which have not-in-menu flag set in page properties\r\n includeNotInMenu = 1\r\n \r\n # Create a menu out of the pages specifically listed under special.value\r\n special = list\r\n special.value = {$menu.top.pages}\r\n}','','','','The MAIN MENU template.\r\n\r\nConfiguration for the top right menu.','',0,0,0,43),(15,13,0,0,0,'',0,0,0,0,0,1260552214,1,1258294829,3,'root_menu','',0,0,0,0,0,'','','','','','','The MENU ROOT template. \r\n\r\nThis template will be called by the MASTER ROOT template. \r\nIt reads the templates for the menu parts, like the default menu \r\nsetup, language menu, header- and footermenu\'s.\r\n\r\nIn this template record are only other template records included.','14,10,56,55,57,61',0,0,0,35),(16,12,0,0,0,'',0,0,0,0,0,1318952770,256,1258294829,3,'tt_content','',0,0,0,0,0,'','// Remove targets\r\nstyles.content.links.extTarget =','tt_content { \r\n # Make some modifications to the rendering of the standard MAIL form records\r\n mailform.20 {\r\n accessibility = 1\r\n }\r\n \r\n # Remove the ancient onfocus=\"blurLink(this);\" from sitemap links\r\n # Unfortunately this hasn\'t been fully implemented in css_styled_content yet\r\n # See also bug 11367\r\n menu.20 {\r\n default.1.noBlur = 1\r\n 1.1.noBlur = 1\r\n 4.1.noBlur = 1\r\n 5.1.noBlur = 1\r\n 6.1.noBlur = 1\r\n 7.1.noBlur = 1\r\n 7.2.noBlur = 1\r\n }\r\n\r\n # Define different wrappers for content elements depending on the page column\r\n stdWrap.outerWrap.cObject = CASE\r\n stdWrap.outerWrap.cObject {\r\n # Define wrappers for each column position (colPos 0,1,2,3)\r\n key.field = colPos\r\n \r\n # Default is no wrapper\r\n default = TEXT\r\n default.value = |\r\n \r\n # Add wrapper for content in right column (colPos=2)\r\n # we use this to style the box around content in this column\r\n 2 = CASE\r\n 2 {\r\n # Add wrapping to all content elements\r\n default = TEXT\r\n default.value =
    |
    \r\n \r\n # But - exclude inserted records from being wrapped\r\n key.field = CType\r\n shortcut = TEXT\r\n shortcut.value = |\r\n image = TEXT\r\n image.value = |\r\n html = TEXT\r\n html.value = |\r\n }\r\n\r\n }\r\n \r\n # Define max image width for each content column separately\r\n image.20.maxW.cObject = CASE\r\n image.20.maxW.cObject {\r\n key.field = colPos\r\n default = TEXT\r\n default.value = 417\r\n # normal\r\n 0 = TEXT\r\n 0.value = 417\r\n # left\r\n 1 = TEXT\r\n 1.value = 150\r\n # right\r\n 2 = TEXT\r\n 2.value = 155\r\n }\r\n \r\n image.20.maxWInText.cObject = CASE\r\n image.20.maxWInText.cObject {\r\n key.field = colPos\r\n default = TEXT\r\n default.value = 260\r\n # normal\r\n 0 = TEXT\r\n 0.value = 260\r\n # left\r\n 1 = TEXT\r\n 1.value = 70\r\n # right\r\n 2 = TEXT\r\n 2.value = 70\r\n }\r\n\r\n}','','','','The TT_CONTENT template\r\n\r\ntt_content is responsible for the styling of the content objects, together with css_styled_content. In this template we made some changes to influence the styling.','',0,0,0,59),(18,12,0,0,0,'',0,0,0,0,0,1258562349,64,1258294829,3,'lib.parseFunc_RTE','',0,0,0,0,0,'','','# remove class=\"bodytext\" from paragraphs\r\nlib.parseFunc_RTE {\r\n nonTypoTagStdWrap.encapsLines {\r\n addAttributes.P.class >\r\n addAttributes.P.class.setOnly >\r\n }\r\n}','','','','The LIB.PARSEFUNC_RTE template\r\n\r\nContent which is added by using the RTE is parsed before the output to the screen. In this template you will find some settings to influence this parsing process.','',0,0,0,60),(19,12,0,0,0,'',0,0,0,0,0,1277023019,32,1258294829,3,'css_styled_content','',0,0,0,0,0,'EXT:css_styled_content/static/','','tt_content.mailform.20.RADIO.layout =
    ###LABEL### ###FIELD###
    \r\ntt_content.mailform.20.radioWrap.accessibilityWrap = ###RADIO_GROUP_LABEL###|','','','','The CSS STYLED CONTENT template\r\n\r\nThis template includes the static template for css_styled_content, which is responsible for most of the default styling.','',0,0,0,53),(20,12,0,0,0,'',0,0,0,0,0,1318952479,16,1258294829,3,'root_systemConfiguration','',0,0,0,0,0,'','','','','','','The CONFIGURATION ROOT template. \r\n\r\nThis template will be called by the MASTER ROOT template. \r\nIt reads the templates for changes in tt_content, lib.stdHeader etc.\r\n\r\nIn this template record are only other template records included.','19,18,16,67',0,0,0,36),(27,11,0,0,0,'',0,0,0,0,0,1276372619,576,1258294829,3,'lib.content','',0,0,0,0,0,'','','# Insert the news plugin in single-view mode instead of normal page content if a news article is requested\r\n[globalVar = GP:tx_ttnews|tt_news > 0] && [globalVar = TSFE:id = {$plugin.tt_news.singlePid}]\r\n\r\nlib.content < plugin.tt_news\r\nlib.content {\r\n # First empty the code field and then set it to single-view\r\n code >\r\n code = SINGLE\r\n}\r\n[else]\r\n\r\n# In all other cases, get the content of the middle column and add it to the \'content\' part\r\nlib.content < styles.content.get\r\n\r\n[global]\r\n\r\nlib.content {\r\n # Wrap it in the markers for the search engine, so it knows that this part has to be indexed\r\n stdWrap.wrap = | \r\n}\r\n','','','','The CONTENT template\r\n\r\nThis template will fill the part \'content\' in the HTML template. Normally we just get the content with styles.content.get, but we need the wrapper around it for indexed search, so it knows what to index.','',0,0,0,71),(36,11,0,0,0,'',0,0,0,0,0,1260552154,512,1258294829,3,'root_blocks','',0,0,0,0,0,'','','','','','','The PAGE BLOCKS ROOT template\r\n\r\nLib (Blocks) templates contain TypoScript to generate \r\nthe building blocks for your website, except menu\'s.\r\n\r\nIn this template record are only other template records included.','27,63,64,60,59,62',0,0,0,61),(49,9,0,0,0,'',0,0,0,0,0,1287577026,128,1258294829,3,'root_extensionConfiguration','',0,0,0,0,0,'','','','','','','The EXTENSION CONFIGURATION ROOT template. \r\n\r\nThis template will be called by the MASTER ROOT template. \r\nIt reads the templates for the extensions.\r\n\r\nIn this template record are only other template records included.','53,52,58,54,65,66',0,0,0,37),(50,8,0,0,0,'',0,0,0,0,0,1323786143,256,1258294829,3,'ROOT','TYPO3 Introduction Package',0,0,0,1,3,'','\n\nfilepaths {\n # cat=filepaths; type=string; label=HTML Templates: Location of the (X)HTML templates relative to site\n templates = fileadmin/default/templates/\n \n # cat=filepaths; type=string; label=CSS: Location of the Cascading Style Sheets relative to site\n css = fileadmin/default/templates/css/\n \n # cat=filepaths; type=string; label=Images: Location of the images relative to site\n images = fileadmin/default/templates/images/\n\n # cat=filepaths; type=string; label=Scripts: Location of the Javascript files relative to site\n scripts = fileadmin/default/templates/scripts/\n\n # cat=filepaths; type=string; label=HTML Templates for extensions: Location of the (X)HTML templates for extensions\n extensiontemplates = fileadmin/default/templates/extensions/\n}\n\nmenu {\n # cat=navigation menus; type=string; label= Top-menu pages: Comma separated list of page id\'s to be included in top-right menu.\n top.pages = 28\n}\n\nplugin.tx_automaketemplate_pi1 {\n # cat=plugin.automaketemplate; type:string; label= HTML template file: Name of the HTML page template file (without path, see contant for filepath.templates)\n templatefile = typo3-intro-template.html\n}\n\nplugin.tt_news {\n # cat=plugin.tt_news; type=string; label= pid_list: Comma separated list of folder id\'s containing which contain news records.\n pid_list = 18\n \n # cat=plugin.tt_news; type=int+; label= singlePid: Default ID of the page containing the tt_news SINGLE-view plugin\n singlePid = 23\n \n # cat=plugin.tt_news; type=int+; label= limit: Default maximum number of items to be shown in LIST-view\n limit = 100\n \n # Date and time formats according to active locales\n dateformat = %x\n dateandtimeformat = %c\n \n # Short notation date format according to international ISO standard\n shortdateformat = %Y-%m-%d\n timeformat = %H:%M\n}\n\nplugin.tx_indexedsearch {\n # cat=plugin.indexed_search; type=int+; label= Search Page ID: UID of the page which contains the indexed search plugin.\n searchpageID = 17\n}\n\nplugin.meta {\n # cat=plugin.meta; type=string; label= Description: Write a short abstract for your website.\n description = This TYPO3 Introduction Package helps you to get started with TYPO3. It provides a basic website setup with examples for the most used features. On top of that, this package contains many helpful comments and notes on how the system works\n \n # cat=plugin.meta; type=string; label= Keywords: Enter a comma separated list of keywords.\n keywords = TYPO3, introduction package, install, demo site, example setup, content management, enterprise\n\n # cat=plugin.meta; type=string; label= Robots: Use for instance these codes: Index all pages: \"all\". Index no pages: \"none\". Only this page: \"index,nofollow\". Only subpages: \"noindex,follow\"\n robots = all\n\n # cat=plugin.meta; type=string; label= Copyright info: Enter copyright information, eg. \"Me Myself and I, 2001. All rights reserved.\"\n copyright = typo3.org GPL\n\n # cat=plugin.meta; type=string; label= Reply-to email\n email = \n\n # cat=plugin.meta; type=string; label= Author: Enter name of author.\n author = T3UXW09 / typo3.org\n \n # cat=plugin.meta; type=int+; label= Revisit after: Number of days between search engine visits.\n revisit = 7\n\n\n # The meta tags below are not used on this website, if you want to use these, you can configure that in TypoScript template page.meta\n \n # cat=plugin.meta; type=boolean; label=Always include global.\n includeGlobal = \n\n # cat=plugin.meta; type=options[,Arabic=ar,Chinese=zh,Danish=dk,Dutch=nl,English=en,Finnish=fi,French=fr,German=de,Greek=el,Hebrew=he,Icelandic=is,Italian=it,Japanese=ja,Norwegian=no,Polish=pl,Portuguese=pt,Russian=ru,Spanish=es,Swedish=sv,Turkish=tr,Multi language=mul]; label= Language: Select language of the content.\n language = en\n \n # cat=plugin.meta; type=string; label= Distribution\n distribution = GLOBAL\n \n # cat=plugin.meta; type=options[,General,Mature,14 years,Restricted]; label= Rating\n rating = General \n}\n\nstyles.content {\n # This defines the maximum width of images inserted in content records of type Images or Text-with-images.\n # There are seperate settings for images floated next to text (..InText)\n imgtext {\n maxW = 651\n maxWInText = 651\n borderThick = 1\n linkWrap.newWindow = 1\n }\n uploads {\n jumpurl_secure = 1\n jumpurl_secure_mimeTypes = pdf=application/pdf, doc=application/msword\n jumpurl = 1\n }\n}\n\ncontentpage {\n # cat=contentpage; type=int+; label= Footer source PID: Parent ID of the footer record used on content pages.\n footerPID = 20\n \n # cat=contentpage; type=int+; label= ID of the home page: ID of the home (root) page of the site.\n homeID = 1\n\n # cat=contentpage; type=int+; label= loginboxPID: ID of the folder containing the login box record (to be shown on multiple pages)\n loginboxPID = 21\n\n # cat=contentpage; type=int+; label= loginboxUID: UID of the login box record (to be shown on multiple pages)\n loginboxUID = 31\n\n # cat=contentpage; type=int+; label= loginpageID: UID of the customer login page.\n loginpageID = 28\n \n # cat=contentpage; type=int+; label= examplelanguagesID: UID of the page which has the language menu enabled\n examplelanguagesID = 25\n \n # cat=contentpage; type=string; label= language1: name of the default language of this site\n language1 = English\n\n # cat=contentpage; type=string; label= language2: name of the second language of this site\n language2 = Dansk\n}\n\n# Set the language of meta tag with DC.language to Danish, when in Danish\n[globalVar = GP:L = 1]\nplugin.meta.language = da\n[global]\n','','','','','The ROOT template. \r\n\r\nThis template will be called by the \"Introduction Package\" template recored in the root page. It reads the root templates for every part, like page, menu, systemConfiguration and extensionConfiguration.\r\n','20,49,15,36,8',0,0,1,49),(58,9,0,0,0,'',0,0,0,0,0,1280484130,1024,1258456536,4,'plugin.indexed_search','',0,0,0,0,0,'','','# Configuration for indexedsearch plugin\r\n\r\nplugin.tx_indexedsearch {\r\n\r\n templateFile = {$filepaths.extensiontemplates}indexed_search/tx_indexedsearch_pi1_template.html\r\n forwardSearchWordsInResultLink = 0\r\n show { \r\n rules = 0\r\n advancedSearchLink = 0\r\n }\r\n search {\r\n rootPidList =\r\n exactCount = 1\r\n }\r\n\r\n _CSS_DEFAULT_STYLE >\r\n _DEFAULT_PI_VARS {\r\n results = 10\r\n }\r\n}\r\n\r\n# Adjust search results when visitor has chosen another language\r\n[globalVar = GP:L = 1]\r\nplugin.tx_indexedsearch._DEFAULT_PI_VARS.lang = 1\r\n[global]\r\n','','','','The INDEXED_SEARCH template\r\nIndexed Search an extension for searching content in the frontend. \r\n\r\nFor a full description of the configuration options, check the manual of this extension. Extension manuals are normally included in the extensions as Open Office documents, and can be accessed directly from the module Ext Manager in the TYPO3 backend (select the option \'loaded extensions or install extension\'.\r\n\r\nFor the extension indexed search, the documentation is delivered in a separated extension with the extension key \'doc_indexed_search\', which is also provided with this Demo Package.','',0,0,0,0),(52,9,0,0,0,'',0,0,0,0,0,1258563143,768,1258299414,4,'plugin.felogin','',0,0,0,0,0,'','','plugin.tx_felogin_pi1 {\r\n # Use our own HTML template from the fileadmin directory\r\n # so we can freely modify it without changing the extension\r\n templateFile = {$filepaths.extensiontemplates}felogin/tx_felogin_pi1_template.html\r\n \r\n # Clear default CSS additions - we take care of that in our own CSS files\r\n _CSS_DEFAULT_STYLE =\r\n}\r\n','','','','The FELOGIN template\r\n\r\nThe felogin extension handles the login for access restricted frontend pages. It displays a form when the user is not logged in, a status when logged in and handles the login process.\r\n\r\nFor a full description of the configuration options, check the manual of this extension. Extension manuals are normally included in the extensions as Open Office documents, and can be accessed directly from the module Ext Manager in the TYPO3 backend (select the option \'loaded extensions or install extension\'.','',0,0,0,0),(54,9,0,0,0,'',0,0,0,0,0,1277199998,1280,1258382313,4,'plugin.tt_news','',0,0,0,0,0,'EXT:tt_news/pi/static/ts_new/','','plugin.tt_news {\r\n templateFile = {$filepaths.extensiontemplates}tt_news/tx_ttnews_pi1_template.html\r\n dontUseBackPid = 1\r\n excludeAlreadyDisplayedNews = 0\r\n noNewsToListMsg_stdWrap.wrap =

    |

    \r\n \r\n displaySingle {\r\n subheader_stdWrap.wrap =
    |
    \r\n image {\r\n file.maxW = 250\r\n file.maxH = 300\r\n #imageLinkWrap = 0\r\n }\r\n }\r\n\r\n # define rendering of LATEST mode\r\n displayLatest {\r\n subheader_stdWrap.cObject >\r\n \r\n subheader_stdWrap {\r\n stripHtml = 1\r\n crop = 70 | ... | 1\r\n ifEmpty.field = bodytext\r\n required = 1\r\n }\r\n /*\r\n image {\r\n file.maxW = 60\r\n file.maxH = 60\r\n imageLinkWrap = 0\r\n }\r\n */\r\n }\r\n\r\n # rendering of LIST mode\r\n displayList {\r\n \r\n subheader_stdWrap {\r\n crop = 250 | ... | 1\r\n required = 1\r\n wrap >\r\n }\r\n content_stdWrap {\r\n wrap =
    |
    \r\n required = 1\r\n }\r\n image {\r\n file.maxW = 175\r\n file.maxH = 175\r\n imageLinkWrap = 0\r\n }\r\n\r\n }\r\n\r\n # Override some of the text labels for tt_news with our own text.\r\n # See EXT:tt_news/pi/locallang.xml for all language labels\r\n _LOCAL_LANG.default {\r\n # Remove the header that tt_news adds by default above the LATEST listing\r\n latestHeader =\r\n \r\n # replace the word \'more\' after article text in news list or latest with \'>>\'\r\n more = >>\r\n }\r\n\r\n # Date & time formats for news display. The easiest way to change them is by changing the values\r\n # of the constants in TypoScript template ROOT in the root folder of the TypoScript Templates.\r\n # There are configuration options for various types of news display. If you want, you can modify\r\n # each separately according to your own preferences.\r\n \r\n archiveTitleCObject {\r\n 10.strftime = %Y-%B\r\n }\r\n getRelatedCObject.10 {\r\n default.20.strftime = {$plugin.tt_news.dateformat} {$plugin.tt_news.timeformat}\r\n 1.20.strftime = {$plugin.tt_news.dateformat} {$plugin.tt_news.timeformat}\r\n 2.20.strftime = {$plugin.tt_news.dateformat} {$plugin.tt_news.timeformat}\r\n }\r\n displaySingle {\r\n date_stdWrap.strftime = {$plugin.tt_news.dateformat}\r\n time_stdWrap.strftime = {$plugin.tt_news.timeformat}\r\n }\r\n displayLatest {\r\n date_stdWrap.strftime = {$plugin.tt_news.dateformat}\r\n time_stdWrap.strftime = {$plugin.tt_news.timeformat}\r\n }\r\n displayList {\r\n date_stdWrap.strftime = {$plugin.tt_news.dateformat}\r\n time_stdWrap.strftime = {$plugin.tt_news.timeformat}\r\n }\r\n}','','','','The TT_NEWS template\r\n\r\nThe name says it all, this is a news plugin.\r\n\r\nFor a full description of the configuration options, check the manual of this extension. Extension manuals are normally included in the extensions as Open Office documents, and can be accessed directly from the module Ext Manager in the TYPO3 backend (select the option \'loaded extensions or install extension\'.','',0,0,0,0),(56,13,0,0,0,'',0,0,0,0,10,1258641618,640,1258385424,4,'menu.secondlevel','',0,0,0,0,0,'','','# This menu is slightly more complicated than the others because we copy our default menu again, but then we\'ll start overriding some settings from the default menu.\r\n# To get a full overview of the configuration of this menu you should look at both our default \'menu\' and the \'menu.secondlevel\' as shown below.\r\n# You can use the TypoScript Object Browser to view the end result of this.\r\n# (go to the Template module and select \'Typoscript Object Browser\' in the selectbox in the right frame.)\r\n\r\nmenu.secondlevel < menu\r\nmenu.secondlevel {\r\n entryLevel = 1\r\n \r\n 1 {\r\n NO {\r\n wrapItemAndSub =
  • |
  • \r\n }\r\n \r\n # First clear the ATagParams setting of the ACT state because we are working with a copy of the object \'menu\'\r\n # After that we add our modified configuration for menu.secondlevel\r\n ACT {\r\n ATagParams >\r\n wrapItemAndSub =
  • |
  • \r\n }\r\n\r\n CUR {\r\n ATagParams >\r\n wrapItemAndSub =
  • |
  • \r\n }\r\n\r\n }\r\n \r\n # Copy the configuration of the first level of this menu to level 2 and 3\r\n 2 < .1\r\n 3 < .1\r\n}','','','','The SECOND LEVEL MENU template.\r\n\r\nConfiguration for the menu of the sublevels of pages. It inherits the MAIN MENU template and has some small modifications on top of it, in this case the settings of the entryLevel. ','',0,0,0,43),(57,13,0,0,0,'',0,0,0,0,0,1258653358,896,1258409599,4,'menu.language','',0,0,0,0,0,'','','menu.language = HMENU\r\n\r\n# We use a condition to show the language menu only on the page with the id from constant contentpage.examplelanguagesID\r\n[globalVar = TSFE:id = {$contentpage.examplelanguagesID}]\r\n\r\nmenu.language {\r\n special = language\r\n special.value = 0,1\r\n 1 = TMENU\r\n 1 {\r\n wrap =
      |
    \r\n \r\n # Remove the (old) default behaviour which adds onfocus=\"blurLink(this);\" to all links\r\n noBlur = 1\r\n \r\n NO = 1\r\n NO {\r\n # Override the standard menu item value (which is the page title) with our own cObject\r\n stdWrap.cObject = TEXT\r\n \r\n # Use the TypoScript option split function to display different values for the first and second item\r\n stdWrap.cObject.value = {$contentpage.language1} || {$contentpage.language2}\r\n allWrap =
  • |
  • \r\n }\r\n \r\n ACT < .NO\r\n ACT {\r\n ATagParams = class=\"active\"\r\n }\r\n }\r\n}\r\n\r\n[global]\r\n','','','','The LANGUAGE menu\r\n\r\nGenerates a list of available languages on a page. If the page has no language overlay, there is no link available to switch to the language.','',0,0,0,0),(62,11,0,0,0,'',0,0,0,0,0,1277208666,768,1258476895,4,'lib.footer','',0,0,0,0,0,'','','# The method used here to fetch a record from a page or folder is slightly different from the one used \r\n# to fetch the loginbox in lib.contentleft\r\n# The method here doesn\'t refer to a specific record but takes the first record from the folder. This\r\n# has the advantage that an editor can delete the record and just create a new one, and it still works.\r\n/*\r\nlib.footer = CONTENT\r\nlib.footer {\r\n table = tt_content\r\n select {\r\n orderBy = sorting\r\n max = 1\r\n pidInList = {$contentpage.footerPID}\r\n }\r\n}\r\n*/\r\n\r\nlib.footer = COA\r\n\r\nlib.footer.10 < styles.content.getLeft\r\nlib.footer.10.select.pidInList = {$contentpage.footerPID}\r\nlib.footer.10.stdWrap.wrap =
    |
    \r\n\r\nlib.footer.20 < styles.content.get\r\nlib.footer.20.select.pidInList = {$contentpage.footerPID}\r\nlib.footer.20.stdWrap.wrap =
    |
    \r\n\r\nlib.footer.30 < styles.content.getRight\r\nlib.footer.30.select.pidInList = {$contentpage.footerPID}\r\nlib.footer.30.stdWrap.wrap =
    |
    \r\n','','','','lib.footer fetches the content record in \'Generated content > Footer content\' and displays that on all pages.','',0,0,0,0),(63,11,0,0,0,'',0,0,0,0,0,1258645191,640,1258484363,4,'lib.contentleft','',0,0,0,0,0,'','','lib.contentleft = COA\r\n\r\n# Insert the content from the left column into lib.contentleft\r\nlib.contentleft {\r\n 20 < styles.content.getLeft\r\n}','','','','TypoScript template which compiles the contents for the left column on the pages','',0,0,0,0),(64,11,0,0,0,'',0,0,0,0,63,1258655161,704,1258645083,4,'lib.contentright','',0,0,0,0,0,'','','lib.contentright = COA\r\n\r\n# The configuration below this condition will only be included on the page loginpageID, or on its subpages\r\n[PIDinRootline = {$contentpage.loginpageID}]\r\n\r\n# Insert a loginbox above the content (but below the menu) in the left column.\r\n# We fetch the loginbox record from the SysFolder \'Login Box\' under \'Generated content\'\r\n# There are different ways to do this, in lib.footer you will see a slightly different approach.\r\nlib.contentright {\r\n 10 = CONTENT\r\n 10 {\r\n table = tt_content\r\n select.pidInList = {$contentpage.loginboxPID}\r\n select.uidInList = {$contentpage.loginboxUID}\r\n }\r\n}\r\n\r\n# End of the conditional part\r\n[global]\r\n\r\n# In all other cases, get the content of the middle column and add it to the \'content\' part\r\nlib.contentright.20 < styles.content.getRight\r\n','','','','TypoScript template which compiles the contents for the right column on the pages','',0,0,0,0),(65,9,0,0,0,'',0,0,0,0,54,1319056839,1536,1280242156,12,'plugin.wt_spamshield','',0,0,0,0,0,'EXT:wt_spamshield/static/','','plugin.wt_spamshield {\r\n enable.standardMailform = 1\r\n}','','','','The wt_spamshield template\r\n\r\nThis template enables the wt_spamshield extension for the standard mailform\r\n\r\nFor a full description of the configuration options, check the manual of this extension. Extension manuals are normally included in the extensions as Open Office documents, and can be accessed directly from the module Ext Manager in the TYPO3 backend (select the option \'loaded extensions or install extension\'.','',0,0,0,0),(66,9,0,0,0,NULL,0,0,0,0,0,1287577004,1792,1287577004,1,'jquerycolorbox','',0,0,0,0,0,'EXT:jquerycolorbox/static/','','','','','','Includes static template from the jquerycolorbox extension','',0,0,0,0),(67,12,0,0,0,NULL,0,0,0,0,0,1319440872,512,1318952440,1,'tt_content.mailform','',0,0,0,0,0,'EXT:form/Configuration/TypoScript/','','','','','','','',0,0,0,0); +/*!40000 ALTER TABLE sys_template ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_ter` +-- + +DROP TABLE IF EXISTS sys_ter; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_ter ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + title varchar(150) DEFAULT NULL, + description mediumtext, + wsdl_url varchar(100) DEFAULT NULL, + mirror_url varchar(100) DEFAULT NULL, + lastUpdated int(11) unsigned NOT NULL DEFAULT '0', + extCount int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (uid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_ter` +-- + +LOCK TABLES sys_ter WRITE; +/*!40000 ALTER TABLE sys_ter DISABLE KEYS */; +/*!40000 ALTER TABLE sys_ter ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_workspace` +-- + +DROP TABLE IF EXISTS sys_workspace; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_workspace ( + uid int(11) NOT NULL AUTO_INCREMENT, + pid int(11) NOT NULL DEFAULT '0', + tstamp int(11) NOT NULL DEFAULT '0', + deleted tinyint(1) NOT NULL DEFAULT '0', + title varchar(30) DEFAULT NULL, + description varchar(255) DEFAULT NULL, + adminusers varchar(4000) NOT NULL DEFAULT '', + members varchar(4000) NOT NULL DEFAULT '', + reviewers varchar(4000) NOT NULL DEFAULT '', + db_mountpoints varchar(255) DEFAULT NULL, + file_mountpoints varchar(255) DEFAULT NULL, + publish_time int(11) NOT NULL DEFAULT '0', + unpublish_time int(11) NOT NULL DEFAULT '0', + freeze tinyint(3) NOT NULL DEFAULT '0', + live_edit tinyint(3) NOT NULL DEFAULT '0', + vtypes tinyint(3) NOT NULL DEFAULT '0', + disable_autocreate tinyint(1) NOT NULL DEFAULT '0', + swap_modes tinyint(3) NOT NULL DEFAULT '0', + publish_access tinyint(3) NOT NULL DEFAULT '0', + custom_stages int(11) NOT NULL DEFAULT '0', + stagechg_notification tinyint(3) NOT NULL DEFAULT '0', + edit_notification_mode tinyint(3) NOT NULL DEFAULT '0', + edit_notification_defaults varchar(255) NOT NULL DEFAULT '', + edit_allow_notificaton_settings tinyint(3) NOT NULL DEFAULT '0', + publish_notification_mode tinyint(3) NOT NULL DEFAULT '0', + publish_notification_defaults varchar(255) NOT NULL DEFAULT '', + publish_allow_notificaton_settings tinyint(3) NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY parent (pid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_workspace` +-- + +LOCK TABLES sys_workspace WRITE; +/*!40000 ALTER TABLE sys_workspace DISABLE KEYS */; +/*!40000 ALTER TABLE sys_workspace ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sys_workspace_stage` +-- + +DROP TABLE IF EXISTS sys_workspace_stage; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE sys_workspace_stage ( + uid int(11) NOT NULL AUTO_INCREMENT, + pid int(11) NOT NULL DEFAULT '0', + tstamp int(11) NOT NULL DEFAULT '0', + deleted tinyint(1) NOT NULL DEFAULT '0', + sorting int(11) unsigned NOT NULL DEFAULT '0', + title varchar(30) DEFAULT NULL, + responsible_persons varchar(255) DEFAULT NULL, + default_mailcomment text, + parentid int(11) NOT NULL DEFAULT '0', + parenttable tinytext NOT NULL, + notification_mode tinyint(3) NOT NULL DEFAULT '0', + notification_defaults varchar(255) NOT NULL DEFAULT '', + allow_notificaton_settings tinyint(3) NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY parent (pid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `sys_workspace_stage` +-- + +LOCK TABLES sys_workspace_stage WRITE; +/*!40000 ALTER TABLE sys_workspace_stage DISABLE KEYS */; +INSERT INTO sys_workspace_stage (uid, pid, tstamp, deleted, sorting, title, responsible_persons, default_mailcomment, parentid, parenttable, notification_mode, notification_defaults, allow_notificaton_settings) VALUES (1,0,1290048921,0,1,'Stage 1','be_users_3','',1,'sys_workspace',0,'',0); +/*!40000 ALTER TABLE sys_workspace_stage ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tt_content` +-- + +DROP TABLE IF EXISTS tt_content; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tt_content ( + uid int(11) NOT NULL AUTO_INCREMENT, + pid int(11) NOT NULL DEFAULT '0', + t3ver_oid int(11) NOT NULL DEFAULT '0', + t3ver_id int(11) NOT NULL DEFAULT '0', + t3ver_wsid int(11) NOT NULL DEFAULT '0', + t3ver_label varchar(255) DEFAULT NULL, + t3ver_state tinyint(4) NOT NULL DEFAULT '0', + t3ver_stage int(11) NOT NULL DEFAULT '0', + t3ver_count int(11) NOT NULL DEFAULT '0', + t3ver_tstamp int(11) NOT NULL DEFAULT '0', + t3ver_move_id int(11) NOT NULL DEFAULT '0', + t3_origuid int(11) NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + crdate int(11) unsigned NOT NULL DEFAULT '0', + cruser_id int(11) unsigned NOT NULL DEFAULT '0', + hidden tinyint(4) unsigned NOT NULL DEFAULT '0', + sorting int(11) unsigned NOT NULL DEFAULT '0', + CType varchar(30) DEFAULT NULL, + header varchar(255) DEFAULT NULL, + header_position varchar(6) DEFAULT NULL, + bodytext mediumtext, + image text, + imagewidth mediumint(11) unsigned NOT NULL DEFAULT '0', + imageorient tinyint(4) unsigned NOT NULL DEFAULT '0', + imagecaption text, + imagecols tinyint(4) unsigned NOT NULL DEFAULT '0', + imageborder tinyint(4) unsigned NOT NULL DEFAULT '0', + media text, + layout tinyint(3) unsigned NOT NULL DEFAULT '0', + deleted tinyint(4) unsigned NOT NULL DEFAULT '0', + cols tinyint(3) unsigned NOT NULL DEFAULT '0', + records text, + pages tinytext, + starttime int(11) unsigned NOT NULL DEFAULT '0', + endtime int(11) unsigned NOT NULL DEFAULT '0', + colPos tinyint(3) unsigned NOT NULL DEFAULT '0', + subheader varchar(255) DEFAULT NULL, + spaceBefore smallint(5) unsigned NOT NULL DEFAULT '0', + spaceAfter smallint(5) unsigned NOT NULL DEFAULT '0', + fe_group varchar(100) NOT NULL DEFAULT '0', + header_link varchar(255) DEFAULT NULL, + imagecaption_position varchar(6) DEFAULT NULL, + image_link text, + image_zoom tinyint(3) unsigned NOT NULL DEFAULT '0', + image_noRows tinyint(3) unsigned NOT NULL DEFAULT '0', + image_effects tinyint(3) unsigned NOT NULL DEFAULT '0', + image_compression tinyint(3) unsigned NOT NULL DEFAULT '0', + altText text, + titleText text, + longdescURL text, + header_layout varchar(30) NOT NULL DEFAULT '0', + text_align varchar(6) DEFAULT NULL, + text_face tinyint(3) unsigned NOT NULL DEFAULT '0', + text_size tinyint(3) unsigned NOT NULL DEFAULT '0', + text_color tinyint(3) unsigned NOT NULL DEFAULT '0', + text_properties tinyint(3) unsigned NOT NULL DEFAULT '0', + menu_type varchar(30) NOT NULL DEFAULT '0', + list_type varchar(36) NOT NULL DEFAULT '0', + table_border tinyint(3) unsigned NOT NULL DEFAULT '0', + table_cellspacing tinyint(3) unsigned NOT NULL DEFAULT '0', + table_cellpadding tinyint(3) unsigned NOT NULL DEFAULT '0', + table_bgColor tinyint(3) unsigned NOT NULL DEFAULT '0', + select_key varchar(80) DEFAULT NULL, + sectionIndex tinyint(3) unsigned NOT NULL DEFAULT '0', + linkToTop tinyint(3) unsigned NOT NULL DEFAULT '0', + filelink_size tinyint(3) unsigned NOT NULL DEFAULT '0', + section_frame tinyint(3) unsigned NOT NULL DEFAULT '0', + `date` int(10) unsigned NOT NULL DEFAULT '0', + splash_layout varchar(30) NOT NULL DEFAULT '0', + multimedia tinytext, + image_frames tinyint(3) unsigned NOT NULL DEFAULT '0', + recursive tinyint(3) unsigned NOT NULL DEFAULT '0', + imageheight mediumint(8) unsigned NOT NULL DEFAULT '0', + rte_enabled tinyint(4) NOT NULL DEFAULT '0', + sys_language_uid int(11) NOT NULL DEFAULT '0', + tx_impexp_origuid int(11) NOT NULL DEFAULT '0', + pi_flexform mediumtext, + l18n_parent int(11) NOT NULL DEFAULT '0', + l18n_diffsource mediumblob, + PRIMARY KEY (uid), + KEY t3ver_oid (t3ver_oid,t3ver_wsid), + KEY parent (pid,sorting), + KEY `language` (l18n_parent,sys_language_uid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tt_content` +-- + +LOCK TABLES tt_content WRITE; +/*!40000 ALTER TABLE tt_content DISABLE KEYS */; +INSERT INTO tt_content (uid, pid, t3ver_oid, t3ver_id, t3ver_wsid, t3ver_label, t3ver_state, t3ver_stage, t3ver_count, t3ver_tstamp, t3ver_move_id, t3_origuid, tstamp, crdate, cruser_id, hidden, sorting, CType, header, header_position, bodytext, image, imagewidth, imageorient, imagecaption, imagecols, imageborder, media, layout, deleted, cols, records, pages, starttime, endtime, colPos, subheader, spaceBefore, spaceAfter, fe_group, header_link, imagecaption_position, image_link, image_zoom, image_noRows, image_effects, image_compression, altText, titleText, longdescURL, header_layout, text_align, text_face, text_size, text_color, text_properties, menu_type, list_type, table_border, table_cellspacing, table_cellpadding, table_bgColor, select_key, sectionIndex, linkToTop, filelink_size, section_frame, date, splash_layout, multimedia, image_frames, recursive, imageheight, rte_enabled, sys_language_uid, tx_impexp_origuid, pi_flexform, l18n_parent, l18n_diffsource) VALUES (246,52,0,0,0,'',0,0,0,0,0,0,1277202304,1277199637,24,0,320,'textpic','From an Individual to a Vibrant Community','','In 1997, Kasper Skårhøj began developing TYPO3 from scratch. At the time, the term Content Management was still widely unheard of. Today there are many open source and proprietary CMS solutions on the market, but none come close to TYPO3 in terms of sheer functionality and maturity. After more than ten years of active, incremental development, TYPO3 is effectively feature-complete, making it an extremely compelling solution for web content management.','kasper-skarhoj1_01.jpeg',0,25,'',1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,260,0,0,0,NULL,0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(247,52,0,0,0,'',0,0,0,0,0,0,1277199681,1277199681,24,0,576,'text','Commitment to Open Source','','TYPO3 was founded on the belief that true open source, community-oriented development can make tools that surpass proprietary solutions. It is free and open to everyone, yet powerful enough for mission-critical commercial use. TYPO3 is an ever-expanding open source project that draws its strength from the imagination and ingenuity of those who use it. You do not have to pay a licensing fee for TYPO3 and you never will—leading to significantly reduced total cost of ownership (TCO) in both the short and long-term.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(239,67,0,0,0,'',0,0,0,0,0,0,1277149308,1277149308,23,0,256,'text','Thank you for your feedback','','An email has been sent, we appreciate your feedback.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(240,28,0,0,0,'',0,0,0,0,0,0,1277154458,1277151090,23,0,428,'html','Login Link for customer1','','

    Use this link to log in as customer1

    \r\n',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'-1','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(243,28,0,0,0,'',0,0,0,0,0,33,1277154432,1277152779,23,0,440,'text','','','Username: someone
    Password: someone
    This user only has access to the \'Any login page\'.','',0,0,NULL,1,0,'',0,0,0,'','',0,0,0,'',0,0,'-1','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(25,20,0,0,0,'',0,0,0,0,0,0,1276447390,1258388150,4,0,256,'text','Related Links','','TYPO3 Documentation
    TYPO3 Books
    TYPO3 Mailing Lists
    TYPO3 Usergroups
    TYPO3 Events
    TYPO3 Wiki',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'4','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(26,23,0,0,0,'',0,0,0,0,0,0,1258389366,1258389272,4,0,256,'list','All news articles','',NULL,NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','9',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,'\n\n \n \n \n \n LIST\n \n \n datetime\n \n \n \n \n \n 1\n \n \n 1,2\n \n \n \n \n \n 0\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n 0\n \n \n 0\n \n \n \n \n \n \n \n \n 0\n \n \n \n \n \n \n \n',0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:9:\"list_type\";N;s:11:\"pi_flexform\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(27,23,0,0,0,'',0,0,0,0,0,0,1258753668,1258393417,4,0,128,'list','Latest news','','',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','9',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,'\n\n \n \n \n \n LATEST\n \n \n datetime\n \n \n desc\n \n \n 1\n \n \n 1,2\n \n \n \n \n \n 0\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n 0\n \n \n 0\n \n \n \n \n \n \n \n \n 0\n \n \n \n \n \n \n \n',0,'a:1:{s:6:\"hidden\";N;}'),(207,16,0,0,0,'',0,0,0,0,0,0,1274455483,1274454999,19,0,256,'text','Page not found','','The page you were looking for cannot be found. You may have followed a bad link or mis-typed an URL. Possibly the page has been moved, discarded or is from the past. Our apologies.

    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(28,17,0,0,0,'',0,0,0,0,0,0,1258456962,1258456907,4,0,256,'list','','',NULL,NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,'',0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','indexed_search',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:18:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:9:\"list_type\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(29,25,0,0,0,'',0,0,0,0,0,0,1276349876,1258457490,3,0,256,'text','Examples','','
    1. Bulgarian: Жълтата Ð´ÑŽÐ»Ñ Ð±ÐµÑˆÐµ щаÑтлива, че пухът, който цъфна, замръзна като гьон.
    2. Czech: PříliÅ¡ žluÅ¥ouÄký kůň úpÄ›l Äábelské kódy.
    3. Dutch: Pa\'s wijze lynx bezag vroom het fikse aquaduct.
    4. English: The quick brown fox jumps over the lazy dog.
    5. Esperanto: EÄ¥oÅanÄo ĉiuĵaÅ­de.
    6. French: Les naïfs ægithales hâtifs pondant à Noël où il gèle sont sûrs d\'être déçus et de voir leurs drôles d\'œufs abîmés.
    7. German: Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. (1)
    8. German: Im finsteren Jagdschloß am offenen Felsquellwasser patzte der affig-flatterhafte kauzig-höf‌liche Bäcker über seinem versifften kniffligen C-Xylophon. (2)
    9. Greek (monotonic): ξεσκεπάζω την ψυχοφθόÏα βδελυγμία
    10. Greek (polytonic): ξεσκεπάζω τὴν ψυχοφθόÏα βδελυγμία
    11. Hebrew: ×–×” ×›×™×£ ×¡×ª× ×œ×©×ž×•×¢ ×יך תנצח קרפד ×¢×¥ טוב בגן.
    12. Hungarian: ÃrvíztűrÅ‘ tükörfúrógép.
    13. Icelandic: Sævör grét áðan því úlpan var ónýt.
    14. Irish: "An ḃfuil do Ä‹roí ag bualaḋ ó ḟaitíos an Ä¡rá a á¹eall lena ṗóg éada ó ṡlí do leasa ṫú?" "D\'ḟuascail Ãosa Úrá¹ac na hÓiÄ¡e Beannaiṫe pór Éava agus Ãḋaiá¹."
    15. Jamaican: Chruu, a kwik di kwik brong fox a jomp huova di liezi daag de, yu no siit?
    16. Japanese (Hiragana):
      ã„ã‚ã¯ã«ã»ã¸ã©ã€€ã¡ã‚Šã¬ã‚‹ã‚’
      ã‚ãŒã‚ˆãŸã‚Œãžã€€ã¤ã­ãªã‚‰ã‚€
      ã†ã‚ã®ãŠãã‚„ã¾ã€€ã‘ãµã“ãˆã¦
      ã‚ã•ãゆã‚ã¿ã˜ã€€ã‚‘ã²ã‚‚ã›ãš (4)
    17. Polish: Pchnąć w tę łódź jeża lub ośm skrzyń fig.
    18. Portuguese: O próximo vôo à noite sobre o Atlântico, põe freqüentemente o único médico. (3)
    19. Sami (Northern): Vuol Ruoŧa geÄ‘ggiid leat máŋga luosa ja Äuovžža.
    20. Slovak: Starý kôň na hÅ•be kníh žuje tíško povädnuté ruže, na stĺpe sa Äateľ uÄí kvákaÅ¥ novú ódu o živote.
    21. Spanish: El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro.
    22. Swedish: Flygande bäckasiner söka strax hwila på mjuka tuvor.
    23. Russian: Съешь же ещё Ñтих мÑгких французÑких булок да выпей чаю.
    24. Russian: Ð’ чащах юга жил-был цитруÑ? Да, но фальшивый ÑкземплÑÑ€! Ñ‘ÑŠ.
    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'100','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(30,25,0,0,0,'',0,0,0,0,0,29,1277121573,1258457659,3,0,512,'text','Eksempler','','
    1. Bulgarian: Жълтата Ð´ÑŽÐ»Ñ Ð±ÐµÑˆÐµ щаÑтлива, че пухът, който цъфна, замръзна като гьон.
    2. Czech: PříliÅ¡ žluÅ¥ouÄký kůň úpÄ›l Äábelské kódy.
    3. Dutch: Pa\'s wijze lynx bezag vroom het fikse aquaduct.
    4. English: The quick brown fox jumps over the lazy dog.
    5. Esperanto: EÄ¥oÅanÄo ĉiuĵaÅ­de.
    6. French: Les naïfs ægithales hâtifs pondant à Noël où il gèle sont sûrs d\'être déçus et de voir leurs drôles d\'œufs abîmés.
    7. German: Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. (1)
    8. German: Im finsteren Jagdschloß am offenen Felsquellwasser patzte der affig-flatterhafte kauzig-höf‌liche Bäcker über seinem versifften kniffligen C-Xylophon. (2)
    9. Greek (monotonic): ξεσκεπάζω την ψυχοφθόÏα βδελυγμία
    10. Greek (polytonic): ξεσκεπάζω τὴν ψυχοφθόÏα βδελυγμία
    11. Hebrew: ×–×” ×›×™×£ ×¡×ª× ×œ×©×ž×•×¢ ×יך תנצח קרפד ×¢×¥ טוב בגן.
    12. Hungarian: ÃrvíztűrÅ‘ tükörfúrógép.
    13. Icelandic: Sævör grét áðan því úlpan var ónýt.
    14. Irish: "An ḃfuil do Ä‹roí ag bualaḋ ó ḟaitíos an Ä¡rá a á¹eall lena ṗóg éada ó ṡlí do leasa ṫú?" "D\'ḟuascail Ãosa Úrá¹ac na hÓiÄ¡e Beannaiṫe pór Éava agus Ãḋaiá¹."
    15. Jamaican: Chruu, a kwik di kwik brong fox a jomp huova di liezi daag de, yu no siit?
    16. Japanese (Hiragana):
      ã„ã‚ã¯ã«ã»ã¸ã©ã€€ã¡ã‚Šã¬ã‚‹ã‚’
      ã‚ãŒã‚ˆãŸã‚Œãžã€€ã¤ã­ãªã‚‰ã‚€
      ã†ã‚ã®ãŠãã‚„ã¾ã€€ã‘ãµã“ãˆã¦
      ã‚ã•ãゆã‚ã¿ã˜ã€€ã‚‘ã²ã‚‚ã›ãš (4)
    17. Polish: Pchnąć w tę łódź jeża lub ośm skrzyń fig.
    18. Portuguese: O próximo vôo à noite sobre o Atlântico, põe freqüentemente o único médico. (3)
    19. Sami (Northern): Vuol Ruoŧa geÄ‘ggiid leat máŋga luosa ja Äuovžža.
    20. Slovak: Starý kôň na hÅ•be kníh žuje tíško povädnuté ruže, na stĺpe sa Äateľ uÄí kvákaÅ¥ novú ódu o živote.
    21. Spanish: El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro.
    22. Swedish: Flygande bäckasiner söka strax hwila på mjuka tuvor.
    23. Russian: Съешь же ещё Ñтих мÑгких французÑких булок да выпей чаю.
    24. Russian: Ð’ чащах юга жил-был цитруÑ? Да, но фальшивый ÑкземплÑÑ€! Ñ‘ÑŠ.
    ','',0,0,NULL,1,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'100','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,1,0,NULL,29,'a:20:{s:5:\"CType\";s:4:\"text\";s:16:\"sys_language_uid\";s:1:\"0\";s:6:\"colPos\";s:1:\"0\";s:11:\"spaceBefore\";s:1:\"0\";s:10:\"spaceAfter\";s:1:\"0\";s:13:\"section_frame\";s:1:\"0\";s:12:\"sectionIndex\";s:1:\"1\";s:6:\"hidden\";s:1:\"0\";s:6:\"header\";s:8:\"Examples\";s:15:\"header_position\";s:0:\"\";s:13:\"header_layout\";s:3:\"100\";s:11:\"header_link\";s:0:\"\";s:4:\"date\";s:1:\"0\";s:9:\"linkToTop\";s:1:\"0\";s:8:\"bodytext\";s:2808:\"
    1. Bulgarian: Жълтата Ð´ÑŽÐ»Ñ Ð±ÐµÑˆÐµ щаÑтлива, че пухът, който цъфна, замръзна като гьон.
    2. Czech: PříliÅ¡ žluÅ¥ouÄký kůň úpÄ›l Äábelské kódy.
    3. Dutch: Pa\'s wijze lynx bezag vroom het fikse aquaduct.
    4. English: The quick brown fox jumps over the lazy dog.
    5. Esperanto: EÄ¥oÅanÄo ĉiuĵaÅ­de.
    6. French: Les naïfs ægithales hâtifs pondant à Noël où il gèle sont sûrs d\'être déçus et de voir leurs drôles d\'œufs abîmés.
    7. German: Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. (1)
    8. German: Im finsteren Jagdschloß am offenen Felsquellwasser patzte der affig-flatterhafte kauzig-höf‌liche Bäcker über seinem versifften kniffligen C-Xylophon. (2)
    9. Greek (monotonic): ξεσκεπάζω την ψυχοφθόÏα βδελυγμία
    10. Greek (polytonic): ξεσκεπάζω τὴν ψυχοφθόÏα βδελυγμία
    11. Hebrew: ×–×” ×›×™×£ ×¡×ª× ×œ×©×ž×•×¢ ×יך תנצח קרפד ×¢×¥ טוב בגן.
    12. Hungarian: ÃrvíztűrÅ‘ tükörfúrógép.
    13. Icelandic: Sævör grét áðan því úlpan var ónýt.
    14. Irish: "An ḃfuil do Ä‹roí ag bualaḋ ó ḟaitíos an Ä¡rá a á¹eall lena ṗóg éada ó ṡlí do leasa ṫú?" "D\'ḟuascail Ãosa Úrá¹ac na hÓiÄ¡e Beannaiṫe pór Éava agus Ãḋaiá¹."
    15. Jamaican: Chruu, a kwik di kwik brong fox a jomp huova di liezi daag de, yu no siit?
    16. Japanese (Hiragana):
      ã„ã‚ã¯ã«ã»ã¸ã©ã€€ã¡ã‚Šã¬ã‚‹ã‚’
      ã‚ãŒã‚ˆãŸã‚Œãžã€€ã¤ã­ãªã‚‰ã‚€
      ã†ã‚ã®ãŠãã‚„ã¾ã€€ã‘ãµã“ãˆã¦
      ã‚ã•ãゆã‚ã¿ã˜ã€€ã‚‘ã²ã‚‚ã›ãš (4)
    17. Polish: Pchnąć w tę łódź jeża lub ośm skrzyń fig.
    18. Portuguese: O próximo vôo à noite sobre o Atlântico, põe freqüentemente o único médico. (3)
    19. Sami (Northern): Vuol Ruoŧa geÄ‘ggiid leat máŋga luosa ja Äuovžža.
    20. Slovak: Starý kôň na hÅ•be kníh žuje tíško povädnuté ruže, na stĺpe sa Äateľ uÄí kvákaÅ¥ novú ódu o živote.
    21. Spanish: El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro.
    22. Swedish: Flygande bäckasiner söka strax hwila på mjuka tuvor.
    23. Russian: Съешь же ещё Ñтих мÑгких французÑких булок да выпей чаю.
    24. Russian: Ð’ чащах юга жил-был цитруÑ? Да, но фальшивый ÑкземплÑÑ€! Ñ‘ÑŠ.
    \";s:11:\"rte_enabled\";s:1:\"0\";s:9:\"starttime\";s:1:\"0\";s:7:\"endtime\";s:1:\"0\";s:8:\"fe_group\";s:0:\"\";s:11:\"l18n_parent\";s:1:\"0\";}'),(31,21,0,0,0,'',0,0,0,0,0,0,1277040534,1258479179,4,0,256,'login','Login box','',NULL,NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,'\n\n \n \n \n \n 1\n \n \n 1\n \n \n 29\n \n \n \n \n \n \n \n \n \n \n \n \n logout\n \n \n 0\n \n \n 31\n \n \n \n \n \n 28\n \n \n 0\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n',0,'a:18:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:11:\"pi_flexform\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(32,28,0,0,0,'',0,0,0,0,0,0,1258481622,1258481622,4,0,512,'text','You can now view the protected pages!','','You are logged in, so you can now view the protected pages which you can find in the navigation menu on the left.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'-2','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(33,28,0,0,0,'',0,0,0,0,0,0,1277152831,1258482129,4,0,416,'text','Login to this website','','You are currently not logged in. Visitors who have an account can login to the website to get access to protected pages and content on this website. \r\nBy default this website has 2 user accounts installed which you can use to test this feature:\r\nUsername: customer1
    Password: customer1
    This user has access to all protected content on the default site.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'-1','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(244,28,0,0,0,'',0,0,0,0,0,240,1277154477,1277152850,23,0,476,'html','Login Link for someone','','

    Use this link to log in as someone

    \r\n','',0,0,NULL,1,0,'',0,0,0,'','',0,0,0,'',0,0,'-1','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(34,31,0,0,0,'',0,0,0,0,0,27,1277112418,1258482446,4,0,256,'list','Internal news','','','',0,0,NULL,1,0,'',0,0,0,'','',0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','9',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,'\n\n \n \n \n \n LATEST\n \n \n datetime\n \n \n desc\n \n \n 1\n \n \n 3\n \n \n \n \n \n 0\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n 0\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n 0\n \n \n 0\n \n \n \n \n \n \n \n \n 0\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n',0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:9:\"list_type\";N;s:11:\"pi_flexform\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(35,30,0,0,0,'',0,0,0,0,0,27,1277112544,1258482470,4,0,256,'list','Internal news','','','',0,0,NULL,1,0,'',0,0,0,'','',0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','9',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,'\n\n \n \n \n \n LATEST\n \n \n datetime\n \n \n desc\n \n \n 1\n \n \n 3\n \n \n \n \n \n 0\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n 0\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n 0\n \n \n 0\n \n \n \n \n \n \n \n \n 0\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n',0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:9:\"list_type\";N;s:11:\"pi_flexform\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(38,44,0,0,0,'',0,0,0,0,0,44,1258558361,1258542915,4,0,5376,'text','Header 5. level (right-justified)','right','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','5','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,55,'',0,'a:1:{s:6:\"header\";N;}'),(39,44,0,0,0,'',0,0,0,0,0,43,1258558361,1258542915,4,0,5120,'text','Header 4. level (right-justified)','right','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','4','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,56,'',0,'a:1:{s:6:\"header\";N;}'),(40,44,0,0,0,'',0,0,0,0,0,42,1258558361,1258542915,4,0,4864,'text','Header 3. level (right-justified)','right','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','3','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,57,'',0,'a:1:{s:6:\"header\";N;}'),(41,44,0,0,0,'',0,0,0,0,0,41,1258558361,1258542915,4,0,4608,'text','Header 2. level (right-justified)','right','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,58,'',0,'a:1:{s:6:\"header\";N;}'),(135,51,0,0,0,'',0,0,0,0,0,3,1277203380,1258560852,12,0,64,'textpic','TYPO3 - The Enterprise CMS','','TYPO3 is a free, open source content management framework designed to simplify the creation of feature-rich websites that can be updated by nontechnical editors. It is written in PHP and is compatible with a number of popular databases, including MySQL. \r\n

    Feature-rich and Extensible Core

    \r\nTYPO3 stands out among other content management systems because of the impressive array of functionality that is incorporated into its core. This extensive core functionality allows users to quickly develop sophisticated sites with out-of-the-box TYPO3 installations. Moreover, TYPO3\'s well-documented extension-based architecture makes it possible for the system to grow to meet the unique needs of each individual or organization. During the course of the last ten years, tens of thousands of TYPO3 service providers and enthusiasts have created over 500,000 sites, including\r\n
    • global, multi-language enterprise solutions
    • corporate web portals
    • community and government web portals
    • enterprise web applications
    • full-featured eCommerce sites
    • online brochure and catalog sites
    • small business sites
    • nonprofit web sites
    • personal and corporate weblogs
    \r\n

    Dedicated to Open Source

    \r\nTYPO3 is maintained by a nonprofit core development team and an active worldwide community of users. TYPO3 operates under the GPL license.','TYPO3-Logo-8bit_04.png',125,18,'',1,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'TYPO3 logo','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,1,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(42,44,0,0,0,'',0,0,0,0,0,40,1258558361,1258542915,4,0,4352,'text','Header 1. level (right-justified)','right','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,59,'',0,'a:1:{s:6:\"header\";N;}'),(44,44,0,0,0,'',0,0,0,0,0,44,1258558361,1258542915,4,0,3840,'text','Header 5. level (centered)','center','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','5','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,50,'',0,'a:1:{s:6:\"header\";N;}'),(45,44,0,0,0,'',0,0,0,0,0,43,1258558361,1258542915,4,0,3584,'text','Header 4. level (centered)','center','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','4','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,51,'',0,'a:1:{s:6:\"header\";N;}'),(46,44,0,0,0,'',0,0,0,0,0,42,1258558361,1258542915,4,0,3328,'text','Header 3. level (centered)','center','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','3','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,52,'',0,'a:1:{s:6:\"header\";N;}'),(47,44,0,0,0,'',0,0,0,0,0,41,1258558361,1258542915,4,0,3072,'text','Header 2. level (centered)','center','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,53,'',0,'a:1:{s:6:\"header\";N;}'),(48,44,0,0,0,'',0,0,0,0,0,40,1258558361,1258542915,4,0,2816,'text','Header 1. level (centered)','center','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,54,'',0,'a:1:{s:6:\"header\";N;}'),(50,44,0,0,0,'',0,0,0,0,0,44,1258558361,1258542915,4,0,2304,'text','Header 5. level (with link)','','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','44','','',0,0,0,0,'','','','5','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,45,'',0,'a:1:{s:6:\"header\";N;}'),(51,44,0,0,0,'',0,0,0,0,0,43,1258558361,1258542915,4,0,2048,'text','Header 4. level (with link)','','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','44','','',0,0,0,0,'','','','4','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,46,'',0,'a:1:{s:6:\"header\";N;}'),(52,44,0,0,0,'',0,0,0,0,0,42,1258558361,1258542915,4,0,1792,'text','Header 3. level (with link)','','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','44','','',0,0,0,0,'','','','3','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,47,'',0,'a:1:{s:6:\"header\";N;}'),(53,44,0,0,0,'',0,0,0,0,0,41,1258558361,1258542915,4,0,1536,'text','Header 2 level (with link)','','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','44','','',0,0,0,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,48,'',0,'a:1:{s:6:\"header\";N;}'),(54,44,0,0,0,'',0,0,0,0,0,40,1258558361,1258542915,4,0,1280,'text','Header 1. level (with link)','','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','44','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,49,'',0,'a:1:{s:6:\"header\";N;}'),(56,44,0,0,0,'',0,0,0,0,0,0,1258558361,1258542915,4,0,768,'text','Header 5 level','','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','5','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,44,'',0,'a:1:{s:6:\"header\";N;}'),(57,44,0,0,0,'',0,0,0,0,0,0,1258558361,1258542915,4,0,512,'text','Header 4. level','','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','4','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,43,'',0,'a:1:{s:6:\"header\";N;}'),(58,44,0,0,0,'',0,0,0,0,0,0,1258558361,1258542915,4,0,256,'text','Header 3. level','','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','3','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,42,'',0,'a:1:{s:6:\"header\";N;}'),(59,44,0,0,0,'',0,0,0,0,0,0,1258558361,1258542915,4,0,128,'text','Header 2. level','','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,41,'',0,'a:1:{s:6:\"header\";N;}'),(60,44,0,0,0,'',0,0,0,0,0,0,1258558361,1258542915,4,0,64,'text','Header 1. level','','','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,40,'',0,'a:1:{s:6:\"header\";N;}'),(249,40,0,0,0,'',0,0,0,0,0,87,1277206571,1277206453,24,0,5,'textpic','6 images in 3 columns','','','typo3_image1_02.jpg,typo3_image10_02.jpg,typo3_image4_02.jpg,typo3_image3_01.jpg,typo3_image5_03.jpg,typo3_image2_02.jpg',70,2,'Image 1\r\nImage 2\r\nImage 3\r\nImage 4\r\nImage 5\r\nImage 6',3,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,78,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(63,43,0,0,0,'',0,0,0,0,0,0,1277082949,1258542915,4,0,256,'text','','','You can insert internal links (links to pages within the website), external links (links to external sites) or e-mail links (links that open the user\'s email client when clicked).','',0,0,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,140,'',0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(125,45,0,0,0,'',0,0,0,0,0,0,1258549194,1258549194,11,0,256,'text','Ruler before','','You can set a rulers before or after each content element.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,5,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(64,43,0,0,0,'',0,0,0,0,0,0,1277082839,1258542915,4,0,128,'text','Examples of Rich Text Content Elements ','','Continuous text: text, optional in bold or italic or in a combination of bold and italic. \r\nSpecial characters can be used: @ © ® ¢ ¼ ½ ¾ § ± a² m³ Ω π µ γ β α H2O\r\nTexts in foreign languages can be mixed on one page.
    The font has to be installed on the device though:\r\ncyrillic: РуÑÑÐºÐ°Ñ Ð²ÐµÑ€ÑиÑ
    chinese: 中文版
    arabic: الْعَرَبيّة \r\n

    Centered text

    \r\n

    Text justified right

    \r\nBulleted list:\r\n
    • first level
    • first level
      • second level
      • second level
        • third level
        • third level
    \r\nOrdered list:\r\n
    1. first level
    2. first level
      1. second level
      2. second level
        1. third level
        2. third level
    \r\nIndented paragraph:\r\n
    Aenean ante elit, elementum et, varius ut, condimentum ut, sem. Aenean ante neque, imperdiet sed, ultricies vitae, aliquam dictum, arcu. Aenean arcu est, semper vitae, euismod quis, vehicula eu, risus.
    \r\nIndented even more:\r\n
    Donec dui mauris, vestibulum id, venenatis at, rhoncus ut, dui. Donec elit felis, rhoncus congue, posuere vel, aliquet at, massa. Donec justo est, bibendum non, volutpat sed, eleifend quis, risus.
    \r\n
    \r\n
    Donec dui mauris, vestibulum id, venenatis at, rhoncus ut, dui. Donec elit felis, rhoncus congue, posuere vel, aliquet at, massa. Donec justo est, bibendum non, volutpat sed, eleifend quis, risus.
    \r\nBlockquote:\r\nAenean ante elit, elementum et, varius ut, condimentum ut, sem. Aenean ante neque, imperdiet sed, ultricies vitae, aliquam dictum, arcu. Aenean arcu est, semper vitae, euismod quis, vehicula eu, risus.\r\n
    Aenean ante elit, elementum et, varius ut, condimentum ut, sem. Aenean ante neque, imperdiet sed, ultricies vitae, aliquam dictum, arcu. Aenean arcu est, semper vitae, euismod quis, vehicula eu, risus.
    \r\nAenean ante elit, elementum et, varius ut, condimentum ut, sem. Aenean ante neque, imperdiet sed, ultricies vitae, aliquam dictum, arcu. Aenean arcu est, semper vitae, euismod quis, vehicula eu, risus.','',0,8,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,64,'',0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(65,42,0,0,0,'',0,0,0,0,0,69,1277204950,1258542915,4,0,2816,'textpic','Position: Below, right','',' Nam aliquam, lorem nec dapibus feugiat, ipsum quam laoreet arcu, sed ullamcorper augue augue vitae magna. \r\nHambiam est lectus, interdum id, accumsan a, blandit quis, mauris placerat sit amet, nibh. Lacus lectus est mattis vel, pharetra sit amet. Nam laoreet, erat ac laoreet euismod, sapien felis pretium libero, semper euismod mauris metus quis tortor. ','typo3_image4.jpg',120,9,'',1,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'Alternative text of the image','Title text of the image','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,75,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(66,42,0,0,0,'',0,0,0,0,0,69,1277204166,1258542915,4,0,2560,'textpic','Position: Below, center','',' Nam aliquam, lorem nec dapibus feugiat, ipsum quam laoreet arcu, sed ullamcorper augue augue vitae magna. \r\nHambiam est lectus, interdum id, accumsan a, blandit quis, mauris placerat sit amet, nibh. Lacus lectus est mattis vel, pharetra sit amet. Nam laoreet, erat ac laoreet euismod, sapien felis pretium libero, semper euismod mauris metus quis tortor. ','typo3_image9.jpeg',120,8,'',1,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'Alternative text of the image','Title text of the image','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,74,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(67,42,0,0,0,'',0,0,0,0,0,69,1277204149,1258542915,4,0,2304,'textpic','Position: Below, left','',' Nam aliquam, lorem nec dapibus feugiat, ipsum quam laoreet arcu, sed ullamcorper augue augue vitae magna. \r\nHambiam est lectus, interdum id, accumsan a, blandit quis, mauris placerat sit amet, nibh. Lacus lectus est mattis vel, pharetra sit amet. Nam laoreet, erat ac laoreet euismod, sapien felis pretium libero, semper euismod mauris metus quis tortor. ','typo3_image8.jpg',120,10,'',1,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'Alternative text of the image','Title text of the image','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,73,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(68,42,0,0,0,'',0,0,0,0,0,69,1277204132,1258542915,4,0,2048,'textpic','Position: Above, right','',' Nam aliquam, lorem nec dapibus feugiat, ipsum quam laoreet arcu, sed ullamcorper augue augue vitae magna. \r\nHambiam est lectus, interdum id, accumsan a, blandit quis, mauris placerat sit amet, nibh. Lacus lectus est mattis vel, pharetra sit amet. Nam laoreet, erat ac laoreet euismod, sapien felis pretium libero, semper euismod mauris metus quis tortor. ','typo3_image7.jpg',120,1,'',1,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'Alternative text of the image','Title text of the image','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,72,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(69,42,0,0,0,'',0,0,0,0,0,69,1277203803,1258542915,4,0,1792,'textpic','Position: Above, center','',' Nam aliquam, lorem nec dapibus feugiat, ipsum quam laoreet arcu, sed ullamcorper augue augue vitae magna. \r\nHambiam est lectus, interdum id, accumsan a, blandit quis, mauris placerat sit amet, nibh. Lacus lectus est mattis vel, pharetra sit amet. Nam laoreet, erat ac laoreet euismod, sapien felis pretium libero, semper euismod mauris metus quis tortor. ','typo3_image6.jpg',120,0,'',1,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'Alternative text of the image','Title text of the image','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,71,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(70,42,0,0,0,'',0,0,0,0,0,69,1277203787,1258542915,4,0,1536,'textpic','Position: Above, left','',' Nam aliquam, lorem nec dapibus feugiat, ipsum quam laoreet arcu, sed ullamcorper augue augue vitae magna. \r\nHambiam est lectus, interdum id, accumsan a, blandit quis, mauris placerat sit amet, nibh. Lacus lectus est mattis vel, pharetra sit amet. Nam laoreet, erat ac laoreet euismod, sapien felis pretium libero, semper euismod mauris metus quis tortor. ','typo3_image5.jpg',120,2,'',1,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'Alternative text of the image','Title text of the image','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,70,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(71,42,0,0,0,'',0,0,0,0,0,66,1277204936,1258542915,4,0,1280,'textpic','Position: Beside text, right','',' Nam aliquam, lorem nec dapibus feugiat, ipsum quam laoreet arcu, sed ullamcorper augue augue vitae magna. \r\nHambiam est lectus, interdum id, accumsan a, blandit quis, mauris placerat sit amet, nibh. Lacus lectus est mattis vel, pharetra sit amet. Nam laoreet, erat ac laoreet euismod, sapien felis pretium libero, semper euismod mauris metus quis tortor. ','typo3_image10_01.jpg',120,25,'',1,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'Alternative text of the image','Title text of the image','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,69,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(72,42,0,0,0,'',0,0,0,0,0,66,1277205078,1258542915,4,0,1024,'textpic','Position: Beside text, left','',' Nam aliquam, lorem nec dapibus feugiat, ipsum quam laoreet arcu, sed ullamcorper augue augue vitae magna. \r\nHambiam est lectus, interdum id, accumsan a, blandit quis, mauris placerat sit amet, nibh. Lacus lectus est mattis vel, pharetra sit amet. Nam laoreet, erat ac laoreet euismod, sapien felis pretium libero, semper euismod mauris metus quis tortor. ','typo3_image1.jpg',120,26,'',1,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'Alternative text of the image','Title text of the image','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,68,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(128,45,0,0,0,'',0,0,0,0,0,0,1258549901,1258549888,11,0,1024,'text','Indent, 33/66%','','Mauris magna nisl, dapibus dapibus faucibus ultrices, congue vehicula ligula. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque ac quam sed odio blandit commodo! Vivamus dui urna, volutpat nec ultrices in, consectetur vitae sapien. Nulla facilisi.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,11,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(73,42,0,0,0,'',0,0,0,0,0,66,1277203743,1258542915,4,0,768,'textpic','Position: In text, right','',' Nam aliquam, lorem nec dapibus feugiat, ipsum quam laoreet arcu, sed ullamcorper augue augue vitae magna. \r\nHambiam est lectus, interdum id, accumsan a, blandit quis, mauris placerat sit amet, nibh. Lacus lectus est mattis vel, pharetra sit amet. Nam laoreet, erat ac laoreet euismod, sapien felis pretium libero, semper euismod mauris metus quis tortor. ','typo3_image2.jpg',120,17,'',1,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'Alternative text of the image','Title text of the image','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,67,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(129,45,0,0,0,'',0,0,0,0,0,0,1258549931,1258549931,11,0,1280,'text','Indent, 66/33%','','Proin rhoncus augue quis est eleifend consequat. Fusce varius vehicula feugiat. In quis ipsum neque. Sed venenatis risus diam. Praesent tincidunt lacinia pellentesque. Donec non justo eros, lacinia hendrerit est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Maecenas et urna sed lorem venenatis tempor quis vel eros? Proin pellentesque ultricies enim sed aliquet. ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,12,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(74,42,0,0,0,'',0,0,0,0,0,0,1277205062,1258542915,4,0,512,'textpic','Position: In text, left','','Nam aliquam, lorem nec dapibus feugiat, ipsum quam laoreet arcu, sed ullamcorper augue augue vitae magna. \r\nHambiam est lectus, interdum id, accumsan a, blandit quis, mauris placerat sit amet, nibh. Lacus lectus est mattis vel, pharetra sit amet. Nam laoreet, erat ac laoreet euismod, sapien felis pretium libero, semper euismod mauris metus quis tortor. ','typo3_image3_03.jpg',120,18,'',1,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'Alternative text of the image','Title text of the image','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,66,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(130,45,0,0,0,'',0,0,0,0,0,0,1258549960,1258549960,11,0,1536,'text','Frame 1','','Duis luctus, enim commodo auctor sodales, mi dui facilisis elit, a lobortis quam lacus nec velit. Nam pharetra, augue quis tristique consequat, arcu orci tincidunt dolor, et vehicula nulla risus vel nisi? Maecenas vel ligula lorem. Pellentesque ullamcorper dolor non justo faucibus eleifend. Sed nec sapien vel massa vulputate vehicula eget eu nisl. ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,20,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(126,45,0,0,0,'',0,0,0,0,0,0,1258549230,1258549230,11,0,512,'text','Ruler after','','Here the ruler is positioned after the element.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,6,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(77,41,0,0,0,'',0,0,0,0,0,76,1277206127,1258542915,4,0,128,'textpic','Images Linked to Internal and External Pages','','Each image can be linked using the link field in the back-end. Multiple links can be added by separating each link with a comma. Values entered into the link field can be page id, a URL, or an e-mail address.','typo3_image7_01.jpg,typo3_image8_01.jpg',100,18,'click to startpage\r\nclick to typo3.org',2,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','1\nwww.typo3.org',0,0,0,0,'alternative text for first image\r\nalternative text for second image','title text for first image\r\ntitle text for second image','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,77,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(131,45,0,0,0,'',0,0,0,0,0,0,1258549982,1258549982,11,0,1792,'text','Frame 2','','Duis vitae ipsum et ante sollicitudin tincidunt a nec sem. Maecenas ultricies lacinia nunc at adipiscing? Nam ullamcorper commodo elit in euismod. Fusce nec varius tortor. Fusce justo diam, interdum quis egestas et, luctus a purus.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,21,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(79,41,0,0,0,'',0,0,0,0,0,0,1277206094,1258542915,4,0,32,'textpic','Image Click-enlarge Functionality','','Check the "click-enlarge" checkbox in the back-end to allow users to click to show the full-size image.\r\n\r\n','typo3_image5_01.jpg,typo3_image6_01.jpg',100,18,'click on image shows large version\r\nclick enlarge',2,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',1,0,0,0,'alternative text for first image\r\nalternative text for second image','title text for first image\r\ntitle text for second image','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,76,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(80,40,0,0,0,'',0,0,0,0,0,83,1258587440,1258542915,4,0,40,'textpic','Fixed height for images with different width-height ratio','','','a1_02.jpg,b2_02.jpg,f6_02.jpg,d4_08.jpg,e5_02.jpg,c3_02.jpg',0,10,'',3,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,80,0,0,85,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(81,40,0,0,0,'',0,0,0,0,0,83,1258587290,1258542915,4,0,128,'textpic','Fixed width and \"no rows\" flagged','','','a1_01.jpg,b2_01.jpg,f6_01.jpg,d4_07.jpg,e5_01.jpg,c3_01.jpg',100,10,'',3,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,1,0,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,84,'',0,'a:1:{s:13:\"header_layout\";N;}'),(82,40,0,0,0,'',0,0,0,0,0,0,1258587419,1258542915,4,0,64,'textpic','Fixed width for images with different width-height ratio','','','a1.jpg,b2.jpg,c3.jpg,d4_06.jpg,e5.jpg,f6.jpg',100,10,'',3,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,83,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(87,40,0,0,0,'',0,0,0,0,0,0,1277206533,1258542915,4,0,2,'textpic','6 images in 6 columns','','','typo3_image1_01.jpg,typo3_image10.jpg,typo3_image2_01.jpg,typo3_image3.jpg,typo3_image5_02.jpg,typo3_image4_01.jpg',70,2,'Image 1\r\nImage 2\r\nImage 3\r\nImage 4\r\nImage 5\r\nImage 6',6,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,78,'',0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(89,39,0,0,0,'',0,0,0,0,0,91,1258587767,1258542915,4,0,2816,'textpic','Effect: darker','','','a4_23.jpg,b4_15.jpg,c4_13.jpg',100,0,'',3,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,26,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,96,'',0,'a:1:{s:12:\"imagecaption\";N;}'),(90,39,0,0,0,'',0,0,0,0,0,91,1258587767,1258542915,4,0,2560,'textpic','Effect: brighter','','','a4_22.jpg,b4_14.jpg,c4_12.jpg',100,0,'',3,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,25,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,95,'',0,'a:1:{s:12:\"imagecaption\";N;}'),(91,39,0,0,0,'',0,0,0,0,0,91,1258587767,1258542915,4,0,2304,'textpic','Effect: contrast','','','a4_21.jpg,b4_13.jpg,c4_11.jpg',100,0,'',3,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,23,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,94,'',0,'a:1:{s:12:\"imagecaption\";N;}'),(92,39,0,0,0,'',0,0,0,0,0,91,1258587767,1258542915,4,0,2048,'textpic','Effect: normalize','','','a4_20.jpg,b4_12.jpg,c4_10.jpg',100,0,'',3,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,20,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,93,'',0,'a:1:{s:12:\"imagecaption\";N;}'),(93,39,0,0,0,'',0,0,0,0,0,91,1258587767,1258542915,4,0,1792,'textpic','Effect: sharpen','','','a4_19.jpg,b4_11.jpg,c4_09.jpg',100,0,'',3,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,11,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,92,'',0,'a:1:{s:12:\"imagecaption\";N;}'),(94,39,0,0,0,'',0,0,0,0,0,87,1258587767,1258542915,4,0,1536,'textpic','Effect: grayscale','','','a4_18.jpg,b4_10.jpg,c4_08.jpg',100,0,'',3,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,10,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,91,'',0,'a:1:{s:12:\"imagecaption\";N;}'),(95,39,0,0,0,'',0,0,0,0,0,87,1258587767,1258542915,4,0,1280,'textpic','Rotate 180','','','a4_17.jpg,b4_09.jpg,c4_07.jpg',100,0,'',3,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,3,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,90,'',0,'a:1:{s:12:\"imagecaption\";N;}'),(96,39,0,0,0,'',0,0,0,0,0,87,1258587767,1258542915,4,0,1024,'textpic','Rotate -90 CCW','','','a4_16.jpg,b4_08.jpg,c4_06.jpg',100,0,'',3,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,2,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,89,'',0,'a:1:{s:12:\"imagecaption\";N;}'),(97,39,0,0,0,'',0,0,0,0,0,87,1258587767,1258542915,4,0,768,'textpic','Rotate 90 CCW','','','a4_15.jpg,b4_07.jpg,c4_05.jpg',100,0,'',3,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,1,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,88,'',0,'a:1:{s:12:\"imagecaption\";N;}'),(98,39,0,0,0,'',0,0,0,0,0,0,1258587767,1258542915,4,0,512,'textpic','Normal Version','','','a4_14.jpg,b4_06.jpg,c4_04.jpg',100,0,'',3,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,87,'',0,'a:1:{s:12:\"imagecaption\";N;}'),(100,38,0,0,0,'',0,0,0,0,0,97,1280227617,1258542915,4,0,256,'table','Table layout 3','','|Area A|Area B|Area C\r\n2007|50.000|35.000|62.400\r\n2008|52.500|39.700|61.500\r\n2009|54.000|41.000|62.000','',0,8,'',0,0,'',3,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,99,'\n\n \n \n \n \n \n \n \n \n \n \n 0\n \n \n \n \n \n 0\n \n \n \n \n \n \n \n \n \n \n \n \n 124\n \n \n \n \n',0,'a:25:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:6:\"layout\";N;s:13:\"table_bgColor\";N;s:12:\"table_border\";N;s:17:\"table_cellspacing\";N;s:17:\"table_cellpadding\";N;s:4:\"cols\";N;s:8:\"bodytext\";N;s:11:\"pi_flexform\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(101,38,0,0,0,'',0,0,0,0,0,97,1280227605,1258542915,4,0,128,'table','Table layout 2','','|Area A|Area B|Area C\r\n2007|50.000|35.000|62.400\r\n2008|52.500|39.700|61.500\r\n2009|54.000|41.000|62.000','',0,8,'',0,0,'',2,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,98,'\n\n \n \n \n \n \n \n \n \n \n \n 0\n \n \n \n \n \n 0\n \n \n \n \n \n \n \n \n \n \n \n \n 124\n \n \n \n \n',0,'a:25:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:6:\"layout\";N;s:13:\"table_bgColor\";N;s:12:\"table_border\";N;s:17:\"table_cellspacing\";N;s:17:\"table_cellpadding\";N;s:4:\"cols\";N;s:8:\"bodytext\";N;s:11:\"pi_flexform\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(102,38,0,0,0,'',0,0,0,0,0,0,1280227593,1258542915,4,0,64,'table','Table layout 1','','|Area A|Area B|Area C\r\n2007|50.000|35.000|62.400\r\n2008|52.500|39.700|61.500\r\n2009|54.000|41.000|62.000','',0,8,'',0,0,'',1,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,97,'\n\n \n \n \n \n Caption\n \n \n Summary\n \n \n 1\n \n \n top\n \n \n 0\n \n \n \n \n \n \n \n \n \n \n \n \n 124\n \n \n \n \n',0,'a:25:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:6:\"layout\";N;s:13:\"table_bgColor\";N;s:12:\"table_border\";N;s:17:\"table_cellspacing\";N;s:17:\"table_cellpadding\";N;s:4:\"cols\";N;s:8:\"bodytext\";N;s:11:\"pi_flexform\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(103,38,0,0,0,'',0,0,0,0,0,0,1280227675,1258542915,4,0,32,'text','RTE table','','
    Caption
    Area AArea BArea C
    2008 50.000 50.000 50.000
    2009 50.000 50.000 50.000
    ','',0,0,'',1,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,149,'',0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(233,4,0,0,0,'',0,0,0,0,0,0,1276897695,1276897695,22,0,128,'text','Content Management Made Easy','','To help get you started with TYPO3, we’ve included usage examples of the core content elements that have made TYPO3 so popular. ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(104,37,0,0,0,'',0,0,0,0,0,135,1277149842,1258542915,4,0,256,'bullets','Unordered List - Alternate Layout 2','','Morbi in sem quis dui placerat ornare\r\nPraesent dapibus, neque id cursus faucibus\r\nPhasellus ultrices nulla quis nibh. Quisque a lectus. Donec consectetuer ligula vulputate sem tristique cursus. Nam nulla quam, gravida non','',0,0,'',0,0,'',3,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,137,'',0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:6:\"layout\";N;s:8:\"bodytext\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(105,37,0,0,0,'',0,0,0,0,0,135,1277149824,1258542915,4,0,128,'bullets','Unordered List - Alternate Layout 1','','Morbi in sem quis dui placerat ornare\r\nPraesent dapibus, neque id cursus faucibus\r\nPhasellus ultrices nulla quis nibh. Quisque a lectus. Donec consectetuer ligula vulputate sem tristique cursus. Nam nulla quam, gravida non','',0,0,'',0,0,'',2,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,136,'',0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:6:\"layout\";N;s:8:\"bodytext\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(106,37,0,0,0,'',0,0,0,0,0,134,1277149790,1258542915,4,0,64,'bullets','Default Ordered List','','Morbi in sem quis dui placerat ornare\r\nPraesent dapibus, neque id cursus faucibus\r\nPhasellus ultrices nulla quis nibh. Quisque a lectus. Donec consectetuer ligula vulputate sem tristique cursus. Nam nulla quam, gravida non','',0,0,'',0,0,'',1,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,135,'',0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:6:\"layout\";N;s:8:\"bodytext\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(107,37,0,0,0,'',0,0,0,0,0,0,1277149773,1258542915,4,0,32,'bullets','Default Unordered List','','Morbi in sem quis dui placerat ornare\r\nPraesent dapibus, neque id cursus faucibus\r\nPhasellus ultrices nulla quis nibh. Quisque a lectus. Donec consectetuer ligula vulputate sem tristique cursus. Nam nulla quam, gravida non','',0,0,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,134,'',0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:6:\"layout\";N;s:8:\"bodytext\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(253,36,0,0,0,NULL,0,0,0,0,0,0,1319061974,1318975429,1,0,512,'mailform','','','prefix = tx_form\nconfirmation = 1\npostProcessor {\n 1 = mail\n 1 {\n recipientEmail = \n senderEmail = \n }\n}\n10 = FIELDSET\n10 {\n 10 = TEXTLINE\n 10 {\n name = name\n value = Enter your name here\n label {\n value = Name\n }\n }\n 20 = TEXTLINE\n 20 {\n name = email\n label {\n value = E-Mail\n }\n }\n 30 = TEXTAREA\n 30 {\n cols = 40\n rows = 5\n name = enquiry\n label {\n value = Your enquiry\n }\n }\n 40 = CHECKBOX\n 40 {\n name = get-in-touch\n value = yes\n label {\n value = Do you want us to get in touch?\n }\n }\n 50 = SUBMIT\n 50 {\n name = submit\n value = Send Feedback\n }\n}\nrules {\n 1 = required\n 1 {\n breakOnError = 0\n showMessage = 1\n message = *\n error = This field is required\n element = name\n }\n 2 = required\n 2 {\n breakOnError = 0\n showMessage = 1\n message = *\n error = This field is required\n element = email\n }\n 3 = email\n 3 {\n breakOnError = 0\n showMessage = \n message = (john.doe@domain.com)\n error = This is not a valid email address\n element = email\n }\n 4 = required\n 4 {\n breakOnError = 0\n showMessage = 1\n message = *\n error = This field is required\n element = enquiry\n }\n}\n',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,NULL,0,0,'','','',NULL,0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,NULL,1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:1:{s:8:\"bodytext\";N;}'),(127,45,0,0,0,'',0,0,0,0,0,0,1258549871,1258549852,11,0,768,'text','Indent','','Donec volutpat pulvinar enim tincidunt sagittis. Duis rutrum enim leo. Maecenas euismod congue blandit? Aliquam et auctor sapien. Phasellus ut pellentesque tellus. Sed ac libero vitae quam porttitor viverra. Nullam neque libero, luctus suscipit ultricies in, tincidunt ac justo?',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,10,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(109,36,0,0,0,'',0,0,0,0,0,0,1258555228,1258542915,4,0,128,'login','Please login','','','',0,0,'',0,0,'',0,0,0,'','',0,0,2,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,139,'\n\n \n \n \n \n 0\n \n \n 1\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n 0\n \n \n \n \n \n \n \n \n \n \n \n 0\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n',0,'a:18:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:11:\"pi_flexform\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(110,35,0,0,0,'',0,0,0,0,0,111,1277207398,1258542915,4,0,256,'uploads','Download with preview, filesize and description','','','',0,0,'Description of the file',0,0,'typo3_image2.jpg',3,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,1,0,0,'0','',0,0,0,0,0,113,'',0,'a:26:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:5:\"media\";N;s:10:\"select_key\";N;s:6:\"layout\";N;s:13:\"table_bgColor\";N;s:12:\"table_border\";N;s:17:\"table_cellspacing\";N;s:17:\"table_cellpadding\";N;s:13:\"filelink_size\";N;s:12:\"imagecaption\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(111,35,0,0,0,'',0,0,0,0,0,111,1277151860,1258542915,4,0,128,'uploads','Download with icon, filesize and description','','','',0,0,'Description of the file',0,0,'TYPO3_Logo_Guide_v3_03.pdf',1,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,1,0,0,'0','',0,0,0,0,0,112,'',0,'a:1:{s:5:\"media\";N;}'),(112,35,0,0,0,'',0,0,0,0,0,109,1277151860,1258542915,4,0,64,'uploads','Download with icon and filesize','','','',0,0,'',0,0,'TYPO3_Logo_Guide_v3_02.pdf',1,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,1,0,0,'0','',0,0,0,0,0,111,'',0,'a:1:{s:5:\"media\";N;}'),(113,35,0,0,0,'',0,0,0,0,0,109,1277151860,1258542915,4,0,32,'uploads','Download with icon, no filesize','','','',0,0,'',0,0,'TYPO3_Logo_Guide_v3_01.pdf',1,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,110,'',0,'a:1:{s:5:\"media\";N;}'),(114,35,0,0,0,'',0,0,0,0,0,0,1277151860,1258542915,4,0,16,'uploads','Download no icon, no filesize','','','',0,0,'',0,0,'TYPO3_Logo_Guide_v3.pdf',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,109,'',0,'a:1:{s:5:\"media\";N;}'),(245,28,0,0,0,'',0,0,0,0,0,243,1277154413,1277154390,23,0,494,'text','','','Finally, this particular piece of text will disappear as soon as a visitor logs in. This is done by choosing \'Hide at login\' in the Access tab of the content record.','',0,0,NULL,1,0,'',0,0,0,'','',0,0,0,'',0,0,'-1','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(115,34,0,0,0,'',0,0,0,0,0,0,1258588087,1258542915,4,0,256,'menu','Section index (pagecontent w/Index checked)','','','',0,0,'',0,0,'',0,0,0,'','38',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'3','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,121,'',0,'a:1:{s:13:\"header_layout\";N;}'),(118,34,0,0,0,'',0,0,0,0,0,0,1258588087,1258542915,4,0,32,'menu','Sitemap','','','',0,0,'',0,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'2','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,115,'',0,'a:1:{s:13:\"header_layout\";N;}'),(120,34,0,0,0,'',0,0,0,0,0,0,1258588139,1258542915,4,0,8,'menu','Related pages (based on keywords)','','','',0,0,'',0,0,'',0,0,0,'','',0,0,2,'',0,0,'','','','',0,0,0,0,'','','','2','',0,0,0,0,'6','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,126,'',0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:9:\"menu_type\";N;s:5:\"pages\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(211,52,0,0,0,'',0,0,0,0,0,0,1277199826,1276892076,22,0,64,'text','A Mature, Reliable CMS','','TYPO3 is a mature, stable, and secure platform that has been actively developed and improved for over ten years. Unlike many newer, less sophisticated CMS solutions, TYPO3 is a full-grown, enterprise CMS that has been widely adopted by companies of all sizes across the world, and is an established standard throughout many universities, governments and organizations.
',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(216,57,0,0,0,'',0,0,0,0,0,0,1277146112,1276893579,22,0,128,'text','Feature Complete Out-of-the-box','','TYPO3 is unique in the quantity and quality of features that are part of its core. While there are over 4,500 extensions in the TYPO3 extension repository, the following features are present without having to install any community-developed extensions.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(219,3,0,0,0,'',0,0,0,0,0,0,1276968622,1276894433,22,0,128,'text','4,500 Extensions and Counting','','TYPO3 is an extremely modular system that can be easily enhanced with custom extensions. All TYPO3 sites are built on top of the TYPO3 core, which contains the system\'s fundamental functionality. Custom extensions interact with the core through the stable, clearly documented extension API. While the TYPO3 core does change in each new release, the interfaces between extensions and the core do not, ensuring easy updates and future-proof development.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(236,2,0,0,0,'',0,0,0,0,0,0,1276897933,1276897933,22,0,64,'text','You Make TYPO3 Better!','','TYPO3 has always been about its users and about inspiring people to share. Share your experiences with us. Send us a note. Let us know how we can improve TYPO3 or, even better, let us know how you think you can improve TYPO3. We’re all ears!',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(205,2,0,0,0,'',0,0,0,0,0,0,1277150817,1258755114,2,0,128,'text','About the Introduction Package','','This TYPO3 Introduction Package is maintained at forge.typo3.org, which is a repository and collaborative tool used by core and community TYPO3 developers.\r\nIf you have any issues with the Introduction Package or suggestions for improvements please don’t hesitate to get in touch with us.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(206,6,0,0,0,'',0,0,0,0,0,0,1276899322,1272271682,1,0,18,'text','How Do I Log in?','','
    Log in using one of the user names below and the password you chose during the installation process. This password has been assigned to four different demo users with different levels of access:
    \r\n
    • admin
    • advanced_editor 
    • simple_editor  
    • news_editor  
    \r\n
    The password you chose is also the master password for the "install tool"—the vital configuration center for your TYPO3 installation. 
    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(191,44,0,0,0,'',0,0,0,0,0,0,1277082700,1258739412,2,0,16,'text','Full Control Over All Content Elements','','

    TYPO3 offers editors full control over all content elements; even simple content elements like headers are accompanied by several configuration options. Site administrators may, for example, predefine several different header layouts for editors to utilize across the site.

    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(195,20,0,0,0,'',0,0,0,0,0,0,1277208798,1258741334,11,0,112,'image','TYPO3 in social networks','','','twitter_01.png,facebook_01.png,slideshare.png,linkedin_01.png,vimeo_01.png',0,2,'',3,0,NULL,0,0,0,NULL,NULL,0,0,2,'',0,0,'','','','http://twitter.com/typo3/\nhttp://www.facebook.com/typo3/\nhttp://www.slideshare.net/group/typo3\nhttp://www.linkedin.com/groups?gid=70999\nhttp://vimeo.com/typo3/',0,0,0,1,'','','','4','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:33:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(197,41,0,0,0,'',0,0,0,0,0,0,1277148436,1258744223,2,0,8,'text','No HTML Required','','

    With TYPO3, controlling the behavior of images is simple. Editors with no knowledge of HTML can easily manage links, popups, captions, alignment, and more.

    \r\n',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(193,39,0,0,0,'',0,0,0,0,0,0,1277149395,1258739833,2,0,128,'text','TYPO3 and ImageMagick','','

    TYPO3 takes full advantage of the rich functionality provided by the ImageMagick library including the ability to post-process images, manage colors, and apply effects. TYPO3 automates the tedious and time-consuming process of optimizing images for the web.

    \r\n',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(194,20,0,0,0,'',0,0,0,0,0,0,1280747403,1258741300,11,0,128,'text','Powered by','','TYPO3 Enterprise Open Source CMS

    Donate
    TYPO3.org',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,1,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'4','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(248,20,0,0,0,'',0,0,0,0,0,0,1278284778,1277206411,15,0,120,'html','','','
    \r\n The TYPO3 Introduction Package by the TYPO3 community is licensed:\r\n
    \r\n
    \r\n \r\n \"Creative\r\n \r\n
    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,66,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(196,40,0,0,0,'',0,0,0,0,0,0,1277149209,1258743199,2,0,0,'text','Multiple Image Layout Options','','

    TYPO3 provides users with numerous possibilities for laying out images on a page. The back-end interface provides users with easy control over image formats, sizes, widths, groupings, and quality.

    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(212,52,0,0,0,'',0,0,0,0,0,0,1276892231,1276892231,22,0,32,'text','Why \"TYPO3?\"','','In the late 1990s, after an evening of tireless development, Kasper SkÃ¥rhøj—the creator of TYPO3—inadvertently entered a typo into the command line, instantly deleting over a week’s worth of work.\r\nAfter the initial shock at his mistake subsided, Kasper went back to work and eventually realized that the new code was significantly better than what he had lost.\r\nA typo, it seemed, had led him to build an even better product. Struck by this reminder that we can benefit from our mistakes, TYPO3 was born.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(169,25,0,0,0,'',0,0,0,0,0,0,1277082332,1258719499,2,0,128,'text','About these pages','','The pages in this section of the introduction package demonstrate the various content elements available to editors in the TYPO3 back-end interface, and their appearance in the front-end.\r\nThe layout and behavior of these examples are configurable via Typoscript and, of course, CSS.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(214,53,0,0,0,'',0,0,0,0,0,0,1277203202,1276892701,22,0,96,'textpic','Community Events','','There are a number of recurring TYPO3 events and conferences. Each year, the TYPO3 Community organizes a snowboard tour "T3Board" in the mountains of central Europe, giving TYPO3 developers an opportunity to meet face-to-face. Furthermore, there is an annual "Developer Days" event that aims to give PHP developers a chance to collaborate and focus on the TYPO3 core.\r\nThere are annual conferences held in the US and in Europe with talks aimed at web marketers, site integrators and developers. Many regions also host active TYPO3 usergroups, which are invaluable sources of shared knowledge.','team-t3board10.jpg',190,17,'Group photo at T3BOARD10
    Photo by (c) Jochen Rau',1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',1,0,0,0,NULL,NULL,'http://www.flickr.com/photos/jocrau/4408947675/in/set-72157623535402924/','2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(172,37,0,0,0,'',0,0,0,0,0,0,1258722115,1258720867,2,0,16,'shortcut','About these pages','','',NULL,0,0,NULL,1,0,NULL,0,0,0,'tt_content_169',NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:7:\"records\";N;s:6:\"layout\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(213,53,0,0,0,'',0,0,0,0,0,0,1277146005,1276892651,22,0,64,'text','TYPO3: Inspiring People to Share','','The real driving force behind TYPO3’s development is its expanding, vibrant community of nearly 100,000 members. Over the past decade, TYPO3 has been installed more than 500,000 times, and these numbers are growing daily. This truly international community is composed of individuals and consultancies working with TYPO3 in countries across the world.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(174,35,0,0,0,'',0,0,0,0,0,172,1277151860,1258722570,2,0,8,'shortcut','About these pages','','','',0,0,NULL,1,0,'',0,0,0,'tt_content_169','',0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,NULL,0,'a:1:{s:5:\"media\";N;}'),(175,36,0,0,0,'',0,0,0,0,0,172,1258722599,1258722599,2,0,64,'shortcut','About these pages','','','',0,0,NULL,1,0,'',0,0,0,'tt_content_169','',0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:7:\"records\";N;s:6:\"layout\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(176,45,0,0,0,'',0,0,0,0,0,172,1258722705,1258722705,2,0,128,'shortcut','About these pages','','','',0,0,NULL,1,0,'',0,0,0,'tt_content_169','',0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:7:\"records\";N;s:6:\"layout\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(177,44,0,0,0,'',0,0,0,0,0,172,1258722731,1258722731,2,0,32,'shortcut','About these pages','','','',0,0,NULL,1,0,'',0,0,0,'tt_content_169','',0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:7:\"records\";N;s:6:\"layout\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(178,39,0,0,0,'',0,0,0,0,0,172,1258722738,1258722738,2,0,256,'shortcut','About these pages','','','',0,0,NULL,1,0,'',0,0,0,'tt_content_169','',0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:7:\"records\";N;s:6:\"layout\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(179,40,0,0,0,'',0,0,0,0,0,172,1258722745,1258722745,2,0,1,'shortcut','About these pages','','','',0,0,NULL,1,0,'',0,0,0,'tt_content_169','',0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:7:\"records\";N;s:6:\"layout\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(180,34,0,0,0,'',0,0,0,0,0,172,1258722752,1258722752,2,0,4,'shortcut','About these pages','','','',0,0,NULL,1,0,'',0,0,0,'tt_content_169','',0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:7:\"records\";N;s:6:\"layout\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(181,38,0,0,0,'',0,0,0,0,0,172,1258722761,1258722761,2,0,16,'shortcut','About these pages','','','',0,0,NULL,1,0,'',0,0,0,'tt_content_169','',0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:7:\"records\";N;s:6:\"layout\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(182,42,0,0,0,'',0,0,0,0,0,172,1258722772,1258722772,2,0,256,'shortcut','About these pages','','','',0,0,NULL,1,0,'',0,0,0,'tt_content_169','',0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:7:\"records\";N;s:6:\"layout\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(183,43,0,0,0,'',0,0,0,0,0,172,1258722779,1258722779,2,0,64,'shortcut','About these pages','','','',0,0,NULL,1,0,'',0,0,0,'tt_content_169','',0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:7:\"records\";N;s:6:\"layout\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(184,41,0,0,0,'',0,0,0,0,0,172,1258727827,1258727827,2,0,16,'shortcut','About these pages','','','',0,0,NULL,1,0,'',0,0,0,'tt_content_169','',0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:7:\"records\";N;s:6:\"layout\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(185,25,0,0,0,'',0,0,0,0,0,0,1277148306,1258728847,2,0,64,'text','TYPO3 Speaks Your Language','','

    TYPO3 supports all languages, characters and encoding out-of-the-box. All front-end, back-end and database interactions fully support UTF-8.

    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(186,37,0,0,0,'',0,0,0,0,0,0,1277149745,1258737110,2,0,8,'text','Multiple Layouts for Standard Content Types','','

    Ordered and unordered lists are available in TYPO3 as a standard content element. Users are able to create multiple predefined list layouts, which help to ensure site-wide visual consistency.

    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(188,36,0,0,0,'',0,0,0,0,0,0,1280259293,1258737664,2,0,32,'text','Powerful Form Handling','','

    Setting up a contact or mail form is very easy. The layout of forms is handled centrally, which allows editors to focus on the content of the form.

    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:9:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:13:\"header_layout\";N;s:4:\"date\";N;s:8:\"bodytext\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;}'),(189,45,0,0,0,'',0,0,0,0,0,0,1277149558,1258738254,2,0,64,'text','Content-specific Layouts','','

    Frames are centrally configured layouts for different content elements. Frames can be used, for example, to allow a content editor to apply a specific background image and/or color to specific content elements throughout the website.

    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(215,53,0,0,0,'',0,0,0,0,0,0,1319444085,1276892870,22,0,32,'text','Join the Association','','TYPO3 Association membership is open to anyone who is willing to endorse the goals and  objectives of the TYPO3 Association.\r\nIndividuals and companies who use TYPO3 on a regular basis are encouraged to contribute by becoming a supporting member. Your support will help to ensure that TYPO3 continues to be the leading open source CMS solution.\r\nJoin the TYPO3 Association Today.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:20:{s:5:\"CType\";N;s:6:\"colPos\";N;s:16:\"sys_language_uid\";N;s:6:\"header\";N;s:13:\"header_layout\";N;s:15:\"header_position\";N;s:4:\"date\";N;s:11:\"header_link\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:6:\"layout\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:6:\"hidden\";N;s:12:\"sectionIndex\";N;s:9:\"linkToTop\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(199,34,0,0,0,'',0,0,0,0,0,0,1277150054,1258744692,2,0,2,'text','Dynamic Site Maps','','

    In addition to generating basic site maps based on the structure of the page tree, TYPO3 is able to build advanced site maps such as a key-word based site map of related pages.

    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(200,42,0,0,0,'',0,0,0,0,0,0,1277083234,1258745254,2,0,128,'text','Easily Position Text and Images','','

    TYPO3 makes working with text and images a snap. TYPO3\'s text with image content element gives editors precise control over captions, alternative text attributes, image size and quality, and layout. TYPO3\'s core tools for manipulating images can automatically optimize image files uploaded by back-end editors to reduce file size and reduce the time required to load a page.

    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(201,43,0,0,0,'',0,0,0,0,0,0,1277082996,1258745770,2,0,32,'text','TYPO3\'s Built-in Rich Text Editor','','

    TYPO3 contains a sophisticated, built-in rich text editor (RTE). This editor contains all of the features one would expect from an enterprise CMS, and is highly configurable.

    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(202,6,0,0,0,'',0,0,0,0,0,0,1277142930,1258751114,2,0,24,'html','','','
    \r\n

    Congratulations, you have succesfully installed TYPO3

    \r\n

    So—what\'s next ?

    \r\n

    Grab a cup of coffee and start browsing through this site to learn why TYPO3 is the most powerful open source content management system.

    \r\n

    Check out the sample pages in the \"examples\" section of this website or…

    \r\n

    Log into TYPO3

    \r\n

    Get involved!

    \r\n
    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(204,2,0,0,0,'',0,0,0,0,0,0,1319060202,1258754609,2,0,512,'mailform','','','prefix = tx_form\r\nconfirmation = 1\r\npostProcessor {\r\n 1 = mail\r\n 1 {\r\n recipientEmail = \r\n senderEmail = \r\n }\r\n}\r\n10 = FIELDSET\r\n10 {\r\n legend {\r\n value = Contact us\r\n }\r\n 10 = TEXTLINE\r\n 10 {\r\n name = name\r\n value = Enter your name here\r\n label {\r\n value = Name\r\n }\r\n }\r\n 20 = TEXTLINE\r\n 20 {\r\n name = email\r\n label {\r\n value = E-Mail\r\n }\r\n }\r\n 30 = TEXTAREA\r\n 30 {\r\n cols = 40\r\n rows = 5\r\n name = enquiry\r\n label {\r\n value = Your enquiry\r\n }\r\n }\r\n 40 = SUBMIT\r\n 40 {\r\n name = submit\r\n value = Send Feedback\r\n }\r\n}\r\nrules {\r\n 1 = required\r\n 1 {\r\n breakOnError = 0\r\n showMessage = 1\r\n message = *\r\n error = This field is required\r\n element = name\r\n }\r\n 2 = required\r\n 2 {\r\n breakOnError = 0\r\n showMessage = 1\r\n message = *\r\n error = This field is required\r\n element = email\r\n }\r\n 3 = email\r\n 3 {\r\n breakOnError = 0\r\n showMessage = \r\n message = (john.doe@domain.com)\r\n error = This is not a valid email address\r\n element = email\r\n }\r\n 4 = required\r\n 4 {\r\n breakOnError = 0\r\n showMessage = 1\r\n message = *\r\n error = This field is required\r\n element = enquiry\r\n }\r\n}\r\n',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,'67',0,0,0,'introduction-feedback@typo3.org',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:18:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(208,16,0,0,0,'',0,0,0,0,0,0,1274455323,1274455323,19,0,512,'menu','Sitemap','',NULL,NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,'1',0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'2','',0,0,0,0,'2','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:9:\"menu_type\";N;s:5:\"pages\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(209,16,0,0,0,'',0,0,0,0,0,0,1277207913,1274455516,19,0,128,'text','What to do','','

    The information might still be available.
    You can try to look for the information in the sitemap at this page.

    Also you can try the search.

    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'2','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(210,51,0,0,0,'',0,0,0,0,0,0,1277081556,1276891563,22,0,32,'text','TYPO3 History','','TYPO3 was conceived by Danish developer Kasper Skårhøj in 1997. The idea was to solve what had emerged as a problem for the young internet—as websites grew, the need to separate the management of design and content became apparent.

    By August 2000, the core components were distributed to a development community that extended the concept and functionality of TYPO3 into the robust, and richly featured CMS that it is today.

    TYPO3 now runs more than 500,000 websites worldwide and powers sites for many esteemed institutions, including Cisco Systems, General Electric, Mercedes-Benz, and Harvard University.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(217,57,0,0,0,'',0,0,0,0,0,0,1277148229,1276893750,22,0,192,'text','','','

    Ease of Use

    \r\nTYPO3 is built around content management concepts that are intuitive and easy to master. Pages are organized into a hierarchical page tree. Each piece of content is clearly represented in the page module. All records can be accessed with a universal list module. Built-in WYSIWYG editors allow non-technical users to efficiently and effectively manage content.\r\n

    Versioning and Workspaces

    \r\nTYPO3 contains built-in versioning functionality that allows users to revert content to a previous version with ease. TYPO3 also features “workspaces,†which make it possible for users to edit content in one or more draft workspaces, and to confirm editorial approval before content is published.\r\n

    Multi-Language and Multiple Domains

    \r\nSupport for multiple domains within a single TYPO3 installation and for multiple languages are built-in to the TYPO3 core and are integrated at every level of the system’s architecture.\r\n

    Granular Front-end and Back-end Access Rights

    \r\nAll front-end pages and content can be limited to specific front-end user groups. Back-end editors can easily be restricted to specific sections of the page tree, modules, and directories in the file system.\r\n

    No Front-end Design Constraints

    \r\nBecause the TYPO3 front-end and back-end are separate and distinct interfaces, developers have complete and total control of their front-end markup, CSS, and javascript, down to the most minute details.\r\n

    Front-end Editing

    \r\nWhile the back-end offers complete control over all site content, TYPO3 also includes a front-end editing interface for even faster, more intuitive content management by nontechnical editors.\r\n

    Enterprise Features

    \r\nIn addition to everything one would expect in a sophisticated content management system, TYPO3 also possesses a number of important enterprise features including content-specific caching backends, a database abstraction layer, documented serviced-based APIs for authentication, well-defined interfaces for third-party systems integration, reporting tools, a digital asset manager, and an interface for scheduled jobs.  \r\n

    And More...

    \r\nFor a full list of all that the TYPO3 core has to offer, take a look at the feature matrix on typo3.com. Or browse the list of over 4,500 extensions on the TYPO3 extension repository.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(218,57,0,0,0,'',0,0,0,0,0,0,1277146343,1276894125,22,0,64,'text','Upgrading TYPO3? No problem.','','From its inception TYPO3 has emphasized the importance of stable APIs and full backwards-compatibility.  The TYPO3 core team follows a regular release schedule and take great care to ensure easy, non-breaking updates.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(220,3,0,0,0,'',0,0,0,0,0,0,1277147635,1276894540,22,0,192,'text','','','

    The TYPO3 Extension Manager

    \r\nTYPO3 relies on the TYPO3 extension manager— included in the TYPO3 core—for installing, activating, and deactivating extensions on a given TYPO3 installation. Extensions can be quickly imported and installed with just a couple clicks in the TYPO3 backend.\r\n

    Kickstarter Simplifies Extension Development

    \r\nThe extension kickstarter significantly reduces the time required to create a new TYPO3 extension, and automates the creation of interfaces for custom database records in the TYPO3 backend.\r\n

    ExtBase: TYPO3\'s Built-in MVC Framework

    \r\nRecent versions of TYPO3 include a built-in Model-View-Controller (MVC) framework called extBase, which allows developers to take advantage of this popular PHP design pattern.\r\n

    FLUID: Next Generation Templating

    \r\nFluid—TYPO3\'s next generation templating system—is used for creating custom extension templates. Fluid was created for TYPO3 5.0, currently under development, and has been back-ported to the TYPO3 4.x branch. Fluid\'s approach to creating templates emphasizes simplicity, flexibility, extensibility, and easy of use.\r\n

    Extensive Configuration Options

    \r\nNearly every aspect of the TYPO3 backend is configurable and customizable. Backend interfaces can often be configured using TSConfig. Nearly all rendered HTML content can be configured using Typoscript, a declarative configuration language used throughout TYPO3 for controlling front-end output.

    ',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(221,3,0,0,0,'',0,0,0,0,0,0,1276989479,1276894611,22,0,64,'shortcut','[TYPO3 History]','','',NULL,0,0,NULL,1,0,NULL,0,0,0,'tt_content_210',NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:7:\"records\";N;s:6:\"layout\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(222,62,0,0,0,'',0,0,0,0,0,0,1277147718,1276895746,22,0,256,'text','TYPO3: A True Open Source Community','','A widespread, international community of users and developers contributes to the ongoing evolution and success of TYPO3. Get acquainted with the latest enhancements, view tutorials, screen shots, and sample sites at the hub of the TYPO3 community—typo3.org. Follow some of the links below to connect with like-minded users and developers.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(223,62,0,0,0,'',0,0,0,0,0,0,1277148020,1276895856,22,0,512,'text','','','

    Core Team

    \r\nDevelopment and maintenance of TYPO3—and all of its built-in modules and features—is led by the core team, a group of 30 volunteers and developers sponsored, in part, by the non-profit TYPO3 Association.\r\n

    Extension Developers

    \r\nThe 4,500+ extensions of TYPO3 are created by savvy, enthusiastic users (like you!), and can be found in the vast TYPO3 Extension Repository (TER). Here you will find everything from simple site templates to advanced plug-ins as well as user-generated documentation and tutorials.\r\n

    Finding Help

    \r\nActive mailing lists are the heart of the TYPO3 open source community. Here you can ask questions, and seek out users who are engaged in similar projects or interests. There are hundreds of subscribers to the user list and most questions generate a helpful, timely response. Subscribe today and start meeting other members of the TYPO3 community.\r\nHelp is also available through Internet Relay Chat on the TYPO3 IRC Channel. If you want to join, log in to your  favorite IRC client and direct it to irc.freenode.net, channel #typo3.\r\nFor more help in developing your project with TYPO3, consider also the services of one of many approved consultancies that offer professional help with TYPO3 projects.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(224,62,0,0,0,'',0,0,0,0,0,0,1277204815,1276895947,22,0,128,'text','Pick Up a Book!','','The following titles are now available at Amazon.com and other online booksellers:\r\n
    • TYPO3: Enterprise Content Management
    • Building Websites with TYPO3: A practical guide to getting your TYPO3 website up and running fast
    • TYPO3 4.3 Multimedia Cookbook
    • Mastering TypoScript: TYPO3 Website, Template, and Extension Development
    • TYPO3 Extension Development
    \r\nBy buying a book through these links you are supporting the TYPO3 Association with a small percentage of the book\'s (unchanged) price.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(225,63,0,0,0,'',0,0,0,0,0,0,1276899456,1276896100,22,0,256,'text','Need Help? Tap into the TYPO3 Consultancy Network','','Many of TYPO3\'s most knowledgeable contributors are the web developers and consultants around the world who use it everyday. These certified consultants are among the most active members of the TYPO3 community and offer proven professional services—whether you simply need help with hosting or a complete development strategy for building a new website.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(226,63,0,0,0,'',0,0,0,0,0,0,1276896186,1276896147,22,0,128,'shortcut','','','',NULL,0,0,NULL,1,0,NULL,0,0,0,'tt_content_224',NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:7:\"records\";N;s:6:\"layout\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(227,64,0,0,0,'',0,0,0,0,0,0,1277148140,1276896294,22,0,64,'text','Extensive Documentation','','As a global, user-supported project, documentation for TYPO3 exists in many locations (and, thankfully, in many different languages). For the answer to most questions look first to the central TYPO3 Document Library where you will find several useful tutorials, and guides to installation, configuration, and getting started with TYPO3.\r\nThe Getting Started tutorial is based on the Introduction Package and is the number one resource to get you on your way with TYPO3. The Getting Started tutorial\'s permanent URL is: http://typo3.org/documentation/document-library/tutorials/doc_tut_quickstart/current/',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(228,64,0,0,0,'',0,0,0,0,0,0,1276896959,1276896723,22,0,128,'text','','','

    TYPO3 Wiki

    \r\nFind additional documentation in the TYPO3 Wiki, which provides how-to guides conveniently classified for different types of TYPO3 users.\r\n
    • Editors can find documents on how to handle and manage their content.
    • Administrators can find documents on how to manage security, users, and fine-tune performance.
    • Developers can find how-to guides to get started in creating their own TYPO3 extensions.
    \r\n

    TYPO3 API Documentation

    \r\nThe TYPO3 source code contains abundant internal documentation, which will allow developers to understand many functions and features just by browsing through the various classes and methods. Because TYPO3 uses JavaDoc style documentation, it is possible to automatically create a complete documentation of the TYPO3 core.

    Additionally, the TYPO3 Core APIs manual from the Documentation Library describes important components of the API, and gives many examples how to use it.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(229,64,0,0,0,'',0,0,0,0,0,226,1277149789,1276897017,22,0,512,'shortcut','Pick Up a Book!','','','',0,0,NULL,1,0,'',0,0,0,'tt_content_224','',0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:7:\"records\";N;s:6:\"layout\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(230,65,0,0,0,'',0,0,0,0,0,0,1277203403,1276897330,22,0,256,'textpic','Backed by the TYPO3 Association','','In November 2004 a group of longstanding contributors from the TYPO3 community, including Kasper Skårhøj, founded a non-profit organization called the TYPO3 Association. Since then, the Association has continued to drive TYPO3 development and foster community.','TYPO3-Logo-8bit_03.png',125,18,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:35:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:5:\"image\";N;s:11:\"imageorient\";N;s:9:\"imagecols\";N;s:12:\"image_noRows\";N;s:11:\"imageborder\";N;s:10:\"imagewidth\";N;s:11:\"imageheight\";N;s:10:\"image_link\";N;s:10:\"image_zoom\";N;s:12:\"imagecaption\";N;s:21:\"imagecaption_position\";N;s:7:\"altText\";N;s:9:\"titleText\";N;s:11:\"longdescURL\";N;s:17:\"image_compression\";N;s:13:\"image_effects\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(231,65,0,0,0,'',0,0,0,0,0,0,1276897436,1276897436,22,0,512,'text','Goals and Objectives','','The Association\'s overall goal is to promote TYPO3 and ensure the ongoing success and growth of the project. Specifically, the goals of the Association include:\r\n
    • supporting ongoing development of the TYPO3 core
    • organizing and sponsoring TYPO3-related events
    • education and certification, to ensure quality service
    • promoting the use and adoption of TYPO3

    \r\nThe TYPO3 Association depends heavily on the contribution of the users and developers who wish to support the project. Make a donation to the TYPO3 Association to help them continue their work!',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'3','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(232,65,0,0,0,'',0,0,0,0,0,0,1276897552,1276897526,22,0,128,'shortcut','','','',NULL,0,0,NULL,1,0,NULL,0,0,0,'tt_content_215',NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:14:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:7:\"records\";N;s:6:\"layout\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(234,4,0,0,0,'',0,0,0,0,0,0,1276897754,1276897754,22,0,192,'text','','','These examples illustrate how straight out-of-the-box, TYPO3 delivers a vast amount of freedom to content editors. Unlike more static content management systems, TYPO3 content management is highly object-oriented and granular. Click on any of the links in the secondary navigation, to the left, to see examples of each core content element.\r\nFeel free to log into the TYPO3 backend to see how easily these content elements (and pages) can be created, deleted, and modified!',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(235,4,0,0,0,'',0,0,0,0,0,0,1276897820,1276897820,22,0,64,'text','Limitless Possibilities','','The content elements that appear on subpages are just the core content elements. TYPO3 can be easily extended to include custom content elements. It is also possible to create dynamic, database-driven content elements (plug-ins) using the TYPO3 extension API.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:19:{s:5:\"CType\";N;s:16:\"sys_language_uid\";N;s:6:\"colPos\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;s:12:\"sectionIndex\";N;s:6:\"hidden\";N;s:6:\"header\";N;s:15:\"header_position\";N;s:13:\"header_layout\";N;s:11:\"header_link\";N;s:4:\"date\";N;s:9:\"linkToTop\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;}'),(237,25,0,0,0,'',0,0,0,0,0,169,1277119904,1277119627,11,0,192,'text','Om disse sider','','Siderne i dette underafsnit af introduktions-pakken, demonstrerer de forskellige indholdselementer tilgængelige for redaktører i TYPO3\'s backend interface, og hvorledes de ser ud i frontenden.\r\nUdseende og adfærd på disse indholdselementer er naturligvist fuldt ud konfigurérbar med Typoscript og CSS','',0,0,NULL,1,0,'',0,0,0,'','',0,0,2,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,1,0,NULL,169,'a:20:{s:5:\"CType\";s:4:\"text\";s:16:\"sys_language_uid\";s:1:\"0\";s:6:\"colPos\";s:1:\"2\";s:11:\"spaceBefore\";s:1:\"0\";s:10:\"spaceAfter\";s:1:\"0\";s:13:\"section_frame\";s:1:\"0\";s:12:\"sectionIndex\";s:1:\"1\";s:6:\"hidden\";s:1:\"0\";s:6:\"header\";s:17:\"About these pages\";s:15:\"header_position\";s:0:\"\";s:13:\"header_layout\";s:1:\"0\";s:11:\"header_link\";s:0:\"\";s:4:\"date\";s:1:\"0\";s:9:\"linkToTop\";s:1:\"0\";s:8:\"bodytext\";s:283:\"The pages in this section of the introduction package demonstrate the various content elements available to editors in the TYPO3 back-end interface, and their appearance in the front-end.\r\nThe layout and behavior of these examples are configurable via Typoscript and, of course, CSS.\";s:11:\"rte_enabled\";s:1:\"0\";s:9:\"starttime\";s:1:\"0\";s:7:\"endtime\";s:1:\"0\";s:8:\"fe_group\";s:0:\"\";s:11:\"l18n_parent\";s:1:\"0\";}'),(238,25,0,0,0,'',0,0,0,0,0,185,1277122190,1277121342,11,0,96,'text','TYPO3 kender ingen grænser','','

    TYPO3 understøtter alle sprog og tegnsæt. Alle frontend-, backend- og database-interaktioner understøtter fuldt ud UTF-8.

    ','',0,0,NULL,1,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,1,0,NULL,185,'a:20:{s:5:\"CType\";s:4:\"text\";s:16:\"sys_language_uid\";s:1:\"0\";s:6:\"colPos\";s:1:\"0\";s:11:\"spaceBefore\";s:1:\"0\";s:10:\"spaceAfter\";s:1:\"0\";s:13:\"section_frame\";s:1:\"0\";s:12:\"sectionIndex\";s:1:\"1\";s:6:\"hidden\";s:1:\"0\";s:6:\"header\";s:25:\"TYPO3 knows no boundaries\";s:15:\"header_position\";s:0:\"\";s:13:\"header_layout\";s:1:\"0\";s:11:\"header_link\";s:0:\"\";s:4:\"date\";s:1:\"0\";s:9:\"linkToTop\";s:1:\"0\";s:8:\"bodytext\";s:172:\"

    TYPO3 supports all languages, characters and encoding out-of-the-box. All front-end, back-end and database interactions fully support UTF-8.

    \";s:11:\"rte_enabled\";s:1:\"0\";s:9:\"starttime\";s:1:\"0\";s:7:\"endtime\";s:1:\"0\";s:8:\"fe_group\";s:0:\"\";s:11:\"l18n_parent\";s:1:\"0\";}'),(250,71,0,0,1,'INITIAL PLACEHOLDER',1,0,0,0,0,0,1290049001,1290049001,1,0,256,'text','This content is new','',NULL,NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,NULL,0,0,'0',NULL,'',NULL,0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,NULL,1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,NULL),(251,-1,250,1,1,'First draft version',-1,0,0,0,0,0,1290049001,1290049001,1,0,256,'text','This content is new','','This is some content that is in a Draft Workspace.',NULL,0,0,NULL,1,0,NULL,0,0,0,NULL,NULL,0,0,0,NULL,0,0,'','','',NULL,0,0,0,0,NULL,NULL,NULL,'0','',0,0,0,0,'0','',0,0,0,0,NULL,1,0,0,0,0,'0',NULL,0,0,0,0,0,0,NULL,0,'a:20:{s:5:\"CType\";N;s:6:\"colPos\";N;s:16:\"sys_language_uid\";N;s:6:\"header\";N;s:13:\"header_layout\";N;s:15:\"header_position\";N;s:4:\"date\";N;s:11:\"header_link\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:6:\"hidden\";N;s:12:\"sectionIndex\";N;s:9:\"linkToTop\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;s:6:\"layout\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;}'),(252,-1,219,1,1,'Auto-created for WS #1',0,0,0,0,0,219,1290049034,1290049034,1,0,128,'text','4,500 Extensions and Counting','','TYPO3 is an extremely modular system that can be easily enhanced with custom extensions. All TYPO3 sites are built on top of the TYPO3 core, which contains the system\'s fundamental functionality. Custom extensions interact with the core through the stable, clearly documented extension API. While the TYPO3 core does change in each new release, the interfaces between extensions and the core do not, ensuring easy updates and future-proof development.\r\nAnd TYPO3 4.5 comes with long time support!','',0,0,'',1,0,'',0,0,0,'','',0,0,0,'',0,0,'','','','',0,0,0,0,'','','','0','',0,0,0,0,'0','',0,0,0,0,'',1,0,0,0,0,'0','',0,0,0,0,0,0,'',0,'a:20:{s:5:\"CType\";N;s:6:\"colPos\";N;s:16:\"sys_language_uid\";N;s:6:\"header\";N;s:13:\"header_layout\";N;s:15:\"header_position\";N;s:4:\"date\";N;s:11:\"header_link\";N;s:8:\"bodytext\";N;s:11:\"rte_enabled\";N;s:6:\"hidden\";N;s:12:\"sectionIndex\";N;s:9:\"linkToTop\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;s:6:\"layout\";N;s:11:\"spaceBefore\";N;s:10:\"spaceAfter\";N;s:13:\"section_frame\";N;}'); +/*!40000 ALTER TABLE tt_content ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tt_news` +-- + +DROP TABLE IF EXISTS tt_news; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tt_news ( + uid int(11) NOT NULL AUTO_INCREMENT, + pid int(11) NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + crdate int(11) unsigned NOT NULL DEFAULT '0', + cruser_id int(11) unsigned NOT NULL DEFAULT '0', + editlock tinyint(4) unsigned NOT NULL DEFAULT '0', + deleted tinyint(3) unsigned NOT NULL DEFAULT '0', + hidden tinyint(4) unsigned NOT NULL DEFAULT '0', + starttime int(11) unsigned NOT NULL DEFAULT '0', + endtime int(11) unsigned NOT NULL DEFAULT '0', + fe_group varchar(100) NOT NULL DEFAULT '0', + title text, + `datetime` int(11) unsigned NOT NULL DEFAULT '0', + image text, + imagecaption text, + imagealttext text, + imagetitletext text, + related int(11) NOT NULL DEFAULT '0', + short text, + bodytext mediumtext, + author varchar(255) DEFAULT NULL, + author_email varchar(255) DEFAULT NULL, + category int(11) NOT NULL DEFAULT '0', + news_files text, + links text, + `type` tinyint(4) NOT NULL DEFAULT '0', + `page` int(11) NOT NULL DEFAULT '0', + keywords text, + archivedate int(11) NOT NULL DEFAULT '0', + ext_url varchar(255) DEFAULT NULL, + sys_language_uid int(11) NOT NULL DEFAULT '0', + l18n_parent int(11) NOT NULL DEFAULT '0', + l18n_diffsource mediumblob NOT NULL, + no_auto_pb tinyint(4) unsigned NOT NULL DEFAULT '0', + t3ver_oid int(11) NOT NULL DEFAULT '0', + t3ver_id int(11) NOT NULL DEFAULT '0', + t3ver_wsid int(11) NOT NULL DEFAULT '0', + t3ver_label varchar(30) DEFAULT NULL, + t3ver_state tinyint(4) NOT NULL DEFAULT '0', + t3ver_stage tinyint(4) NOT NULL DEFAULT '0', + t3ver_count int(11) NOT NULL DEFAULT '0', + t3ver_tstamp int(11) NOT NULL DEFAULT '0', + t3_origuid int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY parent (pid), + KEY t3ver_oid (t3ver_oid,t3ver_wsid), + KEY `datetime` (`datetime`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tt_news` +-- + +LOCK TABLES tt_news WRITE; +/*!40000 ALTER TABLE tt_news DISABLE KEYS */; +INSERT INTO tt_news (uid, pid, tstamp, crdate, cruser_id, editlock, deleted, hidden, starttime, endtime, fe_group, title, datetime, image, imagecaption, imagealttext, imagetitletext, related, short, bodytext, author, author_email, category, news_files, links, type, page, keywords, archivedate, ext_url, sys_language_uid, l18n_parent, l18n_diffsource, no_auto_pb, t3ver_oid, t3ver_id, t3ver_wsid, t3ver_label, t3ver_state, t3ver_stage, t3ver_count, t3ver_tstamp, t3_origuid) VALUES (1,18,1276970586,1258389302,10,0,0,0,0,0,'','TYPO3 celebrates 20th anniversary',1497627180,'','','','',0,'TYPO3 celebrates it\'s 20th anniversary. Having been one of the very first Content Management Systems on the market 20 years of market leadership...','TYPO3 celebrates it\'s 20th anniversary. Having been one of the very first Content Management Systems on the market 20 years of market leadership is an achievement truly worth celebrating.\r\nLet\'s take a minute to reflect on the 20 years passed:\r\n1997: The idea for TYPO3 is born
    2000: The TYPO3 community is born
    2005: the first TYPO3 conference is held
    2008: TYPO3 reaches a market share of close to 40% in central Europe
    2010: TYPO3 5.0 shakes up the CMS world
    2014: 95% of the world\'s websites run on Open Source and 60% on TYPO3
    2017: Happy 20th Birthday TYPO3\r\nAll the TYPO3 enthusiasts in the world: Keep up the great work!','','',1,'','',0,0,'',1432504800,'',0,0,'a:19:{s:6:\"hidden\";N;s:4:\"type\";N;s:5:\"title\";N;s:5:\"short\";N;s:8:\"bodytext\";N;s:8:\"datetime\";N;s:11:\"archivedate\";N;s:6:\"author\";N;s:8:\"keywords\";N;s:5:\"image\";N;s:12:\"imagecaption\";N;s:12:\"imagealttext\";N;s:14:\"imagetitletext\";N;s:5:\"links\";N;s:10:\"news_files\";N;s:8:\"category\";N;s:7:\"related\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;}',0,0,0,0,'',0,0,0,0,0),(2,18,1272147458,1258389401,10,0,0,0,0,0,'','The TYPO3 Association is founded',1095348780,'','','','',0,'Months in the planning, on this very day the TYPO3 Association was founded by a group of long-time contributors headed by Kasper Skårhøj.','Months in the planning, on this very day the TYPO3 Association was founded by a group of long-time contributors headed by Kasper Skårhøj. The Association is located in Switzerland and will act as a heart of the project by funding development of the system\'s core, providing certficiation and representing the project officially. \r\nGoals and Objectives

    \r\n
    • Fostering development of TYPO3;
    • Organisation of events for the purpose of information and education of its members;
    • Supporting the adaption of international software standards within TYPO3;
    • Education and certification to ensure quality of service;
    • Communication with its members and the general public, to spread and further knowledge and proficiency for the usage of the TYPO3 software, especially by virtue of it’s project website;
    ','','',1,'','',0,0,'',1432504800,'',0,0,'a:24:{s:6:\"hidden\";N;s:4:\"type\";N;s:5:\"title\";N;s:5:\"short\";N;s:8:\"bodytext\";N;s:10:\"no_auto_pb\";N;s:8:\"datetime\";N;s:11:\"archivedate\";N;s:6:\"author\";N;s:12:\"author_email\";N;s:8:\"keywords\";N;s:16:\"sys_language_uid\";N;s:5:\"image\";N;s:12:\"imagecaption\";N;s:12:\"imagealttext\";N;s:14:\"imagetitletext\";N;s:5:\"links\";N;s:10:\"news_files\";N;s:8:\"category\";N;s:7:\"related\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;s:8:\"editlock\";N;}',0,0,0,0,'',0,0,0,0,1),(3,18,1277202238,1258389405,10,0,0,0,0,0,'','T3UXW09 - The first TYPO3 User eXperience Week',1258389180,'team-t3uxw09_01.jpg','30 hand-picked specializists participating in the T3UXW09','','',0,'30 attendants for the T3UXW09 have arrived in rural Behringen (Germany) to work on TYPO3\'s usability for one whole week.','It is saturday the 14th of november. Almost everyone has arrived at the castle in Behringen at around 2-3 o\'clock in the afternoon. The castle is barrierfree, which means it is all adopted for disabled people. Although we are not working on accessibility I can safely assume most of the attendants support that. The castle itself is situated in a really nice rural environment. The air is really fresh. A welcome change for city dwellers. The whole castle belongs to the team this week. The network team, that rapidly volunteered, set up the whole wireless environment in a few hours. Punkt.de provided the switches they also use for the TYPO3 conferences. Joey brought a monster PC where he virtualised five servers. One for every team. Supportive tools like SVN, IRC and alike where all set up on this machine with the help of various people. Jens Hoffmann welcomed the attendants a little later in the afternoon and split up the available rooms among the attendants. After that the composition of the different teams was announced. ','','',1,'','',0,0,'',1432504800,'',0,0,'a:24:{s:6:\"hidden\";N;s:4:\"type\";N;s:5:\"title\";N;s:5:\"short\";N;s:8:\"bodytext\";N;s:10:\"no_auto_pb\";N;s:8:\"datetime\";N;s:11:\"archivedate\";N;s:6:\"author\";N;s:12:\"author_email\";N;s:8:\"keywords\";N;s:16:\"sys_language_uid\";N;s:5:\"image\";N;s:12:\"imagecaption\";N;s:12:\"imagealttext\";N;s:14:\"imagetitletext\";N;s:5:\"links\";N;s:10:\"news_files\";N;s:8:\"category\";N;s:7:\"related\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;s:8:\"editlock\";N;}',0,0,0,0,'',0,0,0,0,1),(4,18,1277202222,1258389409,10,0,0,0,0,0,'','TYPO3 - An idea is born',856629180,'kasper-skarhoj2_01.jpeg','TYPO3 Inventor: Kasper SkÃ¥rhøj','','',0,'Kasper SkÃ¥rhøj was contracted this week by a Danish company to build a content management solution for their corporate website. ','Kasper SkÃ¥rhøj was contracted today by a Danish company this week to build a content management solution for their corporate website. The term "Content Management" is still widely unknown. The idea of content management is a straight forward solution to an emerging problem for the young internet - as websites are going to grow and the complexity of them increase, the need for separation of design and content has become inevitable.\r\nOver the next months many meetings will define the exact requirements for this new system, enabling the client to manage the content on their website independant from HTML coders.\r\nStay tuned on what will help with this experiment.','','',1,'','',0,0,'',1432504800,'',0,0,'a:24:{s:6:\"hidden\";N;s:4:\"type\";N;s:5:\"title\";N;s:5:\"short\";N;s:8:\"bodytext\";N;s:10:\"no_auto_pb\";N;s:8:\"datetime\";N;s:11:\"archivedate\";N;s:6:\"author\";N;s:12:\"author_email\";N;s:8:\"keywords\";N;s:16:\"sys_language_uid\";N;s:5:\"image\";N;s:12:\"imagecaption\";N;s:12:\"imagealttext\";N;s:14:\"imagetitletext\";N;s:5:\"links\";N;s:10:\"news_files\";N;s:8:\"category\";N;s:7:\"related\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;s:8:\"editlock\";N;}',0,0,0,0,'',0,0,0,0,1),(7,18,1277112201,1277112142,11,0,0,0,0,0,'','Internal news item',1277111760,'','','','',0,'This news item has been categorized as \"Internal\"','This news item will only show up on pages displaying news from the category "Internal". It is meant as part of a demonstration of the concept of front end user login.','','',1,'','',0,0,'',1432504800,'',0,0,'a:24:{s:6:\"hidden\";N;s:4:\"type\";N;s:5:\"title\";N;s:5:\"short\";N;s:8:\"bodytext\";N;s:10:\"no_auto_pb\";N;s:8:\"datetime\";N;s:11:\"archivedate\";N;s:6:\"author\";N;s:12:\"author_email\";N;s:8:\"keywords\";N;s:16:\"sys_language_uid\";N;s:5:\"image\";N;s:12:\"imagecaption\";N;s:12:\"imagealttext\";N;s:14:\"imagetitletext\";N;s:5:\"links\";N;s:10:\"news_files\";N;s:8:\"category\";N;s:7:\"related\";N;s:9:\"starttime\";N;s:7:\"endtime\";N;s:8:\"fe_group\";N;s:8:\"editlock\";N;}',0,0,0,0,'',0,0,0,0,0); +/*!40000 ALTER TABLE tt_news ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tt_news_cache` +-- + +DROP TABLE IF EXISTS tt_news_cache; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tt_news_cache ( + id int(11) unsigned NOT NULL AUTO_INCREMENT, + identifier varchar(32) DEFAULT NULL, + content text NOT NULL, + crdate int(11) NOT NULL DEFAULT '0', + lifetime int(11) NOT NULL DEFAULT '0', + tags varchar(255) NOT NULL DEFAULT '', + PRIMARY KEY (id), + KEY cache_id (identifier), + KEY tags (tags) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tt_news_cache` +-- + +LOCK TABLES tt_news_cache WRITE; +/*!40000 ALTER TABLE tt_news_cache DISABLE KEYS */; +/*!40000 ALTER TABLE tt_news_cache ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tt_news_cache_tags` +-- + +DROP TABLE IF EXISTS tt_news_cache_tags; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tt_news_cache_tags ( + id int(11) unsigned NOT NULL AUTO_INCREMENT, + identifier varchar(128) DEFAULT NULL, + tag varchar(128) DEFAULT NULL, + PRIMARY KEY (id), + KEY cache_id (identifier), + KEY cache_tag (tag) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tt_news_cache_tags` +-- + +LOCK TABLES tt_news_cache_tags WRITE; +/*!40000 ALTER TABLE tt_news_cache_tags DISABLE KEYS */; +/*!40000 ALTER TABLE tt_news_cache_tags ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tt_news_cat` +-- + +DROP TABLE IF EXISTS tt_news_cat; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tt_news_cat ( + uid int(11) NOT NULL AUTO_INCREMENT, + pid int(11) NOT NULL DEFAULT '0', + tstamp int(11) unsigned NOT NULL DEFAULT '0', + crdate int(11) unsigned NOT NULL DEFAULT '0', + hidden tinyint(4) unsigned NOT NULL DEFAULT '0', + starttime int(11) unsigned NOT NULL DEFAULT '0', + endtime int(11) unsigned NOT NULL DEFAULT '0', + sorting int(11) unsigned NOT NULL DEFAULT '0', + fe_group varchar(100) NOT NULL DEFAULT '0', + title varchar(255) DEFAULT NULL, + title_lang_ol varchar(255) DEFAULT NULL, + image varchar(255) DEFAULT NULL, + shortcut int(11) unsigned NOT NULL DEFAULT '0', + shortcut_target varchar(255) DEFAULT NULL, + deleted tinyint(3) unsigned NOT NULL DEFAULT '0', + single_pid int(11) unsigned NOT NULL DEFAULT '0', + parent_category int(11) unsigned NOT NULL DEFAULT '0', + description text, + PRIMARY KEY (uid), + KEY parent (pid), + KEY parent_category (parent_category) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tt_news_cat` +-- + +LOCK TABLES tt_news_cat WRITE; +/*!40000 ALTER TABLE tt_news_cat DISABLE KEYS */; +INSERT INTO tt_news_cat (uid, pid, tstamp, crdate, hidden, starttime, endtime, sorting, fe_group, title, title_lang_ol, image, shortcut, shortcut_target, deleted, single_pid, parent_category, description) VALUES (1,18,1258384931,1258384931,0,0,0,0,'','General','','',0,'',0,0,0,''),(2,18,1258384950,1258384950,0,0,0,0,'','Research','','',0,'',0,0,0,''),(3,18,1258384969,1258384969,0,0,0,0,'','Internal','','',0,'',0,0,0,''); +/*!40000 ALTER TABLE tt_news_cat ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tt_news_cat_mm` +-- + +DROP TABLE IF EXISTS tt_news_cat_mm; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tt_news_cat_mm ( + uid_local int(11) NOT NULL DEFAULT '0', + uid_foreign int(11) NOT NULL DEFAULT '0', + tablenames varchar(30) DEFAULT NULL, + sorting int(11) NOT NULL DEFAULT '0', + KEY uid_local (uid_local), + KEY uid_foreign (uid_foreign) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tt_news_cat_mm` +-- + +LOCK TABLES tt_news_cat_mm WRITE; +/*!40000 ALTER TABLE tt_news_cat_mm DISABLE KEYS */; +INSERT INTO tt_news_cat_mm (uid_local, uid_foreign, tablenames, sorting) VALUES (1,1,'',1),(3,1,'',1),(4,1,'',1),(2,2,'',1),(7,3,'',1),(6,1,'',1); +/*!40000 ALTER TABLE tt_news_cat_mm ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tt_news_related_mm` +-- + +DROP TABLE IF EXISTS tt_news_related_mm; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tt_news_related_mm ( + uid_local int(11) NOT NULL DEFAULT '0', + uid_foreign int(11) NOT NULL DEFAULT '0', + sorting int(11) NOT NULL DEFAULT '0', + tablenames varchar(255) DEFAULT NULL, + KEY uid_local (uid_local), + KEY uid_foreign (uid_foreign) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tt_news_related_mm` +-- + +LOCK TABLES tt_news_related_mm WRITE; +/*!40000 ALTER TABLE tt_news_related_mm DISABLE KEYS */; +/*!40000 ALTER TABLE tt_news_related_mm ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tx_impexp_presets` +-- + +DROP TABLE IF EXISTS tx_impexp_presets; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tx_impexp_presets ( + uid int(11) NOT NULL AUTO_INCREMENT, + user_uid int(11) NOT NULL DEFAULT '0', + title varchar(255) DEFAULT NULL, + public tinyint(3) NOT NULL DEFAULT '0', + item_uid int(11) NOT NULL DEFAULT '0', + preset_data blob, + PRIMARY KEY (uid), + KEY lookup (item_uid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tx_impexp_presets` +-- + +LOCK TABLES tx_impexp_presets WRITE; +/*!40000 ALTER TABLE tx_impexp_presets DISABLE KEYS */; +/*!40000 ALTER TABLE tx_impexp_presets ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tx_linkvalidator_link` +-- + +DROP TABLE IF EXISTS tx_linkvalidator_link; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tx_linkvalidator_link ( + uid int(11) NOT NULL AUTO_INCREMENT, + record_uid int(11) NOT NULL DEFAULT '0', + record_pid int(11) NOT NULL DEFAULT '0', + headline varchar(255) DEFAULT NULL, + field varchar(255) DEFAULT NULL, + table_name varchar(255) DEFAULT NULL, + link_title text, + url text, + url_response text, + last_check int(11) NOT NULL DEFAULT '0', + link_type varchar(50) DEFAULT NULL, + PRIMARY KEY (uid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tx_linkvalidator_link` +-- + +LOCK TABLES tx_linkvalidator_link WRITE; +/*!40000 ALTER TABLE tx_linkvalidator_link DISABLE KEYS */; +/*!40000 ALTER TABLE tx_linkvalidator_link ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tx_realurl_chashcache` +-- + +DROP TABLE IF EXISTS tx_realurl_chashcache; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tx_realurl_chashcache ( + spurl_hash char(32) NOT NULL DEFAULT '', + chash_string varchar(32) DEFAULT NULL, + spurl_string text, + PRIMARY KEY (spurl_hash), + KEY chash_string (chash_string) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tx_realurl_chashcache` +-- + +LOCK TABLES tx_realurl_chashcache WRITE; +/*!40000 ALTER TABLE tx_realurl_chashcache DISABLE KEYS */; +/*!40000 ALTER TABLE tx_realurl_chashcache ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tx_realurl_errorlog` +-- + +DROP TABLE IF EXISTS tx_realurl_errorlog; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tx_realurl_errorlog ( + url_hash int(11) NOT NULL DEFAULT '0', + url text NOT NULL, + error text NOT NULL, + last_referer text NOT NULL, + counter int(11) NOT NULL DEFAULT '0', + cr_date int(11) NOT NULL DEFAULT '0', + tstamp int(11) NOT NULL DEFAULT '0', + rootpage_id int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (url_hash,rootpage_id), + KEY counter (counter,tstamp) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tx_realurl_errorlog` +-- + +LOCK TABLES tx_realurl_errorlog WRITE; +/*!40000 ALTER TABLE tx_realurl_errorlog DISABLE KEYS */; +/*!40000 ALTER TABLE tx_realurl_errorlog ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tx_realurl_pathcache` +-- + +DROP TABLE IF EXISTS tx_realurl_pathcache; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tx_realurl_pathcache ( + cache_id int(11) NOT NULL AUTO_INCREMENT, + page_id int(11) NOT NULL DEFAULT '0', + language_id int(11) NOT NULL DEFAULT '0', + rootpage_id int(11) NOT NULL DEFAULT '0', + mpvar tinytext NOT NULL, + pagepath text NOT NULL, + expire int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (cache_id), + KEY pathq1 (rootpage_id,pagepath(32),expire), + KEY pathq2 (page_id,language_id,rootpage_id,expire), + KEY expire (expire) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tx_realurl_pathcache` +-- + +LOCK TABLES tx_realurl_pathcache WRITE; +/*!40000 ALTER TABLE tx_realurl_pathcache DISABLE KEYS */; +/*!40000 ALTER TABLE tx_realurl_pathcache ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tx_realurl_redirects` +-- + +DROP TABLE IF EXISTS tx_realurl_redirects; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tx_realurl_redirects ( + url_hash int(11) NOT NULL DEFAULT '0', + url text NOT NULL, + destination text NOT NULL, + last_referer text NOT NULL, + counter int(11) NOT NULL DEFAULT '0', + tstamp int(11) NOT NULL DEFAULT '0', + has_moved int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (url_hash) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tx_realurl_redirects` +-- + +LOCK TABLES tx_realurl_redirects WRITE; +/*!40000 ALTER TABLE tx_realurl_redirects DISABLE KEYS */; +/*!40000 ALTER TABLE tx_realurl_redirects ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tx_realurl_uniqalias` +-- + +DROP TABLE IF EXISTS tx_realurl_uniqalias; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tx_realurl_uniqalias ( + uid int(11) NOT NULL AUTO_INCREMENT, + tstamp int(11) NOT NULL DEFAULT '0', + tablename varchar(255) DEFAULT NULL, + field_alias varchar(255) DEFAULT NULL, + field_id varchar(60) DEFAULT NULL, + value_alias varchar(255) DEFAULT NULL, + value_id int(11) NOT NULL DEFAULT '0', + lang int(11) NOT NULL DEFAULT '0', + expire int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY tablename (tablename), + KEY bk_realurl01 (field_alias(20),field_id,value_id,lang,expire), + KEY bk_realurl02 (tablename(32),field_alias(20),field_id,value_alias(20),expire) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tx_realurl_uniqalias` +-- + +LOCK TABLES tx_realurl_uniqalias WRITE; +/*!40000 ALTER TABLE tx_realurl_uniqalias DISABLE KEYS */; +/*!40000 ALTER TABLE tx_realurl_uniqalias ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tx_realurl_urldecodecache` +-- + +DROP TABLE IF EXISTS tx_realurl_urldecodecache; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tx_realurl_urldecodecache ( + url_hash char(32) NOT NULL DEFAULT '', + spurl tinytext NOT NULL, + content blob NOT NULL, + page_id int(11) NOT NULL DEFAULT '0', + rootpage_id int(11) NOT NULL DEFAULT '0', + tstamp int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (url_hash), + KEY page_id (page_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tx_realurl_urldecodecache` +-- + +LOCK TABLES tx_realurl_urldecodecache WRITE; +/*!40000 ALTER TABLE tx_realurl_urldecodecache DISABLE KEYS */; +/*!40000 ALTER TABLE tx_realurl_urldecodecache ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tx_realurl_urlencodecache` +-- + +DROP TABLE IF EXISTS tx_realurl_urlencodecache; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tx_realurl_urlencodecache ( + url_hash char(32) NOT NULL DEFAULT '', + origparams tinytext NOT NULL, + internalExtras tinytext NOT NULL, + content text NOT NULL, + page_id int(11) NOT NULL DEFAULT '0', + tstamp int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (url_hash), + KEY page_id (page_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tx_realurl_urlencodecache` +-- + +LOCK TABLES tx_realurl_urlencodecache WRITE; +/*!40000 ALTER TABLE tx_realurl_urlencodecache DISABLE KEYS */; +/*!40000 ALTER TABLE tx_realurl_urlencodecache ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tx_rsaauth_keys` +-- + +DROP TABLE IF EXISTS tx_rsaauth_keys; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tx_rsaauth_keys ( + uid int(11) NOT NULL AUTO_INCREMENT, + pid int(11) NOT NULL DEFAULT '0', + crdate int(11) NOT NULL DEFAULT '0', + key_value text, + PRIMARY KEY (uid), + KEY crdate (crdate) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tx_rsaauth_keys` +-- + +LOCK TABLES tx_rsaauth_keys WRITE; +/*!40000 ALTER TABLE tx_rsaauth_keys DISABLE KEYS */; +/*!40000 ALTER TABLE tx_rsaauth_keys ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tx_rtehtmlarea_acronym` +-- + +DROP TABLE IF EXISTS tx_rtehtmlarea_acronym; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tx_rtehtmlarea_acronym ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + pid int(11) unsigned NOT NULL DEFAULT '0', + deleted tinyint(4) unsigned NOT NULL DEFAULT '0', + hidden tinyint(4) unsigned NOT NULL DEFAULT '0', + starttime int(11) unsigned NOT NULL DEFAULT '0', + endtime int(11) unsigned NOT NULL DEFAULT '0', + sorting int(11) unsigned NOT NULL DEFAULT '0', + sys_language_uid int(11) NOT NULL DEFAULT '0', + `type` tinyint(3) unsigned NOT NULL DEFAULT '1', + term varchar(255) DEFAULT NULL, + acronym varchar(255) DEFAULT NULL, + static_lang_isocode int(11) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (uid), + KEY parent (pid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tx_rtehtmlarea_acronym` +-- + +LOCK TABLES tx_rtehtmlarea_acronym WRITE; +/*!40000 ALTER TABLE tx_rtehtmlarea_acronym DISABLE KEYS */; +/*!40000 ALTER TABLE tx_rtehtmlarea_acronym ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tx_scheduler_task` +-- + +DROP TABLE IF EXISTS tx_scheduler_task; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tx_scheduler_task ( + uid int(11) unsigned NOT NULL AUTO_INCREMENT, + crdate int(11) unsigned NOT NULL DEFAULT '0', + `disable` tinyint(4) unsigned NOT NULL DEFAULT '0', + classname varchar(255) DEFAULT NULL, + nextexecution int(11) unsigned NOT NULL DEFAULT '0', + lastexecution_time int(11) unsigned NOT NULL DEFAULT '0', + lastexecution_failure text NOT NULL, + lastexecution_context char(3) DEFAULT NULL, + serialized_task_object blob, + serialized_executions blob, + PRIMARY KEY (uid), + KEY index_nextexecution (nextexecution) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tx_scheduler_task` +-- + +LOCK TABLES tx_scheduler_task WRITE; +/*!40000 ALTER TABLE tx_scheduler_task DISABLE KEYS */; +INSERT INTO tx_scheduler_task (uid, crdate, disable, classname, nextexecution, lastexecution_time, lastexecution_failure, lastexecution_context, serialized_task_object, serialized_executions) VALUES (1,1319442861,0,'Tx_Workspaces_Service_AutoPublishTask',1319443200,0,'',NULL,'O:37:\"Tx_Workspaces_Service_AutoPublishTask\":4:{s:10:\"\0*\0taskUid\";i:1;s:11:\"\0*\0disabled\";b:0;s:12:\"\0*\0execution\";O:22:\"tx_scheduler_Execution\":6:{s:8:\"\0*\0start\";i:1317420000;s:6:\"\0*\0end\";s:0:\"\";s:11:\"\0*\0interval\";i:0;s:11:\"\0*\0multiple\";s:1:\"0\";s:10:\"\0*\0cronCmd\";s:9:\"0 * * * *\";s:23:\"\0*\0isNewSingleExecution\";b:0;}s:16:\"\0*\0executionTime\";i:1319443200;}',NULL),(2,1319442888,0,'tx_scheduler_CachingFrameworkGarbageCollection',1319493600,0,'',NULL,'O:46:\"tx_scheduler_CachingFrameworkGarbageCollection\":5:{s:16:\"selectedBackends\";a:2:{i:0;s:29:\"t3lib_cache_backend_DbBackend\";i:1;s:31:\"t3lib_cache_backend_FileBackend\";}s:10:\"\0*\0taskUid\";i:2;s:11:\"\0*\0disabled\";b:0;s:12:\"\0*\0execution\";O:22:\"tx_scheduler_Execution\":6:{s:8:\"\0*\0start\";i:1317420000;s:6:\"\0*\0end\";s:0:\"\";s:11:\"\0*\0interval\";i:0;s:11:\"\0*\0multiple\";s:1:\"0\";s:10:\"\0*\0cronCmd\";s:9:\"0 0 * * *\";s:23:\"\0*\0isNewSingleExecution\";b:0;}s:16:\"\0*\0executionTime\";i:1319493600;}',NULL); +/*!40000 ALTER TABLE tx_scheduler_task ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tx_wtspamshield_log` +-- + +DROP TABLE IF EXISTS tx_wtspamshield_log; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tx_wtspamshield_log ( + uid int(11) NOT NULL AUTO_INCREMENT, + pid int(11) NOT NULL DEFAULT '0', + tstamp int(11) NOT NULL DEFAULT '0', + crdate int(11) NOT NULL DEFAULT '0', + cruser_id int(11) NOT NULL DEFAULT '0', + deleted tinyint(4) NOT NULL DEFAULT '0', + form tinytext NOT NULL, + errormsg text NOT NULL, + pageid tinyint(5) NOT NULL DEFAULT '0', + formvalues text NOT NULL, + ip tinytext NOT NULL, + useragent tinytext NOT NULL, + PRIMARY KEY (uid), + KEY parent (pid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tx_wtspamshield_log` +-- + +LOCK TABLES tx_wtspamshield_log WRITE; +/*!40000 ALTER TABLE tx_wtspamshield_log DISABLE KEYS */; +/*!40000 ALTER TABLE tx_wtspamshield_log ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tx_wtspamshield_veguestbooktemp` +-- + +DROP TABLE IF EXISTS tx_wtspamshield_veguestbooktemp; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE tx_wtspamshield_veguestbooktemp ( + uid int(11) NOT NULL AUTO_INCREMENT, + tstamp int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (uid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tx_wtspamshield_veguestbooktemp` +-- + +LOCK TABLES tx_wtspamshield_veguestbooktemp WRITE; +/*!40000 ALTER TABLE tx_wtspamshield_veguestbooktemp DISABLE KEYS */; +/*!40000 ALTER TABLE tx_wtspamshield_veguestbooktemp ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2011-12-19 12:41:51 diff --git a/typo3conf/ext/phpunit/Changelog b/typo3conf/ext/phpunit/Changelog new file mode 100644 index 0000000..c042c6f --- /dev/null +++ b/typo3conf/ext/phpunit/Changelog @@ -0,0 +1,547 @@ +2011-06-21 Oliver Klee + * Release version 3.5.14 + * Fixed Bug #26573: Mark function assertType as deprecated in auto suggest + * Fixed Bug #13556: Update to the latest versions of PHPUnit and vfsStream + +2011-05-31 Oliver Klee + * Fixed Bug #12165: Make the BE module testable and add some basic tests (part 7, thanks to Christian Kuhn) + +2011-05-01 Oliver Klee + * Fixed Bug #14056: Trace wrong: Tests report wrong fail location on Windows (thanks to Christopher Lörken) + +2011-04-30 Oliver Klee + * Fixed Bug #26389: Document how to run tests of BE modules on the CLI + * Fixed Bug #26229: Drop the second parameter for BackEnd_Module::getLL + * Fixed Bug #12165: Make the BE module testable and add some basic tests (part 6) + * Fixed Bug #26506: Fatal Error if core using the PHP5 constructor + * Fixed Bug #26523: Polish the CSS a bit (thanks to Patrick Shriner) + +2011-04-29 Oliver Klee + * Fixed Bug #26424: Fix some phpcs warnings + +2011-04-26 Oliver Klee + * Fixed Bug #12165: Make the BE module testable and add some basic tests (part 5) + +2011-04-22 Oliver Klee + * Fixed Bug #12165: Make the BE module testable and add some basic tests (parts 3 and 4) + * Fixed Bug #13945: Framework::cleanUp provides an instance of itself that is not required in the interface + * Fixed Bug #13901: Crash with failling assertSame with objects + * Fixed Bug #8340: Add support for Selenium tests (thanks to Bastian Waidelich and Carsten Koenig) + +2011-03-05 Oliver Klee + * Fixed Bug #12165: Make the BE module testable and add some basic tests (part 2) + * Fixed Bug #13481: The locallang files contain some strings that have no hash and orig_language entries + +2011-03-04 Oliver Klee + * Fixed Bug #13615: Deprecate the old fake FE code + * Fixed Bug #11682: Port the testing framework from oelib (parts 3, 4, 5 and 6) + +2011-03-03 Oliver Klee + * Fixed Bug #11682: Port the testing framework from oelib (parts 1 and 2) + +2011-03-02 Oliver Klee + * Fixed Bug #12165: Make the BE module testable and add some basic tests (part 1) + * Fixed Bug #13501: Add a cache for the extensions, an "exists check" and a dummy extension filter to the test finder + * Fixed Bug #13485: Crash when running Tx_Phpunit_Database_TestCaseTest on TYPO3 4.5 + * Fixed Bug #11688: Move the back-end module to Classes + +2011-03-01 Oliver Klee + * Fixed Bug #13399: Add a class for an extension etc. with tests (parts 4 and 5) + +2011-02-28 Oliver Klee + * Fixed Bug #13449: Drop the (broken) "out-of-line tests" feature + * Fixed Bug #13399: Add a class for an extension etc. with tests (parts 1-3) + * Fixed Bug #13427: Use $GLOBALS['TYPO3_CONF_VARS'] instead of $TYPO3_CONF_VARS + +2011-02-27 Oliver Klee + * Fixed Bug #13069: Copy'n'paste of the testnames also copies the text "Run this test only" + * Fixed Bug #11861: Double-clicking a test name also selects the "run this test" icon + * Fixed Bug #13419: Regression: Cannot select extension other than "phpunit" in the drop-down + * Fixed Bug #13420: PHP warnings in the TYPO3 log when running the phpunit unit tests + * Fixed Bug #13401: Document which functions are called in what order for test cases with data providers + * Fixed Bug #13402: The locallang files are not recognized by the llxmltranslate extension + * Fixed Bug #13407: The compare output differences are not side-by-side + * Fixed Bug #5558: Drop the "about" section from the BE module + * Fixed Bug #11695: Display the excluded extensions in the reports module + * Fixed Bug #11694: Display the phpunit include path in the reports module + * Fixed Bug #12262: Add a check for the memory limit being >= 256 MB to the reports module + +2011-02-25 Oliver Klee + * Fixed Bug #12137: compare output is htmlspecialchared twice + * Fixed Bug #13278: vfsStreamWrapper cannot be used if it is not included + +2011-02-14 Oliver Klee + * Fixed Bug #13033: Progress bar is too long (thanks to Patrick Shriner) + * Fixed Bug #11741: Progress bar is too short after running some tests (thanks to Patrick Shriner) + +2011-02-12 Oliver Klee + * Release version 3.5.10 + * Fixed Bug #12241: Update PHPUnit to 3.5.10 + +2011-02-11 Oliver Klee + * Fixed Bug #11731: Make the test listener testable (parts 5, 6 and 7) + +2011-01-17 Oliver Klee + * Fixed Bug #12268: There should be empty PHP files where the test base classes have been + +2011-01-15 Oliver Klee + * Fixed Bug #11700: Move the credits from the About page to the manual + * Fixed Bug #11755: Code-Coverage Report fails due to error in included PHPUnit, patch by Andreas Lappe + * Fixed Bug #12167: Move the test base classes to Classes/ + * Fixed Bug #11731: Make the test listener testable (part 4) + * Fixed Bug #11696: Display the Xdebug status in the reports module + +2011-01-13 Oliver Klee + * Fixed Bug #12152: tx_phpunit_BackEnd_TestListenerTest does not handle extbase-style names + * Fixed Bug #12153: prettifyTestClass does not handle the "Test" suffix + * Fixed Bug #12151: prettifyTestClass adds leading space for the test class name "tx_phpunit_BackEnd_TestListenerTest" + * Fixed Bug #11731: Make the test listener testable (parts 1-3) + * Fixed Bug #11687: Move the test listener to Classes/ + * Fixed Bug #11689: Move the CLI runner to Classes/ + * Fixed Bug #11678: Move the Reports class to Classes/ + +2011-01-12 Oliver Klee + * Fixed Bug #11686: Move all locallang files to Resources/Private/Language + * Fixed Bug #11705: Move the Icons, CSS and JS to Resources/ + * Fixed Bug #11737: Use less static functions + * Fixed Bug #11827: Use strict comparisons + * Fixed Bug #12145: Update PHPUnit to 3.5.7 + +2011-01-01 Oliver Klee + * Fixed Bug #11684: Update copyrights in class comments and manual to 2011 + * Fixed Bug #11703: Add the missing PHPDoc comments + +2010-12-27 Oliver Klee + * Fixed Bug #11743: Crash when assertNull, assertNotNull, assertTrue or assertFalse fails + +2010-12-26 Oliver Klee + * Release version 3.5.6 + * Fixed Bug #5270: Improve failed assertEquals with strings as with NUnit + * Fixed Bug #7394: Fix single test links with data providers + * Fixed Bug #10829: Test-Crash output should be formatted + * Fixed Bug #7390: bar is too long when using data provides + * Fixed Bug #11675: Module background color is different below the "scroll fold" + * Fixed Bug #8090: TYPO3 icon in extension drop-down is misaligned in latest TYPO3 trunk + * Fixed Bug #7822: Include vfsStream for mocking the filesystem in unit tests + * Fixed Bug #11727: Add a link to the bugtracker to the manual + * Fixed Bug #11728: Document how to write extbase tests + * Fixed Bug #11704: Provide the PHPUnit files via an autoloader + * Fixed Bug #11690: Drop the version number from the PHPUnit path + * Fixed Bug #7478: Update PHPUnit to the latest version + +2010-12-25 Oliver Klee + * Fixed Bug #11709: Exceptions in tests are displayed with empty line number and file + +2010-12-24 Oliver Klee + * Fixed Bug #11712: testlistener::startTest reads a non-existent field + * Fixed Bug #11713: Drop the unused JsonPrettyPrinter.php file + * Fixed Bug #11711: Drop code for the experimental progress bar + * Fixed Bug #10135: phpunit shows green bar, although test execution failed with fatal error + * Fixed Bug #5903: Only JavaScript-hide the test contents if all test have completed + * Fixed Bug #11681: Cleanup: Use guard clauses + * Fixed Bug #11685: Drop deprecated classes and functions + * Fixed Bug #9094: Hidden MAC backup files should not be loaded + * Fixed Bug #11679: Use the new XCLASS format + +2010-12-23 Oliver Klee + * Fixed Bug #5570: Reformat the code to conform to the CGL + * Fixed Bug #7273: Use the null time tracker for TYPO3 >= 4.3 + * Fixed Bug #7240: Rely on the autoloader for TYPO3 >= 4.3 + * Fixed Bug #10690: Require TYPO3 >= 4.3 + * Fixed Bug #11570: Add functions to find the relative and absolute path to the Core tests directory + * Fixed Bug #11676: Rename the tests/ directory to Tests/ + +2010-10-22 Oliver Klee + * Fixed Bug #7979: Change Typo3 into TYPO3 in the manual + * Fixed Bug #9895: The CLI script needs to set the locale + +2010-09-10 Oliver Klee + * Fixed Bug #9678: Convert all files to UNIX line endings + +2010-05-28 Oliver Klee + * Fixed Bug #7963: "Run this test only" link from within running a single test is broken + * Fixed Bug #6101: Testcase drop-down is empty in single test view + * Fixed Task #6924: Drop the warnings from the main page for TYPO3 >= 4.3 + * Add Feature #6921: Move the eaccelerator warning to the main page and the reports module + * Fixed Bug #7609: The fake FE should be off by default + * Fixed Bug #7735: Wrong group list if fake TSFE (thanks to Francois Suter) + +2010-04-27 Oliver Klee + * Release version 3.4.12. + * Fixed Bug #7230: Update PHPUnit to the latest version + * Fixed Bug #7234: Update some things in the manual + +2010-04-15 Oliver Klee + * Fixed Bug #5544: Invalid IDs for the checkboxes + +2010-04-14 Oliver Klee + * Fixed Bug #7228: Typo in the CSS file + +2010-04-13 Oliver Klee + * Fixed Bug #5560: "All extensions" cannot be selected + +2010-04-12 Oliver Klee + * Fixed Task #6922: Rename the test cases from *_testcase to *Test + +2010-03-19 Oliver Klee + * Fixed Bug #5550: Convert all locallang files to XML + * Add Feature #5553: Make the PHP comments warning a flash message + +2010-03-18 Oliver Klee + * Fixed Bug #5902: Link for running single test doesn't work from within running a testcase + +2010-03-03 Oliver Klee + * Fixed Bug #6638: Support for *Test.php names instead of _testcase.php, patch by Sebastian Kurfürst + * Fixed Bug #6672: Files included twice, patch by Ingo Renner + * Fixed Bug #6561: Remove the .project file from SVN + +2010-02-18 Oliver Klee + * Fixed Bug #5542: Add CDATA for all script tags + * Fixed Bug #5569: Add and clean up the class documentation comments + * Fixed Bug #6452: Update PHPUnit version 3.4.7 to 3.4.11 + * Fixed Bug #5511: Show a warning if PHP comments are stripped + +2010-01-25 Oliver Klee + * Fixed Bug #5836: Don't use makeInstanceClassName in TYPO3 4.3 + +2010-01-19 Oliver Klee + * Fixed Bug #5557: Drop the display of the changelog + * Fixed bug #5900: Update PHPUnit to 3.4.7 + * Fixed Bug #5555: Register all classes for the autoloader + * Fixed Bug #5950: Remove the mentioning of the ECT from the extension description + +2010-01-18 Oliver Klee + * Fixed Bug #5510: Make sure all phpunit tests actually run + +2010-01-06 Oliver Klee + * Fixed bug #5568: Change all tests to use the @test annotation + +2010-01-05 Oliver Klee + * Release version 3.4.3 + +2009-12-25 Oliver Klee + * Add Feature #5559: When running a testcase or a single test, display the name of the test suite + * Fixed bug #5548: "Run this test only" icon/link is broken + * Fixed Bug #5258: Blank page with BE output compression (thanks to Steffen Gebert) + * Fixed Bug #4198: Calculation of progress bar width broken + * Fixed Bug #5543: There are some literal \n between the options in the testcase drop-down + * Fixed Bug #5549: Use real access modifiers and drop the @access annotations + * Fixed bug #5552: Update the "about" section in the BE module with the new contributors + * Fixed Bug #5537: Update ext_emconf.php with the new team structure + * Fixed Bug #5547: Remove unused variables + * Fixed Bug #5546: Delete commented-out code + +2009-12-20 Oliver Klee + * Fixed bug #5727: Incorrect path used in tx_phpunit_module1::traversePathForTestCases, patch by Mikkel Ricky + +2009-12-07 Oliver Klee + * Fixed bug #5566: Update PHPUnit to 3.4.3 + +2009-11-30 Michael Klapper + * Fixed bug #5581: Add missing flag 'doNotLoadInFE' to ext_emconf.php + +2009-10-26 Michael Klapper + * Update PHPUnit to version 3.4.2 + +2009-10-20 Michael Klapper + * Remove $this->cli_validateArgs() from the tx_phpunit_cli_phpunit because the PHPUnit validate the params by it self. + +2009-10-16 Michael Klapper + * Add PHPUnit_Util_Filter::addFileToFilter to tx_phpunit_* classes + +2009-10-12 Michael Klapper + * Add Feature #4775: Support Data Providers + +2009-10-11 Michael Klapper + * Fixed Bug #3423: having many tests the select is "unhandy" + +2009-10-09 Michael Klapper + * Fixed Bug #3838: Test with data provider fails if test or parent class extends PHPUnit_Framework_TestCase constructor + * Fixed Bug #4239: marktTestSkipped - If an extension to import not installed. + * Add Feature #4793: Enable suffix "Test" for classes and filenames + * Add Feature #4455: show the time and memory usage of each test + * Major Feature #3340: Add PHPUnit to cli_dispatch (Thanks to Axel Jung) + * Fixed Bug #4815: EXT:phpunit does not work together with PHPUnit-3.4.0 + * Bug #3349: hardcoded typo3_src source for core tests + * Update PHPUnit vertion to 3.4.0 + +2009-05-24 Kasper Ligaard + * (Trying) to address upper/lower case problem with new extbase conventions, confer to http://forge.typo3.org/issues/show/3424 + +2009-05-22 Michael Klapper + * Add feature #: Add total count of assertions to the user interface + +2009-05-19 Michael Klapper + * Add feature #2762: it's not possible to run all tests of a testcase + +2009-05-12 Michael Klapper + * Add support for "skipped" and "not implemented" to "tx_phpunit_testlistener" and extend the user interface. + +23. May 2009: 3.3.12. + + Added PHPUnit 3.3.16, see ChangeLog at http://www.phpunit.de/wiki/ChangeLog33#PHPUnit3.3.1610-Apr-2009 + - Removed PHPUnit 3.3.15. + + Issue #2762: Make it possible to run all tests of a testcase, http://forge.typo3.org/issues/show/2762. Thanks to Michael Klapper. + + Issue #3367: Display test case name as human readable text, http://forge.typo3.org/issues/show/3367. Thanks to Michael Klapper. + + Issue #3431: Add total count of assertions to the user interface, http://forge.typo3.org/issues/show/3431. Thanks to Michael Klapper. + + Issue #3408: Import StdDB-feature for database tests, http://forge.typo3.org/issues/show/3408. Thanks goes to Tolleiv Nietsch. + ~ Updated the included YUI! files to version 2.7.0. The changes from 2.6 to 2.7 can be found here: + http://developer.yahoo.com/yui/releasenotes/README.base, + http://developer.yahoo.com/yui/releasenotes/README.connection, + http://developer.yahoo.com/yui/releasenotes/README.json, + http://developer.yahoo.com/yui/releasenotes/README.reset, + http://developer.yahoo.com/yui/releasenotes/README.fonts, + http://developer.yahoo.com/yui/releasenotes/README.grids, + http://developer.yahoo.com/yui/releasenotes/README.yahoo, + http://developer.yahoo.com/yui/releasenotes/README.dom, + http://developer.yahoo.com/yui/releasenotes/README.event. + +06. March 2009: 3.3.11. + ~ Initialize content object (tslib_cObj) on demand, http://forge.typo3.org/issues/show/2767 + +05. March 2009: 3.3.10. + ~ Test cases can not end in "TestCase", but always must end in "testcase", http://forge.typo3.org/issues/show/2753 + +03. March 2009: 3.3.9. + ~ Sorting unittests by their classnames for a better overview, http://bugs.typo3.org/view.php?id=10584 + * Background color of selectors is grey but was white, http://forge.typo3.org/issues/show/2718 + +25. February 2009: 3.3.8. A big thank you to Oliver Klee, who did all the heavy lifting for this release. + + Feature #2503 (Resolved): Allow running unit tests for the TYPO3 core, http://forge.typo3.org/issues/show/2503 + + Added PHPUnit 3.3.15, see ChangeLog at http://www.phpunit.de/wiki/ChangeLog33#PHPUnit3.3.1524-Feb-2009 + - Removed PHPUnit 3.3.5. + ~ Task #2640 (Resolved): Static variables should not be backuped, http://forge.typo3.org/issues/show/2640 + * Two fixes for upcoming Typo3 4.3: + * Bug #2512 (Resolved): Fatal error: Call to a member function push() on a non-object in class.tsli..., http://forge.typo3.org/issues/show/2512 + * BE output is buffered with current TYPO3 4.2 branch, http://forge.typo3.org/issues/show/2348 + * Task #2499 (Resolved): Clean up the code, http://forge.typo3.org/issues/show/2499 + +21. November 2008: 3.3.7 + + Added PHPUnit 3.3.5, see ChangeLog at http://www.phpunit.de/wiki/ChangeLog33#PHPUnit3.3.523-Nov-2008 + - Removed PHPUnit 3.3.4. + * Corrected instructions for keyboard shortcut on Macs: It is Ctrl (and not Meta) that should be depressed. + +10. November 2008: 3.3.6 + + Added PHPUnit 3.3.4, see ChangeLog at http://www.phpunit.de/wiki/ChangeLog33#PHPUnit3.3.408-Nov-2008 and http://www.phpunit.de/wiki/ChangeLog33#PHPUnit3.3.303-Nov-2008 + - Removed PHPUnit 3.3.2. + ~ Fix forge bug #1828, http://forge.typo3.org/issues/show/1828 + +20. October 2008: 3.3.5 + + Added PHPUnit 3.3.2, see ChangeLog at http://www.phpunit.de/wiki/ChangeLog33#PHPUnit3.3.220-Oct-2008 + - Removed PHPUnit 3.3.1. + ~ Comment out JavaScript calls to console.log(). + * Fix forge #1698: Showing NEWS file from drop-down menu breaks with symlinks. Cf. http://forge.typo3.org/issues/show/1698 + +19. October 2008: 3.3.4 + + Added keyboard short-cuts. + + Added select YUI! 2.6.0 files. + - Removed old cruft files: and options. + ~ Upped requirements to Typo3 4.2.x (from 4.1) since phpunit now uses loadJavascriptLib() from template.php. + ~ Re-factored JavaScript Prototype parts to use YUI! + ~ Moved 'Collect code coverage' from Extension Manager to a per user setup, done from inside phpunit (point'n'click). + ~ Changed header of page. + ~ Misc. other stuff. See Subversion history, revisions #12953 to #13145. + * Fixed 'suggest' when installing and also upped version number on suggested extensions: pear 2.3.6 (up from 2.3.5), oelib 0.4.2 (up from 0.4.0). + * Fixed opening in new window. + +01. October 2008: 3.3.3 + + Display the leaked memory after the tests. Closes forge #1627. Note that this measurement is only indicative; it will be tried out now, but is the utility is limited, then it will be removed or turned into an option. + +27. September 2008: 3.3.2 + + Added links to forge.typo3.org. + ~ Moved text around at little bit to have added links more prominent, compared to the old links (which are left for completeness). + * Add the colored bar even when executing single tests. Closes forge #1594, thanks goes to Oliver Klee. + * Javascript for experimental progress bar executed although the option is disabled. Closes forge #1595, thanks goes to Oliver Klee. + * Error when calling non-existing test. Closes #1596, thanks goes to Oliver Klee. + * Message flows out of box. Closes forge # 1597, thanks goes to Oliver Klee. + +24. September 2008: 3.3.1 + + Added PHPUnit 3.3.1, see ChangeLog at http://www.phpunit.de/wiki/ChangeLog33#PHPUnit3.3.123-Sep-2008 + - Removed PHPUnit 3.3.0. + +18. September 2008: 3.3.0 + + Added PHPUnit 3.3.0, see ChangeLog at http://www.phpunit.de/wiki/ChangeLog33#PHPUnit3.3.015-Sep-2008 + - Removed PHPUnit 3.2.21. + +08. September 2008: 3.2.21 + + Added PHPUnit 3.2.21, see ChangeLog at http://www.phpunit.de/wiki/ChangeLog32#PHPUnit3.2.2116-Jun-2008. + + Added benchmarking single tests. Solves Forge issue #1317, http://forge.typo3.org/issues/show/1317. Thanks to Oliver Klee. + ~ Changed manual.sxw to use latest documentation template (EXT:doc_template version 1.2.5). + ~ Fixed some validation issues. Solves Forge issue #1316, http://forge.typo3.org/issues/show/1316. Thanks to Oliver Klee. + ~ Changed default in ext_conf_template.txt for field 'excludeextensions': Now extension keys 'lib' and 'div' are per default excluded, since their testsuites try to load extension key 't3unit', which probably does not exist on peoples machines. + - Removed line including non-existant file 'common.js'. Solves Forge issue #1320, http://forge.typo3.org/issues/show/1317. Thanks goes to Niels Pardon. + - Removed PHPUnit 3.2.19 (btw. there never was a release phpunit release including PHPUnit 3.2.20). + * Fixed bug where phpunit could get stuck with 'Extension not loaded [...]'. Now, instead phpunit will default to extension key 'phpunit', if the chosen key does not exist anymore (which can happen if the extension is removed). + +06. May 2008: 3.2.20 + ~ Changed hook key in mod1/index.php (by request). + +24. April 2008: 3.2.19 + + Added PHPUnit 3.2.19, see ChangeLog at http://www.phpunit.de/wiki/ChangeLog32#PHPUnit3.2.1924-Apr-2008 + - Removed PHPUnit 3.2.18. + +20. April 2008: 3.2.18 + ~ Switched to xhtml-rendering, fixes issue #8173, http://bugs.typo3.org/view.php?id=8173, Thanks to Oliver Klee. + * Fixed some typos, code-beautification, fixes issue #8173, http://bugs.typo3.org/view.php?id=8173, Thanks to Oliver Klee + +14. April 2008: 3.2.17 + + Added extension 'oelib' as a suggested install: It provides helper classes for writing unit tests for Typo3. + ~ Updated manual to include a section about Typo3 unit testing helper classes (specifically: oelib). + +07. April 2008: 3.2.16 + + Added possibility to 'hook' which class to run. You will need to implement two methods, init() and main(). + ~ Re-inserted $backupGlobals = false. + +06. April 2008: 3.2.15 + - Removed setting $backupGlobals=false. This should be unnecessary after PHPUnit issue #421 was solved, http://www.phpunit.de/ticket/421. + * Bugfix: Commented out calls to Graphviz. This is a future feature, that had sneaked in prematurely, causing fatal error for users. Closes issue #8037, http://bugs.typo3.org/view.php?id=8037. + ~ Moved NEWS file from 'About PHPUnit BE' to an entry of its own in the dropdown selector. + * Made two private methods, getLL() and getSL(), protected. + +04. April 2008: 3.2.14 + + Added PHPUnit 3.2.18, see Changelog at http://www.phpunit.de/wiki/ChangeLog32#PHPUnit3.2.1804-Apr-2008 + - Removed PHPUnit 3.2.17. + * Changes to stylesheet, to mitigate some of the most glaring usability issues in the Typo3 4 default skin. + ~ Tweaked NEWS file. + +04. April 2008: 3.2.13 + * Bugfix: Moved setting of $backupGlobals from tx_phpunit_database_testcase.php to tx_phpunit_testcase.php. This fixes a 'Fatal Error' on Windows. Thanks goes to Morten Lovbjerg. + +02. April 2008: 3.2.12 + + Added re-run icon to each test: Clicking it, will re-run that test only. Closes issue #6972, http://bugs.typo3.org/view.php?id=6972 (does not work with Experimental UI). + + Added NEWS file to end of 'About PHPUnit BE', to make it easier to access. + + Added option 'alwaysSimulateFrontendEnvironment' which defaults to true, since that is backwards compatible. + + Added method 'simulateFrontendEnvironment()' to tx_phpunit_testcase class. Call this method to load a (simple) simulation of the FE environment. + + Added lib/ directory. Might be removed later, let's see... + - Removed clear.gif. + + Added icon mod1/runner.gif + * Made all files follow the GT3 coding conventions (a derivative of Typo3 CGL, but not a subset). + +31. March 2008: Version 3.2.11 + + Added test file for test suite in tests/class.tx_phpunit_testsuite.php + ~ Improvement to test suite finding in Experimental UI, courtesy of Mikkel Ricky. + +31. March 2008: Version 3.2.10 + * Using strtolower() on database names in tx_phpunit_database_testcase->__construct(), courtesy of Mikkel Ricky, Morten Lovbjerg and Soren Soltveit. + * Fixed Experimental UI to work on Windows, courtesy of Mikkel Ricky. + +31. March 2008: Version 3.2.9 + ~ Moved database tests out of class tx_phpunit_testcase and into tx_phpunit_database_testcase. + * Drops database in createDatabase() before trying to create it. + +31. March 2008: Version 3.2.8 + * Bug fix release. Removed call in mod1/class.tx_phpunit_module1.php to Typo3 4.2 specific function loadJavascriptLib(). + +30. March 2008: Version 3.2.7 + * Bug fix release. Fixes #7964, http://bugs.typo3.org/view.php?id=7964 + +29. March 2008: Version 3.2.6 + + Added extension icons to selector boxes (note: not working with Opera). + + Added PHPUnit 3.2.17, see Changelog at http://phpunit.de/wiki/ChangeLog32#PHPUnit3.2.1729-Mar-2008 + - Removed PHPUnit 3.2.16. + +27. March 2008: Version 3.2.5 + + Added new UI for running tests: You will need to set the new option ' Experimental test interface' in the Extension Manager (EM). This adresses issue #6965, http://bugs.typo3.org/view.php?id=6965. Thanks to Mikkel Ricky who provided the new implementation. + +24. March 2008: Version 3.2.4 + + Experimental support for Code Coverage reporting. Turned of by default, since you need to setup XDebug and it slows down unit testing considerably! + + Previously there was a total timelimit of 30 seconds. Now the timelimit is per testcase; this is done by inserting a call to set_time_limit(30) in the testlistener. + + Expanded 'About PHPUnit BE': Added links to bugs.typo3.org and phpunit on typo3xdev.sf.net. Added Søren Soltveit to contributor list. Added test for XDebug extension (needed for code coverage) and test for memory limit, which should be set to something like 256MB, when using code coverage! + + New (experimental) progressbar: First stab at bugs #6972 and #6975. Turned off by default. Works badly: Overflows to the right, when there are many tests. + + Added PHPUnit 3.2.16, see Changelog at http://www.phpunit.de/wiki/ChangeLog32#PHPUnit3.2.1622-Mar-2008. + + Removed PHPUnit 3.2.15. + - Removed variable addAttrib in SVN revision 8639. Solves issue #7011, http://bugs.typo3.org/view.php?id=7011 + ~ Use t3lib_div::trimExplode in various places, where it was appropriate. + ~ ext_emconf.php: 'Namespace' variables better (in typo3confvars). + ~ Added array type hint to function getFirstNonPHPUnitTrace in class tx_phpunit_testlistener. + * Errors are now marked red (instead of yellow). Solves bug #6977, http://bugs.typo3.org/view.php?id=6977. + +18. March 2008: Version 3.2.3 + + New helper functions in tx_phpunit_testcase: You can now use the Typo3 database from your tests. E.g. for creating new tables for your tests. Reminder: Never run tests in a production environment. + + Tests for new helper functions added in class database_testcase. Note: You will need to manually install the four extensions named 'aaa', 'bbb', 'ccc' and 'ddd' (they can be found in tests/res/). + ~ Upgraded PHPUnit from 3.2.6 to 3.2.15. Changelog: http://www.phpunit.de/wiki/ChangeLog32#PHPUnit3.2.1521-Feb-2008 + ~ ext_emconf now states in description that the phpunit extension is based on PHPUnit 3.2 (instead of just PHPUnit 3). + * (Temporary) fix for issue #7631, http://bugs.typo3.org/view.php?id=7631#c19761, courtesy Mario Rimann. + +19. December 2007: Version 3.2.2 + ~ Changed header in BE module: It now writes the version string from the PHPUnit currently in use. This makes it easier to verify that the correct version is used. Closes http://bugs.typo3.org/view.php?id=6985 + * Removed white background from phpunit-be.css. + * Changed path in ext_localconf.php to uppercase. Solves problem, where using the shipped PHPUnit did not work on systems where upper case / lower case is respected (e.g. Linux systems). + +17. December 2007: Version 3.2.1 - The 'Remember PEAR file structure!' release. + * Moved files in PHPUnit-3.2.6 directory to a PHPUnit sub-directory. Closes http://bugs.typo3.org/view.php?id=6994 + ~ Updated News part of manual. + +17. December 2007: Version 3.2.0 - The 'There is money to be made' release! + ~ Bumped version number, since phpunit now ships with PHPUnit version 3.2.6 + + Added a NEWS file, which holds the info which was previously in the Changelog file. + ~ Changed the Changelog file to hold Subversion commits. This is meant to be added by a pre-commit hook on svn, when extension development is moved to typo3xdev.sf.net. + +22. October 2007: Version 3.1.15 + ~ Extension test selector now groups the tests under the test suite they are part of (Usability request from Elmar Hinz of the ECT). + +17. October 2007: Version 3.1.14 + + Added German translation, thanks to Mario Rimann :-) + +17. October 2007: Version 3.1.13 + + Option to use extension pear as default. If PHPUnit is not installed via pear, then phpunit uses its own PHPUnit version as fallback. (proposal from Extension Coordination Team, ECT). + + Added info to 'About' if 'use pear' is set, but pear is not loaded. Defaults to phpunit provided PHPunit in that case (instead of just aborting). + ~ Updated manual to mention pear integration and made the Changelog current (and updated index). + +17. October 2007: Version 3.1.12 + + Added 'Exclude extensions' option in extension manager setup. This allows you to set extension that phpunit should never search for tests (also applies to 'out of line'-paths). + + Added info about currently excluded extensions to 'About phpunit BE' submodule. + +17. October 2007: Version 3.1.11 + * Two identically named tests in different testsuites are now distinguished. + * Having the same extension installed as both local and global now works: Tests in the active one is run. + +15. October 2007: Version 3.1.10 + + Added 'out-of-line' tests: These are tests that are now in the extension itself, but found on a path you give in the extension manager. + + Added information notice to eAccelerator 0.9.5.1 users about optimizer bug in eAccelerator. + + Added 'Contributors' section to About box. + + Fully translated into danish (except for the texts coming from PHPUnit). + + Added stylesheet file, phpunit-be.css. + ~ Changed layout of test runs to make them more easily readable. + ~ Changed the two failing tests, that comes with phpunit: Now they give a message that they are meant to fail. + ~ Factored out inline styles on elements (now controllable from phpunit-be.css). + * Corrected display of failure notices from failed tests: Assertion types/values are shown again. + * Corrected logo image display in About box. + + +10. October 2007: Version 3.1.9 + + Added 'include_path' output to the 'About' sub-module. This can be used to check where the extension is looking for PHPUnit. + + Added extension manager configuration option to point to another PHPUnit, than the one provided by the extension (could be a PEAR installed PHPUnit). + + Added PHPUnit version 3.1.9 + + Added PHPUnit version 3.0.6: You must provide the absolute path to it in the extension manager conf (including ending slash) to use this version. + - Removed PHPUnit version 3.0.5 + ~ Changed to using Typo3 v. 4.1.x feature of mod.php for the backend module, cf. http://typo3.org/documentation/document-library/core-documentation/doc_core_inside/4.1.0/view/3/5/#id3561091 + ~ Changed version number to 3.1.9. + ~ Changed state to beta. + ~ Changed ChangeLog Legend and updated the complete file to reflect this. + * Corrected the way the lib is found: Now you only have do do it in one place. Note that PHPUnit is expected to be in a sub-directory called 'PHPUnit' of the place you write. + * Corrected the progressbar, so now it stays within the browser window (Thanks to Mikkel Ricky for the fix :-) + * Corrected a bug, where an error about class tx_t3unit_testcase was spewed (Thanks to Mario Rimann for pointing out and Mikkel Ricky for fixing). + +13. March 2007: Version 3.0.52 + + Added class tx_t3unit_testcase for providing backwards compatibility with t3unit (suggested by Robert Lemke). + + Added t3unit and pear_phpunit2 to conflicts in file ext_emconf.php (suggested by Robert Lemke). + ~ Changed version number in file ext_emconf.php to 3.0.52. + * Corrected depends in file ext_emconf.php (suggested by Robert Lemke) + from: 'php' => '5.2.1-0.0.0', 'typo3' => '4.1-0.0.0', + to: 'php' => '5.2.1-', 'typo3' => '4.1-', + * Corrected paragraph in manual about version numbering convention to match reality (I hope!). + +11. March 2007: Version 3.0.51 + + Added tests/ directory to phpunit itself. + + Added test file in tests/ directory (test file includes only dummy tests). + + Added 'Legend' to Changelog file. + ~ Bumped version number to 3.0.5.1. + +11. March 2007: Version 3.0.5 + + Merged T3Unit and PEAR_phpunit. + + Upgraded to PHPUnit 3.0.5. + + Revised documentation (still needs a lot of work). + + Marked as experimental. + + Set version to 3.0.5. + + Upload to TER. + * Corrected EM Conf. so extension is not marked as shy. diff --git a/typo3conf/ext/phpunit/Classes/BackEnd/Ajax.php b/typo3conf/ext/phpunit/Classes/BackEnd/Ajax.php new file mode 100644 index 0000000..462e1a4 --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/BackEnd/Ajax.php @@ -0,0 +1,81 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/** + * This class uses the new AJAX broker in Typo3 4.2. + * + * @see http://bugs.typo3.org/view.php?id=7096 + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Kasper Ligaard + * @author Michael Klapper + * @author Oliver Klee + * @author Bastian Waidelich + * @author Carsten Koenig + */ +class Tx_Phpunit_BackEnd_Ajax { + /** + * Used to broker incoming requests to other calls. + * Called by typo3/ajax.php + * + * @param array $parameters + * additional parameters (not used) + * @param TYPO3AJAX $ajaxObj + * the AJAX object of this request + * + * @return void + */ + public function ajaxBroker(array $parameters, TYPO3AJAX $ajaxObj) { + // Checks for legal input ('white-listing'). + $state = t3lib_div::_POST('state') === 'true' ? 'on' : 'off'; + $checkbox = t3lib_div::_POST('checkbox'); + switch ($checkbox) { + case 'failure': + case 'success': + case 'error': + case 'skipped': + case 'notimplemented': + case 'testdox': + case 'codeCoverage': + case 'showMemoryAndTime': + case 'runSeleniumTests': + break; + default: + $checkbox = FALSE; + } + + if ($checkbox) { + $ajaxObj->setContentFormat('json'); + $GLOBALS['BE_USER']->uc['moduleData']['tools_txphpunitM1'][$checkbox] = $state; + $GLOBALS['BE_USER']->writeUC(); + $ajaxObj->addContent('success', TRUE); + } else { + $ajaxObj->setContentFormat('plain'); + $ajaxObj->setError('Illegal input parameters.'); + } + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/BackEnd/Module.php b/typo3conf/ext/phpunit/Classes/BackEnd/Module.php new file mode 100644 index 0000000..006004e --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/BackEnd/Module.php @@ -0,0 +1,889 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/** + * Back-end module "PHPUnit". + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Kasper Ligaard + * @author Michael Klapper + * @author Oliver Klee + * @author Bastian Waidelich + * @author Carsten Koenig + */ +class Tx_Phpunit_BackEnd_Module extends t3lib_SCbase { + /** + * the extension key + * + * @var string + */ + const EXTENSION_KEY = 'phpunit'; + + /** + * the relative path to this extension + * + * @var string + */ + protected $extensionPath = ''; + + /** + * a test finder + * + * @var Tx_Phpunit_Service_TestFinder + */ + protected $testFinder = NULL; + + /** + * module menu items + * + * @var array + */ + public $MOD_MENU = array( + 'function' => array(), + 'extSel' => '', + 'failure' => '', + 'success' => '', + 'error' => '', + 'codeCoverage' => '', + ); + + /** + * the names of classes which cannot be directly run as test cases + * + * @var array + */ + protected $ignoredTestSuitClasses = array( + 'Tx_Phpunit_TestCase', + 'Tx_Phpunit_Database_TestCase', + 'Tx_Phpunit_Selenium_TestCase', + ); + + /** + * The constructor. + */ + public function __construct() { + $this->init(); + + $this->extensionPath = t3lib_extMgm::extRelPath(self::EXTENSION_KEY); + } + + /** + * The destructor. + */ + public function __destruct() { + unset($this->testFinder); + } + + /** + * Creates a and returns the singleton test finder instance. + * + * @return Tx_Phpunit_Service_TestFinder the test finder instance + */ + protected function getTestFinder() { + if ($this->testFinder === NULL) { + $this->testFinder = t3lib_div::makeInstance('Tx_Phpunit_Service_TestFinder'); + } + + return $this->testFinder; + } + + /** + * Returns the localized string for the key $key. + * + * @param string $key the key of the string to retrieve, must not be empty + * + * @return string the localized string for the key $key + */ + protected function translate($key) { + return $GLOBALS['LANG']->getLL($key); + } + + /** + * Main function of the module. Outputs all content directly instead of + * collecting it and doing the output later. + * + * @return void + */ + public function main() { + if ($GLOBALS['BE_USER']->user['admin']) { + // Draw the header. + $this->doc = t3lib_div::makeInstance('bigDoc'); + $this->doc->backPath = $GLOBALS['BACK_PATH']; + $this->doc->docType = 'xhtml_strict'; + $this->doc->bodyTagAdditions = 'id="doc3"'; + + // JavaScript Libraries + $this->doc->loadJavascriptLib('contrib/prototype/prototype.js'); + $this->doc->loadJavascriptLib($this->extensionPath . 'Resources/Public/YUI/yahoo-dom-event.js'); + $this->doc->loadJavascriptLib($this->extensionPath . 'Resources/Public/YUI/connection-min.js'); + $this->doc->loadJavascriptLib($this->extensionPath . 'Resources/Public/YUI/json-min.js'); + $this->doc->loadJavascriptLib($this->extensionPath . 'Resources/Public/JavaScript/BackEnd.js'); + + // Mis-using JScode to insert CSS _after_ skin. + $this->doc->JScode = ''; + $this->doc->JScode .= ''; + $this->doc->JScode .= ''; + + t3lib_div::cleanOutputBuffers(); + $this->output( + $this->doc->startPage($this->translate('title')) . + $this->doc->header(PHPUnit_Runner_Version::getVersionString()) + ); + + $this->runTests_render(); + + $this->output( + $this->doc->section( + 'Keyboard shortcuts', + '

    Use "a" for running all tests, use "s" for running a single test and + use "r" to re-run the latest tests; to open phpunit in a new window, use "n".

    +

    Depending on your browser and system you will need to press some + modifier keys:

    +
      +
    • Safari, IE and Firefox 1.x: Use "Alt" button on Windows, "Ctrl" on Macs.
    • +
    • Firefox 2.x and 3.x: Use "Alt-Shift" on Windows, "Ctrl-Shift" on Macs
    • +
    ' . + $this->doc->section('', $this->openNewWindowLink()) + ) + ); + } else { + $this->doc = t3lib_div::makeInstance('mediumDoc'); + $this->doc->backPath = $GLOBALS['BACK_PATH']; + + $this->output( + $this->doc->startPage($this->translate('title')) . + $this->doc->header($this->translate('title')) . + $this->translate('admin_rights_needed') + ); + } + + $this->output($this->doc->endPage()); + } + + + /********************************************************* + * + * Screen render functions + * + *********************************************************/ + + /** + * Renders the screens for function "Run tests". + * + * @return void + */ + protected function runTests_render() { + if (($this->MOD_SETTINGS['extSel'] !== 'uuall') + && !$this->isExtensionLoaded($this->MOD_SETTINGS['extSel']) + ) { + // We know that phpunit must be loaded. + $this->MOD_SETTINGS['extSel'] = 'phpunit'; + } + $command = $this->MOD_SETTINGS['extSel'] ? t3lib_div::_GP('command') : ''; + switch ($command) { + case 'runalltests': + // The fallthrough is intentional. + case 'runTestCaseFile': + // The fallthrough is intentional. + case 'runsingletest': + $this->runTests_renderIntro(); + $this->runTests_renderRunningTest(); + break; + default: + $this->runTests_renderIntro(); + } + } + + /** + * Renders the intro screen for the function "Run tests". + * + * @return void + */ + protected function runTests_renderIntro() { + $extensionsWithTestSuites = $this->getExtensionsWithTestSuites(); + if (empty($extensionsWithTestSuites)) { + $this->output($this->translate('could_not_find_exts_with_tests')); + return; + } + + ksort($extensionsWithTestSuites); + + $output = $this->runTests_renderIntro_renderExtensionSelector($extensionsWithTestSuites); + if ($this->MOD_SETTINGS['extSel'] && ($this->MOD_SETTINGS['extSel'] !== 'uuall')) { + $output .= $this->runTests_renderIntro_renderTestSelector( + $extensionsWithTestSuites, + $this->MOD_SETTINGS['extSel'] + ); + } + + $this->output($output); + } + + /** + * Renders the extension drop-down. + * + * @param array $extensionsWithTestSuites + * keys of the extensions for which test suites exist, may be empty + * + * @return string + * HTML code for the drop-down and a surrounding form, will not be empty + */ + protected function runTests_renderIntro_renderExtensionSelector(array $extensionsWithTestSuites) { + $extensionsOptionsArr = array(); + $extensionsOptionsArr[] = ''; + + $selected = strcmp('uuall', $this->MOD_SETTINGS['extSel']) ? '' : ' selected="selected"'; + $extensionsOptionsArr[] = ''; + + foreach (array_keys($extensionsWithTestSuites) as $extensionKey) { + $style = $this->createIconStyle($extensionKey); + $selected = strcmp($extensionKey, $this->MOD_SETTINGS['extSel']) ? '' : ' selected="selected"'; + if ($selected !== '') { + $currentExtName = $extensionKey; + } + $extensionsOptionsArr[] = ''; + } + + try { + $style = $this->createIconStyle($currentExtName); + } catch (Exception $exception) { + $style = ''; + } + + $output = '
    +

    + + + +

    +
    '; + + return $output; + } + + /** + * Renders a drop-down for running single tests for the given extension. + * + * @param array $extensionsWithTestSuites + * keys of the extensions for which test suites exist + * @param string $extensionKey + * keys of the extension for which to render the drop-down + * + * @return string HTML code with the selectorbox and a surrounding form + */ + protected function runTests_renderIntro_renderTestSelector( + array $extensionsWithTestSuites, $extensionKey + ) { + $testSuite = new PHPUnit_Framework_TestSuite('tx_phpunit_basetestsuite'); + + // Loads the files containing test cases from extensions. + $paths = $extensionsWithTestSuites[$extensionKey]; + + if (isset($paths)) { + foreach ($paths as $path => $fileNames) { + foreach ($fileNames as $fileName) { + require_once($path . $fileName); + } + } + } + + // Adds all classes to the test suite which end with "testcase" (case-insensitive) + // or "Test", except the two special classes used as superclasses. + foreach (get_declared_classes() as $class) { + $classReflection = new ReflectionClass($class); + if ((strtolower(substr($class, -8, 8)) === 'testcase' || substr($class, -4, 4) === 'Test') + && $classReflection->isSubclassOf('PHPUnit_Framework_TestCase') + && $this->isAcceptedTestSuitClass($class) + ) { + $testSuite->addTestSuite($class); + } + } + + // testCaseFile + $testCaseFileOptionsArray = array(); + foreach ($testSuite->tests() as $testCases) { + $selected = ($testCases->toString() === t3lib_div::_GP('testCaseFile')) ? ' selected="selected"' : ''; + $testCaseFileOptionsArray[] = ''; + } + + // single test case + $testsOptionsArr = array(); + $testCaseFile = t3lib_div::_GP('testCaseFile'); + foreach ($testSuite->tests() as $testCases) { + if (!is_null($testCaseFile) && ($testCases->getName() !== $testCaseFile)) { + continue; + } + foreach ($testCases->tests() as $test) { + if ($test instanceof PHPUnit_Framework_TestSuite) { + list($testSuiteName, $testName) = explode('::', $test->getName()); + $testIdentifier = $testName . '(' . $testSuiteName . ')'; + } else { + $testName = $test->getName(); + $testIdentifier = $test->toString(); + $testSuiteName = strstr($testIdentifier, '('); + $testSuiteName = trim($testSuiteName, '()'); + } + $selected = ($testIdentifier === t3lib_div::_GP('testname')) ? ' selected="selected"' : ''; + $testsOptionsArr[$testSuiteName][] .= ''; + } + } + + $currentStyle = $this->createIconStyle($extensionKey); + + // builds options for select (including option groups for test suites) + $testOptionsHtml = ''; + foreach ($testsOptionsArr as $suiteName => $testArr) { + $testOptionsHtml .= ''; + foreach ($testArr as $testHtml) { + $testOptionsHtml .= $testHtml; + } + $testOptionsHtml .= ''; + } + + $currentStyle = $this->createIconStyle($extensionKey); + + $output = '
    +

    + + + +

    +
    '; + $output .= '
    +

    + + + + +

    +
    + '; + + $output .= '
    '; + $output .= '
    '; + $failureState = $this->MOD_SETTINGS['failure'] === 'on' ? 'checked="checked"' : ''; + $errorState = $this->MOD_SETTINGS['error'] === 'on' ? 'checked="checked"' : ''; + $skippedState = $this->MOD_SETTINGS['skipped'] === 'on' ? 'checked="checked"' : ''; + $successState = $this->MOD_SETTINGS['success'] === 'on' ? 'checked="checked"' : ''; + $notImplementedState = $this->MOD_SETTINGS['notimplemented'] === 'on' ? 'checked="checked"' : ''; + $showMemoryAndTime = $this->MOD_SETTINGS['showMemoryAndTime'] === 'on' ? 'checked="checked"' : ''; + $testdoxState = $this->MOD_SETTINGS['testdox'] === 'on' ? 'checked="checked"' : ''; + $output .= ''; + $output .= ' '; + $output .= ' '; + $output .= ' '; + $output .= ' '; + $output .= ' '; + $output .= ' '; + + $codecoverageDisable = ''; + $codecoverageForLabelWhenDisabled = ''; + if (!extension_loaded('xdebug')) { + $codecoverageDisable = ' disabled="disabled"'; + $codecoverageForLabelWhenDisabled = ' title="Code coverage requires XDebug to be installed."'; + } + $codeCoverageState = $this->MOD_SETTINGS['codeCoverage'] === 'on' ? 'checked="checked"' : ''; + $output .= ' '; + $runSeleniumTests = $this->MOD_SETTINGS['runSeleniumTests'] === 'on' ? 'checked="checked"' : ''; + $output .= ' '; + $output .= '
    '; + $output .= '
    '; + + return $output; + } + + /** + * Renders the screen for the function "Run tests" which shows and + * runs the actual unit tests. + * + * @return void + */ + protected function runTests_renderRunningTest() { + if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['alwaysSimulateFrontendEnvironment']) { + $this->simulateFrontendEnviroment(); + } + + $extensionsWithTestSuites = $this->getExtensionsWithTestSuites(); + $testSuite = new PHPUnit_Framework_TestSuite('tx_phpunit_basetestsuite'); + $extensionKeysToProcess = array(); + if ($this->MOD_SETTINGS['extSel'] === 'uuall') { + $this->output('

    ' . $this->translate('testing_all_extensions') . '

    '); + $extensionKeysToProcess = array_keys($extensionsWithTestSuites); + } else { + $this->output( + '

    ' . $this->translate('testing_extension') . ': ' . + htmlspecialchars($this->MOD_SETTINGS['extSel']) . '

    ' + ); + $extInfo = $extensionsWithTestSuites[$this->MOD_SETTINGS['extSel']]; + $extensionsWithTestSuites = array(); + $extensionsWithTestSuites[$this->MOD_SETTINGS['extSel']] = $extInfo; + $extensionKeysToProcess = array($this->MOD_SETTINGS['extSel']); + } + + // Loads the files containing test cases from extensions. + foreach ($extensionKeysToProcess as $extensionKey) { + $paths = $extensionsWithTestSuites[$extensionKey]; + $this->loadRequiredTestClasses($paths); + } + + // Adds all classes to the test suite which end with "testcase" or "Test". + foreach (get_declared_classes() as $class) { + $classReflection = new ReflectionClass($class); + if ($classReflection->isSubclassOf('Tx_Phpunit_TestCase') + && ((strtolower(substr($class, -8, 8)) === 'testcase') || (substr($class, -4, 4) === 'Test')) + && ($class !== 'Tx_Phpunit_TestCase') && ($class !== 'Tx_Phpunit_Database_TestCase') + ) { + $testSuite->addTestSuite($class); + } elseif ($this->MOD_SETTINGS['runSeleniumTests'] === 'on' + && $classReflection->isSubclassOf('Tx_Phpunit_Selenium_TestCase') + && ((strtolower(substr($class, -8, 8)) === 'testcase') || (substr($class, -4, 4) === 'Test')) + && ($class !== 'Tx_Phpunit_Selenium_TestCase') + ) { + $testSuite->addTestSuite($class); + } + } + + $result = new PHPUnit_Framework_TestResult(); + + // Sets to collect code coverage information. + if (($GLOBALS['BE_USER']->uc['moduleData']['tools_txphpunitM1']['codeCoverage'] === 'on') + && extension_loaded('xdebug') + ) { + $result->collectCodeCoverageInformation(TRUE); + } + + $testListener = new Tx_PhpUnit_BackEnd_TestListener(); + if ($this->MOD_SETTINGS['testdox'] === 'on') { + $testListener->useHumanReadableTextFormat(); + } + + if ($this->MOD_SETTINGS['showMemoryAndTime'] === 'on') { + $testListener->enableShowMenoryAndTime(); + } + + $result->addListener($testListener); + + $startMemory = memory_get_usage(); + $startTime = microtime(TRUE); + + if (t3lib_div::_GP('testname')) { + $this->runTests_renderInfoAndProgressbar(); + foreach ($testSuite->tests() as $testCases) { + foreach ($testCases->tests() as $test) { + if ($test instanceof PHPUnit_Framework_TestSuite) { + list($testSuiteName, $testName) = explode('::', $test->getName()); + $testListener->setTestSuiteName($testSuiteName); + $testIdentifier = $testName . '(' . $testSuiteName . ')'; + } else { + $testIdentifier = $test->toString(); + list($testSuiteName, $testName) = explode('::', $testIdentifier); + $testListener->setTestSuiteName($testSuiteName); + } + if ($testIdentifier === t3lib_div::_GP('testname')) { + if ($test instanceof PHPUnit_Framework_TestSuite) { + $testListener->setTotalNumberOfTests($test->count()); + } else { + $testListener->setTotalNumberOfTests(1); + } + $this->output('

    Testsuite: ' . $testCases->getName() . '

    '); + $test->run($result); + } + } + } + if (!is_object($result)) { + $this->output( + '

    Error

    The test ' . + htmlspecialchars(t3lib_div::_GP('testCaseFile')) . ' could not be found.

    ' + ); + return; + } + } elseif (t3lib_div::_GP('testCaseFile')) { + $testCaseFileName = t3lib_div::_GP('testCaseFile'); + $testListener->setTestSuiteName($testCaseFileName); + + $suiteNameHasBeenDisplayed = FALSE; + $totalNumberOfTestCases = 0; + foreach ($testSuite->tests() as $testCases) { + foreach ($testCases->tests() as $test) { + if ($test instanceof PHPUnit_Framework_TestSuite) { + list($testIdentifier, $testName) = explode('::', $test->getName()); + } else { + $testIdentifier = get_class($test); + } + if ($testIdentifier === $testCaseFileName) { + if ($test instanceof PHPUnit_Framework_TestSuite) { + $totalNumberOfTestCases += $test->count(); + } else { + $totalNumberOfTestCases++; + } + } + } + } + $testListener->setTotalNumberOfTests($totalNumberOfTestCases); + $this->runTests_renderInfoAndProgressbar(); + + foreach ($testSuite->tests() as $testCases) { + foreach ($testCases->tests() as $test) { + if ($test instanceof PHPUnit_Framework_TestSuite) { + list($testIdentifier, $testName) = explode('::', $test->getName()); + } else { + $testIdentifier = get_class($test); + } + if ($testIdentifier === $testCaseFileName) { + if (!$suiteNameHasBeenDisplayed) { + $this->output('

    Testsuite: ' . $testCaseFileName . '

    '); + $suiteNameHasBeenDisplayed = TRUE; + } + $test->run($result); + } + } + } + if (!is_object($result)) { + $this->output( + '

    Error

    The test ' . + htmlspecialchars(t3lib_div::_GP('testname')) . ' could not be found.

    ' + ); + return; + } + } else { + $testListener->setTotalNumberOfTests($testSuite->count()); + $this->runTests_renderInfoAndProgressbar(); + $testSuite->run($result); + } + + $timeSpent = microtime(TRUE) - $startTime; + $leakedMemory = memory_get_usage() - $startMemory; + + // Displays test statistics. + $testStatistics = ''; + if ($result->wasSuccessful()) { + $testStatistics = '

    ' . $this->translate('testing_success') . '

    '; + } else { + $testStatistics = ' +

    ' . $this->translate('testing_failure') . '

    '; + } + $testStatistics .= '

    ' . $result->count() . ' ' . $this->translate('tests_total') . ', ' . $testListener->assertionCount() . ' ' . + $this->translate('assertions_total') . ', ' . $result->failureCount() . ' ' . $this->translate('tests_failures') . + ', ' . $result->skippedCount() . ' ' . $this->translate('tests_skipped') . ', ' . + $result->notImplementedCount() . ' ' . $this->translate('tests_notimplemented') . ', ' . $result->errorCount() . + ' ' . $this->translate('tests_errors') . ', ' . round($timeSpent, 3) . ' ' . $this->translate('tests_seconds') . + ', ' . t3lib_div::formatSize($leakedMemory) . 'B (' . $leakedMemory . ' B) ' . + $this->translate('tests_leaks') . '

    '; + $this->output($testStatistics); + + $this->output( + '
    +

    + + + + +

    +
    ' . + '
    ' + ); + + if (!t3lib_div::_GP('testname') && $result->getCollectCodeCoverageInformation()) { + require_once('PHP/CodeCoverage/Report/HTML.php'); + + $writer = new PHP_CodeCoverage_Report_HTML(); + $writer->process($result->getCodeCoverage(), t3lib_extMgm::extPath('phpunit') . 'codecoverage/'); + $this->output( + '

    Click here to access the Code Coverage report

    ' . + '

    Memory peak usage: ' . t3lib_div::formatSize(memory_get_peak_usage()) . 'B

    ' + ); + } + } + + /** + * Renders DIVs which contain information and a progressbar to visualize + * the running tests. + * + * The actual information will be written via JS during + * the test runs. + * + * @return void + */ + protected function runTests_renderInfoAndProgressbar() { + $this->output( + '

    +   +   +
    ' + ); + } + + /** + * Roughly simulates the front end although being in the back end. + * + * @deprecated since 3.5.12, will be removed in 3.6.0. Use Tx_Phpunit_Framework::createFakeFrontEnd instead. + * + * @return void + */ + protected function simulateFrontendEnviroment() { + t3lib_div::logDeprecatedFunction(); + + if (isset($GLOBALS['TSFE']) && is_object($GLOBALS['TSFE'])) { + // avoids some memory leaks + unset( + $GLOBALS['TSFE']->tmpl, $GLOBALS['TSFE']->sys_page, $GLOBALS['TSFE']->fe_user, + $GLOBALS['TSFE']->TYPO3_CONF_VARS, $GLOBALS['TSFE']->config, $GLOBALS['TSFE']->TCAcachedExtras, + $GLOBALS['TSFE']->imagesOnPage, $GLOBALS['TSFE']->cObj, $GLOBALS['TSFE']->csConvObj, + $GLOBALS['TSFE']->pagesection_lockObj, $GLOBALS['TSFE']->pages_lockObj + ); + $GLOBALS['TSFE'] = NULL; + $GLOBALS['TT'] = NULL; + } + + $GLOBALS['TT'] = t3lib_div::makeInstance('t3lib_TimeTrackNull'); + $frontEnd = t3lib_div::makeInstance('tslib_fe', $GLOBALS['TYPO3_CONF_VARS'], 0, 0); + + // simulates a normal FE without any logged-in FE or BE user + $frontEnd->beUserLogin = FALSE; + $frontEnd->workspacePreview = ''; + $frontEnd->gr_list = '0,-1'; + + $frontEnd->sys_page = t3lib_div::makeInstance('t3lib_pageSelect'); + $frontEnd->sys_page->init(TRUE); + $frontEnd->initTemplate(); + + // $frontEnd->getConfigArray() doesn't work here because the dummy FE + // is not required to have a template. + $frontEnd->config = array(); + + $GLOBALS['TSFE'] = $frontEnd; + } + + + + /********************************************************* + * + * Helper functions + * + *********************************************************/ + + /** + * Renders a link which opens the current screen in a new window, + * + * @return string + */ + protected function openNewWindowLink() { + $url = t3lib_div::getIndpEnv('TYPO3_REQUEST_SCRIPT') . '?M=tools_txphpunitbeM1'; + $onClick = "phpunitbeWin=window.open('" . $url . + "','phpunitbe','width=790,status=0,menubar=1,resizable=1,location=0,scrollbars=1,toolbar=0');phpunitbeWin.focus();return false;"; + $content = ' + + Open in separate window. + + '; + + return $content; + } + + /** + * Scans all available extensions for test case files. + * + * @return array + * first-level array keys: extension key + * second level array values: paths to the test case files relative + * to the extension directory + */ + protected function getExtensionsWithTestSuites() { + $excludeExtensions = t3lib_div::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['excludeextensions']); + + $extList = explode(',', $GLOBALS['TYPO3_CONF_VARS']['EXT']['extList']); + + $extensionsOwnTestCases = array(); + foreach ($extList as $extKey) { + $extPath = t3lib_extMgm::extPath($extKey); + if (is_dir($extPath . 'Tests/')) { + $testCasesDirectory = $extPath . 'Tests/'; + } else { + $testCasesDirectory = $extPath . 'tests/'; + } + + $testCasesArr = $this->findTestCasesInDir($testCasesDirectory); + if (!empty($testCasesArr)) { + $extensionsOwnTestCases[$extKey] = $testCasesArr; + } + } + + $coreTestCases = array(); + if ($this->getTestFinder()->hasCoreTests()) { + $coreTestCases[Tx_Phpunit_TestableCode::CORE_KEY] + = $this->findTestCasesInDir($this->getTestFinder()->getAbsoluteCoreTestsPath()); + } + + $totalTestsArr = array_merge_recursive($extensionsOwnTestCases, $coreTestCases); + + $returnTestsArr = array_diff_key($totalTestsArr, array_flip($excludeExtensions)); + return $returnTestsArr; + } + + /** + * Recursively finds all test case files in the directory $directory. + * + * @param string $directory + * the absolute path of the directory in which to look for test cases, + * must not be empty + * + * @return array + * files names of the test cases in the directory $dir and all + * its subdirectories relative to $dir, will be empty if no + * test cases have been found + */ + protected function findTestCasesInDir($directory) { + if (!is_dir($directory)) { + return array(); + } + + $testCaseFileNames = $this->getTestFinder()->findTestCasesInDirectory($directory); + + $extensionsArr = array(); + if (!empty($testCaseFileNames)) { + $extensionsArr[$directory] = $testCaseFileNames; + } + + return $extensionsArr; + } + + /** + * Includes all PHP files given in $paths. + * + * @param array $paths + * array keys: absolute path + * array values: file names in that path + * + * @return void + */ + protected function loadRequiredTestClasses(array $paths) { + foreach ($paths as $path => $fileNames) { + foreach ($fileNames as $fileName) { + require_once(realpath($path . '/' . $fileName)); + } + } + } + + /** + * Checks whether a extension is valid and the extension is loaded. + * + * "typo3" is considered as a valid extension key for this purpose, too. + * + * @param string $extensionKey + * the key of the extension to test, may be empty + * + * @return boolean + * TRUE if an extension with the key $extensionKey is loaded, FALSE otherwise + */ + protected function isExtensionLoaded($extensionKey) { + if ($extensionKey === '') { + return FALSE; + } + + return ($extensionKey === Tx_Phpunit_TestableCode::CORE_KEY) + || t3lib_extMgm::isLoaded($extensionKey); + } + + /** + * Creates the CSS style attribute content for an icon for the extension + * $extensionKey. + * + * @param string $extensionKey + * the key of a loaded extension, may also be "typo3" + * + * @return string the content for the "style" attribute, will not be empty + * + * @throws Tx_Phpunit_Exception_NoTestsDirectory + * if there is not extension with tests with the given key + */ + protected function createIconStyle($extensionKey) { + if ($extensionKey === '') { + throw new Tx_Phpunit_Exception_NoTestsDirectory('$extensionKey must not be empty.', 1303503647); + } + if (!$this->isExtensionLoaded($extensionKey)) { + throw new Tx_Phpunit_Exception_NoTestsDirectory( + 'The extension ' . $extensionKey . ' is not loaded.', 1303503664 + ); + } + + $result = 'background: white no-repeat '; + + if ($extensionKey === Tx_Phpunit_TestableCode::CORE_KEY) { + $result .= 'url(' . t3lib_extMgm::extRelPath('phpunit') . 'Resources/Public/Icons/Typo3.png) 3px 50%;'; + } else { + $result .= 'url(' . t3lib_extMgm::extRelPath($extensionKey) . 'ext_icon.gif) 3px 50%;'; + } + + $result .= ' padding: 1px 1px 1px 24px;'; + + return $result; + } + + /** + * Echoes $output. + * + * @param string $output a string to echo, may also be empty + * + * @return void + */ + protected function output($output) { + echo($output); + } + + /** + * Tests whether $class is the name of a class which can be run in the test + * runner. + * + * @param string $class class name to test, must not be empty + * + * @return boolean TRUE if the class is accepted, FALSE otherwise + */ + protected function isAcceptedTestSuitClass($class) { + return !in_array($class, $this->ignoredTestSuitClasses); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/BackEnd/TestListener.php b/typo3conf/ext/phpunit/Classes/BackEnd/TestListener.php new file mode 100644 index 0000000..229d630 --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/BackEnd/TestListener.php @@ -0,0 +1,585 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/** + * This class renders the output of the single tests in the phpunit BE module. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Robert Lemke + * @author Kasper Ligaard + * @author Michael Klapper + * @author Oliver Klee + */ +class Tx_PhpUnit_BackEnd_TestListener implements PHPUnit_Framework_TestListener { + /** + * the total number of tests to run + * + * @var integer + */ + protected $totalNumberOfTests = 0; + /** + * the total number of data provider tests detected + * + * @var integer + */ + protected $totalNumberOfDetectedDataProviderTests = 0; + + /** + * the number of the current test (zero-based) + * + * @var integer + */ + protected $currentTestNumber = 0; + + /** + * the number of the current data provider within a test (zero-based) + * + * @var integer + */ + protected $currentDataProviderNumber = 0; + + /** + * the name of the current test case + * + * @var string + */ + protected $currentTestCaseName = ''; + + /** + * the name of the current test + * + * @var string + */ + protected $previousTestName = ''; + + /** + * used memory (in bytes) before the first test is run + * + * @var integer + */ + protected $memoryUsageStartOfTest = 0; + + /** + * used memory (in bytes) after the last test has been run + * + * @var integer + */ + protected $memoryUsageEndOfTest = 0; + + /** + * the number of bytes that have been in use after running the last test + * (relative to the used bytes before starting the first test) + * + * @var integer + */ + public $totalLeakedMemory = 0; + + /** + * the number of executed assertions + * + * @var integer + */ + protected $testAssertions = 0; + + /** + * whether to use the "testdox" format to display test case and test names + * + * @var boolean + */ + protected $useHumanReadableTextFormat = FALSE; + + /** + * whether to display the used memory and time of each test + * + * @var boolean + */ + protected $enableShowMemoryAndTime = FALSE; + + /** + * a name prettifier for creating readable test and test case names + * + * @var PHPUnit_Util_TestDox_NamePrettifier + */ + protected $namePrettifier = NULL; + + /** + * The constructor. + */ + public function __construct() { + $this->namePrettifier = new PHPUnit_Util_TestDox_NamePrettifier(); + } + + /** + * The destructor. + */ + public function __destruct() { + unset($this->namePrettifier); + } + + /** + * Sets the total number of tests to run (used for displaying the progress + * bar). + * + * @param integer $totalNumberOfTests + * the total number of tests to run, must be >= 0 + * + * @return void + */ + public function setTotalNumberOfTests($totalNumberOfTests) { + $this->totalNumberOfTests = $totalNumberOfTests; + } + + /** + * Gets the total number of tests that were detected to come from data providers. + * + * Note: As these are detected based on similar names, the first test from a data + * provider cannot be detected reliably; the number will always be too low. + * + * @return integer the total number of data-provider related tests detected so far, will be >= 0 + */ + public function getTotalNumberOfDetectedDataProviderTests() { + return $this->totalNumberOfDetectedDataProviderTests; + } + + /** + * Enables the option to show the memory leaks and time usage of the single tests. + * + * @return void + */ + public function enableShowMenoryAndTime() { + $this->enableShowMemoryAndTime = TRUE; + } + + /** + * Enables the option to use human-readable test and test case names. + * + * @return void + */ + public function useHumanReadableTextFormat() { + $this->useHumanReadableTextFormat = TRUE; + } + + /** + * An error has occurred, i.e. an exception has been thrown when running $test. + * + * @param PHPUnit_Framework_Test $test the test that had an error + * @param Exception $e the exception that has caused the error + * @param float $time ? + * + * @return void + */ + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) { + $fileName = str_replace(PATH_site, '', $e->getFile()); + $lineNumber = $e->getLine(); + + echo ' + + ! Error in test case ' . $test->getName() . ' +
    File: ' . $fileName . ' +
    Line: ' . $lineNumber . '' . + '
    ' . nl2br(htmlspecialchars($e->getMessage())) . '
    '; + $this->flushOutputBuffer(); + } + + /** + * A test has failed. + * + * @param PHPUnit_Framework_Test $test the test that has failed + * @param PHPUnit_Framework_AssertionFailedError $e the failed assertion + * @param float $time ? + * + * @return void + */ + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) { + $testCaseTraceArr = $this->getFirstNonPhpUnitTrace($e->getTrace()); + $fileName = str_replace(PATH_site, '', $testCaseTraceArr['file']); + + $this->output( + '' . + '' . + '! Failure in test case ' . $test->getName() . '' . + '
    File: ' . $fileName . '' . + '
    Line: ' . $testCaseTraceArr['line'] . '' + ); + + if (method_exists($e, 'getDescription')) { + $message = $e->getDescription(); + } else { + $message = $e->getMessage(); + } + $this->output('
    ' . nl2br(htmlspecialchars($message)) . '
    '); + + if ($e instanceof PHPUnit_Framework_ExpectationFailedException) { + $comparisonFailure = $e->getComparisonFailure(); + if ($comparisonFailure instanceof PHPUnit_Framework_ComparisonFailure_String) { + $expected = $comparisonFailure->getExpected(); + $actual = $comparisonFailure->getActual(); + + $diff = t3lib_div::makeInstance('t3lib_diff'); + $this->output(''. $diff->makeDiffDisplay($actual, $expected) . ''); + } + } + } + + /** + * Returns the first trace information which is not caused by the PHPUnit file + * "Framework/Assert.php". + * + * @param array $traceData the trace data + * + * @return array trace information + */ + protected function getFirstNonPhpUnitTrace(array $traceData) { + $testCaseTraceData = array(); + + foreach ($traceData as $singleTraceArr) { + if (!stristr($singleTraceArr['file'], 'Framework' . DIRECTORY_SEPARATOR . 'Assert.php')) { + $testCaseTraceData = $singleTraceArr; + break; + } + } + + return $testCaseTraceData; + } + + /** + * A test has been marked as incomplete, i.e. as not implemented yet. + * + * @param PHPUnit_Framework_Test $test the test that has been marked as incomplete + * @param Exception $e an exception about the incomplete test (?) + * @param float $time ? + * + * @return void + */ + public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) { + $this->output( + '' . + '' . + '! Incomplete test ' . $test->getName() . + ' in file ' . $e->getFile() . ' line ' . $e->getLine() . ':
    ' . + $e->getMessage() . '
    ' + ); + } + + /** + * A test has been marked as skipped. + * + * @param PHPUnit_Framework_Test $test the test that has been marked as skipped + * @param Exception $e an exception about the skipped test (?) + * @param float $time ? + * + * @return void + */ + public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) { + $this->output( + '' . + '' . + '! Skipped test ' . $test->getName() . ' in file ' . + $e->getFile() . ' line ' . $e->getLine() . ':
    ' . + $e->getMessage() . '
    ' + ); + } + + /** + * A test suite/case has started. + * + * Note: This function also gets called when a test that uses a data provider + * has started. + * + * @param PHPUnit_Framework_TestSuite $suite the test suite/case that has started + * + * @return void + */ + public function startTestSuite(PHPUnit_Framework_TestSuite $suite) { + $this->setTestSuiteName($suite->getName()); + if (($suite instanceof PHPUnit_Framework_TestSuite_DataProvider) + || ($suite->getName() === 'tx_phpunit_basetestsuite') + ) { + return; + } + + $this->output( + '

    Testsuite: ' . $this->prettifyTestClass($suite->getName()) . '

    ' . + '' + ); + } + + /** + * Sets the name of the test suite that is used for creating the re-run + * link. + * + * @param string $name the name of the test suite, must not be empty + * + * @return void + */ + public function setTestSuiteName($name) { + $this->currentTestCaseName = $name; + } + + /** + * A test suite/case has ended. + * + * Note: This function also gets called when a test that uses a data provider + * has ended. + * + * @param PHPUnit_Framework_TestSuite $suite the test suite/case that has ended + * + * @return void + */ + public function endTestSuite(PHPUnit_Framework_TestSuite $suite) { + } + + /** + * A test has started. + * + * @param PHPUnit_Framework_Test $test the test that has started + * + * @return void + */ + public function startTest(PHPUnit_Framework_Test $test) { + // A single test has to take less than this or else PHP will time out. + $this->setTimeLimit(30); + + $this->output( + '
    ' . + '

    ' . $this->createReRunLink($test) . $this->prettifyTestMethod($test->getName()) . '

    ' + ); + $this->memoryUsageStartOfTest = memory_get_usage(); + } + + /** + * Sets the PHP execution time limit. + * + * @param integer $limit the PHP execution time limit in seconds, must be >= 0 + * + * @return void + */ + protected function setTimeLimit($limit) { + set_time_limit($limit); + } + + /** + * A test has ended. + * + * @param PHPUnit_Framework_Test $test the test that has ended + * @param float $time ? + * + * @return void + */ + public function endTest(PHPUnit_Framework_Test $test, $time) { + $this->memoryUsageEndOfTest = memory_get_usage(); + + if ($test instanceof PHPUnit_Framework_TestCase) { + // Tests with the same name are a sign of data provider usage. + $testNameParts = explode(' ', $test->getName()); + $testName = get_class($test) . ':' . $testNameParts[0]; + if ($testName !== $this->previousTestName) { + $this->currentDataProviderNumber = 0; + $this->currentTestNumber++; + $this->previousTestName = $testName; + } else { + $this->currentDataProviderNumber++; + $this->totalNumberOfDetectedDataProviderTests++; + } + } + + if (($this->totalNumberOfTests - $this->totalNumberOfDetectedDataProviderTests) > 0) { + $percentDone = intval(($this->currentTestNumber / ($this->totalNumberOfTests - $this->totalNumberOfDetectedDataProviderTests)) * 100); + } else { + $percentDone = 0; + } + $leakedMemory = ($this->memoryUsageEndOfTest - $this->memoryUsageStartOfTest); + $this->totalLeakedMemory += $leakedMemory; + + if ($test instanceof PHPUnit_Framework_TestCase) { + $this->testAssertions += $test->getNumAssertions(); + } + + $output = '
    '; + if ($this->enableShowMemoryAndTime === TRUE) { + $output .= 'Memory leak: ' . + t3lib_div::formatSize($leakedMemory) . 'B ' . + 'Time: ' . sprintf('%.4f', $time) . + ' sec.
    '; + } + $output .= '
    ' . + '' . + ''; + + $this->output($output); + $this->flushOutputBuffer(); + } + + /** + * Creates the link (including an icon) to re-run the given single test. + * + * @param PHPUnit_Framework_TestSuite $test + * the test for which to create the re-run link + * + * @return string the link to re-run the given test, will not be empty + */ + protected function createReRunLink(PHPUnit_Framework_TestCase $test) { + $iconImageTag = ''; + return '' . $iconImageTag . ' '; + } + + /** + * Creates the URL to re-run the given test. + * + * @param PHPUnit_Framework_TestSuite $test + * the test for which to create the re-run URL + * + * @return string the htmlspecialchared URL to re-run the given test, will not be empty + */ + protected function createReRunUrl(PHPUnit_Framework_TestCase $test) { + $options = array( + 'M=tools_txphpunitbeM1', + 'command=runsingletest', + 'testCaseFile=' . $this->getTestCaseName(), + 'testname=' . $this->createTestId($test), + ); + + return htmlspecialchars('mod.php?' . implode('&', $options)); + } + + /** + * Creates a unique string ID for $test that can be used in URLs. + * + * @param PHPUnit_Framework_TestCase $test a test for which to create an ID + * + * @return string a unique ID for $test, not htmlspecialchared or URL-encoded yet + */ + protected function createTestId(PHPUnit_Framework_TestCase $test) { + $testNameParts = explode(' ', $test->getName()); + + // This is quite a hack. + // @see http://forge.typo3.org/issues/11735 + if (strpos($this->currentTestCaseName, '::') !== FALSE) { + $result = $testNameParts[0] . '(' . $this->getTestCaseName() . ')'; + } else { + $result = $this->getTestCaseName() . '::' . $testNameParts[0]; + } + + return $result; + } + + /** + * Gets the current test case name. + * + * @return string the current test case name, will not be empty + */ + protected function getTestCaseName() { + $testCaseNameParts = explode('::', $this->currentTestCaseName); + + return $testCaseNameParts[0]; + } + + /** + * Prettifies the name of a test method. + * + * This method will return $testName unchanged if human-readable names + * are disabled. + * + * @param string $testName a camel-case test name, must not be empty + * + * @return string the prettified test name, will not be empty + */ + protected function prettifyTestMethod($testName) { + if (!$this->useHumanReadableTextFormat) { + return $testName; + } + + // this is required because the "setPrefix" work not very well with the prefix "test_" + $testNameWithoutSuffix = preg_replace('/^test_/i', '', $testName); + + $this->namePrettifier->setPrefix('test'); + $this->namePrettifier->setSuffix(NULL); + + return $this->namePrettifier->prettifyTestMethod($testNameWithoutSuffix); + } + + /** + * Prettifies the name of a test class. + * + * This method will return $testClass unchanged if human-readable names + * are disabled. + * + * @param string $testClassName a camel-case test class name, must not be empty + * + * @return string the prettified test class name, will not be empty + */ + protected function prettifyTestClass($testClassName) { + if (!$this->useHumanReadableTextFormat) { + return $testClassName; + } + + $testClassNameWithoutPrefixOrSuffix = preg_replace('/(tx_|Tx_)?(.+)(Test|_testcase)$/', '\2', $testClassName); + $testClassNameWithoutUnderScores = str_replace('_', ' ', $testClassNameWithoutPrefixOrSuffix); + + $this->namePrettifier->setPrefix(NULL); + $this->namePrettifier->setSuffix(NULL); + + return $this->namePrettifier->prettifyTestClass($testClassNameWithoutUnderScores); + } + + /** + * Retrieves the collected amount of processed assertions. + * + * @return integer the number of executed assertions, will be >= 0 + */ + public function assertionCount() { + return $this->testAssertions; + } + + /** + * Echoes $output. + * + * @param string $output a string to echo, may also be empty + * + * @return void + */ + protected function output($output) { + echo($output); + } + + /** + * Flushes the output buffer. + * + * @return void + */ + protected function flushOutputBuffer() { + flush(); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/BackEnd/conf.php b/typo3conf/ext/phpunit/Classes/BackEnd/conf.php new file mode 100644 index 0000000..49b34cf --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/BackEnd/conf.php @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/BackEnd/index.php b/typo3conf/ext/phpunit/Classes/BackEnd/index.php new file mode 100644 index 0000000..58535a0 --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/BackEnd/index.php @@ -0,0 +1,48 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/** + * Module "PHPUnit". + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Kasper Ligaard + */ + +if (!defined('TYPO3_MODE')) { + die('Access denied.'); +} + +if (!defined('PATH_tslib')) { + define('PATH_tslib', t3lib_extMgm::extPath('cms') . 'tslib/'); +} + +require_once('PHPUnit/Autoload.php'); + +$GLOBALS['LANG']->includeLLFile('EXT:phpunit/Resources/Private/Language/locallang_backend.xml'); + +$module = t3lib_div::makeInstance('Tx_Phpunit_BackEnd_Module'); +$module->main(); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/Cli/TestRunner.php b/typo3conf/ext/phpunit/Classes/Cli/TestRunner.php new file mode 100644 index 0000000..240f35c --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/Cli/TestRunner.php @@ -0,0 +1,82 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +if (!defined('TYPO3_cliMode')) { + die('Access denied: CLI only.'); +} + +require_once('PHPUnit/Autoload.php'); + +/** + * This class runs PHPUnit in CLI mode. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Michael Klapper + */ +class Tx_Phpunit_Cli_TestRunner extends t3lib_cli { + /** + * definition of the extension name + * + * @var string + */ + protected $extKey = 'phpunit_cli'; + + /** + * The constructor. + */ + public function __construct() { + setlocale(LC_NUMERIC, 'C'); + + parent::__construct(); + + $this->cli_options = array_merge($this->cli_options, array()); + $this->cli_help = array_merge( + $this->cli_help, + array( + 'name' => 'tx_phpunit_cli_phpunit', + 'synopsis' => $this->extKey . ' command [clientId] ###OPTIONS###', + 'description' => 'This script can update a list of several caches (per CLI-call can one cache be updated)', + 'examples' => 'typo3/cli_dispatch.phpsh', + 'author' => '(c) 2009-2011 AOE media GmbH ', + ) + ); + } + + /** + * Detects the action and calls the related methods. + * + * @return void + */ + public function run() { + define('PHPUnit_MAIN_METHOD', 'PHPUnit_TextUI_Command::main'); + PHPUnit_TextUI_Command::main(); + } +} + +$phpUnit = t3lib_div::makeInstance('Tx_Phpunit_Cli_TestRunner'); +/* @var $phpUnit Tx_Phpunit_Cli_TestRunner */ +$phpUnit->run(); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/Database/TestCase.php b/typo3conf/ext/phpunit/Classes/Database/TestCase.php new file mode 100644 index 0000000..4f86be0 --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/Database/TestCase.php @@ -0,0 +1,399 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/** + * Database testcase base class. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Michael Klapper + * @author Oliver Klee + */ +abstract class Tx_Phpunit_Database_TestCase extends Tx_Phpunit_TestCase { + /** + * name of a test database + * + * @var string + */ + protected $testDatabase = ''; + + /** + * Constructs a test case with the given name. + * + * @param string $name the name of a testcase + * @param array $data ? + * @param string $dataName ? + */ + public function __construct($name = NULL, array $data = array(), $dataName = '') { + parent::__construct($name, $data, $dataName); + $this->testDatabase = strtolower(TYPO3_db . '_test'); + } + + /** + * Selects the TYPO3 database (again). + * + * If you have selected any non-TYPO3 in your unit tests, you need to + * call this function in tearDown() in order to avoid problems with the + * following unit tests and the TYPO3 back-end. + * + * @return void + */ + protected function switchToTypo3Database() { + $GLOBALS['TYPO3_DB']->sql_select_db(TYPO3_db); + } + + /** + * Accesses the TYPO3 database instance and uses it to fetch the list of + * abailable databases. Then this function creates a test database (if none + * has been set up yet). + * + * @return boolean + * TRUE if the database has been created successfully (or if there + * already is a test database), FALSE otherwise + */ + protected function createDatabase() { + $success = TRUE; + + $this->dropDatabase(); + $db = $GLOBALS['TYPO3_DB']; + $databaseNames = $db->admin_get_dbs(); + + if (!in_array($this->testDatabase, $databaseNames)) { + if ($db->admin_query('CREATE DATABASE ' . $this->testDatabase) === FALSE) { + $success = FALSE; + } + } + + return $success; + } + + /** + * Drops all tables in the test database. + * + * @return void + */ + protected function cleanDatabase() { + $db = $GLOBALS['TYPO3_DB']; + if (!in_array($this->testDatabase, $db->admin_get_dbs())) { + return; + } + + $db->sql_select_db($this->testDatabase); + + $tables = $this->getDatabaseTables(); + foreach ($tables as $tableName) { + $db->admin_query('DROP TABLE ' . $tableName); + } + } + + /** + * Drops the test database. + * + * @return boolean + * TRUE if the database has been dropped successfully, FALSE otherwise + */ + protected function dropDatabase() { + $db = $GLOBALS['TYPO3_DB']; + if (!in_array($this->testDatabase, $db->admin_get_dbs())) { + return TRUE; + } + + $db->sql_select_db($this->testDatabase); + + return ($db->admin_query('DROP DATABASE ' . $this->testDatabase) !== FALSE); + } + + /** + * Sets the TYPO3 database instance to a test database. + * + * Note: This function does not back up the currenty TYPO3 database instance. + * + * @param string $databaseName + * the name of the test database to use; if none is provided, the + * name of the current TYPO3 database plus a suffix "_test" is used + * + * @return t3lib_DB the test database + */ + protected function useTestDatabase($databaseName = NULL) { + $db = $GLOBALS['TYPO3_DB']; + + if ($db->sql_select_db($databaseName ? $databaseName : $this->testDatabase) !== TRUE) { + $this->markTestSkipped('This test is skipped because the test database is not available.'); + } + + return $db; + } + + /** + * Imports the ext_tables.sql statements from the given extensions. + * + * @param array $extensions + * keys of the extensions to import, may be empty + * @param boolean $importDependencies + * whether to import dependency extensions on which the given extensions + * depend as well + * @param array &$skipDependencies + * keys of the extensions to skip, may be empty, will be modified + * + * @return void + */ + protected function importExtensions( + array $extensions, $importDependencies = FALSE, array &$skipDependencies = array() + ) { + $this->useTestDatabase(); + + foreach ($extensions as $extensionName) { + if (!t3lib_extMgm::isLoaded($extensionName)) { + $this->markTestSkipped( + 'This test is skipped because the extension ' . $extensionName . + ' which was marked for import is not loaded on your system!' + ); + } elseif (in_array($extensionName, $skipDependencies)) { + continue; + } + + $skipDependencies = array_merge($skipDependencies, array($extensionName)); + + if ($importDependencies) { + $dependencies = $this->findDependencies($extensionName); + if (is_array($dependencies)) { + $this->importExtensions($dependencies, TRUE, $skipDependencies); + } + } + + $this->importExtension($extensionName); + } + + // TODO: The hook should be replaced by real clean up and rebuild the whole + // "TYPO3_CONF_VARS" in order to have a clean testing environment. + // hook to load additional files + if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['importExtensions_additionalDatabaseFiles'])) { + foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['importExtensions_additionalDatabaseFiles'] as $file) { + $sqlFilename = t3lib_div::getFileAbsFileName($file); + $fileContent = t3lib_div::getUrl($sqlFilename); + + $this->importDatabaseDefinitions($fileContent); + } + } + } + + /** + * Gets the names of all tables in the database with the given name. + * + * @param string $databaseName + * the name of the database from which to retrieve the table names, + * if none is provided, the name of the current TYPO3 database plus a + * suffix "_test" is used + * + * @return array + * the names of all tables in the database $databaseName, might be empty + */ + protected function getDatabaseTables($databaseName = NULL) { + $db = $this->useTestDatabase($databaseName); + + $tableNames = array(); + + $res = $db->sql_query('show tables'); + while ($row = $db->sql_fetch_row($res)) { + $tableNames[] = $row[0]; + } + + return $tableNames; + } + + /** + * Imports the ext_tables.sql file of the extension with the given name + * into the test database. + * + * @param string $extensionName + * the name of the installed extension to import, must not be empty + * + * @return void + */ + private function importExtension($extensionName) { + $sqlFilename = t3lib_div::getFileAbsFileName(t3lib_extMgm::extPath($extensionName) . 'ext_tables.sql'); + $fileContent = t3lib_div::getUrl($sqlFilename); + + $this->importDatabaseDefinitions($fileContent); + } + + /** + * Imports the data from the stddb tables.sql file. + * + * Example/intended usage: + * + *
    +	 * public function setUp() {
    +	 *   $this->createDatabase();
    +	 *   $db = $this->useTestDatabase();
    +	 *   $this->importStdDB();
    +	 *   $this->importExtensions(array('cms', 'static_info_tables', 'templavoila'));
    +	 * }
    +	 * 
    + * + * @return void + */ + protected function importStdDb() { + $sqlFilename = t3lib_div::getFileAbsFileName(PATH_t3lib . 'stddb/tables.sql'); + $fileContent = t3lib_div::getUrl($sqlFilename); + + $this->importDatabaseDefinitions($fileContent); + } + + /** + * Imports the SQL definitions from a (ext_)tables.sql file. + * + * @param string $definitionContent + * the SQL to import, must not be empty + * + * @return void + */ + private function importDatabaseDefinitions($definitionContent) { + $install = t3lib_div::makeInstance('t3lib_install'); + $fieldDefinitionsFile = $install->getFieldDefinitions_fileContent($definitionContent); + if (empty($fieldDefinitionsFile)) { + return; + } + + // find statements to query + $fieldDefinitionsDatabase = $install->getFieldDefinitions_fileContent($this->getTestDatabaseSchema()); + $diff = $install->getDatabaseExtra($fieldDefinitionsFile, $fieldDefinitionsDatabase); + $updateStatements = $install->getUpdateSuggestions($diff); + + $updateTypes = array('add', 'change', 'create_table'); + + foreach ($updateTypes as $updateType) { + if (array_key_exists($updateType, $updateStatements)) { + foreach ((array) $updateStatements[$updateType] as $string) { + $GLOBALS['TYPO3_DB']->admin_query($string); + } + } + } + } + + /** + * Returns an SQL dump of the test database. + * + * @return string SQL dump of the test databse, might be empty + */ + private function getTestDatabaseSchema() { + $db = $this->useTestDatabase(); + $tables = $this->getDatabaseTables(); + + // finds create statement for every table + $linefeed = chr(10); + + $schema = ''; + $db->sql_query('SET SQL_QUOTE_SHOW_CREATE = 0'); + foreach ($tables as $tableName) { + $res = $db->sql_query('show create table ' . $tableName); + $row = $db->sql_fetch_row($res); + + // modifies statement to be accepted by TYPO3 + $createStatement = preg_replace('/ENGINE.*$/', '', $row[1]); + $createStatement = preg_replace( + '/(CREATE TABLE.*\()/', $linefeed . '\\1' . $linefeed, $createStatement + ); + $createStatement = preg_replace('/\) $/', $linefeed . ')', $createStatement); + + $schema .= $createStatement . ';'; + } + + return $schema; + } + + /** + * Finds all direct dependencies of the extension with the key $extKey. + * + * @param string $extKey the key of an installed extension, must not be empty + * + * @return array|NULL + * the keys of all extensions on which the given extension depends, + * will be NULL if the dependencies could not be determined + */ + private function findDependencies($extKey) { + $path = t3lib_div::getFileAbsFileName(t3lib_extMgm::extPath($extKey) . 'ext_emconf.php'); + $_EXTKEY = $extKey; + include($path); + + $dependencies = $EM_CONF[$_EXTKEY]['constraints']['depends']; + if (!is_array($dependencies)) { + return NULL; + } + + // remove php and typo3 extension (not real extensions) + if (isset($dependencies['php'])) { + unset($dependencies['php']); + } + if (isset($dependencies['typo3'])) { + unset($dependencies['typo3']); + } + + return array_keys($dependencies); + } + + /** + * Imports a data set into the test database, + * + * @param string $path + * the absolute path to the XML file containing the data set to load + * + * @return void + */ + protected function importDataSet($path) { + $xml = simplexml_load_file($path); + $db = $this->useTestDatabase(); + $foreignKeys = array(); + + foreach ($xml->children() as $table) { + $insertArray = array(); + + foreach ($table->children() as $column) { + $columnName = $column->getName(); + $columnValue = NULL; + + if (isset($column['ref'])) { + list($tableName, $elementId) = explode('#', $column['ref']); + $columnValue = $foreignKeys[$tableName][$elementId]; + } elseif (isset($column['is-NULL']) && ($column['is-NULL'] === 'yes')) { + $columnValue = NULL; + } else { + $columnValue = $table->$columnName; + } + + $insertArray[$columnName] = $columnValue; + } + + $tableName = $table->getName(); + $db->exec_INSERTquery($tableName, $insertArray); + + if (isset($table['id'])) { + $elementId = (string) $table['id']; + $foreignKeys[$tableName][$elementId] = $db->sql_insert_id(); + } + } + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/Exception/Database.php b/typo3conf/ext/phpunit/Classes/Exception/Database.php new file mode 100644 index 0000000..554ce00 --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/Exception/Database.php @@ -0,0 +1,51 @@ + +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +/** + * This class represents an exception that should be thrown when a database + * error has occured. + * + * The exception automatically will use an error message, the error message + * from the DB and the last query. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Oliver Klee + */ +class Tx_Phpunit_Exception_Database extends t3lib_exception { + /** + * The constructor. + */ + public function __construct() { + $message = 'There was an error with the database query.' . LF . $GLOBALS['TYPO3_DB']->sql_error(); + + if ($GLOBALS['TYPO3_DB']->store_lastBuiltQuery || $GLOBALS['TYPO3_DB']->debugOutput) { + $message .= LF . 'The last built query:' . LF . $GLOBALS['TYPO3_DB']->debug_lastBuiltQuery; + } + + parent::__construct($message); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/Exception/EmptyQueryResult.php b/typo3conf/ext/phpunit/Classes/Exception/EmptyQueryResult.php new file mode 100644 index 0000000..19ab3a1 --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/Exception/EmptyQueryResult.php @@ -0,0 +1,50 @@ + +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +/** + * This class represents an exception that should be thrown when a database + * query has an empty result, but shouldn't have. + * + * The exception automatically will use an error message and the last query. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Oliver Klee + */ +class Tx_Phpunit_Exception_EmptyQueryResult extends t3lib_exception { + /** + * The constructor. + */ + public function __construct() { + $message = 'The database query returned an empty result, but should have returned a non-empty result.'; + + if ($GLOBALS['TYPO3_DB']->store_lastBuiltQuery || $GLOBALS['TYPO3_DB']->debugOutput) { + $message .= LF . 'The last built query:' . LF . $GLOBALS['TYPO3_DB']->debug_lastBuiltQuery; + } + + parent::__construct($message); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/Exception/NoTestsDirectory.php b/typo3conf/ext/phpunit/Classes/Exception/NoTestsDirectory.php new file mode 100644 index 0000000..2b4c289 --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/Exception/NoTestsDirectory.php @@ -0,0 +1,36 @@ + +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +/** + * This class represents an exception indicating that there no tests directory + * has been found (for an extension or the TYPO3 Core, + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Oliver Klee + */ +class Tx_Phpunit_Exception_NoTestsDirectory extends t3lib_exception { +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/Framework.php b/typo3conf/ext/phpunit/Classes/Framework.php new file mode 100644 index 0000000..07144a1 --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/Framework.php @@ -0,0 +1,1911 @@ + + * @author Oliver Klee + * @author Saskia Metzler + * @author Niels Pardon + */ +class Tx_Phpunit_Framework { + /** + * prefix of the extension for which this instance of the testing framework + * was instantiated (e.g. "tx_seminars") + * + * @var string + */ + protected $tablePrefix = ''; + + /** + * prefixes of additional extensions to which this instance of the testing + * framework has access (e.g. "tx_seminars") + * + * @var array + */ + protected $additionalTablePrefixes = array(); + + /** + * all own DB table names to which this instance of the testing framework + * has access + * + * @var array + */ + protected $ownAllowedTables = array(); + + /** + * all additional DB table names to which this instance of the testing + * framework has access + * + * @var array + */ + protected $additionalAllowedTables = array(); + + /** + * all sytem table names to which this instance of the testing framework + * has access + * + * @var array + */ + protected $allowedSystemTables = array( + 'be_users', 'fe_groups', 'fe_users', 'pages', 'sys_template', + 'tt_content', 'be_groups' + ); + + /** + * all "dirty" non-system tables (i.e. all tables that were used for testing + * and need to be cleaned up) + * + * @var array + */ + protected $dirtyTables = array(); + + /** + * all "dirty" system tables (i.e. all tables that were used for testing and + * need to be cleaned up) + * + * @var array + */ + protected $dirtySystemTables = array(); + + /** + * sorting values of all relation tables + * + * @var array + */ + protected $relationSorting = array(); + + /** + * the number of unusable UIDs after the maximum UID in a table before the + * auto increment value will be reset by resetAutoIncrementLazily + * + * @var integer + */ + protected $resetAutoIncrementThreshold = 100; + + /** + * the names of the created dummy files relative to the upload folder of the + * extension to test + * + * @var array + */ + protected $dummyFiles = array(); + + /** + * the names of the created dummy folders relative to theupload folder of + * the extension to test + * + * @var array + */ + protected $dummyFolders = array(); + + /** + * the absolute path to the upload folder of the extension to test + * + * @var string + */ + protected $uploadFolderPath = ''; + + /** + * an instance used for retrieving a unique file name + * + * @var t3lib_basicFileFunctions + */ + protected static $fileNameProcessor = NULL; + + /** + * whether a fake front end has been created + * + * @var boolean + */ + protected $hasFakeFrontEnd = FALSE; + + /** + * hook objects for this class + * + * @var array + */ + static protected $hooks = array(); + + /** + * whether the hooks in self::hooks have been retrieved + * + * @var boolean + */ + static protected $hooksHaveBeenRetrieved = FALSE; + + /** + * The constructor for this class. + * + * This testing framework can be instantiated for one extension at a time. + * Example: In your testcase, you'll have something similar to this line of code: + * $this->fixture = new Tx_Phpunit_Framework('tx_seminars'); + * The parameter you provide is the prefix of the table names of that particular + * extension. Like this, we ensure that the testing framework creates and + * deletes records only on table with this prefix. + * + * If you need dummy records on tables of multiple extensions, you'll have to + * instantiate the testing frame work multiple times (once per extension). + * + * @param string $tablePrefix + * the table name prefix of the extension for which this instance of + * the testing framework should be used + * @param array $additionalTablePrefixes + * the additional table name prefixes of the extensions for which + * this instance of the testing framework should be used, may be empty + */ + public function __construct($tablePrefix, array $additionalTablePrefixes = array()) { + $this->tablePrefix = $tablePrefix; + $this->additionalTablePrefixes = $additionalTablePrefixes; + $this->createListOfOwnAllowedTables(); + $this->createListOfAdditionalAllowedTables(); + $this->uploadFolderPath = PATH_site . 'uploads/' . $this->tablePrefix . '/'; + } + + /** + * Creates a new dummy record for unit tests. + * + * If no record data for the new array is given, an empty record will be + * created. It will only contain a valid UID and the "is_dummy_record" flag + * will be set to 1. + * + * Should there be any problem creating the record (wrong table name or a + * problem with the database), 0 instead of a valid UID will be returned. + * + * @param string $tableName + * the name of the table on which the record should be created, must + * not be empty + * @param array $recordData + * associative array that contains the data to save in the new + * record, may be empty, but must not contain the key "uid" + * + * @return integer the UID of the new record, will be > 0 + */ + public function createRecord($tableName, array $recordData = array()) { + if (!$this->isNoneSystemTableNameAllowed($tableName)) { + throw new InvalidArgumentException('The table name "' . $tableName . '" is not allowed.'); + } + if (isset($recordData['uid'])) { + throw new InvalidArgumentException('The column "uid" must not be set in $recordData.'); + } + + return $this->createRecordWithoutTableNameChecks($tableName, $recordData); + } + + /** + * Creates a new dummy record for unit tests without checks for the table + * name. + * + * If no record data for the new array is given, an empty record will be + * created. It will only contain a valid UID and the "is_dummy_record" flag + * will be set to 1. + * + * Should there be any problem creating the record (wrong table name or a + * problem with the database), 0 instead of a valid UID will be returned. + * + * @param string $tableName + * the name of the table on which the record should be created, must + * not be empty + * @param array $recordData + * associative array that contains the data to save in the new + * record, may be empty, but must not contain the key "uid" + * + * @return integer the UID of the new record, will be > 0 + */ + protected function createRecordWithoutTableNameChecks($tableName, array $recordData) { + $dummyColumnName = $this->getDummyColumnName($tableName); + $recordData[$dummyColumnName] = 1; + + $uid = Tx_Phpunit_Service_Database::insert($tableName, $recordData); + $this->markTableAsDirty($tableName); + + return $uid; + } + + /** + * Creates a front-end page on the page with the UID given by the first + * parameter $parentId. + * + * @param integer $parentId + * UID of the page on which the page should be created + * @param array $recordData + * associative array that contains the data to save in the new page, + * may be empty, but must not contain the keys "uid", "pid" or "doktype" + * + * @return integer the UID of the new page, will be > 0 + */ + public function createFrontEndPage($parentId = 0, array $recordData = array()) { + return $this->createGeneralPageRecord(1, $parentId, $recordData); + } + + /** + * Creates a system folder on the page with the UID given by the first + * parameter $parentId. + * + * @param integer $parentId + * UID of the page on which the system folder should be created + * @param array $recordData + * associative array that contains the data to save in the new page, + * may be empty, but must not contain the keys "uid", "pid" or "doktype" + * + * @return integer the UID of the new system folder, will be > 0 + */ + public function createSystemFolder($parentId = 0, array $recordData = array()) { + return $this->createGeneralPageRecord(254, $parentId, $recordData); + } + + /** + * Creates a page record with the document type given by the first parameter + * $documentType. + * + * The record will be created on the page with the UID given by the second + * parameter $parentId. + * + * @param integer $documentType + * document type of the record to create, must be > 0 + * @param integer $parentId + * UID of the page on which the record should be created + * @param array $recordData + * associative array that contains the data to save in the record, + * may be empty, but must not contain the keys "uid", "pid" or "doktype" + * + * @return integer the UID of the new record, will be > 0 + */ + protected function createGeneralPageRecord($documentType, $parentId, array $recordData) { + if (isset($recordData['uid'])) { + throw new InvalidArgumentException('The column "uid" must not be set in $recordData.'); + } + if (isset($recordData['pid'])) { + throw new InvalidArgumentException('The column "pid" must not be set in $recordData.'); + } + if (isset($recordData['doktype'])) { + throw new InvalidArgumentException('The column "doktype" must not be set in $recordData.'); + } + + $completeRecordData = $recordData; + $completeRecordData['pid'] = $parentId; + $completeRecordData['doktype'] = $documentType; + + return $this->createRecordWithoutTableNameChecks('pages', $completeRecordData); + } + + /** + * Creates a FE content element on the page with the UID given by the first + * parameter $pageId. + * + * Created content elements are text elements by default, but the content + * element's type can be overwritten by setting the key 'CType' in the + * parameter $recordData. + * + * @param integer $pageId + * UID of the page on which the content element should be created + * @param array $recordData + * associative array that contains the data to save in the content + * element, may be empty, but must not contain the keys "uid" or "pid" + * + * @return integer the UID of the new content element, will be > 0 + */ + public function createContentElement($pageId = 0, array $recordData = array()) { + if (isset($recordData['uid'])) { + throw new InvalidArgumentException('The column "uid" must not be set in $recordData.'); + } + if (isset($recordData['pid'])) { + throw new InvalidArgumentException('The column "pid" must not be set in $recordData.'); + } + + $completeRecordData = $recordData; + $completeRecordData['pid'] = $pageId; + if (!isset($completeRecordData['CType'])) { + $completeRecordData['CType'] = 'text'; + } + + return $this->createRecordWithoutTableNameChecks('tt_content', $completeRecordData); + } + + /** + * Creates a template on the page with the UID given by the first parameter + * $pageId. + * + * @param integer $pageId + * UID of the page on which the template should be created, must be > 0 + * @param array $recordData + * associative array that contains the data to save in the new + * template, may be empty, but must not contain the keys "uid" or "pid" + * + * @return integer the UID of the new template, will be > 0 + */ + public function createTemplate($pageId, array $recordData = array()) { + if ($pageId <= 0) { + throw new InvalidArgumentException('$pageId must be > 0.'); + } + if (isset($recordData['uid'])) { + throw new InvalidArgumentException('The column "uid" must not be set in $recordData.'); + } + if (isset($recordData['pid'])) { + throw new InvalidArgumentException('The column "pid" must not be set in $recordData.'); + } + + $completeRecordData = $recordData; + $completeRecordData['pid'] = $pageId; + + return $this->createRecordWithoutTableNameChecks('sys_template', $completeRecordData); + } + + /** + * Creates a FE user group. + * + * @param array $recordData + * associative array that contains the data to save in the new user + * group record, may be empty, but must not contain the key "uid" + * + * @return integer the UID of the new user group, will be > 0 + */ + public function createFrontEndUserGroup(array $recordData = array()) { + if (isset($recordData['uid'])) { + throw new InvalidArgumentException('The column "uid" must not be set in $recordData.'); + } + + return $this->createRecordWithoutTableNameChecks('fe_groups', $recordData); + } + + /** + * Creates a FE user record. + * + * @param string $frontEndUserGroups + * comma-separated list of UIDs of the user groups to which the new + * user belongs, each must be > 0, may contain spaces, if empty a new + * FE user group will be created + * @param array $recordData + * associative array that contains the data to save in the new user + * record, may be empty, but must not contain the keys "uid" or + * "usergroup" + * + * @return integer the UID of the new FE user, will be > 0 + */ + public function createFrontEndUser( + $frontEndUserGroups = '', array $recordData = array() + ) { + $frontEndUserGroupsWithoutSpaces = str_replace(' ', '', $frontEndUserGroups); + + if ($frontEndUserGroupsWithoutSpaces === '') { + $frontEndUserGroupsWithoutSpaces = $this->createFrontEndUserGroup(); + } + if (!preg_match('/^(?:[1-9]+[0-9]*,?)+$/', $frontEndUserGroupsWithoutSpaces) + ) { + throw new InvalidArgumentException( + '$frontEndUserGroups must contain a comma-separated list of UIDs. Each UID must be > 0.' + ); + } + if (isset($recordData['uid'])) { + throw new InvalidArgumentException('The column "uid" must not be set in $recordData.'); + } + if (isset($recordData['usergroup'])) { + throw new InvalidArgumentException('The column "usergroup" must not be set in $recordData.'); + } + + $completeRecordData = $recordData; + $completeRecordData['usergroup'] = $frontEndUserGroupsWithoutSpaces; + + return $this->createRecordWithoutTableNameChecks('fe_users', $completeRecordData); + } + + /** + * Creates and logs in an FE user. + * + * @param string $frontEndUserGroups + * comma-separated list of UIDs of the user groups to which the new + * user belongs, each must be > 0, may contain spaces; if empty a new + * front-end user group is created + * @param array $recordData + * associative array that contains the data to save in the new user + * record, may be empty, but must not contain the keys "uid" or + * "usergroup" + * + * @return integer the UID of the new FE user, will be > 0 + */ + public function createAndLoginFrontEndUser($frontEndUserGroups = '', array $recordData = array()) { + $frontEndUserUid = $this->createFrontEndUser($frontEndUserGroups, $recordData); + + $this->loginFrontEndUser($frontEndUserUid); + + return $frontEndUserUid; + } + + /** + * Creates a BE user record. + * + * @param array $recordData + * associative array that contains the data to save in the new user + * record, may be empty, but must not contain the key "uid" + * + * @return integer the UID of the new BE user, will be > 0 + */ + public function createBackEndUser(array $recordData = array()) { + if (isset($recordData['uid'])) { + throw new InvalidArgumentException('The column "uid" must not be set in $recordData.'); + } + + return $this->createRecordWithoutTableNameChecks('be_users', $recordData); + } + + /** + * Creates a BE user group. + * + * @param array $recordData + * associative array that contains the data to save in the new user + * group record, may be empty, but must not contain the key "uid" + * + * @return integer the UID of the new user group, will be > 0 + */ + public function createBackEndUserGroup(array $recordData = array()) { + if (isset($recordData['uid'])) { + throw new InvalidArgumentException('The column "uid" must not be set in $recordData.'); + } + + return $this->createRecordWithoutTableNameChecks('be_groups', $recordData); + } + + /** + * Changes an existing dummy record and stores the new data for this + * record. Only fields that get new values in $recordData will be changed, + * everything else will stay untouched. + * + * The array with the new recordData must contain at least one entry, but + * must not contain a new UID for the record. If you need to change the UID, + * you have to create a new record! + * + * @param string $tableName + * the name of the table, must not be empty + * @param integer $uid + * the UID of the record to change, must not be empty + * @param array $recordData + * associative array containing key => value pairs for those fields + * of the record that need to be changed, must not be empty + * + * @return void + */ + public function changeRecord($tableName, $uid, array $recordData) { + $dummyColumnName = $this->getDummyColumnName($tableName); + + if (!$this->isTableNameAllowed($tableName)) { + throw new InvalidArgumentException( + 'The table "' . $tableName . '" is not on the lists with allowed tables.' + ); + } + if ($uid === 0) { + throw new InvalidArgumentException('The parameter $uid must not be zero.'); + } + if (empty($recordData)) { + throw new InvalidArgumentException('The array with the new record data must not be empty.'); + } + if (isset($recordData['uid'])) { + throw new InvalidArgumentException( + 'The parameter $recordData must not contain changes to the UID of a record.' + ); + } + if (isset($recordData[$dummyColumnName])) { + throw new InvalidArgumentException( + 'The parameter $recordData must not contain changes to the ' . + 'field "' . $dummyColumnName . '". It is impossible to ' . + 'convert a dummy record into a regular record.' + ); + } + if (!$this->countRecords($tableName, 'uid='.$uid)) { + throw new Tx_Phpunit_Exception_Database( + 'There is no record with UID ' . $uid . ' on table "' . $tableName . '".' + ); + } + + Tx_Phpunit_Service_Database::update( + $tableName, + 'uid = ' . $uid . ' AND ' . $dummyColumnName . ' = 1', + $recordData + ); + } + + /** + * Deletes a dummy record from the database. + * + * Important: Only dummy records from non-system tables can be deleted with + * this method. Should there for any reason exist a real record with that + * UID, it won't be deleted. + * + * @param string $tableName + * name of the table from which the record should be deleted, must + * not be empty + * @param integer $uid + * UID of the record to delete, must be > 0 + * + * @return void + */ + public function deleteRecord($tableName, $uid) { + if (!$this->isNoneSystemTableNameAllowed($tableName)) { + throw new InvalidArgumentException('The table name "' . $tableName . '" is not allowed.'); + } + + Tx_Phpunit_Service_Database::delete( + $tableName, + 'uid = ' . $uid . ' AND ' . $this->getDummyColumnName($tableName) . ' = 1' + ); + } + + /** + * Creates a relation between two records on different tables (so called + * m:n relation). + * + * @param string $tableName + * name of the m:n table to which the record should be added, must + * not be empty + * @param integer $uidLocal + * UID of the local table, must be > 0 + * @param integer $uidForeign + * UID of the foreign table, must be > 0 + * @param integer $sorting + * sorting value of the relation, the default value is 0, which + * enables automatic sorting, a value >= 0 overwrites the automatic + * sorting + * + * @return void + */ + public function createRelation($tableName, $uidLocal, $uidForeign, $sorting = 0) { + if (!$this->isNoneSystemTableNameAllowed($tableName)) { + throw new InvalidArgumentException('The table name "' . $tableName . '" is not allowed.'); + } + + // Checks that the two given UIDs are valid. + if (intval($uidLocal) <= 0) { + throw new InvalidArgumentException( + '$uidLocal must be an integer > 0, but actually is "' . $uidLocal . '"' + ); + } + if (intval($uidForeign) <= 0) { + throw new InvalidArgumentException( + '$uidForeign must be an integer > 0, but actually is "' . $uidForeign . '"' + ); + } + + $this->markTableAsDirty($tableName); + + $recordData = array( + 'uid_local' => $uidLocal, + 'uid_foreign' => $uidForeign, + 'sorting' => (($sorting > 0) ? $sorting : $this->getRelationSorting($tableName, $uidLocal)), + $this->getDummyColumnName($tableName) => 1, + ); + + Tx_Phpunit_Service_Database::insert($tableName, $recordData); + } + + /** + * Creates a relation between two records based on the rules defined in TCA + * regarding the relation. + * + * @param string $tableName + * name of the table from which a relation should be created, must + * not be empty + * @param integer $uidLocal + * UID of the record in the local table, must be > 0 + * @param integer $uidForeign + * UID of the record in the foreign table, must be > 0 + * @param string $columnName + * name of the column in which the relation counter should be + * updated, must not be empty + * + * @return void + */ + public function createRelationAndUpdateCounter( + $tableName, $uidLocal, $uidForeign, $columnName + ) { + if (!$this->isTableNameAllowed($tableName)) { + throw new InvalidArgumentException('The table name "' . $tableName . '" is not allowed.'); + } + + if ($uidLocal <= 0) { + throw new InvalidArgumentException( + '$uidLocal must be > 0, but actually is "' . $uidLocal . '"' + ); + } + if ($uidForeign <= 0) { + throw new InvalidArgumentException( + '$uidForeign must be > 0, but actually is "' . $uidForeign . '"' + ); + } + + $tca = Tx_Phpunit_Service_Database::getTcaForTable($tableName); + $relationConfiguration = $tca['columns'][$columnName]; + + if (!isset($relationConfiguration['config']['MM']) || ($relationConfiguration['config']['MM'] === '')) { + throw new t3lib_exception( + 'The column ' . $columnName . ' in the table ' . $tableName . + ' is not configured to contain m:n relations using a m:n table.' + ); + } + + if (!isset($relationConfiguration['config']['MM_opposite_field'])) { + $this->createRelation( + $relationConfiguration['config']['MM'], + $uidLocal, + $uidForeign + ); + } else { + // Switches the order of $uidForeign and $uidLocal as the relation + // is the reverse part of a bidirectional relation. + $this->createRelationAndUpdateCounter( + $relationConfiguration['config']['foreign_table'], + $uidForeign, + $uidLocal, + $relationConfiguration['config']['MM_opposite_field'] + ); + } + + $this->increaseRelationCounter($tableName, $uidLocal, $columnName); + } + + /** + * Deletes a dummy relation from an m:n table in the database. + * + * Important: Only dummy records can be deleted with this method. Should there + * for any reason exist a real record with that combination of local and + * foreign UID, it won't be deleted! + * + * @param string $tableName + * name of the table from which the record should be deleted, must + * not be empty + * @param integer $uidLocal + * UID on the local table, must be > 0 + * @param integer $uidForeign + * UID on the foreign table, must be > 0 + * + * @return void + */ + public function removeRelation($tableName, $uidLocal, $uidForeign) { + if (!$this->isNoneSystemTableNameAllowed($tableName)) { + throw new InvalidArgumentException('The table name "' . $tableName . '" is not allowed.'); + } + + Tx_Phpunit_Service_Database::delete( + $tableName, + 'uid_local = ' . $uidLocal . ' AND uid_foreign = ' . $uidForeign . + ' AND ' . $this->getDummyColumnName($tableName) . ' = 1' + ); + } + + /** + * Deletes all dummy records that have been added through this framework. + * For this, all records with the "is_dummy_record" flag set to 1 will be + * deleted from all tables that have been used within this instance of the + * testing framework. + * + * If you set $performDeepCleanUp to TRUE, it will go through ALL tables to + * which the current instance of the testing framework has access. Please + * consider well, whether you want to do this as it's a huge performance + * issue. + * + * @param boolean $performDeepCleanUp + * whether a deep clean up should be performed + * + * @return void + */ + public function cleanUp($performDeepCleanUp = FALSE) { + $this->cleanUpTableSet(FALSE, $performDeepCleanUp); + $this->cleanUpTableSet(TRUE, $performDeepCleanUp); + $this->deleteAllDummyFoldersAndFiles(); + $this->discardFakeFrontEnd(); + + foreach ($this->getHooks() as $hook) { + if (!($hook instanceof Tx_Phpunit_Interface_FrameworkCleanupHook)) { + throw new t3lib_exception( + 'The class ' . get_class($hook) . ' must implement Tx_Phpunit_Interface_FrameworkCleanupHook.', + 1299257923 + ); + } + $hook->cleanUp(); + } + } + + /** + * Deletes a set of records that have been added through this framework for + * a set of tables (either the test tables or the allowed system tables). + * For this, all records with the "is_dummy_record" flag set to 1 will be + * deleted from all tables that have been used within this instance of the + * testing framework. + * + * If you set $performDeepCleanUp to TRUE, it will go through ALL tables to + * which the current instance of the testing framework has access. Please + * consider well, whether you want to do this as it's a huge performance + * issue. + * + * @param boolean $useSystemTables + * whether to clean up the system tables (TRUE) or the non-system + * test tables (FALSE) + * @param boolean $performDeepCleanUp + * whether a deep clean up should be performed + * + * @return void + */ + protected function cleanUpTableSet($useSystemTables, $performDeepCleanUp) { + if ($useSystemTables) { + $tablesToCleanUp = $performDeepCleanUp ? $this->allowedSystemTables : $this->dirtySystemTables; + } else { + $tablesToCleanUp = $performDeepCleanUp ? $this->ownAllowedTables : $this->dirtyTables; + } + + foreach ($tablesToCleanUp as $currentTable) { + $dummyColumnName = $this->getDummyColumnName($currentTable); + + // Runs a delete query for each allowed table. A + // "one-query-deletes-them-all" approach was tested but we didn't + // find a working solution for that. + Tx_Phpunit_Service_Database::delete($currentTable, $dummyColumnName . ' = 1'); + + // Resets the auto increment setting of the current table. + $this->resetAutoIncrementLazily($currentTable); + } + + // Resets the list of dirty tables. + $this->dirtyTables = array(); + } + + /** + * Deletes all dummy files and folders. + * + * @return void + */ + protected function deleteAllDummyFoldersAndFiles() { + // If the upload folder was created by the testing framework, it can be + // removed at once. + if (isset($this->dummyFolders['uploadFolder'])) { + t3lib_div::rmdir($this->getUploadFolderPath(), TRUE); + $this->dummyFolders = array(); + $this->dummyFiles = array(); + } else { + foreach ($this->dummyFiles as $dummyFile) { + $this->deleteDummyFile($dummyFile); + } + foreach ($this->dummyFolders as $dummyFolder) { + $this->deleteDummyFolder($dummyFolder); + } + } + } + + + // ---------------------------------------------------------------------- + // File creation and deletion + // ---------------------------------------------------------------------- + + /** + * Creates an empty dummy file with a unique file name in the calling + * extension's upload directory. + * + * @param string $fileName + * path of the dummy file to create, relative to the calling + * extension's upload directory, must not be empty + * @param string $content + * string content for the file to create, may be empty + * + * @return string + * the absolute path of the created dummy file, will not be empty + */ + public function createDummyFile($fileName = 'test.txt', $content = '') { + $this->createDummyUploadFolder(); + $uniqueFileName = $this->getUniqueFileOrFolderPath($fileName); + + if (!t3lib_div::writeFile($uniqueFileName, $content)) { + throw new t3lib_exception('The file ' . $uniqueFileName . ' could not be created.'); + } + + $this->addToDummyFileList($uniqueFileName); + + return $uniqueFileName; + } + + /** + * Creates a dummy ZIP archive with a unique file name in the calling + * extension's upload directory. + * + * @param string $fileName + * path of the dummy ZIP archive to create, relative to the calling + * extension's upload directory, must not be empty + * @param array $filesToAddToArchive + * Absolute paths of the files to add to the ZIP archive. Note that + * the archives directory structure will be relative to the upload + * folder path, so only files within this folder or in sub-folders of + * this folder can be added. + * The provided array may be empty, but as ZIP archives cannot be + * empty, a content-less dummy text file will be added to the archive + * then. + * + * @return string + * the absolute path of the created dummy ZIP archive, will not be empty + * + * @throws t3lib_exception if the PHP installation does not provide ZIPArchive + */ + public function createDummyZipArchive($fileName = 'test.zip', array $filesToAddToArchive = array()) { + $this->checkForZipArchive(); + + $this->createDummyUploadFolder(); + $uniqueFileName = $this->getUniqueFileOrFolderPath($fileName); + $zip = t3lib_div::makeInstance('ZipArchive'); + + if ($zip->open($uniqueFileName, ZipArchive::CREATE) !== TRUE) { + throw new t3lib_exception('The new ZIP archive "' . $fileName . '" could not be created.'); + } + + $contents = !empty($filesToAddToArchive) ? $filesToAddToArchive : array($this->createDummyFile()); + + foreach ($contents as $pathToFile) { + if (!file_exists($pathToFile)) { + throw new t3lib_exception( + 'The provided path "' . $pathToFile . '" does not point to an exisiting file.' + ); + } + $zip->addFile($pathToFile, $this->getPathRelativeToUploadDirectory($pathToFile)); + } + + $zip->close(); + $this->addToDummyFileList($uniqueFileName); + + return $uniqueFileName; + } + + /** + * Adds a file name to $this->dummyFiles. + * + * @param string $uniqueFileName + * file name to add, must be the unique name of a dummy file, must + * not be empty + * + * @return void + */ + protected function addToDummyFileList($uniqueFileName) { + $relativeFileName = $this->getPathRelativeToUploadDirectory($uniqueFileName); + + $this->dummyFiles[$relativeFileName] = $relativeFileName; + } + + /** + * Deletes the dummy file specified by the first parameter $fileName. + * + * @param string $fileName + * the path to the file to delete relative to + * $this->uploadFolderPath, must not be empty + * + * @return void + */ + public function deleteDummyFile($fileName) { + $absolutePathToFile = $this->uploadFolderPath . $fileName; + $fileExists = file_exists($absolutePathToFile); + + if (!isset($this->dummyFiles[$fileName])) { + throw new InvalidArgumentException( + 'The file "' . $absolutePathToFile . '" which you are trying to delete ' . + (!$fileExists ? 'does not exist and has never been ' : 'was not ') . + 'created by this instance of the testing framework.' + ); + } + + if ($fileExists && !unlink($absolutePathToFile)) { + throw new t3lib_exception('The file "' . $absolutePathToFile . '" could not be deleted.'); + } + + unset($this->dummyFiles[$fileName]); + } + + /** + * Creates a dummy folder with a unique folder name in the calling + * extension's upload directory. + * + * @param string $folderName + * name of the dummy folder to create relative to + * $this->uploadFolderPath, must not be empty + * + * @return string + * the absolute path of the created dummy folder, will not be empty + */ + public function createDummyFolder($folderName) { + $this->createDummyUploadFolder(); + $uniqueFolderName = $this->getUniqueFileOrFolderPath($folderName); + + if (!t3lib_div::mkdir($uniqueFolderName)) { + throw new t3lib_exception('The folder ' . $uniqueFolderName . ' could not be created.'); + } + + $relativeUniqueFolderName = $this->getPathRelativeToUploadDirectory($uniqueFolderName); + + // Adds the created dummy folder to the top of $this->dummyFolders so + // it gets deleted before previously created folders through + // $this->cleanUpFolders(). This is needed for nested dummy folders. + $this->dummyFolders = array($relativeUniqueFolderName => $relativeUniqueFolderName) + + $this->dummyFolders; + + return $uniqueFolderName; + } + + /** + * Deletes the dummy folder specified in the first parameter $folderName. + * The folder must be empty (no files or subfolders). + * + * @param string $folderName + * the path to the folder to delete relative to + * $this->uploadFolderPath, must not be empty + * + * @return void + */ + public function deleteDummyFolder($folderName) { + $absolutePathToFolder = $this->uploadFolderPath . $folderName; + + if (!is_dir($absolutePathToFolder)) { + throw new InvalidArgumentException( + 'The folder "' . $absolutePathToFolder . '" which you ' . + 'are trying to delete does not exist.' + ); + } + + if (!isset($this->dummyFolders[$folderName])) { + throw new InvalidArgumentException( + 'The folder "' . $absolutePathToFolder . '" which you ' . + 'are trying to delete was not created by this instance of ' . + 'the testing framework.' + ); + } + + if (!t3lib_div::rmdir($absolutePathToFolder)) { + throw new t3lib_exception( + 'The folder "' . $absolutePathToFolder . '" could not be deleted.' + ); + } + + unset($this->dummyFolders[$folderName]); + } + + /** + * Creates the upload folder if it does not exist yet. + * + * @return void + */ + protected function createDummyUploadFolder() { + if (is_dir($this->getUploadFolderPath())) { + return; + } + + if (t3lib_div::mkdir($this->getUploadFolderPath())) { + // registers the upload folder as dummy folder + $this->dummyFolders['uploadFolder'] = ''; + } else { + throw new t3lib_exception( + 'The upload folder ' . $this->getUploadFolderPath() . + ' could not be created.' + ); + } + } + + /** + * Sets the upload folder path. + * + * @param string $absolutePath + * absolute path to the folder where to work on during the tests, can + * be either an existing folder which will be cleaned up after the + * tests or a path of a folder to be created as soon as it is needed + * and deleted during cleanUp, must end with a trailing slash + * + * @return void + * + * @throws t3lib_exception + * if there are dummy files within the current upload folder as + * these files could not be deleted if the upload folder path has + * changed + */ + public function setUploadFolderPath($absolutePath) { + if (!empty($this->dummyFiles) || !empty($this->dummyFolders)) { + throw new t3lib_exception( + 'The upload folder path must not be changed if there are ' . + 'already dummy files or folders.' + ); + } + + $this->uploadFolderPath = $absolutePath; + } + + /** + * Returns the absolute path to the upload folder of the extension to test. + * + * @return string + * the absolute path to the upload folder of the extension to test, + * including the trailing slash + */ + public function getUploadFolderPath() { + return $this->uploadFolderPath; + } + + /** + * Returns the path relative to the calling extension's upload directory for + * a path given in the first parameter $absolutePath. + * + * @param string $absolutePath + * the absolute path to process, must be within the calling + * extension's upload directory, must not be empty + * + * @return string + * the path relative to the calling extension's upload directory + */ + public function getPathRelativeToUploadDirectory($absolutePath) { + if (!preg_match( + '/^' . str_replace('/', '\/', $this->getUploadFolderPath()) . '.*$/', + $absolutePath + )) { + throw new InvalidArgumentException( + 'The first parameter $absolutePath is not within the calling ' . + 'extension\'s upload directory.' + ); + } + + return mb_substr( + $absolutePath, + mb_strlen($this->getUploadFolderPath()) + ); + } + + /** + * Returns a unique absolut path of a file or folder. + * + * @param string $path + * the path of a file or folder relative to the calling extension's + * upload directory, must not be empty + * + * @return string the unique absolut path of a file or folder + */ + public function getUniqueFileOrFolderPath($path) { + if (empty($path)) { + throw new InvalidArgumentException('The first parameter $path must not be empty.'); + } + + if (!self::$fileNameProcessor) { + self::$fileNameProcessor = t3lib_div::makeInstance('t3lib_basicFileFunctions'); + } + + return self::$fileNameProcessor->getUniqueName( + basename($path), + $this->uploadFolderPath . t3lib_div::dirname($path) + ); + } + + + // ---------------------------------------------------------------------- + // Functions concerning a fake front end + // ---------------------------------------------------------------------- + + /** + * Fakes a TYPO3 front end, using $pageUid as front-end page ID if provided. + * + * If $pageUid is zero, the UID of the start page of the current domain + * will be used as page UID. + * + * This function creates $GLOBALS['TSFE'] and $GLOBALS['TT']. + * + * Note: This function does not set TYPO3_MODE to "FE" (because the value of + * a constant cannot be changed after it has once been set). + * + * @param integer $pageUid + * UID of a page record to use, must be >= 0 + * + * @return integer the UID of the used front-end page, will be > 0 + */ + public function createFakeFrontEnd($pageUid = 0) { + if ($pageUid < 0) { + throw new InvalidArgumentException('$pageUid must be >= 0.'); + } + + $this->suppressFrontEndCookies(); + $this->discardFakeFrontEnd(); + + $GLOBALS['TT'] = t3lib_div::makeInstance('t3lib_TimeTrackNull'); + + $frontEnd = t3lib_div::makeInstance('tslib_fe', $GLOBALS['TYPO3_CONF_VARS'], $pageUid, 0); + + // simulates a normal FE without any logged-in FE or BE user + $frontEnd->beUserLogin = FALSE; + $frontEnd->workspacePreview = ''; + $frontEnd->initFEuser(); + $frontEnd->determineId(); + $frontEnd->initTemplate(); + $frontEnd->config = array(); + + $frontEnd->tmpl->getFileName_backPath = PATH_site; + + if (($pageUid > 0) && in_array('sys_template', $this->dirtySystemTables)) { + $frontEnd->tmpl->runThroughTemplates($frontEnd->sys_page->getRootLine($pageUid), 0); + $frontEnd->tmpl->generateConfig(); + $frontEnd->tmpl->loaded = 1; + $frontEnd->settingLanguage(); + $frontEnd->settingLocale(); + } + + $frontEnd->newCObj(); + + $GLOBALS['TSFE'] = $frontEnd; + + $this->hasFakeFrontEnd = TRUE; + $this->logoutFrontEndUser(); + + return $GLOBALS['TSFE']->id; + } + + /** + * Discards the fake front end. + * + * This function nulls out $GLOBALS['TSFE'] and $GLOBALS['TT']. In addition, + * any logged-in front-end user will be logged out. + * + * The page record for the current front end will _not_ be deleted by this + * function, though. + * + * If no fake front end has been created, this function does nothing. + * + * @return void + */ + public function discardFakeFrontEnd() { + if (!$this->hasFakeFrontEnd()) { + return; + } + + $this->logoutFrontEndUser(); + + unset( + $GLOBALS['TSFE']->tmpl, $GLOBALS['TSFE']->sys_page, + $GLOBALS['TSFE']->fe_user, $GLOBALS['TSFE']->TYPO3_CONF_VARS, + $GLOBALS['TSFE']->config, $GLOBALS['TSFE']->TCAcachedExtras, + $GLOBALS['TSFE']->imagesOnPage, $GLOBALS['TSFE']->cObj, + $GLOBALS['TSFE']->csConvObj, $GLOBALS['TSFE']->pagesection_lockObj, + $GLOBALS['TSFE']->pages_lockObj + ); + $GLOBALS['TSFE'] = NULL; + $GLOBALS['TT'] = NULL; + + $this->hasFakeFrontEnd = FALSE; + } + + /** + * Returns whether this testing framework instance has a fake front end. + * + * @return boolean + * TRUE if this instance has a fake front end, FALSE otherwise + */ + public function hasFakeFrontEnd() { + return $this->hasFakeFrontEnd; + } + + /** + * Makes sure that no FE login cookies will be sent. + * + * @return void + */ + protected function suppressFrontEndCookies() { + $GLOBALS['_POST']['FE_SESSION_KEY'] = ''; + $GLOBALS['_GET']['FE_SESSION_KEY'] = ''; + $GLOBALS['TYPO3_CONF_VARS']['FE']['dontSetCookie'] = 1; + } + + + // ---------------------------------------------------------------------- + // FE user activities + // ---------------------------------------------------------------------- + + /** + * Fakes that a front-end user has logged in. + * + * If a front-end user currently is logged in, he/she will be logged out + * first. + * + * Note: To set the logged-in users group data properly, the front-end user + * and his groups must actually exist in the database. + * + * @param integer $userId + * UID of the FE user, must not necessarily exist in the database, + * must be > 0 + * + * @return void + * + * @throws t3lib_exception if no front end has been created + */ + public function loginFrontEndUser($userId) { + if (intval($userId) === 0) { + throw new InvalidArgumentException('The user ID must be > 0.'); + } + if (!$this->hasFakeFrontEnd()) { + throw new t3lib_exception('Please create a front end before calling loginFrontEndUser.'); + } + + if ($this->isLoggedIn()) { + $this->logoutFrontEndUser(); + } + + $this->suppressFrontEndCookies(); + + // Instead of passing the actual user data to createUserSession, we + // pass an empty array to improve performance (e.g. no session record + // will be written to the database). + $GLOBALS['TSFE']->fe_user->createUserSession(array()); + $GLOBALS['TSFE']->fe_user->user = $GLOBALS['TSFE']->fe_user->getRawUserByUid($userId); + $GLOBALS['TSFE']->fe_user->fetchGroupData(); + $GLOBALS['TSFE']->loginUser = 1; + } + + /** + * Logs out the current front-end user. + * + * If no front-end user is logged in, this function does nothing. + * + * @throws t3lib_exception if no front end has been created + * + * @return void + */ + public function logoutFrontEndUser() { + if (!$this->hasFakeFrontEnd()) { + throw new t3lib_exception('Please create a front end before calling logoutFrontEndUser.'); + } + if (!$this->isLoggedIn()) { + return; + } + + $this->suppressFrontEndCookies(); + + $GLOBALS['TSFE']->fe_user->logoff(); + $GLOBALS['TSFE']->loginUser = 0; + } + + /** + * Checks whether a FE user is logged in. + * + * @throws t3lib_exception if no front end has been created + * + * @return boolean TRUE if a FE user is logged in, FALSE otherwise + */ + public function isLoggedIn() { + if (!$this->hasFakeFrontEnd()) { + throw new t3lib_exception('Please create a front end before calling isLoggedIn.'); + } + + return isset($GLOBALS['TSFE']) && is_object($GLOBALS['TSFE']) + && is_array($GLOBALS['TSFE']->fe_user->user); + } + + + // ---------------------------------------------------------------------- + // Various helper functions + // ---------------------------------------------------------------------- + + /** + * Generates a list of allowed tables to which this instance of the testing + * framework has access to create/remove test records. + * + * The generated list is based on the list of all tables that TYPO3 can + * access (which will be all tables in this database), filtered by prefix of + * the extension to test. + * + * The array with the allowed table names is written directly to + * $this->ownAllowedTables. + * + * @return void + */ + protected function createListOfOwnAllowedTables() { + $this->ownAllowedTables = array(); + $allTables = Tx_Phpunit_Service_Database::getAllTableNames(); + $length = strlen($this->tablePrefix); + + foreach ($allTables as $currentTable) { + if (substr_compare($this->tablePrefix, $currentTable, 0, $length) === 0) { + $this->ownAllowedTables[] = $currentTable; + } + } + } + + /** + * Generates a list of additional allowed tables to which this instance of + * the testing framework has access to create/remove test records. + * + * The generated list is based on the list of all tables that TYPO3 can + * access (which will be all tables in this database), filtered by the + * prefixes of additional extensions. + * + * The array with the allowed table names is written directly to + * $this->additionalAllowedTables. + * + * @return void + */ + protected function createListOfAdditionalAllowedTables() { + $allTables = implode(',', Tx_Phpunit_Service_Database::getAllTableNames()); + $additionalTablePrefixes = implode('|', $this->additionalTablePrefixes); + + $matches = array(); + + preg_match_all( + '/(('.$additionalTablePrefixes.')_[a-z0-9]+[a-z0-9_]*)(,|$)/', $allTables, $matches + ); + + if (isset($matches[1])) { + $this->additionalAllowedTables = $matches[1]; + } + } + + /** + * Checks whether the given table name is in the list of allowed tables for + * this instance of the testing framework. + * + * @param string $tableName + * the name of the table to check, must not be empty + * + * @return boolean + * TRUE if the name of the table is in the list of allowed tables, + * FALSE otherwise + */ + protected function isOwnTableNameAllowed($tableName) { + return in_array($tableName, $this->ownAllowedTables); + } + + /** + * Checks whether the given table name is in the list of additional allowed + * tables for this instance of the testing framework. + * + * @param string $tableName + * the name of the table to check, must not be empty + * + * @return boolean + * TRUE if the name of the table is in the list of additional + * allowed tables, FALSE otherwise + */ + protected function isAdditionalTableNameAllowed($tableName) { + return in_array($tableName, $this->additionalAllowedTables); + } + + /** + * Checks whether the given table name is in the list of allowed + * system tables for this instance of the testing framework. + * + * @param string $tableName + * the name of the table to check, must not be empty + * + * @return boolean + * TRUE if the name of the table is in the list of allowed system + * tables, FALSE otherwise + */ + protected function isSystemTableNameAllowed($tableName) { + return in_array($tableName, $this->allowedSystemTables); + } + + /** + * Checks whether the given table name is in the list of allowed tables or + * additional allowed tables for this instance of the testing framework. + * + * @param string $tableName + * the name of the table to check, must not be empty + * + * @return boolean + * TRUE if the name of the table is in the list of allowed tables or + * additional allowed tables, FALSE otherwise + */ + protected function isNoneSystemTableNameAllowed($tableName) { + return $this->isOwnTableNameAllowed($tableName) + || $this->isAdditionalTableNameAllowed($tableName); + } + + /** + * Checks whether the given table name is in the list of allowed tables, + * additional allowed tables or allowed system tables. + * + * @param string $tableName + * the name of the table to check, must not be empty + * + * @return boolean + * TRUE if the name of the table is in the list of allowed tables, + * additional allowed tables or allowed system tables, FALSE otherwise + */ + protected function isTableNameAllowed($tableName) { + return $this->isNoneSystemTableNameAllowed($tableName) + || $this->isSystemTableNameAllowed($tableName); + } + + /** + * Returns the name of the column that marks a record as a dummy record. + * + * On most tables this is "is_dummy_record", but on system tables like + * "pages" or "fe_users", the column is called "tx_phpunit_dummy_record". + * + * On additional tables, the column is built using $this->tablePrefix as + * prefix e.g. "tx_seminars_is_dummy_record" if $this->tablePrefix = + * "tx_seminars". + * + * @param string $tableName + * the table name to look up, must not be empty + * + * @return string the name of the column that marks a record as dummy record + */ + public function getDummyColumnName($tableName) { + $result = 'is_dummy_record'; + + if ($this->isSystemTableNameAllowed($tableName)) { + $result = 'tx_phpunit_' . $result; + } elseif ($this->isAdditionalTableNameAllowed($tableName)) { + $result = $this->tablePrefix . '_' . $result; + } + + return $result; + } + + /** + * Counts the dummy records in the table given by the first parameter $tableName + * that match a given WHERE clause. + * + * @param string $tableName + * the name of the table to query, must not be empty + * @param string $whereClause + * the WHERE part of the query, may be empty (all records will be + * counted in that case) + * + * @return integer the number of records that have been found, will be >= 0 + */ + public function countRecords($tableName, $whereClause = '') { + if (!$this->isTableNameAllowed($tableName)) { + throw new InvalidArgumentException( + 'The given table name is invalid. This means it is either ' . + 'empty or not in the list of allowed tables.' + ); + } + + $whereForDummyColumn = $this->getDummyColumnName($tableName) . ' = 1'; + $compoundWhereClause = ($whereClause !== '') + ? '(' . $whereClause . ') AND ' . $whereForDummyColumn : $whereForDummyColumn; + + return Tx_Phpunit_Service_Database::count($tableName, $compoundWhereClause); + } + + /** + * Checks whether there are any dummy records in the table given by the + * first parameter $tableName that match a given WHERE clause. + * + * @param string $tableName + * the name of the table to query, must not be empty + * @param string $whereClause + * the WHERE part of the query, may be empty (all records will be + * counted in that case) + * + * @return boolean + * TRUE if there is at least one matching record, FALSE otherwise + */ + public function existsRecord($tableName, $whereClause = '') { + return ($this->countRecords($tableName, $whereClause) > 0); + } + + /** + * Checks whether there is a dummy record in the table given by the first + * parameter $tableName that has the given UID. + * + * @param string $tableName + * the name of the table to query, must not be empty + * @param integer $uid + * the UID of the record to look up, must be > 0 + * + * @return boolean TRUE if there is a matching record, FALSE otherwise + */ + public function existsRecordWithUid($tableName, $uid) { + if ($uid <= 0) { + throw new InvalidArgumentException('$uid must be > 0.'); + } + + return ($this->countRecords($tableName, 'uid = ' . $uid) > 0); + } + + /** + * Checks whether there is exactly one dummy record in the table given by + * the first parameter $tableName that matches a given WHERE clause. + * + * @param string $tableName + * the name of the table to query, must not be empty + * @param string $whereClause + * the WHERE part of the query, may be empty (all records will be + * counted in that case) + * + * @return boolean + * TRUE if there is exactly one matching record, FALSE otherwise + */ + public function existsExactlyOneRecord($tableName, $whereClause = '') { + return ($this->countRecords($tableName, $whereClause) === 1); + } + + /** + * Eagerly resets the auto increment value for a given table to the highest + * existing UID + 1. + * + * @param string $tableName + * the name of the table on which we're going to reset the auto + * increment entry, must not be empty + * + * @see resetAutoIncrementLazily + * + * @return void + */ + public function resetAutoIncrement($tableName) { + if (!$this->isTableNameAllowed($tableName)) { + throw new InvalidArgumentException( + 'The given table name is invalid. This means it is either ' . + 'empty or not in the list of allowed tables.' + ); + } + + // Checks whether the current table qualifies for this method. If there + // is no column "uid" that has the "auto_increment" flag set, we should + // not try to reset this inexistent auto increment index to avoid DB + // errors. + if (!Tx_Phpunit_Service_Database::tableHasColumnUid($tableName)) { + return; + } + + $newAutoIncrementValue = $this->getMaximumUidFromTable($tableName) + 1; + + Tx_Phpunit_Service_Database::enableQueryLogging(); + // Updates the auto increment index for this table. The index will be + // set to one UID above the highest existing UID. + $dbResult = $GLOBALS['TYPO3_DB']->sql_query( + 'ALTER TABLE ' . $tableName . ' AUTO_INCREMENT=' . $newAutoIncrementValue . ';' + ); + if (!$dbResult) { + throw new Tx_Phpunit_Exception_Database(); + } + } + + /** + * Resets the auto increment value for a given table to the highest existing + * UID + 1 if the current auto increment value is higher than a certain + * threshold over the current maximum UID. + * + * The threshhold is 100 by default and can be set using + * setResetAutoIncrementThreshold. + * + * @param string $tableName + * the name of the table on which we're going to reset the auto + * increment entry, must not be empty + * + * @see resetAutoIncrement + * + * @return void + */ + public function resetAutoIncrementLazily($tableName) { + if (!$this->isTableNameAllowed($tableName)) { + throw new InvalidArgumentException( + 'The given table name is invalid. This means it is either ' . + 'empty or not in the list of allowed tables.' + ); + } + + // Checks whether the current table qualifies for this method. If there + // is no column "uid" that has the "auto_increment" flag set, we should + // not try to reset this inexistent auto increment index to avoid + // database errors. + if (!Tx_Phpunit_Service_Database::tableHasColumnUid($tableName)) { + return; + } + + if ($this->getAutoIncrement($tableName) > ($this->getMaximumUidFromTable($tableName) + $this->resetAutoIncrementThreshold)) { + $this->resetAutoIncrement($tableName); + } + } + + /** + * Sets the threshold for resetAutoIncrementLazily. + * + * @param integer $threshold + * threshold, must be > 0 + * + * @see resetAutoIncrementLazily + * + * @return void + */ + public function setResetAutoIncrementThreshold($threshold) { + if ($threshold <= 0) { + throw new InvalidArgumentException('$threshold must be > 0.'); + } + + $this->resetAutoIncrementThreshold = $threshold; + } + + /** + * Reads the highest UID for a database table. + * + * This function may only be called after that the provided table name + * has been checked to be non-empty, valid and pointing to an existing + * database table that has the "uid" column. + * + * @param string $tableName + * the name of an existing table that has the "uid" column + * + * @return integer the highest UID from this table, will be >= 0 + */ + protected function getMaximumUidFromTable($tableName) { + $row = Tx_Phpunit_Service_Database::selectSingle('MAX(uid) AS uid', $tableName); + + return $row['uid']; + } + + /** + * Reads the current auto increment value for a given table. + * + * This function is only valid for tables that actually have an auto + * increment value. + * + * @param string $tableName + * the name of the table for which the auto increment value should be + * retrieved, must not be empty + * + * @return integer + * the current auto_increment value of table $tableName, will be > 0 + */ + public function getAutoIncrement($tableName) { + if (!$this->isTableNameAllowed($tableName)) { + throw new InvalidArgumentException( + 'The given table name is invalid. This means it is either ' . + 'empty or not in the list of allowed tables.' + ); + } + + Tx_Phpunit_Service_Database::enableQueryLogging(); + $dbResult = $GLOBALS['TYPO3_DB']->sql_query( + 'SHOW TABLE STATUS WHERE Name = \'' . $tableName . '\';' + ); + if (!$dbResult) { + throw new Tx_Phpunit_Exception_Database(); + } + + $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($dbResult); + $GLOBALS['TYPO3_DB']->sql_free_result($dbResult); + + $autoIncrement = $row['Auto_increment']; + if ($autoIncrement === NULL) { + throw new InvalidArgumentException( + 'The given table name is invalid. This means it is either ' . + 'empty or not in the list of allowed tables.' + ); + } + + return $autoIncrement; + } + + /** + * Returns the list of allowed table names. + * + * @return array + * all allowed table names for this instance of the testing framework + */ + public function getListOfOwnAllowedTableNames() { + return $this->ownAllowedTables; + } + + /** + * Returns the list of additional allowed table names. + * + * @return array + * all additional allowed table names for this instance of the + * testing framework, may be empty + */ + public function getListOfAdditionalAllowedTableNames() { + return $this->additionalAllowedTables; + } + + /** + * Puts one or multiple table names on the list of dirty tables (which + * represents a list of tables that were used for testing and contain dummy + * records and thus are called "dirty" until the next clean up). + * + * @param string $tableNames + * the table name or a comma-separated list of table names to put on + * the list of dirty tables, must not be empty + * + * @return void + */ + public function markTableAsDirty($tableNames) { + foreach (t3lib_div::trimExplode(',', $tableNames) as $currentTable) { + if ($this->isNoneSystemTableNameAllowed($currentTable)) { + $this->dirtyTables[$currentTable] = $currentTable; + } elseif ($this->isSystemTableNameAllowed($currentTable)) { + $this->dirtySystemTables[$currentTable] = $currentTable; + } else { + throw new InvalidArgumentException( + 'The table name "' . $currentTable . '" is not allowed for markTableAsDirty.' + ); + } + } + } + + /** + * Returns the list of tables that contain dummy records from testing. These + * tables are called "dirty tables" as they need to be cleaned up. + * + * @return array + * associative array containing names of database tables that need + * to be cleaned up + */ + public function getListOfDirtyTables() { + return $this->dirtyTables; + } + + /** + * Returns the list of system tables that contain dummy records from + * testing. These tables are called "dirty tables" as they need to be + * cleaned up. + * + * @return array + * associative array containing names of system database tables that + * need to be cleaned up + */ + public function getListOfDirtySystemTables() { + return $this->dirtySystemTables; + } + + /** + * Returns the next sorting value of the relation table which should be used. + * + * TODO: This function doesn't take already existing relations in the + * database - which were created without using the testing framework - into + * account. So you always should create new dummy records and create a + * relation between these two dummy records, so you're sure there aren't + * already relations for a local UID in the database. + * + * @param string $tableName + * the relation table, must not be empty + * @param integer $uidLocal + * UID of the local table, must be > 0 + * + * @return integer the next sorting value to use (> 0) + * + * @see https://bugs.oliverklee.com/show_bug.cgi?id=1423 + */ + public function getRelationSorting($tableName, $uidLocal) { + if (!$this->relationSorting[$tableName][$uidLocal]) { + $this->relationSorting[$tableName][$uidLocal] = 0; + } + + $this->relationSorting[$tableName][$uidLocal]++; + + return $this->relationSorting[$tableName][$uidLocal]; + } + + /** + * Updates an integer field of a database table by one. This is mainly needed + * for counting up the relation counter when creating a database relation. + * + * The field to update must be of type integer. + * + * @param string $tableName + * name of the table, must not be empty + * @param integer $uid + * the UID of the record to modify, must be > 0 + * @param string $fieldName + * the field name of the field to modify, must not be empty + * + * @return void + */ + public function increaseRelationCounter($tableName, $uid, $fieldName) { + if (!$this->isTableNameAllowed($tableName)) { + throw new InvalidArgumentException( + 'The table name "' . $tableName . '" is invalid. This means ' . + 'it is either empty or not in the list of allowed tables.' + ); + } + if (!Tx_Phpunit_Service_Database::tableHasColumn($tableName, $fieldName)) { + throw new InvalidArgumentException( + 'The table ' . $tableName . ' has no column ' . $fieldName . '.' + ); + } + + Tx_Phpunit_Service_Database::enableQueryLogging(); + $dbResult = $GLOBALS['TYPO3_DB']->sql_query( + 'UPDATE ' . $tableName . ' SET ' . $fieldName . '=' . $fieldName . '+1 WHERE uid=' . $uid + ); + if (!$dbResult) { + throw new Tx_Phpunit_Exception_Database(); + } + + if ($GLOBALS['TYPO3_DB']->sql_affected_rows() === 0) { + throw new Tx_Phpunit_Exception_Database( + 'The table ' . $tableName . ' does not contain a record with UID ' . $uid . '.' + ); + } + + $this->markTableAsDirty($tableName); + } + + /** + * Checks whether the ZIPArchive class is provided by the PHP installation. + * + * Note: This function can be used to mark tests as skipped if this class is + * not available but required for a test to pass succesfully. + * + * @throws t3lib_exception if the PHP installation does not provide ZIPArchive + * + * @return void + */ + public function checkForZipArchive() { + if (!in_array('zip', get_loaded_extensions())) { + throw new t3lib_exception('This PHP installation does not provide the ZIPArchive class.'); + } + } + + /** + * Gets all hooks for this class. + * + * @return array the hook objects, will be empty if no hooks have been set + */ + protected function getHooks() { + if (!self::$hooksHaveBeenRetrieved) { + $hookClasses = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['FrameworkCleanUp']; + if (is_array($hookClasses)) { + foreach ($hookClasses as $hookClass) { + self::$hooks[] = t3lib_div::getUserObj($hookClass); + } + } + + self::$hooksHaveBeenRetrieved = TRUE; + } + + return self::$hooks; + } + + /** + * Purges the cached hooks. + * + * @return void + */ + public function purgeHooks() { + self::$hooks = array(); + self::$hooksHaveBeenRetrieved = FALSE; + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/Interface/FrameworkCleanupHook.php b/typo3conf/ext/phpunit/Classes/Interface/FrameworkCleanupHook.php new file mode 100644 index 0000000..ea49686 --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/Interface/FrameworkCleanupHook.php @@ -0,0 +1,42 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/** + * This interface should be used for classes that should get called by a hook + * when Tx_Phpunit_Framework::cleanUp() is called. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Oliver Klee + */ +interface Tx_Phpunit_Interface_FrameworkCleanupHook { + /** + * Cleans up phpunit after running a test. + * + * @return void + */ + public function cleanUp(); +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/Reports/Status.php b/typo3conf/ext/phpunit/Classes/Reports/Status.php new file mode 100644 index 0000000..dbeabd8 --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/Reports/Status.php @@ -0,0 +1,270 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/** + * This class provides a status report for the "Reports" BE module. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Oliver Klee + */ +class Tx_Phpunit_Reports_Status implements tx_reports_StatusProvider { + /** + * @var string + */ + const MEMORY_REQUIRED = '128M'; + /** + * @var string + */ + const MEMORY_RECOMMENDED = '256M'; + + /** + * Returns the status of this extension. + * + * @return array + * status reports for this extension + */ + public function getStatus() { + return array( + $this->getReflectionStatus(), + $this->getEacceleratorStatus(), + $this->getXdebugStatus(), + $this->getMemoryLimitStatus(), + $this->getIncludePathStatus(), + $this->getExcludedExtensionsStatus(), + ); + } + + /** + * Translates a localized string. + * + * @param string $subkey + * the part of the key to translate (without the + * "LLL:EXT:phpunit/Resources/Private/Language/locallang_report.xml:" prefix) + * + * @return string the localized string for $subkey, might be empty + */ + protected function translate($subkey) { + return $GLOBALS['LANG']->sL( + 'LLL:EXT:phpunit/Resources/Private/Language/locallang_report.xml:' . $subkey + ); + } + + /** + * Creates a status concerning whether PHP reflection works correctly. + * + * @return tx_reports_reports_status_Status + * a status indicating whether PHP reflection works correctly + */ + protected function getReflectionStatus() { + $heading = $this->translate('status_phpComments'); + + $method = new ReflectionMethod('tx_phpunit_Reports_Status', 'getStatus'); + if (strlen($method->getDocComment()) > 0) { + $status = t3lib_div::makeInstance( + 'tx_reports_reports_status_Status', + $heading, + $this->translate('status_phpComments_present_short'), + $this->translate('status_phpComments_present_verbose'), + tx_reports_reports_status_Status::OK + ); + } else { + $status = t3lib_div::makeInstance( + 'tx_reports_reports_status_Status', + $heading, + $this->translate('status_phpComments_stripped_short'), + $this->translate('status_phpComments_stripped_verbose'), + tx_reports_reports_status_Status::ERROR + ); + } + + return $status; + } + + /** + * Creates a status concerning eAccelerator not crashing phpunit. + * + * @return tx_reports_reports_status_Status + * a status concerning eAccelerator not crashing phpunit + */ + protected function getEacceleratorStatus() { + $heading = $this->translate('status_eAccelerator'); + + if (!extension_loaded('eaccelerator')) { + $status = t3lib_div::makeInstance( + 'tx_reports_reports_status_Status', + $heading, + $this->translate('status_eAccelerator_notInstalled_short'), + '', + tx_reports_reports_status_Status::OK + ); + } else { + $version = phpversion('eaccelerator'); + + if (version_compare($version, '0.9.5.2', '<')) { + $verboseMessage = sprintf( + $this->translate('status_eAccelerator_installedOld_verbose'), + $version + ); + + $status = t3lib_div::makeInstance( + 'tx_reports_reports_status_Status', + $heading, + $this->translate('status_eAccelerator_installedOld_short'), + $verboseMessage, + tx_reports_reports_status_Status::ERROR + ); + } else { + $verboseMessage = sprintf( + $this->translate('status_eAccelerator_installedNew_verbose'), + $version + ); + + $status = t3lib_div::makeInstance( + 'tx_reports_reports_status_Status', + $heading, + $this->translate('status_eAccelerator_installedNew_short'), + $verboseMessage, + tx_reports_reports_status_Status::OK + ); + } + } + + return $status; + } + + /** + * Creates a status concerning whether Xdebug is loaded. + * + * @return tx_reports_reports_status_Status + * a status concerning whether Xdebug is loaded + */ + protected function getXdebugStatus() { + if (extension_loaded('xdebug')) { + $messageKey = 'status_loaded'; + } else { + $messageKey = 'status_notLoaded'; + } + + return t3lib_div::makeInstance( + 'tx_reports_reports_status_Status', + $this->translate('status_xdebug'), + $this->translate($messageKey), + '', + tx_reports_reports_status_Status::NOTICE + ); + } + + /** + * Creates a status concerning the PHP memory limit. + * + * @return tx_reports_reports_status_Status + * a status indicating whether the PHP memory limit is high enogh + */ + protected function getMemoryLimitStatus() { + $memoryLimitFromConfiguration = ini_get('memory_limit'); + $memoryLimitInBytes = t3lib_div::getBytesFromSizeMeasurement($memoryLimitFromConfiguration); + $requiredMemoryLimitInBytes = t3lib_div::getBytesFromSizeMeasurement(self::MEMORY_REQUIRED); + $recommendedMemoryLimitInBytes = t3lib_div::getBytesFromSizeMeasurement(self::MEMORY_RECOMMENDED); + + $heading = $this->translate('status_memoryLimit'); + $message = sprintf( + $this->translate('status_memoryLimit_tooLittle'), + self::MEMORY_REQUIRED, self::MEMORY_RECOMMENDED + ); + + if ($memoryLimitInBytes < $requiredMemoryLimitInBytes) { + $status = t3lib_div::makeInstance( + 'tx_reports_reports_status_Status', + $heading, + $memoryLimitFromConfiguration, + $message, + tx_reports_reports_status_Status::ERROR + ); + } elseif ($memoryLimitInBytes < $recommendedMemoryLimitInBytes) { + $status = t3lib_div::makeInstance( + 'tx_reports_reports_status_Status', + $heading, + $memoryLimitFromConfiguration, + $message, + tx_reports_reports_status_Status::WARNING + ); + } else { + $status = t3lib_div::makeInstance( + 'tx_reports_reports_status_Status', + $heading, + $memoryLimitFromConfiguration, + '', + tx_reports_reports_status_Status::OK + ); + } + + return $status; + } + + /** + * Creates a status about the PHP include path. + * + * @return tx_reports_reports_status_Status + * a status about the PHP include path + */ + protected function getIncludePathStatus() { + $paths = explode(PATH_SEPARATOR, get_include_path()); + + $escapedPaths = array(); + foreach ($paths as $path) { + $escapedPaths[] = htmlspecialchars($path); + } + + return t3lib_div::makeInstance( + 'tx_reports_reports_status_Status', + $this->translate('status_includePath'), + '', + '' . implode('
    ', $escapedPaths) . '
    ', + tx_reports_reports_status_Status::NOTICE + ); + } + + /** + * Creates a status about the extensions that are excluded from unit testing. + * + * @return tx_reports_reports_status_Status + * a status about the excluded extensions + */ + protected function getExcludedExtensionsStatus() { + $extensionKeys = t3lib_div::trimExplode( + ',', $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['excludeextensions'] + ); + + return t3lib_div::makeInstance( + 'tx_reports_reports_status_Status', + $this->translate('status_excludedExtensions'), + '', + implode('
    ', $extensionKeys), + tx_reports_reports_status_Status::NOTICE + ); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/Selenium/TestCase.php b/typo3conf/ext/phpunit/Classes/Selenium/TestCase.php new file mode 100644 index 0000000..847e4e7 --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/Selenium/TestCase.php @@ -0,0 +1,187 @@ + + * @author Carsten Koenig + */ +class Tx_Phpunit_Selenium_TestCase extends PHPUnit_Extensions_SeleniumTestCase { + /** + * the default Selenium server host address + * + * @var string + */ + const DEFAULT_SELENIUM_HOST = 'localhost'; + + /** + * the default Selenium server port + * + * @var integer + */ + const DEFAULT_SELENIUM_PORT = 4444; + + /** + * the default Selenium browser + * + * @var string + */ + const DEFAULT_SELENIUM_BROWSER = '*chrome'; + + /** + * the default Selenium browser URL + * + * @var string + */ + const DEFAULT_SELENIUM_BROWSER_URL = '/'; + + /** + * The constructor. + * + * @param string $name + * @param array $data + * @param string $dataName + */ + public function __construct($name = NULL, array $data = array(), $dataName = '') { + $browser = array( + 'browser' => $this->getSeleniumBrowser(), + 'host' => $this->getSeleniumHost(), + 'port' => $this->getSeleniumPort(), + ); + parent::__construct($name, $data, $dataName, $browser); + + $this->setBrowserUrl($this->getSeleniumBrowserUrl()); + } + + /** + * Runs the test if the Selenium RC Server is reachable. + * + * If the server is not reachable, the tests will be marked as skipped, and + * a message will be displayed giving a hint on wich host/port the client + * was looking for the Selenium server. + * + * @see PHPUnit_Extensions_SeleniumTestCase::runTest() + * + * @return void + */ + protected function runTest() { + if ($this->isSeleniumServerRunning()) { + parent::runTest(); + } else { + $this->markTestSkipped( + 'Selenium RC server not reachable (host=' . + $this->getSeleniumHost() . ', port=' . + $this->getSeleniumPort() . ').' + ); + } + } + + /** + * Tests if the Selenium RC server is running. + * + * @return boolean TRUE if the server is reachable by opening a socket, FALSE otherwise + */ + protected function isSeleniumServerRunning() { + $seleniumServerIsRunning = FALSE; + + $errorLevel = 0; + $errorMessage = ''; + $timeout = 1; + $socket = @fsockopen( + $this->getSeleniumHost(), $this->getSeleniumPort(), + $errorLevel, $errorMessage, $timeout + ); + + if ($socket !== FALSE) { + $seleniumServerIsRunning = TRUE; + fclose($socket); + } + + return $seleniumServerIsRunning; + } + + /** + * Returns the configured host name of the Selenium RC server. + * + * This function returns "localhost" if no host is configured. + * + * @return string host of the Selenium RC server, will not be empty + */ + protected function getSeleniumHost() { + return isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_host']) + && (strlen($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_host']) > 0) + ? $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_host'] + : self::DEFAULT_SELENIUM_HOST; + } + + /** + * Returns the configured port number of the Selenium RC server. + * + * This functions returns 4444 (the standard Selenium RC port) if no port is + * is configured + * + * @return integer the elenium RC server port, will be > 0 + */ + protected function getSeleniumPort() { + return isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_port']) + && (intval($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_port']) > 0) + ? intval($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_port']) + : self::DEFAULT_SELENIUM_PORT; + } + + /** + * Returns the configured browser that should run the Selenium tests. + * + * This functions returns Firefox in chrome mode if no browser is configured. + * + * @return string Selenium RC browser, will not be empty + */ + protected function getSeleniumBrowser() { + return isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_browser']) + && (strlen($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_browser']) > 0) + ? $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_browser'] + : self::DEFAULT_SELENIUM_BROWSER; + } + + /** + * Returns the configured Selenium RC browser starting URL. + * + * This functions returns the TYPO3_SITE_URL if no URL is configured. + * + * @return string Selenium RC Browser URL, will not be empty + */ + protected function getSeleniumBrowserUrl() { + return isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_browserurl']) + && (strlen($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_browserurl']) > 0) + ? $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_browserurl'] + : rtrim(t3lib_div::getIndpEnv('TYPO3_SITE_URL'), self::DEFAULT_SELENIUM_BROWSER_URL); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/Service/Database.php b/typo3conf/ext/phpunit/Classes/Service/Database.php new file mode 100644 index 0000000..a5253f5 --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/Service/Database.php @@ -0,0 +1,745 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/** + * This class provides some static database-related functions (mostly convenience + * wrappers). + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Oliver Klee + */ +class Tx_Phpunit_Service_Database { + /** + * page object which we will use to call enableFields on + * + * @var t3lib_pageSelect + */ + private static $pageForEnableFields = NULL; + + /** + * cached results for the enableFields function + * + * @var array + */ + private static $enableFieldsCache = array(); + + /** + * @var array cache for the results of existsTable with the table names + * as keys and the table SHOW STATUS information (in an array) + * as values + */ + private static $tableNameCache = array(); + + /** + * cache for the results of hasTableColumn with the column names as keys and + * the SHOW COLUMNS field information (in an array) as values + * + * @var array + */ + private static $tableColumnCache = array(); + + /** + * cache for all TCA arrays + * + * @var array + */ + private static $tcaCache = array(); + + /** + * Enables query logging in TYPO3's DB class. + * + * @return void + */ + public static function enableQueryLogging() { + $GLOBALS['TYPO3_DB']->store_lastBuiltQuery = TRUE; + } + + /** + * Wrapper function for t3lib_pageSelect::enableFields() since it is no + * longer accessible statically. + * + * Returns a part of a WHERE clause which will filter out records with + * start/end times or deleted/hidden/fe_groups fields set to values that + * should de-select them according to the current time, preview settings or + * user login. + * Is using the $TCA arrays "ctrl" part where the key "enablefields" + * determines for each table which of these features applies to that table. + * + * @param string $tableName + * table name found in the $TCA array + * @param integer $showHidden + * If $showHidden is set (0/1), any hidden-fields in records are + * ignored. NOTICE: If you call this function, consider what to do + * with the show_hidden parameter. + * @param array $ignoreArray + * Array you can pass where keys can be "disabled", "starttime", + * "endtime", "fe_group" (keys from "enablefields" in TCA) and if set + * they will make sure that part of the clause is not added. Thus + * disables the specific part of the clause. For previewing etc. + * @param boolean $noVersionPreview + * If set, enableFields will be applied regardless of any versioning + * preview settings which might otherwise disable enableFields. + * + * @return string the WHERE clause starting like " AND ...=... AND ...=..." + */ + public static function enableFields( + $tableName, $showHidden = -1, array $ignoreArray = array(), + $noVersionPreview = FALSE + ) { + if (!in_array($showHidden, array(-1, 0, 1))) { + throw new Exception( + '$showHidden may only be -1, 0 or 1, but actually is ' . + $showHidden + ); + } + + // maps $showHidden (-1..1) to (0..2) which ensures valid array keys + $showHiddenKey = $showHidden + 1; + $ignoresKey = serialize($ignoreArray); + $previewKey = intval($noVersionPreview); + if (!isset(self::$enableFieldsCache[$tableName][$showHiddenKey][$ignoresKey][$previewKey])) { + self::retrievePageForEnableFields(); + self::$enableFieldsCache[$tableName][$showHiddenKey][$ignoresKey][$previewKey] + = self::$pageForEnableFields->enableFields( + $tableName, + $showHidden, + $ignoreArray, + $noVersionPreview + ); + } + + return self::$enableFieldsCache[$tableName][$showHiddenKey][$ignoresKey][$previewKey]; + } + + /** + * Makes sure that self::$pageForEnableFields is a page object. + * + * @return void + */ + private static function retrievePageForEnableFields() { + if (!is_object(self::$pageForEnableFields)) { + if (isset($GLOBALS['TSFE']) + && is_object($GLOBALS['TSFE']->sys_page) + ) { + self::$pageForEnableFields = $GLOBALS['TSFE']->sys_page; + } else { + self::$pageForEnableFields + = t3lib_div::makeInstance('t3lib_pageSelect'); + } + } + } + + /** + * Recursively creates a comma-separated list of subpage UIDs from + * a list of pages. The result also includes the original pages. + * The maximum level of recursion can be limited: + * 0 = no recursion (the default value, will return $startPages), + * 1 = only direct child pages, + * ..., + * 250 = all descendants for all sane cases + * + * Note: The returned page list is _not_ sorted. + * + * @param string $startPages + * comma-separated list of page UIDs to start from, must only contain + * numbers and commas, may be empty + * @param integer $recursionDepth + * maximum depth of recursion, must be >= 0 + * + * @return string + * comma-separated list of subpage UIDs including the UIDs provided + * in $startPages, will be empty if $startPages is empty + */ + public static function createRecursivePageList($startPages, $recursionDepth = 0) { + if ($recursionDepth < 0) { + throw new Exception('$recursionDepth must be >= 0.'); + } + if ($recursionDepth == 0) { + return $startPages; + } + if ($startPages == '') { + return ''; + } + + $dbResult = self::select( + 'uid', + 'pages', + 'pid IN (' . $startPages . ')' . self::enableFields('pages') + ); + + $subPages = array(); + while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($dbResult)) { + $subPages[] = $row['uid']; + } + $GLOBALS['TYPO3_DB']->sql_free_result($dbResult); + + if (!empty($subPages)) { + $result = $startPages . ',' . self::createRecursivePageList( + implode(',', $subPages), $recursionDepth - 1 + ); + } else { + $result = $startPages; + } + + return $result; + } + + + //////////////////////////////// + // Wrappers for common queries + //////////////////////////////// + + /** + * Executes a DELETE query. + * + * @param string $tableName + * the name of the table from which to delete, must not be empty + * @param string $whereClause + * the WHERE clause to select the records, may be empty + * + * @return integer the number of affected rows, might be 0 + * + * @throws Tx_Phpunit_Exception_Database if an error has occured + */ + public static function delete($tableName, $whereClause) { + if ($tableName == '') { + throw new Exception('The table name must not be empty.'); + } + + self::enableQueryLogging(); + $dbResult = $GLOBALS['TYPO3_DB']->exec_DELETEquery( + $tableName, $whereClause + ); + if (!$dbResult) { + throw new Tx_Phpunit_Exception_Database(); + } + + return $GLOBALS['TYPO3_DB']->sql_affected_rows(); + } + + /** + * Executes an UPDATE query. + * + * @param string $tableName + * the name of the table to change, must not be empty + * @param string $whereClause + * the WHERE clause to select the records, may be empty + * @param array $fields + * key/value pairs of the fields to change, may be empty + * + * @return integer the number of affected rows, might be 0 + * + * @throws Tx_Phpunit_Exception_Database if an error has occured + */ + public static function update($tableName, $whereClause, array $fields) { + if ($tableName == '') { + throw new Exception('The table name must not be empty.'); + } + + self::enableQueryLogging(); + $dbResult = $GLOBALS['TYPO3_DB']->exec_UPDATEquery( + $tableName, $whereClause, $fields + ); + if (!$dbResult) { + throw new Tx_Phpunit_Exception_Database(); + } + + return $GLOBALS['TYPO3_DB']->sql_affected_rows(); + } + + /** + * Executes an INSERT query. + * + * @param string $tableName + * the name of the table in which the record should be created, + * must not be empty + * @param array $recordData + * key/value pairs of the record to insert, must not be empty + * + * @return integer + * the UID of the created record, will be 0 if the table has no UID column + * + * @throws Tx_Phpunit_Exception_Database if an error has occured + */ + public static function insert($tableName, array $recordData) { + if ($tableName == '') { + throw new Exception('The table name must not be empty.'); + } + if (empty($recordData)) { + throw new Exception('$recordData must not be empty.'); + } + + self::enableQueryLogging(); + $dbResult = $GLOBALS['TYPO3_DB']->exec_INSERTquery( + $tableName, $recordData + ); + if (!$dbResult) { + throw new Tx_Phpunit_Exception_Database(); + } + + return $GLOBALS['TYPO3_DB']->sql_insert_id(); + } + + /** + * Executes a SELECT query. + * + * @param string $fields + * list of fields to select, may be "*", must not be empty + * @param string $tableNames + * comma-separated list of tables from which to select, must not be empty + * @param string $whereClause + * WHERE clause, may be empty + * @param string $groupBy + * GROUP BY field(s), may be empty + * @param string $orderBy + * ORDER BY field(s), may be empty + * @param string $limit + * LIMIT value ([begin,]max), may be empty + * + * @return resource MySQL result pointer + * + * @throws Tx_Phpunit_Exception_Database if an error has occured + */ + public static function select( + $fields, $tableNames, $whereClause = '', $groupBy = '', $orderBy = '', $limit = '' + ) { + if ($tableNames == '') { + throw new Exception('The table names must not be empty.'); + } + if ($fields == '') { + throw new Exception('$fields must not be empty.'); + } + + self::enableQueryLogging(); + $dbResult = $GLOBALS['TYPO3_DB']->exec_SELECTquery( + $fields, $tableNames, $whereClause, $groupBy, $orderBy, $limit + ); + if (!$dbResult) { + throw new Tx_Phpunit_Exception_Database(); + } + + return $dbResult; + } + + /** + * Executes a SELECT query and returns the single result row as an + * associative array. + * + * If there is more than one matching record, only one will be returned. + * + * @param string $fields + * list of fields to select, may be "*", must not be empty + * @param string $tableNames + * comma-separated list of tables from which to select, must not be empty + * @param string $whereClause + * WHERE clause, may be empty + * @param string $groupBy + * GROUP BY field(s), may be empty + * @param string $orderBy + * ORDER BY field(s), may be empty + * @param integer $offset + * the offset to start the result for, must be >= 0 + * + * @return array the single result row, will not be empty + * + * @throws Tx_Phpunit_Exception_Database if an error has occured + * @throws Tx_Phpunit_Exception_EmptyQueryResult if there is no matching record + */ + public static function selectSingle( + $fields, $tableNames, $whereClause = '', $groupBy = '', $orderBy = '', $offset = 0 + ) { + $result = self::selectMultiple( + $fields, $tableNames, $whereClause, + $groupBy, $orderBy, $offset . ',' . 1 + ); + if (empty($result)) { + throw new Tx_Phpunit_Exception_EmptyQueryResult(); + } + + return $result[0]; + } + + /** + * Executes a SELECT query and returns the result rows as a two-dimensional + * associative array. + * + * @param string $fieldNames + * list of fields to select, may be "*", must not be empty + * @param string $tableNames + * comma-separated list of tables from which to select, must not be empty + * @param string $whereClause + * WHERE clause, may be empty + * @param string $groupBy + * GROUP BY field(s), may be empty + * @param string $orderBy + * ORDER BY field(s), may be empty + * @param string $limit + * LIMIT value ([begin,]max), may be empty + * + * @return array + * the query result rows, will be empty if there are no matching records + * + * @throws Tx_Phpunit_Exception_Database if an error has occured + */ + public static function selectMultiple( + $fieldNames, $tableNames, $whereClause = '', $groupBy = '', $orderBy = '', $limit = '' + ) { + $result = array(); + $dbResult = self::select( + $fieldNames, $tableNames, $whereClause, $groupBy, $orderBy, $limit + ); + + while ($recordData = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($dbResult)) { + $result[] = $recordData; + } + $GLOBALS['TYPO3_DB']->sql_free_result($dbResult); + + return $result; + } + + /** + * Executes a SELECT query and returns one column from the result rows as a + * one-dimensional numeric array. + * + * If there is more than one matching record, only one will be returned. + * + * @param string $fieldName + * name of the field to select, must not be empty + * @param string $tableNames + * comma-separated list of tables from which to select, must not be empty + * @param string $whereClause + * WHERE clause, may be empty + * @param string $groupBy + * GROUP BY field(s), may be empty + * @param string $orderBy + * ORDER BY field(s), may be empty + * @param string $limit + * LIMIT value ([begin,]max), may be empty + * + * @return array + * one column from the the query result rows, will be empty if there + * are no matching records + * + * @throws Tx_Phpunit_Exception_Database if an error has occured + */ + public static function selectColumnForMultiple( + $fieldName, $tableNames, $whereClause = '', $groupBy = '', $orderBy = '', $limit = '' + ) { + $rows = self::selectMultiple( + $fieldName, $tableNames, $whereClause, $groupBy, $orderBy, $limit + ); + + $result = array(); + foreach ($rows as $row) { + $result[] = $row[$fieldName]; + } + + return $result; + } + + /** + * Counts the number of matching records in the database for a particular + * WHERE clause. + * + * @param string $tableNames + * comma-separated list of existing tables from which to count, can + * also be a JOIN, must not be empty + * @param string $whereClause + * WHERE clause, may be empty + * + * @return integer the number of matching records, will be >= 0 + * + * @throws Tx_Phpunit_Exception_Database if an error has occured + */ + public static function count($tableNames, $whereClause = '') { + $isOnlyOneTable = ((strpos($tableNames, ',') === FALSE) + && (stripos(trim($tableNames), ' JOIN ') === FALSE)); + if ($isOnlyOneTable && self::tableHasColumnUid($tableNames)) { + // Counting only the "uid" column is faster than counting *. + $columns = 'uid'; + } else { + $columns = '*'; + } + + $result = self::selectSingle( + 'COUNT(' . $columns . ') AS phpunit_counter', $tableNames, $whereClause + ); + + return intval($result['phpunit_counter']); + } + + /** + * Checks whether there are any records in the table given by the first + * parameter $tableName that match a given WHERE clause. + * + * @param string $tableName + * the name of the table to query, must not be empty + * @param string $whereClause + * the WHERE part of the query, may be empty (all records will be + * counted in that case) + * + * @return boolean + * TRUE if there is at least one matching record, FALSE otherwise + */ + public static function existsRecord($tableName, $whereClause = '') { + return (self::count($tableName, $whereClause) > 0); + } + + /** + * Checks whether there is exactly one record in the table given by the + * first parameter $tableName that matches a given WHERE clause. + * + * @param string $tableName + * the name of the table to query, must not be empty + * @param string $whereClause + * the WHERE part of the query, may be empty (all records will be + * counted in that case) + * + * @return boolean + * TRUE if there is exactly one matching record, FALSE otherwise + */ + public static function existsExactlyOneRecord($tableName, $whereClause = '') { + return (self::count($tableName, $whereClause) == 1); + } + + /** + * Checks whether there is a record in the table given by the first + * parameter $tableName that has the given UID. + * + * Important: This function also returns TRUE if there is a deleted or + * hidden record with that particular UID. + * + * @param string $tableName + * the name of the table to query, must not be empty + * @param integer $uid + * the UID of the record to look up, must be > 0 + * @param string $additionalWhereClause + * additional WHERE clause to append, must either start with " AND" + * or be completely empty + * + * @return boolean TRUE if there is a matching record, FALSE otherwise + */ + public static function existsRecordWithUid( + $tableName, $uid, $additionalWhereClause = '' + ) { + if ($uid <= 0) { + throw new Exception('$uid must be > 0.'); + } + + return ( + self::count($tableName, 'uid = ' . $uid . $additionalWhereClause) > 0 + ); + } + + + ///////////////////////////////////// + // Functions concerning table names + ///////////////////////////////////// + + /** + * Returns a list of all table names that are available in the current + * database. + * + * @return array list of table names + */ + public static function getAllTableNames() { + self::retrieveTableNames(); + + return array_keys(self::$tableNameCache); + } + + /** + * Retrieves the table names of the current DB and stores them in + * self::$tableNameCache. + * + * This function does nothing if the table names already have been + * retrieved. + * + * @return void + */ + private static function retrieveTableNames() { + if (!empty(self::$tableNameCache)) { + return; + } + + self::$tableNameCache = $GLOBALS['TYPO3_DB']->admin_get_tables(); + } + + /** + * Checks whether a database table exists. + * + * @param string $tableName + * the name of the table to check for, must not be empty + * + * @return boolean TRUE if the table $tableName exists, FALSE otherwise + */ + public static function existsTable($tableName) { + if ($tableName == '') { + throw new Exception('The table name must not be empty.'); + } + + self::retrieveTableNames(); + + return isset(self::$tableNameCache[$tableName]); + } + + + //////////////////////////////////////////////// + // Functions concerning the columns of a table + //////////////////////////////////////////////// + + /** + * Gets the column data for a table. + * + * @param string $tableName + * the name of the table for which the column names should be + * retrieved, must not be empty + * + * @return array + * the column data for the table $tableName with the column names as + * keys and the SHOW COLUMNS field information (in an array) as values + */ + public static function getColumnsInTable($tableName) { + self::retrieveColumnsForTable($tableName); + + return self::$tableColumnCache[$tableName]; + } + + /** + * Gets the column definition for a field in $tableName. + * + * @param string $tableName + * the name of the table for which the column names should be + * retrieved, must not be empty + * @param string $column + * the name of the field of which to retrieve the definition, + * must not be empty + * + * @return array + * the field definition for the field in $tableName, will not be empty + */ + public static function getColumnDefinition($tableName, $column) { + self::retrieveColumnsForTable($tableName); + + return self::$tableColumnCache[$tableName][$column]; + } + + /** + * Retrieves and caches the column data for the table $tableName. + * + * If the column data for that table already is cached, this function does + * nothing. + * + * @param string $tableName + * the name of the table for which the column names should be + * retrieved, must not be empty + * + * @return void + */ + private static function retrieveColumnsForTable($tableName) { + if (!isset(self::$tableColumnCache[$tableName])) { + if (!self::existsTable($tableName)) { + throw new Exception( + 'The table "' . $tableName . '" does not exist.' + ); + } + + self::$tableColumnCache[$tableName] = $GLOBALS['TYPO3_DB']->admin_get_fields($tableName); + } + } + + /** + * Checks whether a table has a column with a particular name. + * + * To get a boolean TRUE as result, the table must contain a column with the + * given name. + * + * @param string $tableName + * the name of the table to check, must not be empty + * @param string $column + * the column name to check, must not be empty + * + * @return boolean + * TRUE if the column with the provided name exists, FALSE otherwise + */ + public static function tableHasColumn($tableName, $column) { + if ($column == '') { + return FALSE; + } + + self::retrieveColumnsForTable($tableName); + + return isset(self::$tableColumnCache[$tableName][$column]); + } + + /** + * Checks whether a table has a column "uid". + * + * @param string $tableName + * the name of the table to check, must not be empty + * + * @return boolean TRUE if a valid column was found, FALSE otherwise + */ + public static function tableHasColumnUid($tableName) { + return self::tableHasColumn($tableName, 'uid'); + } + + + ///////////////////////////////// + // Functions concerning the TCA + ///////////////////////////////// + + /** + * Returns the TCA for a certain table. + * + * @param string $tableName + * the table name to look up, must not be empty + * + * @return array associative array with the TCA description for this table + */ + public static function getTcaForTable($tableName) { + if (isset(self::$tcaCache[$tableName])) { + return self::$tcaCache[$tableName]; + } + + if (!self::existsTable($tableName)) { + throw new Exception( + 'The table "' . $tableName . '" does not exist.' + ); + } + + t3lib_div::loadTCA($tableName); + if (!isset($GLOBALS['TCA'][$tableName])) { + throw new Exception( + 'The table "' . $tableName . '" has no TCA.' + ); + } + self::$tcaCache[$tableName] = $GLOBALS['TCA'][$tableName]; + + return self::$tcaCache[$tableName]; + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/Service/TestFinder.php b/typo3conf/ext/phpunit/Classes/Service/TestFinder.php new file mode 100644 index 0000000..9fdcd4e --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/Service/TestFinder.php @@ -0,0 +1,405 @@ + +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +/** + * This class provides functions for finding testcases. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Oliver Klee + */ +class Tx_Phpunit_Service_TestFinder implements t3lib_Singleton { + /** + * suffixes that indicate that a file is a testcase + * + * @var array + */ + static protected $testcaseFileSuffixes = array( + 'Test.php', '_testcase.php' + ); + + /** + * allowed test directory names + * + * @var array + */ + static protected $allowedTestDirectoryNames = array('Tests/', 'tests/'); + + /** + * keys of the dummy extensions of the phpunit extension + * + * @var array + */ + static protected $dummyExtensionKeys = array('aaa', 'bbb', 'ccc', 'ddd'); + + /** + * a cache for the result of findTestableCodeForEverything + * + * @var array + */ + protected $allTestableCodeCache = array(); + + /** + * indicates whether $allTestableCodeCache already has been filled + * + * @var boolean + */ + protected $allTestableCodeIsCached = FALSE; + + /** + * The destructor. + */ + public function __destruct() { + } + + /** + * Gets the path of the TYPO3 Core unit tests relative to PATH_site. + * + * If there is no tests directory for the Core, this function will return an empty string. + * + * @return string + * the path of the TYPO3 Core unit tests relative to PATH_site, + * will be empty if there is no Core tests directory + */ + public function getRelativeCoreTestsPath() { + $possibleTestsPath1 = 'tests/'; + $possibleTestsPath2 = 'typo3_src/tests/'; + + if (file_exists(PATH_site . $possibleTestsPath1)) { + $testsPath = $possibleTestsPath1; + } elseif (file_exists(PATH_site . $possibleTestsPath2)) { + $testsPath = $possibleTestsPath2; + } else { + $testsPath = ''; + } + + return $testsPath; + } + + /** + * Gets the absolute path of the TYPO3 Core unit tests. + * + * If there is no tests directory for the Core, this function will return an empty string. + * + * @return string + * the absolute path of the TYPO3 Core unit tests, + * will be empty if there is no Core tests directory + */ + public function getAbsoluteCoreTestsPath() { + if (!$this->hasCoreTests()) { + return ''; + } + + return PATH_site . $this->getRelativeCoreTestsPath(); + } + + /** + * Checks whether the TYPO3 Core has a tests directory. + * + * @return boolean TRUE if the TYPO3 Core has a tests directory, FALSE otherwise + */ + public function hasCoreTests() { + return ($this->getRelativeCoreTestsPath() !== ''); + } + + /** + * Finds all files that are named like test files in the directory $directory + * and recursively all its subdirectories. + * + * @param string $directory + * the absolute path of the directory in which to look for test cases + * + * @return array + * sorted file names of the testcases in the directory $directory relative + * to $directory, will be empty if no testcases have been found + */ + public function findTestCasesInDirectory($directory) { + if ($directory === '') { + throw new InvalidArgumentException('$directory must not be empty.'); + } + if (!is_dir($directory)) { + throw new InvalidArgumentException('The directory '. $directory . ' does not exist.'); + } + if (!is_readable($directory)) { + throw new InvalidArgumentException('The directory '. $directory . ' exists, but is not readable.'); + } + + $directoryLength = strlen($directory); + + $testFiles = array(); + $allPhpFiles = t3lib_div::getAllFilesAndFoldersInPath(array(), $directory, 'php'); + foreach ($allPhpFiles as $filePath) { + if ($this->isTestCaseFileName($filePath)) { + $testFiles[] = substr($filePath, $directoryLength); + } + } + + sort($testFiles, SORT_STRING); + + return $testFiles; + } + + /** + * Checks whether a file name is named like a testcase file name should be. + * + * @param string $path the absolute path of a file to check + * + * @return boolean TRUE if $fileName is names like a proper testcase, FALSE otherwise + */ + protected function isTestCaseFileName($path) { + $fileName = basename($path); + if ($this->isHiddenMacFile($fileName)) { + return FALSE; + } + + $isTestCase = FALSE; + foreach (self::$testcaseFileSuffixes as $suffix) { + if (substr($fileName, - strlen($suffix)) === $suffix) { + $isTestCase = TRUE; + break; + } + } + + return $isTestCase; + } + + /** + * Checks whether $fileName is a hidden Mac file. + * + * @param string $fileName base name of a file to check + * + * @return TRUE if $fileName is a hidden Mac file, FALSE otherwise + */ + protected function isHiddenMacFile($fileName) { + return (substr($fileName, 0, 2) === '._'); + } + + /** + * Checks whether there is testable code for a key. + * + * @param string $key + * the key to check, might be an extension key, the core key or + * any other string (even an empty string) + * + * @return boolean TRUE if there is testable code with the given key, FALSE otherwise + */ + public function existsTestableCodeForKey($key) { + if ($key === '') { + return FALSE; + } + + $allTestableCode = $this->getTestableCodeForEverything(); + + return isset($allTestableCode[$key]); + } + + /** + * Returns the testable code instance for everything, i.e., the core and + * all installed extensions. + * + * @return array + * testable code for everything using the extension keys or the core key + * as array keys, might be empty + */ + public function getTestableCodeForEverything() { + if (!$this->allTestableCodeIsCached) { + $this->allTestableCodeCache = array_merge( + $this->getTestableCodeForCore(), $this->getTestableCodeForExtensions() + ); + + $this->allTestableCodeIsCached = TRUE; + } + + return $this->allTestableCodeCache; + } + + /** + * Returns the testable code for the TYPO3 Core. + * + * @return array + * testable code for the TYPO3 core, will have exactly one element if + * there are Core tests (using the core key as array key), + * will be empty if there are no Core tests + */ + public function getTestableCodeForCore() { + if (!$this->hasCoreTests()) { + return array(); + } + + $coreTests = t3lib_div::makeInstance('Tx_Phpunit_TestableCode'); + $coreTests->setType(Tx_Phpunit_TestableCode::TYPE_CORE); + $coreTests->setKey(Tx_Phpunit_TestableCode::CORE_KEY); + $coreTests->setTitle('TYPO3 Core'); + $coreTests->setCodePath(PATH_site); + $coreTests->setTestsPath($this->getAbsoluteCoreTestsPath()); + $coreTests->setIconPath(t3lib_extMgm::extRelPath('phpunit') . 'Resources/Public/Icons/Typo3.png'); + + return array(Tx_Phpunit_TestableCode::CORE_KEY => $coreTests); + } + + /** + * Returns the testable code for all installed extensions. + * + * Extensions without a test directory and extensions in the "exclude list" + * will be skipped. + * + * @return array + * testable code for the installed extensions using the extension keys + * as array keys, might be empty + */ + public function getTestableCodeForExtensions() { + $result = array(); + + $extensionKeysToExamine = array_diff( + $this->getLoadedExtensionKeys(), + $this->getExcludedExtensionKeys(), $this->getDummyExtensionKeys() + ); + + foreach ($extensionKeysToExamine as $extensionKey) { + try { + $result[$extensionKey] = $this->createTestableCodeForSingleExtension($extensionKey); + } catch (Tx_Phpunit_Exception_NoTestsDirectory $exception) { + // Just skip extensions without a tests directory. + } + } + + return $result; + } + + /** + * Returns the keys of the loaded extensions. + * + * @return array the keys of the loaded extensions, might be empty + */ + protected function getLoadedExtensionKeys() { + if (!isset($GLOBALS['TYPO3_CONF_VARS']['EXT']['extList'])) { + return array(); + } + + return t3lib_div::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['EXT']['extList'], TRUE); + } + + /** + * Returns the keys of the extensions excluded from unit testing via the + * phpunit configuration. + * + * @return array the keys of the excluded extensions, might be empty + */ + protected function getExcludedExtensionKeys() { + if (!isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['excludeextensions'])) { + return array(); + } + + return t3lib_div::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['excludeextensions'], TRUE); + } + + /** + * Returns the keys of the extensions excluded from unit testing because + * they are the dummy extensions of phpunit. + * + * @return array the keys of the dummy extensions, will not be empty + */ + public function getDummyExtensionKeys() { + return self::$dummyExtensionKeys; + } + + /** + * Creates the testable code instance for the extension with the given key. + * + * @param string $extensionKey the key of an installed extension, must not be empty + * + * @return Tx_Phpunit_TestableCode the test-relevant data of the installed extension + * + * @throws Tx_Phpunit_Exception_NoTestsDirectory if the given extension has no tests directory + */ + protected function createTestableCodeForSingleExtension($extensionKey) { + $testsPath = $this->findTestsPathForExtension($extensionKey); + + $testableCode = t3lib_div::makeInstance('Tx_Phpunit_TestableCode'); + $testableCode->setType(Tx_Phpunit_TestableCode::TYPE_EXTENSION); + $testableCode->setKey($extensionKey); + $testableCode->setTitle($this->retrieveExtensionTitle($extensionKey)); + $testableCode->setCodePath(t3lib_extMgm::extPath($extensionKey)); + $testableCode->setTestsPath($testsPath); + $testableCode->setIconPath(t3lib_extMgm::extRelPath($extensionKey) . 'ext_icon.gif'); + + return $testableCode; + } + + /** + * Finds the absolute path to the tests of the extension with the key $extensionKey. + * + * @param string $extensionKey the key of an installed extension, must not be empty + * + * @return string + * the absolute path of the tests directory of the given extension + * (might differ in case from the actual tests directory on case-insensitive + * file systems) + * + * @throws Tx_Phpunit_Exception_NoTestsDirectory if the given extension has no tests directory + */ + protected function findTestsPathForExtension($extensionKey) { + if ($extensionKey === '') { + throw new InvalidArgumentException('$extensionKey must not be empty.'); + } + + $testsPath = ''; + $extensionPath = t3lib_extMgm::extPath($extensionKey); + foreach (self::$allowedTestDirectoryNames as $testDirectoryName) { + if (is_dir($extensionPath . $testDirectoryName)) { + $testsPath = $extensionPath . $testDirectoryName; + break; + } + } + + if ($testsPath === '') { + throw new Tx_Phpunit_Exception_NoTestsDirectory( + 'The extension "' . $extensionKey . '" does not have a tests directory.' + ); + } + + return $testsPath; + } + + /** + * Retrieves the title of an installed extension. + * + * @param string $extensionKey the key of the extension to retrieve, must not be empty + * + * @return string the title of the extension with the given key, might be empty + */ + protected function retrieveExtensionTitle($extensionKey) { + if ($extensionKey === '') { + throw new InvalidArgumentException('$extensionKey must not be empty.'); + } + + $EM_CONF = array(); + $_EXTKEY = $extensionKey; + include(t3lib_extMgm::extPath($extensionKey) . 'ext_emconf.php'); + + return $EM_CONF[$extensionKey]['title']; + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/TestCase.php b/typo3conf/ext/phpunit/Classes/TestCase.php new file mode 100644 index 0000000..1b97281 --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/TestCase.php @@ -0,0 +1,95 @@ + + * @author Kasper Ligaard + * @author Soren Soltveit + * @author Michael Klapper + * @author Oliver Klee + */ +abstract class Tx_Phpunit_TestCase extends PHPUnit_Framework_TestCase { + /** + * whether global variables should be backuped + * + * @var boolean + */ + protected $backupGlobals = FALSE; + + /** + * whether static attributes should be backuped + * + * @var boolean + */ + protected $backupStaticAttributes = FALSE; + + /** + * Roughly simulates the front end although being in the back end. + * + * @deprecated since 3.5.12, will be removed in 3.6.0. Use Tx_Phpunit_Framework::createFakeFrontEnd instead. + * + * @return void + */ + protected function simulateFrontendEnviroment() { + t3lib_div::logDeprecatedFunction(); + + if (isset($GLOBALS['TSFE']) && is_object($GLOBALS['TSFE'])) { + // avoids some memory leaks + unset( + $GLOBALS['TSFE']->tmpl, $GLOBALS['TSFE']->sys_page, $GLOBALS['TSFE']->fe_user, + $GLOBALS['TSFE']->TYPO3_CONF_VARS, $GLOBALS['TSFE']->config, $GLOBALS['TSFE']->TCAcachedExtras, + $GLOBALS['TSFE']->imagesOnPage, $GLOBALS['TSFE']->cObj, $GLOBALS['TSFE']->csConvObj, + $GLOBALS['TSFE']->pagesection_lockObj, $GLOBALS['TSFE']->pages_lockObj + ); + $GLOBALS['TSFE'] = NULL; + $GLOBALS['TT'] = NULL; + } + + $GLOBALS['TT'] = t3lib_div::makeInstance('t3lib_TimeTrackNull'); + $frontEnd = t3lib_div::makeInstance('tslib_fe', $GLOBALS['TYPO3_CONF_VARS'], 0, 0); + + // simulates a normal FE without any logged-in FE or BE user + $frontEnd->beUserLogin = FALSE; + $frontEnd->workspacePreview = ''; + $frontEnd->gr_list = '0,-1'; + + $frontEnd->sys_page = t3lib_div::makeInstance('t3lib_pageSelect'); + $frontEnd->sys_page->init(TRUE); + $frontEnd->initTemplate(); + + // $frontEnd->getConfigArray() doesn't work here because the fake FE + // is not required to have a template. + $frontEnd->config = array(); + + $GLOBALS['TSFE'] = $frontEnd; + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Classes/TestableCode.php b/typo3conf/ext/phpunit/Classes/TestableCode.php new file mode 100644 index 0000000..285134a --- /dev/null +++ b/typo3conf/ext/phpunit/Classes/TestableCode.php @@ -0,0 +1,311 @@ + +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +/** + * This class represents some code that can be tested. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Oliver Klee + */ +class Tx_Phpunit_TestableCode { + /** + * @var integer + */ + const TYPE_UNDEFINED = 0; + /** + * @var integer + */ + const TYPE_EXTENSION = 1; + /** + * @var integer + */ + const TYPE_CORE = 2; + + /** + * @var string + */ + const CORE_KEY = 'typo3'; + + /** + * @var string + */ + protected $key = ''; + + /** + * @var string + */ + protected $title = ''; + + /** + * @var integer + */ + protected $type = self::TYPE_UNDEFINED; + + /** + * @var string + */ + protected $codePath = ''; + + /** + * @var string + */ + protected $testsPath = ''; + + /** + * files that should be excluded from code coverage + * + * @var array + */ + protected $blacklist = array(); + + /** + * files that should be included in code coverage + * + * @var array + */ + protected $whitelist = array(); + + /** + * @var string + */ + protected $iconPath = ''; + + /** + * Returns the key. + * + * The key is intended to be used e.g., for drop-downs. + * + * For extensions, this will be the extension key. For the TYPO3 core, this + * will be "typo3". For out-of-line tests, this will be full path to the + * tested code. + * + * @return string the key, will not be empty + */ + public function getKey() { + return $this->key; + } + + /** + * Sets the key. + * + * The key is intended to be used e.g., for drop-downs. + * + * For extensions, this must be the extension key. For the TYPO3 core, this + * must be "typo3". For out-of-line tests, this must be full path to the + * tested code. + * + * @param string $key the key, must not be empty + * + * @return void + */ + public function setKey($key) { + if ($key === '') { + throw new InvalidArgumentException('$key must not be empty.'); + } + + $this->key = $key; + } + + /** + * Returns the display title. + * + * @return string the title, might be empty + */ + public function getTitle() { + return $this->title; + } + + /** + * Sets the display title. + * + * @param string $title the title, may be empty + * + * @return void + */ + public function setTitle($title) { + $this->title = $title; + } + + /** + * Returns the type of this testable code. + * + * @return integer + * the type, will be either TYPE_UNDEFINED, TYPE_EXTENSION or TYPE_CORE + */ + public function getType() { + return $this->type; + } + + /** + * Sets the type of this testable code. + * + * @param integer $type + * the type, must be either TYPE_EXTENSION or TYPE_CORE + * + * @return void + */ + public function setType($type) { + $allowedTypes = array(self::TYPE_EXTENSION, self::TYPE_CORE); + if (!in_array($type, $allowedTypes, TRUE)) { + throw new InvalidArgumentException( + '$type must be one of TYPE_EXTENSION, TYPE_CORE, but actually was ' . $type . '.' + ); + } + + $this->type = $type; + } + + /** + * Returns the code path. + * + * This is the absolute path of the code that is tested. + * + * @return string the code path, will not be empty + */ + public function getCodePath() { + return $this->codePath; + } + + /** + * Sets the code path. + * + * This is the absolute path of the code that is tested. + * + * @param string $codePath the code path, must not be empty + * + * @return void + */ + public function setCodePath($codePath) { + if ($codePath === '') { + throw new InvalidArgumentException('$codePath must not be empty.'); + } + + $this->codePath = $codePath; + } + + /** + * Returns the tests path. + * + * This is the absolute path of the unit tests. Usually, this path is + * located within the code path. + * + * @return string the tests path, will not be empty + */ + public function getTestsPath() { + return $this->testsPath; + } + + /** + * Sets the tests path. + * + * This is the absolute path of the unit tests. Usually, this path is + * located within the code path. + * + * @param string $testsPath the tests path, must not be empty + * + * @return void + */ + public function setTestsPath($testsPath) { + if ($testsPath === '') { + throw new InvalidArgumentException('$testsPath must not be empty.'); + } + + $this->testsPath = $testsPath; + } + + /** + * Returns the blacklist, i.e., the absolute paths to the files that should + * be excluded from the code coverage report. + * + * @return array + * the absolute paths to the blacklisted files, might be empty + */ + public function getBlacklist() { + return $this->blacklist; + } + + /** + * Sets the blacklist, i.e., the absolute paths to the files that should + * be excluded from the code coverage report. + * + * @param array $files + * the absolute paths to the blacklisted files, may be empty + * + * @return void + */ + public function setBlacklist(array $files) { + $this->blacklist = $files; + } + + /** + * Returns the whitelist, i.e., the absolute paths to the files that should + * be included in the code coverage report. + * + * @return array + * the absolute paths to the whitelisted files, might be empty + */ + public function getWhitelist() { + return $this->whitelist; + } + + /** + * Sets the whitelist, i.e., the absolute paths to the files that should + * be included in the code coverage report. + * + * @param array $files + * the absolute paths to the whitelisted files, may be empty + * + * @return void + */ + public function setWhitelist(array $files) { + $this->whitelist = $files; + } + + /** + * Returns the relative path to the icon associated with this testable code. + * + * @return string the relative icon path, will not be empty + */ + public function getIconPath() { + return $this->iconPath; + } + + /** + * Sets the relative path to the icon associated with this testable code. + * + * @param string $iconPath the icon path, must not be empty + * + * @return void + */ + public function setIconPath($iconPath) { + if ($iconPath === '') { + throw new InvalidArgumentException('$iconPath must not be empty.'); + } + + $this->iconPath = $iconPath; + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Configuration/TCA/TCA.php b/typo3conf/ext/phpunit/Configuration/TCA/TCA.php new file mode 100644 index 0000000..be0d278 --- /dev/null +++ b/typo3conf/ext/phpunit/Configuration/TCA/TCA.php @@ -0,0 +1,91 @@ + $TCA['tx_phpunit_test']['ctrl'], + 'interface' => array( + 'showRecordFieldList' => 'hidden,starttime,endtime,title,related_records', + ), + 'columns' => array( + 'hidden' => array( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden', + 'config' => array( + 'type' => 'check', + 'default' => '0', + ), + ), + 'starttime' => array( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.starttime', + 'config' => array( + 'type' => 'none', + 'size' => '8', + 'max' => '20', + 'eval' => 'date', + 'default' => '0', + 'checkbox' => '0', + ), + ), + 'endtime' => array( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.endtime', + 'config' => array( + 'type' => 'none', + 'size' => '8', + 'max' => '20', + 'eval' => 'date', + 'checkbox' => '0', + 'default' => '0', + 'range' => array( + 'upper' => mktime(0,0,0,12,31,2020), + 'lower' => mktime(0,0,0,date('m')-1,date('d'),date('Y')), + ), + ), + ), + 'title' => array( + 'exclude' => 0, + 'label' => 'LLL:EXT:phpunit/locallang_db.xml:tx_phpunit_test.title', + 'config' => array( + 'type' => 'none', + 'size' => '30', + ), + ), + 'related_records' => array( + 'l10n_mode' => 'exclude', + 'exclude' => 1, + 'label' => 'Related records (m:n relation using an m:n table)', + 'config' => array( + 'type' => 'select', + 'foreign_table' => 'tx_phpunit_test', + 'size' => 4, + 'minitems' => 0, + 'maxitems' => 99, + 'MM' => 'tx_phpunit_test_article_mm', + ), + ), + 'bidirectional' => array( + 'l10n_mode' => 'exclude', + 'exclude' => 1, + 'label' => 'Related records (m:n relation using an m:n table)', + 'config' => array( + 'type' => 'select', + 'foreign_table' => 'tx_phpunit_test', + 'size' => 4, + 'minitems' => 0, + 'maxitems' => 99, + 'MM' => 'tx_phpunit_test_article_mm', + 'MM_opposite_field' => 'related_records', + ), + ), + ), + 'types' => array( + '0' => array('showitem' => 'title;;;;2-2-2, related_records'), + ), + 'palettes' => array( + '1' => array('showitem' => 'starttime, endtime'), + ), +); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/Archive/Tar.php b/typo3conf/ext/phpunit/PEAR/Archive/Tar.php new file mode 100644 index 0000000..33fac9c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/Archive/Tar.php @@ -0,0 +1,1909 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * @category File_Formats + * @package Archive_Tar + * @author Vincent Blavet + * @copyright 1997-2008 The Authors + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Tar.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/Archive_Tar + */ + +require_once 'PEAR.php'; + + +define ('ARCHIVE_TAR_ATT_SEPARATOR', 90001); +define ('ARCHIVE_TAR_END_BLOCK', pack("a512", '')); + +/** +* Creates a (compressed) Tar archive +* +* @author Vincent Blavet +* @version $Revision: 295988 $ +* @license http://www.opensource.org/licenses/bsd-license.php New BSD License +* @package Archive_Tar +*/ +class Archive_Tar extends PEAR +{ + /** + * @var string Name of the Tar + */ + var $_tarname=''; + + /** + * @var boolean if true, the Tar file will be gzipped + */ + var $_compress=false; + + /** + * @var string Type of compression : 'none', 'gz' or 'bz2' + */ + var $_compress_type='none'; + + /** + * @var string Explode separator + */ + var $_separator=' '; + + /** + * @var file descriptor + */ + var $_file=0; + + /** + * @var string Local Tar name of a remote Tar (http:// or ftp://) + */ + var $_temp_tarname=''; + + /** + * @var string regular expression for ignoring files or directories + */ + var $_ignore_regexp=''; + + // {{{ constructor + /** + * Archive_Tar Class constructor. This flavour of the constructor only + * declare a new Archive_Tar object, identifying it by the name of the + * tar file. + * If the compress argument is set the tar will be read or created as a + * gzip or bz2 compressed TAR file. + * + * @param string $p_tarname The name of the tar archive to create + * @param string $p_compress can be null, 'gz' or 'bz2'. This + * parameter indicates if gzip or bz2 compression + * is required. For compatibility reason the + * boolean value 'true' means 'gz'. + * @access public + */ + function Archive_Tar($p_tarname, $p_compress = null) + { + $this->PEAR(); + $this->_compress = false; + $this->_compress_type = 'none'; + if (($p_compress === null) || ($p_compress == '')) { + if (@file_exists($p_tarname)) { + if ($fp = @fopen($p_tarname, "rb")) { + // look for gzip magic cookie + $data = fread($fp, 2); + fclose($fp); + if ($data == "\37\213") { + $this->_compress = true; + $this->_compress_type = 'gz'; + // No sure it's enought for a magic code .... + } elseif ($data == "BZ") { + $this->_compress = true; + $this->_compress_type = 'bz2'; + } + } + } else { + // probably a remote file or some file accessible + // through a stream interface + if (substr($p_tarname, -2) == 'gz') { + $this->_compress = true; + $this->_compress_type = 'gz'; + } elseif ((substr($p_tarname, -3) == 'bz2') || + (substr($p_tarname, -2) == 'bz')) { + $this->_compress = true; + $this->_compress_type = 'bz2'; + } + } + } else { + if (($p_compress === true) || ($p_compress == 'gz')) { + $this->_compress = true; + $this->_compress_type = 'gz'; + } else if ($p_compress == 'bz2') { + $this->_compress = true; + $this->_compress_type = 'bz2'; + } else { + $this->_error("Unsupported compression type '$p_compress'\n". + "Supported types are 'gz' and 'bz2'.\n"); + return false; + } + } + $this->_tarname = $p_tarname; + if ($this->_compress) { // assert zlib or bz2 extension support + if ($this->_compress_type == 'gz') + $extname = 'zlib'; + else if ($this->_compress_type == 'bz2') + $extname = 'bz2'; + + if (!extension_loaded($extname)) { + PEAR::loadExtension($extname); + } + if (!extension_loaded($extname)) { + $this->_error("The extension '$extname' couldn't be found.\n". + "Please make sure your version of PHP was built ". + "with '$extname' support.\n"); + return false; + } + } + } + // }}} + + // {{{ destructor + function _Archive_Tar() + { + $this->_close(); + // ----- Look for a local copy to delete + if ($this->_temp_tarname != '') + @unlink($this->_temp_tarname); + $this->_PEAR(); + } + // }}} + + // {{{ create() + /** + * This method creates the archive file and add the files / directories + * that are listed in $p_filelist. + * If a file with the same name exist and is writable, it is replaced + * by the new tar. + * The method return false and a PEAR error text. + * The $p_filelist parameter can be an array of string, each string + * representing a filename or a directory name with their path if + * needed. It can also be a single string with names separated by a + * single blank. + * For each directory added in the archive, the files and + * sub-directories are also added. + * See also createModify() method for more details. + * + * @param array $p_filelist An array of filenames and directory names, or a + * single string with names separated by a single + * blank space. + * @return true on success, false on error. + * @see createModify() + * @access public + */ + function create($p_filelist) + { + return $this->createModify($p_filelist, '', ''); + } + // }}} + + // {{{ add() + /** + * This method add the files / directories that are listed in $p_filelist in + * the archive. If the archive does not exist it is created. + * The method return false and a PEAR error text. + * The files and directories listed are only added at the end of the archive, + * even if a file with the same name is already archived. + * See also createModify() method for more details. + * + * @param array $p_filelist An array of filenames and directory names, or a + * single string with names separated by a single + * blank space. + * @return true on success, false on error. + * @see createModify() + * @access public + */ + function add($p_filelist) + { + return $this->addModify($p_filelist, '', ''); + } + // }}} + + // {{{ extract() + function extract($p_path='') + { + return $this->extractModify($p_path, ''); + } + // }}} + + // {{{ listContent() + function listContent() + { + $v_list_detail = array(); + + if ($this->_openRead()) { + if (!$this->_extractList('', $v_list_detail, "list", '', '')) { + unset($v_list_detail); + $v_list_detail = 0; + } + $this->_close(); + } + + return $v_list_detail; + } + // }}} + + // {{{ createModify() + /** + * This method creates the archive file and add the files / directories + * that are listed in $p_filelist. + * If the file already exists and is writable, it is replaced by the + * new tar. It is a create and not an add. If the file exists and is + * read-only or is a directory it is not replaced. The method return + * false and a PEAR error text. + * The $p_filelist parameter can be an array of string, each string + * representing a filename or a directory name with their path if + * needed. It can also be a single string with names separated by a + * single blank. + * The path indicated in $p_remove_dir will be removed from the + * memorized path of each file / directory listed when this path + * exists. By default nothing is removed (empty path '') + * The path indicated in $p_add_dir will be added at the beginning of + * the memorized path of each file / directory listed. However it can + * be set to empty ''. The adding of a path is done after the removing + * of path. + * The path add/remove ability enables the user to prepare an archive + * for extraction in a different path than the origin files are. + * See also addModify() method for file adding properties. + * + * @param array $p_filelist An array of filenames and directory names, + * or a single string with names separated by + * a single blank space. + * @param string $p_add_dir A string which contains a path to be added + * to the memorized path of each element in + * the list. + * @param string $p_remove_dir A string which contains a path to be + * removed from the memorized path of each + * element in the list, when relevant. + * @return boolean true on success, false on error. + * @access public + * @see addModify() + */ + function createModify($p_filelist, $p_add_dir, $p_remove_dir='') + { + $v_result = true; + + if (!$this->_openWrite()) + return false; + + if ($p_filelist != '') { + if (is_array($p_filelist)) + $v_list = $p_filelist; + elseif (is_string($p_filelist)) + $v_list = explode($this->_separator, $p_filelist); + else { + $this->_cleanFile(); + $this->_error('Invalid file list'); + return false; + } + + $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir); + } + + if ($v_result) { + $this->_writeFooter(); + $this->_close(); + } else + $this->_cleanFile(); + + return $v_result; + } + // }}} + + // {{{ addModify() + /** + * This method add the files / directories listed in $p_filelist at the + * end of the existing archive. If the archive does not yet exists it + * is created. + * The $p_filelist parameter can be an array of string, each string + * representing a filename or a directory name with their path if + * needed. It can also be a single string with names separated by a + * single blank. + * The path indicated in $p_remove_dir will be removed from the + * memorized path of each file / directory listed when this path + * exists. By default nothing is removed (empty path '') + * The path indicated in $p_add_dir will be added at the beginning of + * the memorized path of each file / directory listed. However it can + * be set to empty ''. The adding of a path is done after the removing + * of path. + * The path add/remove ability enables the user to prepare an archive + * for extraction in a different path than the origin files are. + * If a file/dir is already in the archive it will only be added at the + * end of the archive. There is no update of the existing archived + * file/dir. However while extracting the archive, the last file will + * replace the first one. This results in a none optimization of the + * archive size. + * If a file/dir does not exist the file/dir is ignored. However an + * error text is send to PEAR error. + * If a file/dir is not readable the file/dir is ignored. However an + * error text is send to PEAR error. + * + * @param array $p_filelist An array of filenames and directory + * names, or a single string with names + * separated by a single blank space. + * @param string $p_add_dir A string which contains a path to be + * added to the memorized path of each + * element in the list. + * @param string $p_remove_dir A string which contains a path to be + * removed from the memorized path of + * each element in the list, when + * relevant. + * @return true on success, false on error. + * @access public + */ + function addModify($p_filelist, $p_add_dir, $p_remove_dir='') + { + $v_result = true; + + if (!$this->_isArchive()) + $v_result = $this->createModify($p_filelist, $p_add_dir, + $p_remove_dir); + else { + if (is_array($p_filelist)) + $v_list = $p_filelist; + elseif (is_string($p_filelist)) + $v_list = explode($this->_separator, $p_filelist); + else { + $this->_error('Invalid file list'); + return false; + } + + $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir); + } + + return $v_result; + } + // }}} + + // {{{ addString() + /** + * This method add a single string as a file at the + * end of the existing archive. If the archive does not yet exists it + * is created. + * + * @param string $p_filename A string which contains the full + * filename path that will be associated + * with the string. + * @param string $p_string The content of the file added in + * the archive. + * @return true on success, false on error. + * @access public + */ + function addString($p_filename, $p_string) + { + $v_result = true; + + if (!$this->_isArchive()) { + if (!$this->_openWrite()) { + return false; + } + $this->_close(); + } + + if (!$this->_openAppend()) + return false; + + // Need to check the get back to the temporary file ? .... + $v_result = $this->_addString($p_filename, $p_string); + + $this->_writeFooter(); + + $this->_close(); + + return $v_result; + } + // }}} + + // {{{ extractModify() + /** + * This method extract all the content of the archive in the directory + * indicated by $p_path. When relevant the memorized path of the + * files/dir can be modified by removing the $p_remove_path path at the + * beginning of the file/dir path. + * While extracting a file, if the directory path does not exists it is + * created. + * While extracting a file, if the file already exists it is replaced + * without looking for last modification date. + * While extracting a file, if the file already exists and is write + * protected, the extraction is aborted. + * While extracting a file, if a directory with the same name already + * exists, the extraction is aborted. + * While extracting a directory, if a file with the same name already + * exists, the extraction is aborted. + * While extracting a file/directory if the destination directory exist + * and is write protected, or does not exist but can not be created, + * the extraction is aborted. + * If after extraction an extracted file does not show the correct + * stored file size, the extraction is aborted. + * When the extraction is aborted, a PEAR error text is set and false + * is returned. However the result can be a partial extraction that may + * need to be manually cleaned. + * + * @param string $p_path The path of the directory where the + * files/dir need to by extracted. + * @param string $p_remove_path Part of the memorized path that can be + * removed if present at the beginning of + * the file/dir path. + * @return boolean true on success, false on error. + * @access public + * @see extractList() + */ + function extractModify($p_path, $p_remove_path) + { + $v_result = true; + $v_list_detail = array(); + + if ($v_result = $this->_openRead()) { + $v_result = $this->_extractList($p_path, $v_list_detail, + "complete", 0, $p_remove_path); + $this->_close(); + } + + return $v_result; + } + // }}} + + // {{{ extractInString() + /** + * This method extract from the archive one file identified by $p_filename. + * The return value is a string with the file content, or NULL on error. + * @param string $p_filename The path of the file to extract in a string. + * @return a string with the file content or NULL. + * @access public + */ + function extractInString($p_filename) + { + if ($this->_openRead()) { + $v_result = $this->_extractInString($p_filename); + $this->_close(); + } else { + $v_result = NULL; + } + + return $v_result; + } + // }}} + + // {{{ extractList() + /** + * This method extract from the archive only the files indicated in the + * $p_filelist. These files are extracted in the current directory or + * in the directory indicated by the optional $p_path parameter. + * If indicated the $p_remove_path can be used in the same way as it is + * used in extractModify() method. + * @param array $p_filelist An array of filenames and directory names, + * or a single string with names separated + * by a single blank space. + * @param string $p_path The path of the directory where the + * files/dir need to by extracted. + * @param string $p_remove_path Part of the memorized path that can be + * removed if present at the beginning of + * the file/dir path. + * @return true on success, false on error. + * @access public + * @see extractModify() + */ + function extractList($p_filelist, $p_path='', $p_remove_path='') + { + $v_result = true; + $v_list_detail = array(); + + if (is_array($p_filelist)) + $v_list = $p_filelist; + elseif (is_string($p_filelist)) + $v_list = explode($this->_separator, $p_filelist); + else { + $this->_error('Invalid string list'); + return false; + } + + if ($v_result = $this->_openRead()) { + $v_result = $this->_extractList($p_path, $v_list_detail, "partial", + $v_list, $p_remove_path); + $this->_close(); + } + + return $v_result; + } + // }}} + + // {{{ setAttribute() + /** + * This method set specific attributes of the archive. It uses a variable + * list of parameters, in the format attribute code + attribute values : + * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ','); + * @param mixed $argv variable list of attributes and values + * @return true on success, false on error. + * @access public + */ + function setAttribute() + { + $v_result = true; + + // ----- Get the number of variable list of arguments + if (($v_size = func_num_args()) == 0) { + return true; + } + + // ----- Get the arguments + $v_att_list = &func_get_args(); + + // ----- Read the attributes + $i=0; + while ($i<$v_size) { + + // ----- Look for next option + switch ($v_att_list[$i]) { + // ----- Look for options that request a string value + case ARCHIVE_TAR_ATT_SEPARATOR : + // ----- Check the number of parameters + if (($i+1) >= $v_size) { + $this->_error('Invalid number of parameters for ' + .'attribute ARCHIVE_TAR_ATT_SEPARATOR'); + return false; + } + + // ----- Get the value + $this->_separator = $v_att_list[$i+1]; + $i++; + break; + + default : + $this->_error('Unknow attribute code '.$v_att_list[$i].''); + return false; + } + + // ----- Next attribute + $i++; + } + + return $v_result; + } + // }}} + + // {{{ setIgnoreRegexp() + /** + * This method sets the regular expression for ignoring files and directories + * at import, for example: + * $arch->setIgnoreRegexp("#CVS|\.svn#"); + * @param string $regexp regular expression defining which files or directories to ignore + * @access public + */ + function setIgnoreRegexp($regexp) + { + $this->_ignore_regexp = $regexp; + } + // }}} + + // {{{ setIgnoreList() + /** + * This method sets the regular expression for ignoring all files and directories + * matching the filenames in the array list at import, for example: + * $arch->setIgnoreList(array('CVS', '.svn', 'bin/tool')); + * @param array $list a list of file or directory names to ignore + * @access public + */ + function setIgnoreList($list) + { + $regexp = str_replace(array('#', '.', '^', '$'), array('\#', '\.', '\^', '\$'), $list); + $regexp = '#/'.join('$|/', $list).'#'; + $this->setIgnoreRegexp($regexp); + } + // }}} + + // {{{ _error() + function _error($p_message) + { + // ----- To be completed + $this->raiseError($p_message); + } + // }}} + + // {{{ _warning() + function _warning($p_message) + { + // ----- To be completed + $this->raiseError($p_message); + } + // }}} + + // {{{ _isArchive() + function _isArchive($p_filename=NULL) + { + if ($p_filename == NULL) { + $p_filename = $this->_tarname; + } + clearstatcache(); + return @is_file($p_filename) && !@is_link($p_filename); + } + // }}} + + // {{{ _openWrite() + function _openWrite() + { + if ($this->_compress_type == 'gz') + $this->_file = @gzopen($this->_tarname, "wb9"); + else if ($this->_compress_type == 'bz2') + $this->_file = @bzopen($this->_tarname, "w"); + else if ($this->_compress_type == 'none') + $this->_file = @fopen($this->_tarname, "wb"); + else + $this->_error('Unknown or missing compression type (' + .$this->_compress_type.')'); + + if ($this->_file == 0) { + $this->_error('Unable to open in write mode \'' + .$this->_tarname.'\''); + return false; + } + + return true; + } + // }}} + + // {{{ _openRead() + function _openRead() + { + if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') { + + // ----- Look if a local copy need to be done + if ($this->_temp_tarname == '') { + $this->_temp_tarname = uniqid('tar').'.tmp'; + if (!$v_file_from = @fopen($this->_tarname, 'rb')) { + $this->_error('Unable to open in read mode \'' + .$this->_tarname.'\''); + $this->_temp_tarname = ''; + return false; + } + if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) { + $this->_error('Unable to open in write mode \'' + .$this->_temp_tarname.'\''); + $this->_temp_tarname = ''; + return false; + } + while ($v_data = @fread($v_file_from, 1024)) + @fwrite($v_file_to, $v_data); + @fclose($v_file_from); + @fclose($v_file_to); + } + + // ----- File to open if the local copy + $v_filename = $this->_temp_tarname; + + } else + // ----- File to open if the normal Tar file + $v_filename = $this->_tarname; + + if ($this->_compress_type == 'gz') + $this->_file = @gzopen($v_filename, "rb"); + else if ($this->_compress_type == 'bz2') + $this->_file = @bzopen($v_filename, "r"); + else if ($this->_compress_type == 'none') + $this->_file = @fopen($v_filename, "rb"); + else + $this->_error('Unknown or missing compression type (' + .$this->_compress_type.')'); + + if ($this->_file == 0) { + $this->_error('Unable to open in read mode \''.$v_filename.'\''); + return false; + } + + return true; + } + // }}} + + // {{{ _openReadWrite() + function _openReadWrite() + { + if ($this->_compress_type == 'gz') + $this->_file = @gzopen($this->_tarname, "r+b"); + else if ($this->_compress_type == 'bz2') { + $this->_error('Unable to open bz2 in read/write mode \'' + .$this->_tarname.'\' (limitation of bz2 extension)'); + return false; + } else if ($this->_compress_type == 'none') + $this->_file = @fopen($this->_tarname, "r+b"); + else + $this->_error('Unknown or missing compression type (' + .$this->_compress_type.')'); + + if ($this->_file == 0) { + $this->_error('Unable to open in read/write mode \'' + .$this->_tarname.'\''); + return false; + } + + return true; + } + // }}} + + // {{{ _close() + function _close() + { + //if (isset($this->_file)) { + if (is_resource($this->_file)) { + if ($this->_compress_type == 'gz') + @gzclose($this->_file); + else if ($this->_compress_type == 'bz2') + @bzclose($this->_file); + else if ($this->_compress_type == 'none') + @fclose($this->_file); + else + $this->_error('Unknown or missing compression type (' + .$this->_compress_type.')'); + + $this->_file = 0; + } + + // ----- Look if a local copy need to be erase + // Note that it might be interesting to keep the url for a time : ToDo + if ($this->_temp_tarname != '') { + @unlink($this->_temp_tarname); + $this->_temp_tarname = ''; + } + + return true; + } + // }}} + + // {{{ _cleanFile() + function _cleanFile() + { + $this->_close(); + + // ----- Look for a local copy + if ($this->_temp_tarname != '') { + // ----- Remove the local copy but not the remote tarname + @unlink($this->_temp_tarname); + $this->_temp_tarname = ''; + } else { + // ----- Remove the local tarname file + @unlink($this->_tarname); + } + $this->_tarname = ''; + + return true; + } + // }}} + + // {{{ _writeBlock() + function _writeBlock($p_binary_data, $p_len=null) + { + if (is_resource($this->_file)) { + if ($p_len === null) { + if ($this->_compress_type == 'gz') + @gzputs($this->_file, $p_binary_data); + else if ($this->_compress_type == 'bz2') + @bzwrite($this->_file, $p_binary_data); + else if ($this->_compress_type == 'none') + @fputs($this->_file, $p_binary_data); + else + $this->_error('Unknown or missing compression type (' + .$this->_compress_type.')'); + } else { + if ($this->_compress_type == 'gz') + @gzputs($this->_file, $p_binary_data, $p_len); + else if ($this->_compress_type == 'bz2') + @bzwrite($this->_file, $p_binary_data, $p_len); + else if ($this->_compress_type == 'none') + @fputs($this->_file, $p_binary_data, $p_len); + else + $this->_error('Unknown or missing compression type (' + .$this->_compress_type.')'); + + } + } + return true; + } + // }}} + + // {{{ _readBlock() + function _readBlock() + { + $v_block = null; + if (is_resource($this->_file)) { + if ($this->_compress_type == 'gz') + $v_block = @gzread($this->_file, 512); + else if ($this->_compress_type == 'bz2') + $v_block = @bzread($this->_file, 512); + else if ($this->_compress_type == 'none') + $v_block = @fread($this->_file, 512); + else + $this->_error('Unknown or missing compression type (' + .$this->_compress_type.')'); + } + return $v_block; + } + // }}} + + // {{{ _jumpBlock() + function _jumpBlock($p_len=null) + { + if (is_resource($this->_file)) { + if ($p_len === null) + $p_len = 1; + + if ($this->_compress_type == 'gz') { + @gzseek($this->_file, gztell($this->_file)+($p_len*512)); + } + else if ($this->_compress_type == 'bz2') { + // ----- Replace missing bztell() and bzseek() + for ($i=0; $i<$p_len; $i++) + $this->_readBlock(); + } else if ($this->_compress_type == 'none') + @fseek($this->_file, $p_len*512, SEEK_CUR); + else + $this->_error('Unknown or missing compression type (' + .$this->_compress_type.')'); + + } + return true; + } + // }}} + + // {{{ _writeFooter() + function _writeFooter() + { + if (is_resource($this->_file)) { + // ----- Write the last 0 filled block for end of archive + $v_binary_data = pack('a1024', ''); + $this->_writeBlock($v_binary_data); + } + return true; + } + // }}} + + // {{{ _addList() + function _addList($p_list, $p_add_dir, $p_remove_dir) + { + $v_result=true; + $v_header = array(); + + // ----- Remove potential windows directory separator + $p_add_dir = $this->_translateWinPath($p_add_dir); + $p_remove_dir = $this->_translateWinPath($p_remove_dir, false); + + if (!$this->_file) { + $this->_error('Invalid file descriptor'); + return false; + } + + if (sizeof($p_list) == 0) + return true; + + foreach ($p_list as $v_filename) { + if (!$v_result) { + break; + } + + // ----- Skip the current tar name + if ($v_filename == $this->_tarname) + continue; + + if ($v_filename == '') + continue; + + // ----- ignore files and directories matching the ignore regular expression + if ($this->_ignore_regexp && preg_match($this->_ignore_regexp, '/'.$v_filename)) { + $this->_warning("File '$v_filename' ignored"); + continue; + } + + if (!file_exists($v_filename)) { + $this->_warning("File '$v_filename' does not exist"); + continue; + } + + // ----- Add the file or directory header + if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir)) + return false; + + if (@is_dir($v_filename) && !@is_link($v_filename)) { + if (!($p_hdir = opendir($v_filename))) { + $this->_warning("Directory '$v_filename' can not be read"); + continue; + } + while (false !== ($p_hitem = readdir($p_hdir))) { + if (($p_hitem != '.') && ($p_hitem != '..')) { + if ($v_filename != ".") + $p_temp_list[0] = $v_filename.'/'.$p_hitem; + else + $p_temp_list[0] = $p_hitem; + + $v_result = $this->_addList($p_temp_list, + $p_add_dir, + $p_remove_dir); + } + } + + unset($p_temp_list); + unset($p_hdir); + unset($p_hitem); + } + } + + return $v_result; + } + // }}} + + // {{{ _addFile() + function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir) + { + if (!$this->_file) { + $this->_error('Invalid file descriptor'); + return false; + } + + if ($p_filename == '') { + $this->_error('Invalid file name'); + return false; + } + + // ----- Calculate the stored filename + $p_filename = $this->_translateWinPath($p_filename, false);; + $v_stored_filename = $p_filename; + if (strcmp($p_filename, $p_remove_dir) == 0) { + return true; + } + if ($p_remove_dir != '') { + if (substr($p_remove_dir, -1) != '/') + $p_remove_dir .= '/'; + + if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) + $v_stored_filename = substr($p_filename, strlen($p_remove_dir)); + } + $v_stored_filename = $this->_translateWinPath($v_stored_filename); + if ($p_add_dir != '') { + if (substr($p_add_dir, -1) == '/') + $v_stored_filename = $p_add_dir.$v_stored_filename; + else + $v_stored_filename = $p_add_dir.'/'.$v_stored_filename; + } + + $v_stored_filename = $this->_pathReduction($v_stored_filename); + + if ($this->_isArchive($p_filename)) { + if (($v_file = @fopen($p_filename, "rb")) == 0) { + $this->_warning("Unable to open file '".$p_filename + ."' in binary read mode"); + return true; + } + + if (!$this->_writeHeader($p_filename, $v_stored_filename)) + return false; + + while (($v_buffer = fread($v_file, 512)) != '') { + $v_binary_data = pack("a512", "$v_buffer"); + $this->_writeBlock($v_binary_data); + } + + fclose($v_file); + + } else { + // ----- Only header for dir + if (!$this->_writeHeader($p_filename, $v_stored_filename)) + return false; + } + + return true; + } + // }}} + + // {{{ _addString() + function _addString($p_filename, $p_string) + { + if (!$this->_file) { + $this->_error('Invalid file descriptor'); + return false; + } + + if ($p_filename == '') { + $this->_error('Invalid file name'); + return false; + } + + // ----- Calculate the stored filename + $p_filename = $this->_translateWinPath($p_filename, false);; + + if (!$this->_writeHeaderBlock($p_filename, strlen($p_string), + time(), 384, "", 0, 0)) + return false; + + $i=0; + while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') { + $v_binary_data = pack("a512", $v_buffer); + $this->_writeBlock($v_binary_data); + } + + return true; + } + // }}} + + // {{{ _writeHeader() + function _writeHeader($p_filename, $p_stored_filename) + { + if ($p_stored_filename == '') + $p_stored_filename = $p_filename; + $v_reduce_filename = $this->_pathReduction($p_stored_filename); + + if (strlen($v_reduce_filename) > 99) { + if (!$this->_writeLongHeader($v_reduce_filename)) + return false; + } + + $v_info = lstat($p_filename); + $v_uid = sprintf("%07s", DecOct($v_info[4])); + $v_gid = sprintf("%07s", DecOct($v_info[5])); + $v_perms = sprintf("%07s", DecOct($v_info['mode'] & 000777)); + + $v_mtime = sprintf("%011s", DecOct($v_info['mtime'])); + + $v_linkname = ''; + + if (@is_link($p_filename)) { + $v_typeflag = '2'; + $v_linkname = readlink($p_filename); + $v_size = sprintf("%011s", DecOct(0)); + } elseif (@is_dir($p_filename)) { + $v_typeflag = "5"; + $v_size = sprintf("%011s", DecOct(0)); + } else { + $v_typeflag = '0'; + clearstatcache(); + $v_size = sprintf("%011s", DecOct($v_info['size'])); + } + + $v_magic = 'ustar '; + + $v_version = ' '; + + if (function_exists('posix_getpwuid')) + { + $userinfo = posix_getpwuid($v_info[4]); + $groupinfo = posix_getgrgid($v_info[5]); + + $v_uname = $userinfo['name']; + $v_gname = $groupinfo['name']; + } + else + { + $v_uname = ''; + $v_gname = ''; + } + + $v_devmajor = ''; + + $v_devminor = ''; + + $v_prefix = ''; + + $v_binary_data_first = pack("a100a8a8a8a12a12", + $v_reduce_filename, $v_perms, $v_uid, + $v_gid, $v_size, $v_mtime); + $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", + $v_typeflag, $v_linkname, $v_magic, + $v_version, $v_uname, $v_gname, + $v_devmajor, $v_devminor, $v_prefix, ''); + + // ----- Calculate the checksum + $v_checksum = 0; + // ..... First part of the header + for ($i=0; $i<148; $i++) + $v_checksum += ord(substr($v_binary_data_first,$i,1)); + // ..... Ignore the checksum value and replace it by ' ' (space) + for ($i=148; $i<156; $i++) + $v_checksum += ord(' '); + // ..... Last part of the header + for ($i=156, $j=0; $i<512; $i++, $j++) + $v_checksum += ord(substr($v_binary_data_last,$j,1)); + + // ----- Write the first 148 bytes of the header in the archive + $this->_writeBlock($v_binary_data_first, 148); + + // ----- Write the calculated checksum + $v_checksum = sprintf("%06s ", DecOct($v_checksum)); + $v_binary_data = pack("a8", $v_checksum); + $this->_writeBlock($v_binary_data, 8); + + // ----- Write the last 356 bytes of the header in the archive + $this->_writeBlock($v_binary_data_last, 356); + + return true; + } + // }}} + + // {{{ _writeHeaderBlock() + function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0, + $p_type='', $p_uid=0, $p_gid=0) + { + $p_filename = $this->_pathReduction($p_filename); + + if (strlen($p_filename) > 99) { + if (!$this->_writeLongHeader($p_filename)) + return false; + } + + if ($p_type == "5") { + $v_size = sprintf("%011s", DecOct(0)); + } else { + $v_size = sprintf("%011s", DecOct($p_size)); + } + + $v_uid = sprintf("%07s", DecOct($p_uid)); + $v_gid = sprintf("%07s", DecOct($p_gid)); + $v_perms = sprintf("%07s", DecOct($p_perms & 000777)); + + $v_mtime = sprintf("%11s", DecOct($p_mtime)); + + $v_linkname = ''; + + $v_magic = 'ustar '; + + $v_version = ' '; + + if (function_exists('posix_getpwuid')) + { + $userinfo = posix_getpwuid($p_uid); + $groupinfo = posix_getgrgid($p_gid); + + $v_uname = $userinfo['name']; + $v_gname = $groupinfo['name']; + } + else + { + $v_uname = ''; + $v_gname = ''; + } + + $v_devmajor = ''; + + $v_devminor = ''; + + $v_prefix = ''; + + $v_binary_data_first = pack("a100a8a8a8a12A12", + $p_filename, $v_perms, $v_uid, $v_gid, + $v_size, $v_mtime); + $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", + $p_type, $v_linkname, $v_magic, + $v_version, $v_uname, $v_gname, + $v_devmajor, $v_devminor, $v_prefix, ''); + + // ----- Calculate the checksum + $v_checksum = 0; + // ..... First part of the header + for ($i=0; $i<148; $i++) + $v_checksum += ord(substr($v_binary_data_first,$i,1)); + // ..... Ignore the checksum value and replace it by ' ' (space) + for ($i=148; $i<156; $i++) + $v_checksum += ord(' '); + // ..... Last part of the header + for ($i=156, $j=0; $i<512; $i++, $j++) + $v_checksum += ord(substr($v_binary_data_last,$j,1)); + + // ----- Write the first 148 bytes of the header in the archive + $this->_writeBlock($v_binary_data_first, 148); + + // ----- Write the calculated checksum + $v_checksum = sprintf("%06s ", DecOct($v_checksum)); + $v_binary_data = pack("a8", $v_checksum); + $this->_writeBlock($v_binary_data, 8); + + // ----- Write the last 356 bytes of the header in the archive + $this->_writeBlock($v_binary_data_last, 356); + + return true; + } + // }}} + + // {{{ _writeLongHeader() + function _writeLongHeader($p_filename) + { + $v_size = sprintf("%11s ", DecOct(strlen($p_filename))); + + $v_typeflag = 'L'; + + $v_linkname = ''; + + $v_magic = ''; + + $v_version = ''; + + $v_uname = ''; + + $v_gname = ''; + + $v_devmajor = ''; + + $v_devminor = ''; + + $v_prefix = ''; + + $v_binary_data_first = pack("a100a8a8a8a12a12", + '././@LongLink', 0, 0, 0, $v_size, 0); + $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", + $v_typeflag, $v_linkname, $v_magic, + $v_version, $v_uname, $v_gname, + $v_devmajor, $v_devminor, $v_prefix, ''); + + // ----- Calculate the checksum + $v_checksum = 0; + // ..... First part of the header + for ($i=0; $i<148; $i++) + $v_checksum += ord(substr($v_binary_data_first,$i,1)); + // ..... Ignore the checksum value and replace it by ' ' (space) + for ($i=148; $i<156; $i++) + $v_checksum += ord(' '); + // ..... Last part of the header + for ($i=156, $j=0; $i<512; $i++, $j++) + $v_checksum += ord(substr($v_binary_data_last,$j,1)); + + // ----- Write the first 148 bytes of the header in the archive + $this->_writeBlock($v_binary_data_first, 148); + + // ----- Write the calculated checksum + $v_checksum = sprintf("%06s ", DecOct($v_checksum)); + $v_binary_data = pack("a8", $v_checksum); + $this->_writeBlock($v_binary_data, 8); + + // ----- Write the last 356 bytes of the header in the archive + $this->_writeBlock($v_binary_data_last, 356); + + // ----- Write the filename as content of the block + $i=0; + while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') { + $v_binary_data = pack("a512", "$v_buffer"); + $this->_writeBlock($v_binary_data); + } + + return true; + } + // }}} + + // {{{ _readHeader() + function _readHeader($v_binary_data, &$v_header) + { + if (strlen($v_binary_data)==0) { + $v_header['filename'] = ''; + return true; + } + + if (strlen($v_binary_data) != 512) { + $v_header['filename'] = ''; + $this->_error('Invalid block size : '.strlen($v_binary_data)); + return false; + } + + if (!is_array($v_header)) { + $v_header = array(); + } + // ----- Calculate the checksum + $v_checksum = 0; + // ..... First part of the header + for ($i=0; $i<148; $i++) + $v_checksum+=ord(substr($v_binary_data,$i,1)); + // ..... Ignore the checksum value and replace it by ' ' (space) + for ($i=148; $i<156; $i++) + $v_checksum += ord(' '); + // ..... Last part of the header + for ($i=156; $i<512; $i++) + $v_checksum+=ord(substr($v_binary_data,$i,1)); + + $v_data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" + ."a8checksum/a1typeflag/a100link/a6magic/a2version/" + ."a32uname/a32gname/a8devmajor/a8devminor", + $v_binary_data); + + // ----- Extract the checksum + $v_header['checksum'] = OctDec(trim($v_data['checksum'])); + if ($v_header['checksum'] != $v_checksum) { + $v_header['filename'] = ''; + + // ----- Look for last block (empty block) + if (($v_checksum == 256) && ($v_header['checksum'] == 0)) + return true; + + $this->_error('Invalid checksum for file "'.$v_data['filename'] + .'" : '.$v_checksum.' calculated, ' + .$v_header['checksum'].' expected'); + return false; + } + + // ----- Extract the properties + $v_header['filename'] = $v_data['filename']; + if ($this->_maliciousFilename($v_header['filename'])) { + $this->_error('Malicious .tar detected, file "' . $v_header['filename'] . + '" will not install in desired directory tree'); + return false; + } + $v_header['mode'] = OctDec(trim($v_data['mode'])); + $v_header['uid'] = OctDec(trim($v_data['uid'])); + $v_header['gid'] = OctDec(trim($v_data['gid'])); + $v_header['size'] = OctDec(trim($v_data['size'])); + $v_header['mtime'] = OctDec(trim($v_data['mtime'])); + if (($v_header['typeflag'] = $v_data['typeflag']) == "5") { + $v_header['size'] = 0; + } + $v_header['link'] = trim($v_data['link']); + /* ----- All these fields are removed form the header because + they do not carry interesting info + $v_header[magic] = trim($v_data[magic]); + $v_header[version] = trim($v_data[version]); + $v_header[uname] = trim($v_data[uname]); + $v_header[gname] = trim($v_data[gname]); + $v_header[devmajor] = trim($v_data[devmajor]); + $v_header[devminor] = trim($v_data[devminor]); + */ + + return true; + } + // }}} + + // {{{ _maliciousFilename() + /** + * Detect and report a malicious file name + * + * @param string $file + * @return bool + * @access private + */ + function _maliciousFilename($file) + { + if (strpos($file, '/../') !== false) { + return true; + } + if (strpos($file, '../') === 0) { + return true; + } + return false; + } + // }}} + + // {{{ _readLongHeader() + function _readLongHeader(&$v_header) + { + $v_filename = ''; + $n = floor($v_header['size']/512); + for ($i=0; $i<$n; $i++) { + $v_content = $this->_readBlock(); + $v_filename .= $v_content; + } + if (($v_header['size'] % 512) != 0) { + $v_content = $this->_readBlock(); + $v_filename .= trim($v_content); + } + + // ----- Read the next header + $v_binary_data = $this->_readBlock(); + + if (!$this->_readHeader($v_binary_data, $v_header)) + return false; + + $v_filename = trim($v_filename); + $v_header['filename'] = $v_filename; + if ($this->_maliciousFilename($v_filename)) { + $this->_error('Malicious .tar detected, file "' . $v_filename . + '" will not install in desired directory tree'); + return false; + } + + return true; + } + // }}} + + // {{{ _extractInString() + /** + * This method extract from the archive one file identified by $p_filename. + * The return value is a string with the file content, or NULL on error. + * @param string $p_filename The path of the file to extract in a string. + * @return a string with the file content or NULL. + * @access private + */ + function _extractInString($p_filename) + { + $v_result_str = ""; + + While (strlen($v_binary_data = $this->_readBlock()) != 0) + { + if (!$this->_readHeader($v_binary_data, $v_header)) + return NULL; + + if ($v_header['filename'] == '') + continue; + + // ----- Look for long filename + if ($v_header['typeflag'] == 'L') { + if (!$this->_readLongHeader($v_header)) + return NULL; + } + + if ($v_header['filename'] == $p_filename) { + if ($v_header['typeflag'] == "5") { + $this->_error('Unable to extract in string a directory ' + .'entry {'.$v_header['filename'].'}'); + return NULL; + } else { + $n = floor($v_header['size']/512); + for ($i=0; $i<$n; $i++) { + $v_result_str .= $this->_readBlock(); + } + if (($v_header['size'] % 512) != 0) { + $v_content = $this->_readBlock(); + $v_result_str .= substr($v_content, 0, + ($v_header['size'] % 512)); + } + return $v_result_str; + } + } else { + $this->_jumpBlock(ceil(($v_header['size']/512))); + } + } + + return NULL; + } + // }}} + + // {{{ _extractList() + function _extractList($p_path, &$p_list_detail, $p_mode, + $p_file_list, $p_remove_path) + { + $v_result=true; + $v_nb = 0; + $v_extract_all = true; + $v_listing = false; + + $p_path = $this->_translateWinPath($p_path, false); + if ($p_path == '' || (substr($p_path, 0, 1) != '/' + && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) { + $p_path = "./".$p_path; + } + $p_remove_path = $this->_translateWinPath($p_remove_path); + + // ----- Look for path to remove format (should end by /) + if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/')) + $p_remove_path .= '/'; + $p_remove_path_size = strlen($p_remove_path); + + switch ($p_mode) { + case "complete" : + $v_extract_all = TRUE; + $v_listing = FALSE; + break; + case "partial" : + $v_extract_all = FALSE; + $v_listing = FALSE; + break; + case "list" : + $v_extract_all = FALSE; + $v_listing = TRUE; + break; + default : + $this->_error('Invalid extract mode ('.$p_mode.')'); + return false; + } + + clearstatcache(); + + while (strlen($v_binary_data = $this->_readBlock()) != 0) + { + $v_extract_file = FALSE; + $v_extraction_stopped = 0; + + if (!$this->_readHeader($v_binary_data, $v_header)) + return false; + + if ($v_header['filename'] == '') { + continue; + } + + // ----- Look for long filename + if ($v_header['typeflag'] == 'L') { + if (!$this->_readLongHeader($v_header)) + return false; + } + + if ((!$v_extract_all) && (is_array($p_file_list))) { + // ----- By default no unzip if the file is not found + $v_extract_file = false; + + for ($i=0; $i strlen($p_file_list[$i])) + && (substr($v_header['filename'], 0, strlen($p_file_list[$i])) + == $p_file_list[$i])) { + $v_extract_file = TRUE; + break; + } + } + + // ----- It is a file, so compare the file names + elseif ($p_file_list[$i] == $v_header['filename']) { + $v_extract_file = TRUE; + break; + } + } + } else { + $v_extract_file = TRUE; + } + + // ----- Look if this file need to be extracted + if (($v_extract_file) && (!$v_listing)) + { + if (($p_remove_path != '') + && (substr($v_header['filename'], 0, $p_remove_path_size) + == $p_remove_path)) + $v_header['filename'] = substr($v_header['filename'], + $p_remove_path_size); + if (($p_path != './') && ($p_path != '/')) { + while (substr($p_path, -1) == '/') + $p_path = substr($p_path, 0, strlen($p_path)-1); + + if (substr($v_header['filename'], 0, 1) == '/') + $v_header['filename'] = $p_path.$v_header['filename']; + else + $v_header['filename'] = $p_path.'/'.$v_header['filename']; + } + if (file_exists($v_header['filename'])) { + if ( (@is_dir($v_header['filename'])) + && ($v_header['typeflag'] == '')) { + $this->_error('File '.$v_header['filename'] + .' already exists as a directory'); + return false; + } + if ( ($this->_isArchive($v_header['filename'])) + && ($v_header['typeflag'] == "5")) { + $this->_error('Directory '.$v_header['filename'] + .' already exists as a file'); + return false; + } + if (!is_writeable($v_header['filename'])) { + $this->_error('File '.$v_header['filename'] + .' already exists and is write protected'); + return false; + } + if (filemtime($v_header['filename']) > $v_header['mtime']) { + // To be completed : An error or silent no replace ? + } + } + + // ----- Check the directory availability and create it if necessary + elseif (($v_result + = $this->_dirCheck(($v_header['typeflag'] == "5" + ?$v_header['filename'] + :dirname($v_header['filename'])))) != 1) { + $this->_error('Unable to create path for '.$v_header['filename']); + return false; + } + + if ($v_extract_file) { + if ($v_header['typeflag'] == "5") { + if (!@file_exists($v_header['filename'])) { + if (!@mkdir($v_header['filename'], 0777)) { + $this->_error('Unable to create directory {' + .$v_header['filename'].'}'); + return false; + } + } + } elseif ($v_header['typeflag'] == "2") { + if (@file_exists($v_header['filename'])) { + @unlink($v_header['filename']); + } + if (!@symlink($v_header['link'], $v_header['filename'])) { + $this->_error('Unable to extract symbolic link {' + .$v_header['filename'].'}'); + return false; + } + } else { + if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) { + $this->_error('Error while opening {'.$v_header['filename'] + .'} in write binary mode'); + return false; + } else { + $n = floor($v_header['size']/512); + for ($i=0; $i<$n; $i++) { + $v_content = $this->_readBlock(); + fwrite($v_dest_file, $v_content, 512); + } + if (($v_header['size'] % 512) != 0) { + $v_content = $this->_readBlock(); + fwrite($v_dest_file, $v_content, ($v_header['size'] % 512)); + } + + @fclose($v_dest_file); + + // ----- Change the file mode, mtime + @touch($v_header['filename'], $v_header['mtime']); + if ($v_header['mode'] & 0111) { + // make file executable, obey umask + $mode = fileperms($v_header['filename']) | (~umask() & 0111); + @chmod($v_header['filename'], $mode); + } + } + + // ----- Check the file size + clearstatcache(); + if (filesize($v_header['filename']) != $v_header['size']) { + $this->_error('Extracted file '.$v_header['filename'] + .' does not have the correct file size \'' + .filesize($v_header['filename']) + .'\' ('.$v_header['size'] + .' expected). Archive may be corrupted.'); + return false; + } + } + } else { + $this->_jumpBlock(ceil(($v_header['size']/512))); + } + } else { + $this->_jumpBlock(ceil(($v_header['size']/512))); + } + + /* TBC : Seems to be unused ... + if ($this->_compress) + $v_end_of_file = @gzeof($this->_file); + else + $v_end_of_file = @feof($this->_file); + */ + + if ($v_listing || $v_extract_file || $v_extraction_stopped) { + // ----- Log extracted files + if (($v_file_dir = dirname($v_header['filename'])) + == $v_header['filename']) + $v_file_dir = ''; + if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == '')) + $v_file_dir = '/'; + + $p_list_detail[$v_nb++] = $v_header; + if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) { + return true; + } + } + } + + return true; + } + // }}} + + // {{{ _openAppend() + function _openAppend() + { + if (filesize($this->_tarname) == 0) + return $this->_openWrite(); + + if ($this->_compress) { + $this->_close(); + + if (!@rename($this->_tarname, $this->_tarname.".tmp")) { + $this->_error('Error while renaming \''.$this->_tarname + .'\' to temporary file \''.$this->_tarname + .'.tmp\''); + return false; + } + + if ($this->_compress_type == 'gz') + $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb"); + elseif ($this->_compress_type == 'bz2') + $v_temp_tar = @bzopen($this->_tarname.".tmp", "r"); + + if ($v_temp_tar == 0) { + $this->_error('Unable to open file \''.$this->_tarname + .'.tmp\' in binary read mode'); + @rename($this->_tarname.".tmp", $this->_tarname); + return false; + } + + if (!$this->_openWrite()) { + @rename($this->_tarname.".tmp", $this->_tarname); + return false; + } + + if ($this->_compress_type == 'gz') { + while (!@gzeof($v_temp_tar)) { + $v_buffer = @gzread($v_temp_tar, 512); + if ($v_buffer == ARCHIVE_TAR_END_BLOCK) { + // do not copy end blocks, we will re-make them + // after appending + continue; + } + $v_binary_data = pack("a512", $v_buffer); + $this->_writeBlock($v_binary_data); + } + + @gzclose($v_temp_tar); + } + elseif ($this->_compress_type == 'bz2') { + while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) { + if ($v_buffer == ARCHIVE_TAR_END_BLOCK) { + continue; + } + $v_binary_data = pack("a512", $v_buffer); + $this->_writeBlock($v_binary_data); + } + + @bzclose($v_temp_tar); + } + + if (!@unlink($this->_tarname.".tmp")) { + $this->_error('Error while deleting temporary file \'' + .$this->_tarname.'.tmp\''); + } + + } else { + // ----- For not compressed tar, just add files before the last + // one or two 512 bytes block + if (!$this->_openReadWrite()) + return false; + + clearstatcache(); + $v_size = filesize($this->_tarname); + + // We might have zero, one or two end blocks. + // The standard is two, but we should try to handle + // other cases. + fseek($this->_file, $v_size - 1024); + if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) { + fseek($this->_file, $v_size - 1024); + } + elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) { + fseek($this->_file, $v_size - 512); + } + } + + return true; + } + // }}} + + // {{{ _append() + function _append($p_filelist, $p_add_dir='', $p_remove_dir='') + { + if (!$this->_openAppend()) + return false; + + if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir)) + $this->_writeFooter(); + + $this->_close(); + + return true; + } + // }}} + + // {{{ _dirCheck() + + /** + * Check if a directory exists and create it (including parent + * dirs) if not. + * + * @param string $p_dir directory to check + * + * @return bool TRUE if the directory exists or was created + */ + function _dirCheck($p_dir) + { + clearstatcache(); + if ((@is_dir($p_dir)) || ($p_dir == '')) + return true; + + $p_parent_dir = dirname($p_dir); + + if (($p_parent_dir != $p_dir) && + ($p_parent_dir != '') && + (!$this->_dirCheck($p_parent_dir))) + return false; + + if (!@mkdir($p_dir, 0777)) { + $this->_error("Unable to create directory '$p_dir'"); + return false; + } + + return true; + } + + // }}} + + // {{{ _pathReduction() + + /** + * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar", + * rand emove double slashes. + * + * @param string $p_dir path to reduce + * + * @return string reduced path + * + * @access private + * + */ + function _pathReduction($p_dir) + { + $v_result = ''; + + // ----- Look for not empty path + if ($p_dir != '') { + // ----- Explode path by directory names + $v_list = explode('/', $p_dir); + + // ----- Study directories from last to first + for ($i=sizeof($v_list)-1; $i>=0; $i--) { + // ----- Look for current path + if ($v_list[$i] == ".") { + // ----- Ignore this directory + // Should be the first $i=0, but no check is done + } + else if ($v_list[$i] == "..") { + // ----- Ignore it and ignore the $i-1 + $i--; + } + else if ( ($v_list[$i] == '') + && ($i!=(sizeof($v_list)-1)) + && ($i!=0)) { + // ----- Ignore only the double '//' in path, + // but not the first and last / + } else { + $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?'/' + .$v_result:''); + } + } + } + $v_result = strtr($v_result, '\\', '/'); + return $v_result; + } + + // }}} + + // {{{ _translateWinPath() + function _translateWinPath($p_path, $p_remove_disk_letter=true) + { + if (defined('OS_WINDOWS') && OS_WINDOWS) { + // ----- Look for potential disk letter + if ( ($p_remove_disk_letter) + && (($v_position = strpos($p_path, ':')) != false)) { + $p_path = substr($p_path, $v_position+1); + } + // ----- Change potential windows directory separator + if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { + $p_path = strtr($p_path, '\\', '/'); + } + } + return $p_path; + } + // }}} + +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/Cache/Lite.php b/typo3conf/ext/phpunit/PEAR/Cache/Lite.php new file mode 100644 index 0000000..b4506b0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/Cache/Lite.php @@ -0,0 +1,846 @@ + +* +* Nota : A chinese documentation (thanks to RainX ) is +* available at : +* http://rainx.phpmore.com/manual/cache_lite.html +* +* @package Cache_Lite +* @category Caching +* @version $Id: Lite.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @author Fabien MARTY +*/ + +define('CACHE_LITE_ERROR_RETURN', 1); +define('CACHE_LITE_ERROR_DIE', 8); + +class Cache_Lite +{ + + // --- Private properties --- + + /** + * Directory where to put the cache files + * (make sure to add a trailing slash) + * + * @var string $_cacheDir + */ + var $_cacheDir = '/tmp/'; + + /** + * Enable / disable caching + * + * (can be very usefull for the debug of cached scripts) + * + * @var boolean $_caching + */ + var $_caching = true; + + /** + * Cache lifetime (in seconds) + * + * If null, the cache is valid forever. + * + * @var int $_lifeTime + */ + var $_lifeTime = 3600; + + /** + * Enable / disable fileLocking + * + * (can avoid cache corruption under bad circumstances) + * + * @var boolean $_fileLocking + */ + var $_fileLocking = true; + + /** + * Timestamp of the last valid cache + * + * @var int $_refreshTime + */ + var $_refreshTime; + + /** + * File name (with path) + * + * @var string $_file + */ + var $_file; + + /** + * File name (without path) + * + * @var string $_fileName + */ + var $_fileName; + + /** + * Enable / disable write control (the cache is read just after writing to detect corrupt entries) + * + * Enable write control will lightly slow the cache writing but not the cache reading + * Write control can detect some corrupt cache files but maybe it's not a perfect control + * + * @var boolean $_writeControl + */ + var $_writeControl = true; + + /** + * Enable / disable read control + * + * If enabled, a control key is embeded in cache file and this key is compared with the one + * calculated after the reading. + * + * @var boolean $_writeControl + */ + var $_readControl = true; + + /** + * Type of read control (only if read control is enabled) + * + * Available values are : + * 'md5' for a md5 hash control (best but slowest) + * 'crc32' for a crc32 hash control (lightly less safe but faster, better choice) + * 'strlen' for a length only test (fastest) + * + * @var boolean $_readControlType + */ + var $_readControlType = 'crc32'; + + /** + * Pear error mode (when raiseError is called) + * + * (see PEAR doc) + * + * @see setToDebug() + * @var int $_pearErrorMode + */ + var $_pearErrorMode = CACHE_LITE_ERROR_RETURN; + + /** + * Current cache id + * + * @var string $_id + */ + var $_id; + + /** + * Current cache group + * + * @var string $_group + */ + var $_group; + + /** + * Enable / Disable "Memory Caching" + * + * NB : There is no lifetime for memory caching ! + * + * @var boolean $_memoryCaching + */ + var $_memoryCaching = false; + + /** + * Enable / Disable "Only Memory Caching" + * (be carefull, memory caching is "beta quality") + * + * @var boolean $_onlyMemoryCaching + */ + var $_onlyMemoryCaching = false; + + /** + * Memory caching array + * + * @var array $_memoryCachingArray + */ + var $_memoryCachingArray = array(); + + /** + * Memory caching counter + * + * @var int $memoryCachingCounter + */ + var $_memoryCachingCounter = 0; + + /** + * Memory caching limit + * + * @var int $memoryCachingLimit + */ + var $_memoryCachingLimit = 1000; + + /** + * File Name protection + * + * if set to true, you can use any cache id or group name + * if set to false, it can be faster but cache ids and group names + * will be used directly in cache file names so be carefull with + * special characters... + * + * @var boolean $fileNameProtection + */ + var $_fileNameProtection = true; + + /** + * Enable / disable automatic serialization + * + * it can be used to save directly datas which aren't strings + * (but it's slower) + * + * @var boolean $_serialize + */ + var $_automaticSerialization = false; + + /** + * Disable / Tune the automatic cleaning process + * + * The automatic cleaning process destroy too old (for the given life time) + * cache files when a new cache file is written. + * 0 => no automatic cache cleaning + * 1 => systematic cache cleaning + * x (integer) > 1 => automatic cleaning randomly 1 times on x cache write + * + * @var int $_automaticCleaning + */ + var $_automaticCleaningFactor = 0; + + /** + * Nested directory level + * + * Set the hashed directory structure level. 0 means "no hashed directory + * structure", 1 means "one level of directory", 2 means "two levels"... + * This option can speed up Cache_Lite only when you have many thousands of + * cache file. Only specific benchs can help you to choose the perfect value + * for you. Maybe, 1 or 2 is a good start. + * + * @var int $_hashedDirectoryLevel + */ + var $_hashedDirectoryLevel = 0; + + /** + * Umask for hashed directory structure + * + * @var int $_hashedDirectoryUmask + */ + var $_hashedDirectoryUmask = 0700; + + /** + * API break for error handling in CACHE_LITE_ERROR_RETURN mode + * + * In CACHE_LITE_ERROR_RETURN mode, error handling was not good because + * for example save() method always returned a boolean (a PEAR_Error object + * would be better in CACHE_LITE_ERROR_RETURN mode). To correct this without + * breaking the API, this option (false by default) can change this handling. + * + * @var boolean + */ + var $_errorHandlingAPIBreak = false; + + // --- Public methods --- + + /** + * Constructor + * + * $options is an assoc. Available options are : + * $options = array( + * 'cacheDir' => directory where to put the cache files (string), + * 'caching' => enable / disable caching (boolean), + * 'lifeTime' => cache lifetime in seconds (int), + * 'fileLocking' => enable / disable fileLocking (boolean), + * 'writeControl' => enable / disable write control (boolean), + * 'readControl' => enable / disable read control (boolean), + * 'readControlType' => type of read control 'crc32', 'md5', 'strlen' (string), + * 'pearErrorMode' => pear error mode (when raiseError is called) (cf PEAR doc) (int), + * 'memoryCaching' => enable / disable memory caching (boolean), + * 'onlyMemoryCaching' => enable / disable only memory caching (boolean), + * 'memoryCachingLimit' => max nbr of records to store into memory caching (int), + * 'fileNameProtection' => enable / disable automatic file name protection (boolean), + * 'automaticSerialization' => enable / disable automatic serialization (boolean), + * 'automaticCleaningFactor' => distable / tune automatic cleaning process (int), + * 'hashedDirectoryLevel' => level of the hashed directory system (int), + * 'hashedDirectoryUmask' => umask for hashed directory structure (int), + * 'errorHandlingAPIBreak' => API break for better error handling ? (boolean) + * ); + * + * If sys_get_temp_dir() is available and the + * 'cacheDir' option is not provided in the + * constructor options array its output is used + * to determine the suitable temporary directory. + * + * @see http://de.php.net/sys_get_temp_dir + * @see http://pear.php.net/bugs/bug.php?id=18328 + * + * @param array $options options + * @access public + */ + function Cache_Lite($options = array(NULL)) + { + foreach($options as $key => $value) { + $this->setOption($key, $value); + } + if (!isset($options['cacheDir']) && function_exists('sys_get_temp_dir')) { + $this->setOption('cacheDir', sys_get_temp_dir() . DIRECTORY_SEPARATOR); + } + } + + /** + * Generic way to set a Cache_Lite option + * + * see Cache_Lite constructor for available options + * + * @var string $name name of the option + * @var mixed $value value of the option + * @access public + */ + function setOption($name, $value) + { + $availableOptions = array('errorHandlingAPIBreak', 'hashedDirectoryUmask', 'hashedDirectoryLevel', 'automaticCleaningFactor', 'automaticSerialization', 'fileNameProtection', 'memoryCaching', 'onlyMemoryCaching', 'memoryCachingLimit', 'cacheDir', 'caching', 'lifeTime', 'fileLocking', 'writeControl', 'readControl', 'readControlType', 'pearErrorMode'); + if (in_array($name, $availableOptions)) { + $property = '_'.$name; + $this->$property = $value; + } + } + + /** + * Test if a cache is available and (if yes) return it + * + * @param string $id cache id + * @param string $group name of the cache group + * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested + * @return string data of the cache (else : false) + * @access public + */ + function get($id, $group = 'default', $doNotTestCacheValidity = false) + { + $this->_id = $id; + $this->_group = $group; + $data = false; + if ($this->_caching) { + $this->_setRefreshTime(); + $this->_setFileName($id, $group); + clearstatcache(); + if ($this->_memoryCaching) { + if (isset($this->_memoryCachingArray[$this->_file])) { + if ($this->_automaticSerialization) { + return unserialize($this->_memoryCachingArray[$this->_file]); + } + return $this->_memoryCachingArray[$this->_file]; + } + if ($this->_onlyMemoryCaching) { + return false; + } + } + if (($doNotTestCacheValidity) || (is_null($this->_refreshTime))) { + if (file_exists($this->_file)) { + $data = $this->_read(); + } + } else { + if ((file_exists($this->_file)) && (@filemtime($this->_file) > $this->_refreshTime)) { + $data = $this->_read(); + } + } + if (($data) and ($this->_memoryCaching)) { + $this->_memoryCacheAdd($data); + } + if (($this->_automaticSerialization) and (is_string($data))) { + $data = unserialize($data); + } + return $data; + } + return false; + } + + /** + * Save some data in a cache file + * + * @param string $data data to put in cache (can be another type than strings if automaticSerialization is on) + * @param string $id cache id + * @param string $group name of the cache group + * @return boolean true if no problem (else : false or a PEAR_Error object) + * @access public + */ + function save($data, $id = NULL, $group = 'default') + { + if ($this->_caching) { + if ($this->_automaticSerialization) { + $data = serialize($data); + } + if (isset($id)) { + $this->_setFileName($id, $group); + } + if ($this->_memoryCaching) { + $this->_memoryCacheAdd($data); + if ($this->_onlyMemoryCaching) { + return true; + } + } + if ($this->_automaticCleaningFactor>0 && ($this->_automaticCleaningFactor==1 || mt_rand(1, $this->_automaticCleaningFactor)==1)) { + $this->clean(false, 'old'); + } + if ($this->_writeControl) { + $res = $this->_writeAndControl($data); + if (is_bool($res)) { + if ($res) { + return true; + } + // if $res if false, we need to invalidate the cache + @touch($this->_file, time() - 2*abs($this->_lifeTime)); + return false; + } + } else { + $res = $this->_write($data); + } + if (is_object($res)) { + // $res is a PEAR_Error object + if (!($this->_errorHandlingAPIBreak)) { + return false; // we return false (old API) + } + } + return $res; + } + return false; + } + + /** + * Remove a cache file + * + * @param string $id cache id + * @param string $group name of the cache group + * @param boolean $checkbeforeunlink check if file exists before removing it + * @return boolean true if no problem + * @access public + */ + function remove($id, $group = 'default', $checkbeforeunlink = false) + { + $this->_setFileName($id, $group); + if ($this->_memoryCaching) { + if (isset($this->_memoryCachingArray[$this->_file])) { + unset($this->_memoryCachingArray[$this->_file]); + $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1; + } + if ($this->_onlyMemoryCaching) { + return true; + } + } + if ( $checkbeforeunlink ) { + if (!file_exists($this->_file)) return true; + } + return $this->_unlink($this->_file); + } + + /** + * Clean the cache + * + * if no group is specified all cache files will be destroyed + * else only cache files of the specified group will be destroyed + * + * @param string $group name of the cache group + * @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup', + * 'callback_myFunction' + * @return boolean true if no problem + * @access public + */ + function clean($group = false, $mode = 'ingroup') + { + return $this->_cleanDir($this->_cacheDir, $group, $mode); + } + + /** + * Set to debug mode + * + * When an error is found, the script will stop and the message will be displayed + * (in debug mode only). + * + * @access public + */ + function setToDebug() + { + $this->setOption('pearErrorMode', CACHE_LITE_ERROR_DIE); + } + + /** + * Set a new life time + * + * @param int $newLifeTime new life time (in seconds) + * @access public + */ + function setLifeTime($newLifeTime) + { + $this->_lifeTime = $newLifeTime; + $this->_setRefreshTime(); + } + + /** + * Save the state of the caching memory array into a cache file cache + * + * @param string $id cache id + * @param string $group name of the cache group + * @access public + */ + function saveMemoryCachingState($id, $group = 'default') + { + if ($this->_caching) { + $array = array( + 'counter' => $this->_memoryCachingCounter, + 'array' => $this->_memoryCachingArray + ); + $data = serialize($array); + $this->save($data, $id, $group); + } + } + + /** + * Load the state of the caching memory array from a given cache file cache + * + * @param string $id cache id + * @param string $group name of the cache group + * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested + * @access public + */ + function getMemoryCachingState($id, $group = 'default', $doNotTestCacheValidity = false) + { + if ($this->_caching) { + if ($data = $this->get($id, $group, $doNotTestCacheValidity)) { + $array = unserialize($data); + $this->_memoryCachingCounter = $array['counter']; + $this->_memoryCachingArray = $array['array']; + } + } + } + + /** + * Return the cache last modification time + * + * BE CAREFUL : THIS METHOD IS FOR HACKING ONLY ! + * + * @return int last modification time + */ + function lastModified() + { + return @filemtime($this->_file); + } + + /** + * Trigger a PEAR error + * + * To improve performances, the PEAR.php file is included dynamically. + * The file is so included only when an error is triggered. So, in most + * cases, the file isn't included and perfs are much better. + * + * @param string $msg error message + * @param int $code error code + * @access public + */ + function raiseError($msg, $code) + { + include_once('PEAR.php'); + return PEAR::raiseError($msg, $code, $this->_pearErrorMode); + } + + /** + * Extend the life of a valid cache file + * + * see http://pear.php.net/bugs/bug.php?id=6681 + * + * @access public + */ + function extendLife() + { + @touch($this->_file); + } + + // --- Private methods --- + + /** + * Compute & set the refresh time + * + * @access private + */ + function _setRefreshTime() + { + if (is_null($this->_lifeTime)) { + $this->_refreshTime = null; + } else { + $this->_refreshTime = time() - $this->_lifeTime; + } + } + + /** + * Remove a file + * + * @param string $file complete file path and name + * @return boolean true if no problem + * @access private + */ + function _unlink($file) + { + if (!@unlink($file)) { + return $this->raiseError('Cache_Lite : Unable to remove cache !', -3); + } + return true; + } + + /** + * Recursive function for cleaning cache file in the given directory + * + * @param string $dir directory complete path (with a trailing slash) + * @param string $group name of the cache group + * @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup', + 'callback_myFunction' + * @return boolean true if no problem + * @access private + */ + function _cleanDir($dir, $group = false, $mode = 'ingroup') + { + if ($this->_fileNameProtection) { + $motif = ($group) ? 'cache_'.md5($group).'_' : 'cache_'; + } else { + $motif = ($group) ? 'cache_'.$group.'_' : 'cache_'; + } + if ($this->_memoryCaching) { + foreach($this->_memoryCachingArray as $key => $v) { + if (strpos($key, $motif) !== false) { + unset($this->_memoryCachingArray[$key]); + $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1; + } + } + if ($this->_onlyMemoryCaching) { + return true; + } + } + if (!($dh = opendir($dir))) { + return $this->raiseError('Cache_Lite : Unable to open cache directory !', -4); + } + $result = true; + while ($file = readdir($dh)) { + if (($file != '.') && ($file != '..')) { + if (substr($file, 0, 6)=='cache_') { + $file2 = $dir . $file; + if (is_file($file2)) { + switch (substr($mode, 0, 9)) { + case 'old': + // files older than lifeTime get deleted from cache + if (!is_null($this->_lifeTime)) { + if ((time() - @filemtime($file2)) > $this->_lifeTime) { + $result = ($result and ($this->_unlink($file2))); + } + } + break; + case 'notingrou': + if (strpos($file2, $motif) === false) { + $result = ($result and ($this->_unlink($file2))); + } + break; + case 'callback_': + $func = substr($mode, 9, strlen($mode) - 9); + if ($func($file2, $group)) { + $result = ($result and ($this->_unlink($file2))); + } + break; + case 'ingroup': + default: + if (strpos($file2, $motif) !== false) { + $result = ($result and ($this->_unlink($file2))); + } + break; + } + } + if ((is_dir($file2)) and ($this->_hashedDirectoryLevel>0)) { + $result = ($result and ($this->_cleanDir($file2 . '/', $group, $mode))); + } + } + } + } + return $result; + } + + /** + * Add some date in the memory caching array + * + * @param string $data data to cache + * @access private + */ + function _memoryCacheAdd($data) + { + $this->_memoryCachingArray[$this->_file] = $data; + if ($this->_memoryCachingCounter >= $this->_memoryCachingLimit) { + list($key, ) = each($this->_memoryCachingArray); + unset($this->_memoryCachingArray[$key]); + } else { + $this->_memoryCachingCounter = $this->_memoryCachingCounter + 1; + } + } + + /** + * Make a file name (with path) + * + * @param string $id cache id + * @param string $group name of the group + * @access private + */ + function _setFileName($id, $group) + { + + if ($this->_fileNameProtection) { + $suffix = 'cache_'.md5($group).'_'.md5($id); + } else { + $suffix = 'cache_'.$group.'_'.$id; + } + $root = $this->_cacheDir; + if ($this->_hashedDirectoryLevel>0) { + $hash = md5($suffix); + for ($i=0 ; $i<$this->_hashedDirectoryLevel ; $i++) { + $root = $root . 'cache_' . substr($hash, 0, $i + 1) . '/'; + } + } + $this->_fileName = $suffix; + $this->_file = $root.$suffix; + } + + /** + * Read the cache file and return the content + * + * @return string content of the cache file (else : false or a PEAR_Error object) + * @access private + */ + function _read() + { + $fp = @fopen($this->_file, "rb"); + if ($fp) { + if ($this->_fileLocking) @flock($fp, LOCK_SH); + clearstatcache(); + $length = @filesize($this->_file); + $mqr = get_magic_quotes_runtime(); + if ($mqr) { + set_magic_quotes_runtime(0); + } + if ($this->_readControl) { + $hashControl = @fread($fp, 32); + $length = $length - 32; + } + if ($length) { + $data = @fread($fp, $length); + } else { + $data = ''; + } + if ($mqr) { + set_magic_quotes_runtime($mqr); + } + if ($this->_fileLocking) @flock($fp, LOCK_UN); + @fclose($fp); + if ($this->_readControl) { + $hashData = $this->_hash($data, $this->_readControlType); + if ($hashData != $hashControl) { + if (!(is_null($this->_lifeTime))) { + @touch($this->_file, time() - 2*abs($this->_lifeTime)); + } else { + @unlink($this->_file); + } + return false; + } + } + return $data; + } + return $this->raiseError('Cache_Lite : Unable to read cache !', -2); + } + + /** + * Write the given data in the cache file + * + * @param string $data data to put in cache + * @return boolean true if ok (a PEAR_Error object else) + * @access private + */ + function _write($data) + { + if ($this->_hashedDirectoryLevel > 0) { + $hash = md5($this->_fileName); + $root = $this->_cacheDir; + for ($i=0 ; $i<$this->_hashedDirectoryLevel ; $i++) { + $root = $root . 'cache_' . substr($hash, 0, $i + 1) . '/'; + if (!(@is_dir($root))) { + @mkdir($root, $this->_hashedDirectoryUmask); + } + } + } + $fp = @fopen($this->_file, "wb"); + if ($fp) { + if ($this->_fileLocking) @flock($fp, LOCK_EX); + if ($this->_readControl) { + @fwrite($fp, $this->_hash($data, $this->_readControlType), 32); + } + $mqr = get_magic_quotes_runtime(); + if ($mqr) { + set_magic_quotes_runtime(0); + } + @fwrite($fp, $data); + if ($mqr) { + set_magic_quotes_runtime($mqr); + } + if ($this->_fileLocking) @flock($fp, LOCK_UN); + @fclose($fp); + return true; + } + return $this->raiseError('Cache_Lite : Unable to write cache file : '.$this->_file, -1); + } + + /** + * Write the given data in the cache file and control it just after to avoir corrupted cache entries + * + * @param string $data data to put in cache + * @return boolean true if the test is ok (else : false or a PEAR_Error object) + * @access private + */ + function _writeAndControl($data) + { + $result = $this->_write($data); + if (is_object($result)) { + return $result; # We return the PEAR_Error object + } + $dataRead = $this->_read(); + if (is_object($dataRead)) { + return $dataRead; # We return the PEAR_Error object + } + if ((is_bool($dataRead)) && (!$dataRead)) { + return false; + } + return ($dataRead==$data); + } + + /** + * Make a control key with the string containing datas + * + * @param string $data data + * @param string $controlType type of control 'md5', 'crc32' or 'strlen' + * @return string control key + * @access private + */ + function _hash($data, $controlType) + { + switch ($controlType) { + case 'md5': + return md5($data); + case 'crc32': + return sprintf('% 32d', crc32($data)); + case 'strlen': + return sprintf('% 32d', strlen($data)); + default: + return $this->raiseError('Unknown controlType ! (available values are only \'md5\', \'crc32\', \'strlen\')', -5); + } + } + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/Cache/Lite/File.php b/typo3conf/ext/phpunit/PEAR/Cache/Lite/File.php new file mode 100644 index 0000000..fc739fc --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/Cache/Lite/File.php @@ -0,0 +1,93 @@ + +*/ + +require_once('Cache/Lite.php'); + +class Cache_Lite_File extends Cache_Lite +{ + + // --- Private properties --- + + /** + * Complete path of the file used for controlling the cache lifetime + * + * @var string $_masterFile + */ + var $_masterFile = ''; + + /** + * Masterfile mtime + * + * @var int $_masterFile_mtime + */ + var $_masterFile_mtime = 0; + + // --- Public methods ---- + + /** + * Constructor + * + * $options is an assoc. To have a look at availables options, + * see the constructor of the Cache_Lite class in 'Cache_Lite.php' + * + * Comparing to Cache_Lite constructor, there is another option : + * $options = array( + * (...) see Cache_Lite constructor + * 'masterFile' => complete path of the file used for controlling the cache lifetime(string) + * ); + * + * @param array $options options + * @access public + */ + function Cache_Lite_File($options = array(NULL)) + { + $options['lifetime'] = 0; + $this->Cache_Lite($options); + if (isset($options['masterFile'])) { + $this->_masterFile = $options['masterFile']; + } else { + return $this->raiseError('Cache_Lite_File : masterFile option must be set !'); + } + if (!($this->_masterFile_mtime = @filemtime($this->_masterFile))) { + return $this->raiseError('Cache_Lite_File : Unable to read masterFile : '.$this->_masterFile, -3); + } + } + + /** + * Test if a cache is available and (if yes) return it + * + * @param string $id cache id + * @param string $group name of the cache group + * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested + * @return string data of the cache (else : false) + * @access public + */ + function get($id, $group = 'default', $doNotTestCacheValidity = false) + { + if ($data = parent::get($id, $group, true)) { + if ($filemtime = $this->lastModified()) { + if ($filemtime > $this->_masterFile_mtime) { + return $data; + } + } + } + return false; + } + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/Cache/Lite/Function.php b/typo3conf/ext/phpunit/PEAR/Cache/Lite/Function.php new file mode 100644 index 0000000..2e3f706 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/Cache/Lite/Function.php @@ -0,0 +1,211 @@ + +* @author Fabien MARTY +*/ + +require_once('Cache/Lite.php'); + +class Cache_Lite_Function extends Cache_Lite +{ + + // --- Private properties --- + + /** + * Default cache group for function caching + * + * @var string $_defaultGroup + */ + var $_defaultGroup = 'Cache_Lite_Function'; + + /** + * Don't cache the method call when its output contains the string "NOCACHE" + * + * if set to true, the output of the method will never be displayed (because the output is used + * to control the cache) + * + * @var boolean $_dontCacheWhenTheOutputContainsNOCACHE + */ + var $_dontCacheWhenTheOutputContainsNOCACHE = false; + + /** + * Don't cache the method call when its result is false + * + * @var boolean $_dontCacheWhenTheResultIsFalse + */ + var $_dontCacheWhenTheResultIsFalse = false; + + /** + * Don't cache the method call when its result is null + * + * @var boolean $_dontCacheWhenTheResultIsNull + */ + var $_dontCacheWhenTheResultIsNull = false; + + /** + * Debug the Cache_Lite_Function caching process + * + * @var boolean $_debugCacheLiteFunction + */ + var $_debugCacheLiteFunction = false; + + // --- Public methods ---- + + /** + * Constructor + * + * $options is an assoc. To have a look at availables options, + * see the constructor of the Cache_Lite class in 'Cache_Lite.php' + * + * Comparing to Cache_Lite constructor, there is another option : + * $options = array( + * (...) see Cache_Lite constructor + * 'debugCacheLiteFunction' => (bool) debug the caching process, + * 'defaultGroup' => default cache group for function caching (string), + * 'dontCacheWhenTheOutputContainsNOCACHE' => (bool) don't cache when the function output contains "NOCACHE", + * 'dontCacheWhenTheResultIsFalse' => (bool) don't cache when the function result is false, + * 'dontCacheWhenTheResultIsNull' => (bool don't cache when the function result is null + * ); + * + * @param array $options options + * @access public + */ + function Cache_Lite_Function($options = array(NULL)) + { + $availableOptions = array('debugCacheLiteFunction', 'defaultGroup', 'dontCacheWhenTheOutputContainsNOCACHE', 'dontCacheWhenTheResultIsFalse', 'dontCacheWhenTheResultIsNull'); + while (list($name, $value) = each($options)) { + if (in_array($name, $availableOptions)) { + $property = '_'.$name; + $this->$property = $value; + } + } + reset($options); + $this->Cache_Lite($options); + } + + /** + * Calls a cacheable function or method (or not if there is already a cache for it) + * + * Arguments of this method are read with func_get_args. So it doesn't appear + * in the function definition. Synopsis : + * call('functionName', $arg1, $arg2, ...) + * (arg1, arg2... are arguments of 'functionName') + * + * @return mixed result of the function/method + * @access public + */ + function call() + { + $arguments = func_get_args(); + $id = $this->_makeId($arguments); + $data = $this->get($id, $this->_defaultGroup); + if ($data !== false) { + if ($this->_debugCacheLiteFunction) { + echo "Cache hit !\n"; + } + $array = unserialize($data); + $output = $array['output']; + $result = $array['result']; + } else { + if ($this->_debugCacheLiteFunction) { + echo "Cache missed !\n"; + } + ob_start(); + ob_implicit_flush(false); + $target = array_shift($arguments); + if (is_array($target)) { + // in this case, $target is for example array($obj, 'method') + $object = $target[0]; + $method = $target[1]; + $result = call_user_func_array(array(&$object, $method), $arguments); + } else { + if (strstr($target, '::')) { // classname::staticMethod + list($class, $method) = explode('::', $target); + $result = call_user_func_array(array($class, $method), $arguments); + } else if (strstr($target, '->')) { // object->method + // use a stupid name ($objet_123456789 because) of problems where the object + // name is the same as this var name + list($object_123456789, $method) = explode('->', $target); + global $$object_123456789; + $result = call_user_func_array(array($$object_123456789, $method), $arguments); + } else { // function + $result = call_user_func_array($target, $arguments); + } + } + $output = ob_get_contents(); + ob_end_clean(); + if ($this->_dontCacheWhenTheResultIsFalse) { + if ((is_bool($result)) && (!($result))) { + echo($output); + return $result; + } + } + if ($this->_dontCacheWhenTheResultIsNull) { + if (is_null($result)) { + echo($output); + return $result; + } + } + if ($this->_dontCacheWhenTheOutputContainsNOCACHE) { + if (strpos($output, 'NOCACHE') > -1) { + return $result; + } + } + $array['output'] = $output; + $array['result'] = $result; + $this->save(serialize($array), $id, $this->_defaultGroup); + } + echo($output); + return $result; + } + + /** + * Drop a cache file + * + * Arguments of this method are read with func_get_args. So it doesn't appear + * in the function definition. Synopsis : + * remove('functionName', $arg1, $arg2, ...) + * (arg1, arg2... are arguments of 'functionName') + * + * @return boolean true if no problem + * @access public + */ + function drop() + { + $id = $this->_makeId(func_get_args()); + return $this->remove($id, $this->_defaultGroup); + } + + /** + * Make an id for the cache + * + * @var array result of func_get_args for the call() or the remove() method + * @return string id + * @access private + */ + function _makeId($arguments) + { + $id = serialize($arguments); // Generate a cache id + if (!$this->_fileNameProtection) { + $id = md5($id); + // if fileNameProtection is set to false, then the id has to be hashed + // because it's a very bad file name in most cases + } + return $id; + } + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/Cache/Lite/Output.php b/typo3conf/ext/phpunit/PEAR/Cache/Lite/Output.php new file mode 100644 index 0000000..168e9a1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/Cache/Lite/Output.php @@ -0,0 +1,72 @@ + +*/ + +require_once('Cache/Lite.php'); + +class Cache_Lite_Output extends Cache_Lite +{ + + // --- Public methods --- + + /** + * Constructor + * + * $options is an assoc. To have a look at availables options, + * see the constructor of the Cache_Lite class in 'Cache_Lite.php' + * + * @param array $options options + * @access public + */ + function Cache_Lite_Output($options) + { + $this->Cache_Lite($options); + } + + /** + * Start the cache + * + * @param string $id cache id + * @param string $group name of the cache group + * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested + * @return boolean true if the cache is hit (false else) + * @access public + */ + function start($id, $group = 'default', $doNotTestCacheValidity = false) + { + $data = $this->get($id, $group, $doNotTestCacheValidity); + if ($data !== false) { + echo($data); + return true; + } + ob_start(); + ob_implicit_flush(false); + return false; + } + + /** + * Stop the cache + * + * @access public + */ + function end() + { + $data = ob_get_contents(); + ob_end_clean(); + $this->save($data, $this->_id, $this->_group); + echo($data); + } + +} + + +?> diff --git a/typo3conf/ext/phpunit/PEAR/Console/Getopt.php b/typo3conf/ext/phpunit/PEAR/Console/Getopt.php new file mode 100644 index 0000000..f99cd57 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/Console/Getopt.php @@ -0,0 +1,366 @@ + + * @license http://www.php.net/license/3_0.txt PHP 3.0 + * @version CVS: $Id: Getopt.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/Console_Getopt + */ + +require_once 'PEAR.php'; + +/** + * Command-line options parsing class. + * + * @category Console + * @package Console_Getopt + * @author Andrei Zmievski + * @license http://www.php.net/license/3_0.txt PHP 3.0 + * @link http://pear.php.net/package/Console_Getopt + */ +class Console_Getopt +{ + + /** + * Parses the command-line options. + * + * The first parameter to this function should be the list of command-line + * arguments without the leading reference to the running program. + * + * The second parameter is a string of allowed short options. Each of the + * option letters can be followed by a colon ':' to specify that the option + * requires an argument, or a double colon '::' to specify that the option + * takes an optional argument. + * + * The third argument is an optional array of allowed long options. The + * leading '--' should not be included in the option name. Options that + * require an argument should be followed by '=', and options that take an + * option argument should be followed by '=='. + * + * The return value is an array of two elements: the list of parsed + * options and the list of non-option command-line arguments. Each entry in + * the list of parsed options is a pair of elements - the first one + * specifies the option, and the second one specifies the option argument, + * if there was one. + * + * Long and short options can be mixed. + * + * Most of the semantics of this function are based on GNU getopt_long(). + * + * @param array $args an array of command-line arguments + * @param string $short_options specifies the list of allowed short options + * @param array $long_options specifies the list of allowed long options + * @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option + * + * @return array two-element array containing the list of parsed options and + * the non-option arguments + * @access public + */ + function getopt2($args, $short_options, $long_options = null, $skip_unknown = false) + { + return Console_Getopt::doGetopt(2, $args, $short_options, $long_options, $skip_unknown); + } + + /** + * This function expects $args to start with the script name (POSIX-style). + * Preserved for backwards compatibility. + * + * @param array $args an array of command-line arguments + * @param string $short_options specifies the list of allowed short options + * @param array $long_options specifies the list of allowed long options + * + * @see getopt2() + * @return array two-element array containing the list of parsed options and + * the non-option arguments + */ + function getopt($args, $short_options, $long_options = null, $skip_unknown = false) + { + return Console_Getopt::doGetopt(1, $args, $short_options, $long_options, $skip_unknown); + } + + /** + * The actual implementation of the argument parsing code. + * + * @param int $version Version to use + * @param array $args an array of command-line arguments + * @param string $short_options specifies the list of allowed short options + * @param array $long_options specifies the list of allowed long options + * @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option + * + * @return array + */ + function doGetopt($version, $args, $short_options, $long_options = null, $skip_unknown = false) + { + // in case you pass directly readPHPArgv() as the first arg + if (PEAR::isError($args)) { + return $args; + } + + if (empty($args)) { + return array(array(), array()); + } + + $non_opts = $opts = array(); + + settype($args, 'array'); + + if ($long_options) { + sort($long_options); + } + + /* + * Preserve backwards compatibility with callers that relied on + * erroneous POSIX fix. + */ + if ($version < 2) { + if (isset($args[0]{0}) && $args[0]{0} != '-') { + array_shift($args); + } + } + + reset($args); + while (list($i, $arg) = each($args)) { + /* The special element '--' means explicit end of + options. Treat the rest of the arguments as non-options + and end the loop. */ + if ($arg == '--') { + $non_opts = array_merge($non_opts, array_slice($args, $i + 1)); + break; + } + + if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) { + $non_opts = array_merge($non_opts, array_slice($args, $i)); + break; + } elseif (strlen($arg) > 1 && $arg{1} == '-') { + $error = Console_Getopt::_parseLongOption(substr($arg, 2), + $long_options, + $opts, + $args, + $skip_unknown); + if (PEAR::isError($error)) { + return $error; + } + } elseif ($arg == '-') { + // - is stdin + $non_opts = array_merge($non_opts, array_slice($args, $i)); + break; + } else { + $error = Console_Getopt::_parseShortOption(substr($arg, 1), + $short_options, + $opts, + $args, + $skip_unknown); + if (PEAR::isError($error)) { + return $error; + } + } + } + + return array($opts, $non_opts); + } + + /** + * Parse short option + * + * @param string $arg Argument + * @param string[] $short_options Available short options + * @param string[][] &$opts + * @param string[] &$args + * @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option + * + * @access private + * @return void + */ + function _parseShortOption($arg, $short_options, &$opts, &$args, $skip_unknown) + { + for ($i = 0; $i < strlen($arg); $i++) { + $opt = $arg{$i}; + $opt_arg = null; + + /* Try to find the short option in the specifier string. */ + if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':') { + if ($skip_unknown === true) { + break; + } + + $msg = "Console_Getopt: unrecognized option -- $opt"; + return PEAR::raiseError($msg); + } + + if (strlen($spec) > 1 && $spec{1} == ':') { + if (strlen($spec) > 2 && $spec{2} == ':') { + if ($i + 1 < strlen($arg)) { + /* Option takes an optional argument. Use the remainder of + the arg string if there is anything left. */ + $opts[] = array($opt, substr($arg, $i + 1)); + break; + } + } else { + /* Option requires an argument. Use the remainder of the arg + string if there is anything left. */ + if ($i + 1 < strlen($arg)) { + $opts[] = array($opt, substr($arg, $i + 1)); + break; + } else if (list(, $opt_arg) = each($args)) { + /* Else use the next argument. */; + if (Console_Getopt::_isShortOpt($opt_arg) + || Console_Getopt::_isLongOpt($opt_arg)) { + $msg = "option requires an argument --$opt"; + return PEAR::raiseError("Console_Getopt:" . $msg); + } + } else { + $msg = "option requires an argument --$opt"; + return PEAR::raiseError("Console_Getopt:" . $msg); + } + } + } + + $opts[] = array($opt, $opt_arg); + } + } + + /** + * Checks if an argument is a short option + * + * @param string $arg Argument to check + * + * @access private + * @return bool + */ + function _isShortOpt($arg) + { + return strlen($arg) == 2 && $arg[0] == '-' + && preg_match('/[a-zA-Z]/', $arg[1]); + } + + /** + * Checks if an argument is a long option + * + * @param string $arg Argument to check + * + * @access private + * @return bool + */ + function _isLongOpt($arg) + { + return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' && + preg_match('/[a-zA-Z]+$/', substr($arg, 2)); + } + + /** + * Parse long option + * + * @param string $arg Argument + * @param string[] $long_options Available long options + * @param string[][] &$opts + * @param string[] &$args + * + * @access private + * @return void|PEAR_Error + */ + function _parseLongOption($arg, $long_options, &$opts, &$args, $skip_unknown) + { + @list($opt, $opt_arg) = explode('=', $arg, 2); + + $opt_len = strlen($opt); + + for ($i = 0; $i < count($long_options); $i++) { + $long_opt = $long_options[$i]; + $opt_start = substr($long_opt, 0, $opt_len); + + $long_opt_name = str_replace('=', '', $long_opt); + + /* Option doesn't match. Go on to the next one. */ + if ($long_opt_name != $opt) { + continue; + } + + $opt_rest = substr($long_opt, $opt_len); + + /* Check that the options uniquely matches one of the allowed + options. */ + if ($i + 1 < count($long_options)) { + $next_option_rest = substr($long_options[$i + 1], $opt_len); + } else { + $next_option_rest = ''; + } + + if ($opt_rest != '' && $opt{0} != '=' && + $i + 1 < count($long_options) && + $opt == substr($long_options[$i+1], 0, $opt_len) && + $next_option_rest != '' && + $next_option_rest{0} != '=') { + + $msg = "Console_Getopt: option --$opt is ambiguous"; + return PEAR::raiseError($msg); + } + + if (substr($long_opt, -1) == '=') { + if (substr($long_opt, -2) != '==') { + /* Long option requires an argument. + Take the next argument if one wasn't specified. */; + if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) { + $msg = "Console_Getopt: option requires an argument --$opt"; + return PEAR::raiseError($msg); + } + + if (Console_Getopt::_isShortOpt($opt_arg) + || Console_Getopt::_isLongOpt($opt_arg)) { + $msg = "Console_Getopt: option requires an argument --$opt"; + return PEAR::raiseError($msg); + } + } + } else if ($opt_arg) { + $msg = "Console_Getopt: option --$opt doesn't allow an argument"; + return PEAR::raiseError($msg); + } + + $opts[] = array('--' . $opt, $opt_arg); + return; + } + + if ($skip_unknown === true) { + return; + } + + return PEAR::raiseError("Console_Getopt: unrecognized option --$opt"); + } + + /** + * Safely read the $argv PHP array across different PHP configurations. + * Will take care on register_globals and register_argc_argv ini directives + * + * @access public + * @return mixed the $argv PHP array or PEAR error if not registered + */ + function readPHPArgv() + { + global $argv; + if (!is_array($argv)) { + if (!@is_array($_SERVER['argv'])) { + if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) { + $msg = "Could not read cmd args (register_argc_argv=Off?)"; + return PEAR::raiseError("Console_Getopt: " . $msg); + } + return $GLOBALS['HTTP_SERVER_VARS']['argv']; + } + return $_SERVER['argv']; + } + return $argv; + } + +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/File/Iterator.php b/typo3conf/ext/phpunit/PEAR/File/Iterator.php new file mode 100644 index 0000000..aa0022b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/File/Iterator.php @@ -0,0 +1,197 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package File + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @since File available since Release 1.0.0 + */ + +/** + * FilterIterator implementation that filters files based on prefix(es) and/or + * suffix(es). Hidden files and files from hidden directories are also filtered. + * + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.2.6 + * @link http://github.com/sebastianbergmann/php-file-iterator/tree + * @since Class available since Release 1.0.0 + */ +class File_Iterator extends FilterIterator +{ + const PREFIX = 0; + const SUFFIX = 1; + + /** + * @var array + */ + protected $suffixes = array(); + + /** + * @var array + */ + protected $prefixes = array(); + + /** + * @var array + */ + protected $exclude = array(); + + /** + * @var string + */ + protected $basepath; + + /** + * @param Iterator $iterator + * @param array $suffixes + * @param array $prefixes + * @param array $exclude + * @param string $basepath + */ + public function __construct(Iterator $iterator, array $suffixes = array(), array $prefixes = array(), array $exclude = array(), $basepath = NULL) + { + $exclude = array_filter(array_map('realpath', $exclude)); + + if ($basepath !== NULL) { + $basepath = realpath($basepath); + } + + if ($basepath === FALSE) { + $basepath = NULL; + } else { + foreach ($exclude as &$_exclude) { + $_exclude = str_replace($basepath, '', $_exclude); + } + } + + $this->prefixes = $prefixes; + $this->suffixes = $suffixes; + $this->exclude = $exclude; + $this->basepath = $basepath; + + parent::__construct($iterator); + } + + /** + * @return boolean + */ + public function accept() + { + $current = $this->getInnerIterator()->current(); + $filename = $current->getFilename(); + $realpath = $current->getRealPath(); + + if ($this->basepath !== NULL) { + $realpath = str_replace($this->basepath, '', $realpath); + } + + // Filter files in hidden directories. + if (preg_match('=/\.[^/]*/=', $realpath)) { + return FALSE; + } + + return $this->acceptPath($realpath) && + $this->acceptPrefix($filename) && + $this->acceptSuffix($filename); + } + + /** + * @param string $path + * @return boolean + * @since Method available since Release 1.1.0 + */ + protected function acceptPath($path) + { + foreach ($this->exclude as $exclude) { + if (strpos($path, $exclude) === 0) { + return FALSE; + } + } + + return TRUE; + } + + /** + * @param string $filename + * @return boolean + * @since Method available since Release 1.1.0 + */ + protected function acceptPrefix($filename) + { + return $this->acceptSubString($filename, $this->prefixes, self::PREFIX); + } + + /** + * @param string $filename + * @return boolean + * @since Method available since Release 1.1.0 + */ + protected function acceptSuffix($filename) + { + return $this->acceptSubString($filename, $this->suffixes, self::SUFFIX); + } + + /** + * @param string $filename + * @param array $subString + * @param integer $type + * @return boolean + * @since Method available since Release 1.1.0 + */ + protected function acceptSubString($filename, array $subStrings, $type) + { + if (empty($subStrings)) { + return TRUE; + } + + $matched = FALSE; + + foreach ($subStrings as $string) { + if (($type == self::PREFIX && strpos($filename, $string) === 0) || + ($type == self::SUFFIX && + substr($filename, -1 * strlen($string)) == $string)) { + $matched = TRUE; + break; + } + } + + return $matched; + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/File/Iterator/Factory.php b/typo3conf/ext/phpunit/PEAR/File/Iterator/Factory.php new file mode 100644 index 0000000..b10729b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/File/Iterator/Factory.php @@ -0,0 +1,159 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package File + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @since File available since Release 1.1.0 + */ + +require_once 'File/Iterator.php'; + +/** + * Factory Method implementation that creates a File_Iterator that operates on + * an AppendIterator that contains an RecursiveDirectoryIterator for each given + * path. + * + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.2.6 + * @link http://github.com/sebastianbergmann/php-file-iterator/tree + * @since Class available since Release 1.1.0 + */ +class File_Iterator_Factory +{ + /** + * @param array|string $paths + * @param array|string $suffixes + * @param array|string $prefixes + * @param array $exclude + * @return AppendIterator + */ + public static function getFileIterator($paths, $suffixes = '', $prefixes = '', array $exclude = array()) + { + if (is_string($paths)) { + $paths = array($paths); + } + + $_paths = array(); + + foreach ($paths as $path) { + if ($locals = glob($path, GLOB_ONLYDIR)) { + $_paths = array_merge($_paths, $locals); + } else { + $_paths[] = $path; + } + } + + $paths = $_paths; + unset($_paths); + + if (is_string($prefixes)) { + if ($prefixes != '') { + $prefixes = array($prefixes); + } else { + $prefixes = array(); + } + } + + if (is_string($suffixes)) { + if ($suffixes != '') { + $suffixes = array($suffixes); + } else { + $suffixes = array(); + } + } + + $iterator = new AppendIterator; + + foreach ($paths as $path) { + if (is_dir($path)) { + $iterator->append( + new File_Iterator( + new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($path) + ), + $suffixes, + $prefixes, + $exclude, + $path + ) + ); + } + } + + return $iterator; + } + + /** + * @param array|string $paths + * @param array|string $suffixes + * @param array|string $prefixes + * @param array $exclude + * @return array + */ + public static function getFilesAsArray($paths, $suffixes = '', $prefixes = '', array $exclude = array()) + { + if (is_string($paths)) { + $paths = array($paths); + } + + $result = array(); + + $iterator = self::getFileIterator( + $paths, $suffixes, $prefixes, $exclude + ); + + foreach ($iterator as $file) { + $file = $file->getRealPath(); + + if ($file) { + $result[] = $file; + } + } + + foreach ($paths as $path) { + if (is_file($path)) { + $result[] = realpath($path); + } + } + + return array_unique($result); + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/OS/Guess.php b/typo3conf/ext/phpunit/PEAR/OS/Guess.php new file mode 100644 index 0000000..19c239a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/OS/Guess.php @@ -0,0 +1,338 @@ + + * @author Gregory Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Guess.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since PEAR 0.1 + */ + +// {{{ uname examples + +// php_uname() without args returns the same as 'uname -a', or a PHP-custom +// string for Windows. +// PHP versions prior to 4.3 return the uname of the host where PHP was built, +// as of 4.3 it returns the uname of the host running the PHP code. +// +// PC RedHat Linux 7.1: +// Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown +// +// PC Debian Potato: +// Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown +// +// PC FreeBSD 3.3: +// FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000 root@example.com:/usr/src/sys/compile/CONFIG i386 +// +// PC FreeBSD 4.3: +// FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001 root@example.com:/usr/src/sys/compile/CONFIG i386 +// +// PC FreeBSD 4.5: +// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb 6 23:59:23 CET 2002 root@example.com:/usr/src/sys/compile/CONFIG i386 +// +// PC FreeBSD 4.5 w/uname from GNU shellutils: +// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb i386 unknown +// +// HP 9000/712 HP-UX 10: +// HP-UX iq B.10.10 A 9000/712 2008429113 two-user license +// +// HP 9000/712 HP-UX 10 w/uname from GNU shellutils: +// HP-UX host B.10.10 A 9000/712 unknown +// +// IBM RS6000/550 AIX 4.3: +// AIX host 3 4 000003531C00 +// +// AIX 4.3 w/uname from GNU shellutils: +// AIX host 3 4 000003531C00 unknown +// +// SGI Onyx IRIX 6.5 w/uname from GNU shellutils: +// IRIX64 host 6.5 01091820 IP19 mips +// +// SGI Onyx IRIX 6.5: +// IRIX64 host 6.5 01091820 IP19 +// +// SparcStation 20 Solaris 8 w/uname from GNU shellutils: +// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc +// +// SparcStation 20 Solaris 8: +// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20 +// +// Mac OS X (Darwin) +// Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug 5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC Power Macintosh +// +// Mac OS X early versions +// + +// }}} + +/* TODO: + * - define endianness, to allow matchSignature("bigend") etc. + */ + +/** + * Retrieves information about the current operating system + * + * This class uses php_uname() to grok information about the current OS + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Gregory Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class OS_Guess +{ + var $sysname; + var $nodename; + var $cpu; + var $release; + var $extra; + + function OS_Guess($uname = null) + { + list($this->sysname, + $this->release, + $this->cpu, + $this->extra, + $this->nodename) = $this->parseSignature($uname); + } + + function parseSignature($uname = null) + { + static $sysmap = array( + 'HP-UX' => 'hpux', + 'IRIX64' => 'irix', + ); + static $cpumap = array( + 'i586' => 'i386', + 'i686' => 'i386', + 'ppc' => 'powerpc', + ); + if ($uname === null) { + $uname = php_uname(); + } + $parts = preg_split('/\s+/', trim($uname)); + $n = count($parts); + + $release = $machine = $cpu = ''; + $sysname = $parts[0]; + $nodename = $parts[1]; + $cpu = $parts[$n-1]; + $extra = ''; + if ($cpu == 'unknown') { + $cpu = $parts[$n - 2]; + } + + switch ($sysname) { + case 'AIX' : + $release = "$parts[3].$parts[2]"; + break; + case 'Windows' : + switch ($parts[1]) { + case '95/98': + $release = '9x'; + break; + default: + $release = $parts[1]; + break; + } + $cpu = 'i386'; + break; + case 'Linux' : + $extra = $this->_detectGlibcVersion(); + // use only the first two digits from the kernel version + $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]); + break; + case 'Mac' : + $sysname = 'darwin'; + $nodename = $parts[2]; + $release = $parts[3]; + if ($cpu == 'Macintosh') { + if ($parts[$n - 2] == 'Power') { + $cpu = 'powerpc'; + } + } + break; + case 'Darwin' : + if ($cpu == 'Macintosh') { + if ($parts[$n - 2] == 'Power') { + $cpu = 'powerpc'; + } + } + $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]); + break; + default: + $release = preg_replace('/-.*/', '', $parts[2]); + break; + } + + if (isset($sysmap[$sysname])) { + $sysname = $sysmap[$sysname]; + } else { + $sysname = strtolower($sysname); + } + if (isset($cpumap[$cpu])) { + $cpu = $cpumap[$cpu]; + } + return array($sysname, $release, $cpu, $extra, $nodename); + } + + function _detectGlibcVersion() + { + static $glibc = false; + if ($glibc !== false) { + return $glibc; // no need to run this multiple times + } + $major = $minor = 0; + include_once "System.php"; + // Use glibc's header file to + // get major and minor version number: + if (@file_exists('/usr/include/features.h') && + @is_readable('/usr/include/features.h')) { + if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) { + $features_file = fopen('/usr/include/features.h', 'rb'); + while (!feof($features_file)) { + $line = fgets($features_file, 8192); + if (!$line || (strpos($line, '#define') === false)) { + continue; + } + if (strpos($line, '__GLIBC__')) { + // major version number #define __GLIBC__ version + $line = preg_split('/\s+/', $line); + $glibc_major = trim($line[2]); + if (isset($glibc_minor)) { + break; + } + continue; + } + + if (strpos($line, '__GLIBC_MINOR__')) { + // got the minor version number + // #define __GLIBC_MINOR__ version + $line = preg_split('/\s+/', $line); + $glibc_minor = trim($line[2]); + if (isset($glibc_major)) { + break; + } + continue; + } + } + fclose($features_file); + if (!isset($glibc_major) || !isset($glibc_minor)) { + return $glibc = ''; + } + return $glibc = 'glibc' . trim($glibc_major) . "." . trim($glibc_minor) ; + } // no cpp + + $tmpfile = System::mktemp("glibctest"); + $fp = fopen($tmpfile, "w"); + fwrite($fp, "#include \n__GLIBC__ __GLIBC_MINOR__\n"); + fclose($fp); + $cpp = popen("/usr/bin/cpp $tmpfile", "r"); + while ($line = fgets($cpp, 1024)) { + if ($line{0} == '#' || trim($line) == '') { + continue; + } + + if (list($major, $minor) = explode(' ', trim($line))) { + break; + } + } + pclose($cpp); + unlink($tmpfile); + } // features.h + + if (!($major && $minor) && @is_link('/lib/libc.so.6')) { + // Let's try reading the libc.so.6 symlink + if (preg_match('/^libc-(.*)\.so$/', basename(readlink('/lib/libc.so.6')), $matches)) { + list($major, $minor) = explode('.', $matches[1]); + } + } + + if (!($major && $minor)) { + return $glibc = ''; + } + + return $glibc = "glibc{$major}.{$minor}"; + } + + function getSignature() + { + if (empty($this->extra)) { + return "{$this->sysname}-{$this->release}-{$this->cpu}"; + } + return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}"; + } + + function getSysname() + { + return $this->sysname; + } + + function getNodename() + { + return $this->nodename; + } + + function getCpu() + { + return $this->cpu; + } + + function getRelease() + { + return $this->release; + } + + function getExtra() + { + return $this->extra; + } + + function matchSignature($match) + { + $fragments = is_array($match) ? $match : explode('-', $match); + $n = count($fragments); + $matches = 0; + if ($n > 0) { + $matches += $this->_matchFragment($fragments[0], $this->sysname); + } + if ($n > 1) { + $matches += $this->_matchFragment($fragments[1], $this->release); + } + if ($n > 2) { + $matches += $this->_matchFragment($fragments[2], $this->cpu); + } + if ($n > 3) { + $matches += $this->_matchFragment($fragments[3], $this->extra); + } + return ($matches == $n); + } + + function _matchFragment($fragment, $value) + { + if (strcspn($fragment, '*?') < strlen($fragment)) { + $reg = '/^' . str_replace(array('*', '?', '/'), array('.*', '.', '\\/'), $fragment) . '\\z/'; + return preg_match($reg, $value); + } + return ($fragment == '*' || !strcasecmp($fragment, $value)); + } + +} +/* + * Local Variables: + * indent-tabs-mode: nil + * c-basic-offset: 4 + * End: + */ \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR.php b/typo3conf/ext/phpunit/PEAR/PEAR.php new file mode 100644 index 0000000..18fd4dd --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR.php @@ -0,0 +1,1063 @@ + + * @author Stig Bakken + * @author Tomas V.V.Cox + * @author Greg Beaver + * @copyright 1997-2010 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: PEAR.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/**#@+ + * ERROR constants + */ +define('PEAR_ERROR_RETURN', 1); +define('PEAR_ERROR_PRINT', 2); +define('PEAR_ERROR_TRIGGER', 4); +define('PEAR_ERROR_DIE', 8); +define('PEAR_ERROR_CALLBACK', 16); +/** + * WARNING: obsolete + * @deprecated + */ +define('PEAR_ERROR_EXCEPTION', 32); +/**#@-*/ +define('PEAR_ZE2', (function_exists('version_compare') && + version_compare(zend_version(), "2-dev", "ge"))); + +if (substr(PHP_OS, 0, 3) == 'WIN') { + define('OS_WINDOWS', true); + define('OS_UNIX', false); + define('PEAR_OS', 'Windows'); +} else { + define('OS_WINDOWS', false); + define('OS_UNIX', true); + define('PEAR_OS', 'Unix'); // blatant assumption +} + +$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; +$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; +$GLOBALS['_PEAR_destructor_object_list'] = array(); +$GLOBALS['_PEAR_shutdown_funcs'] = array(); +$GLOBALS['_PEAR_error_handler_stack'] = array(); + +@ini_set('track_errors', true); + +/** + * Base class for other PEAR classes. Provides rudimentary + * emulation of destructors. + * + * If you want a destructor in your class, inherit PEAR and make a + * destructor method called _yourclassname (same name as the + * constructor, but with a "_" prefix). Also, in your constructor you + * have to call the PEAR constructor: $this->PEAR();. + * The destructor method will be called without parameters. Note that + * at in some SAPI implementations (such as Apache), any output during + * the request shutdown (in which destructors are called) seems to be + * discarded. If you need to get any debug information from your + * destructor, use error_log(), syslog() or something similar. + * + * IMPORTANT! To use the emulated destructors you need to create the + * objects by reference: $obj =& new PEAR_child; + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V.V. Cox + * @author Greg Beaver + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @see PEAR_Error + * @since Class available since PHP 4.0.2 + * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear + */ +class PEAR +{ + /** + * Whether to enable internal debug messages. + * + * @var bool + * @access private + */ + var $_debug = false; + + /** + * Default error mode for this object. + * + * @var int + * @access private + */ + var $_default_error_mode = null; + + /** + * Default error options used for this object when error mode + * is PEAR_ERROR_TRIGGER. + * + * @var int + * @access private + */ + var $_default_error_options = null; + + /** + * Default error handler (callback) for this object, if error mode is + * PEAR_ERROR_CALLBACK. + * + * @var string + * @access private + */ + var $_default_error_handler = ''; + + /** + * Which class to use for error objects. + * + * @var string + * @access private + */ + var $_error_class = 'PEAR_Error'; + + /** + * An array of expected errors. + * + * @var array + * @access private + */ + var $_expected_errors = array(); + + /** + * Constructor. Registers this object in + * $_PEAR_destructor_object_list for destructor emulation if a + * destructor object exists. + * + * @param string $error_class (optional) which class to use for + * error objects, defaults to PEAR_Error. + * @access public + * @return void + */ + function PEAR($error_class = null) + { + $classname = strtolower(get_class($this)); + if ($this->_debug) { + print "PEAR constructor called, class=$classname\n"; + } + + if ($error_class !== null) { + $this->_error_class = $error_class; + } + + while ($classname && strcasecmp($classname, "pear")) { + $destructor = "_$classname"; + if (method_exists($this, $destructor)) { + global $_PEAR_destructor_object_list; + $_PEAR_destructor_object_list[] = &$this; + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + break; + } else { + $classname = get_parent_class($classname); + } + } + } + + /** + * Destructor (the emulated type of...). Does nothing right now, + * but is included for forward compatibility, so subclass + * destructors should always call it. + * + * See the note in the class desciption about output from + * destructors. + * + * @access public + * @return void + */ + function _PEAR() { + if ($this->_debug) { + printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); + } + } + + /** + * If you have a class that's mostly/entirely static, and you need static + * properties, you can use this method to simulate them. Eg. in your method(s) + * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); + * You MUST use a reference, or they will not persist! + * + * @access public + * @param string $class The calling classname, to prevent clashes + * @param string $var The variable to retrieve. + * @return mixed A reference to the variable. If not set it will be + * auto initialised to NULL. + */ + function &getStaticProperty($class, $var) + { + static $properties; + if (!isset($properties[$class])) { + $properties[$class] = array(); + } + + if (!array_key_exists($var, $properties[$class])) { + $properties[$class][$var] = null; + } + + return $properties[$class][$var]; + } + + /** + * Use this function to register a shutdown method for static + * classes. + * + * @access public + * @param mixed $func The function name (or array of class/method) to call + * @param mixed $args The arguments to pass to the function + * @return void + */ + function registerShutdownFunc($func, $args = array()) + { + // if we are called statically, there is a potential + // that no shutdown func is registered. Bug #6445 + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); + } + + /** + * Tell whether a value is a PEAR error. + * + * @param mixed $data the value to test + * @param int $code if $data is an error object, return true + * only if $code is a string and + * $obj->getMessage() == $code or + * $code is an integer and $obj->getCode() == $code + * @access public + * @return bool true if parameter is an error + */ + function isError($data, $code = null) + { + if (!is_a($data, 'PEAR_Error')) { + return false; + } + + if (is_null($code)) { + return true; + } elseif (is_string($code)) { + return $data->getMessage() == $code; + } + + return $data->getCode() == $code; + } + + /** + * Sets how errors generated by this object should be handled. + * Can be invoked both in objects and statically. If called + * statically, setErrorHandling sets the default behaviour for all + * PEAR objects. If called in an object, setErrorHandling sets + * the default behaviour for that object. + * + * @param int $mode + * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. + * + * @param mixed $options + * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one + * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * + * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected + * to be the callback function or method. A callback + * function is a string with the name of the function, a + * callback method is an array of two elements: the element + * at index 0 is the object, and the element at index 1 is + * the name of the method to call in the object. + * + * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is + * a printf format string used when printing the error + * message. + * + * @access public + * @return void + * @see PEAR_ERROR_RETURN + * @see PEAR_ERROR_PRINT + * @see PEAR_ERROR_TRIGGER + * @see PEAR_ERROR_DIE + * @see PEAR_ERROR_CALLBACK + * @see PEAR_ERROR_EXCEPTION + * + * @since PHP 4.0.5 + */ + function setErrorHandling($mode = null, $options = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + $setmode = &$this->_default_error_mode; + $setoptions = &$this->_default_error_options; + } else { + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + } + + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + } + + /** + * This method is used to tell which errors you expect to get. + * Expected errors are always returned with error mode + * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, + * and this method pushes a new element onto it. The list of + * expected errors are in effect until they are popped off the + * stack with the popExpect() method. + * + * Note that this method can not be called statically + * + * @param mixed $code a single error code or an array of error codes to expect + * + * @return int the new depth of the "expected errors" stack + * @access public + */ + function expectError($code = '*') + { + if (is_array($code)) { + array_push($this->_expected_errors, $code); + } else { + array_push($this->_expected_errors, array($code)); + } + return count($this->_expected_errors); + } + + /** + * This method pops one element off the expected error codes + * stack. + * + * @return array the list of error codes that were popped + */ + function popExpect() + { + return array_pop($this->_expected_errors); + } + + /** + * This method checks unsets an error code if available + * + * @param mixed error code + * @return bool true if the error code was unset, false otherwise + * @access private + * @since PHP 4.3.0 + */ + function _checkDelExpect($error_code) + { + $deleted = false; + foreach ($this->_expected_errors as $key => $error_array) { + if (in_array($error_code, $error_array)) { + unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); + $deleted = true; + } + + // clean up empty arrays + if (0 == count($this->_expected_errors[$key])) { + unset($this->_expected_errors[$key]); + } + } + + return $deleted; + } + + /** + * This method deletes all occurences of the specified element from + * the expected error codes stack. + * + * @param mixed $error_code error code that should be deleted + * @return mixed list of error codes that were deleted or error + * @access public + * @since PHP 4.3.0 + */ + function delExpect($error_code) + { + $deleted = false; + if ((is_array($error_code) && (0 != count($error_code)))) { + // $error_code is a non-empty array here; we walk through it trying + // to unset all values + foreach ($error_code as $key => $error) { + $deleted = $this->_checkDelExpect($error) ? true : false; + } + + return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } elseif (!empty($error_code)) { + // $error_code comes alone, trying to unset it + if ($this->_checkDelExpect($error_code)) { + return true; + } + + return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } + + // $error_code is empty + return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME + } + + /** + * This method is a wrapper that returns an instance of the + * configured error class with this object's default error + * handling applied. If the $mode and $options parameters are not + * specified, the object's defaults are used. + * + * @param mixed $message a text error message or a PEAR error object + * + * @param int $code a numeric error code (it is up to your class + * to define these if you want to use codes) + * + * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. + * + * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter + * specifies the PHP-internal error level (one of + * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * If $mode is PEAR_ERROR_CALLBACK, this + * parameter specifies the callback function or + * method. In other error modes this parameter + * is ignored. + * + * @param string $userinfo If you need to pass along for example debug + * information, this parameter is meant for that. + * + * @param string $error_class The returned error object will be + * instantiated from this class, if specified. + * + * @param bool $skipmsg If true, raiseError will only pass error codes, + * the error message parameter will be dropped. + * + * @access public + * @return object a PEAR error object + * @see PEAR::setErrorHandling + * @since PHP 4.0.5 + */ + function &raiseError($message = null, + $code = null, + $mode = null, + $options = null, + $userinfo = null, + $error_class = null, + $skipmsg = false) + { + // The error is yet a PEAR error object + if (is_object($message)) { + $code = $message->getCode(); + $userinfo = $message->getUserInfo(); + $error_class = $message->getType(); + $message->error_message_prefix = ''; + $message = $message->getMessage(); + } + + if ( + isset($this) && + isset($this->_expected_errors) && + count($this->_expected_errors) > 0 && + count($exp = end($this->_expected_errors)) + ) { + if ($exp[0] == "*" || + (is_int(reset($exp)) && in_array($code, $exp)) || + (is_string(reset($exp)) && in_array($message, $exp)) + ) { + $mode = PEAR_ERROR_RETURN; + } + } + + // No mode given, try global ones + if ($mode === null) { + // Class error handler + if (isset($this) && isset($this->_default_error_mode)) { + $mode = $this->_default_error_mode; + $options = $this->_default_error_options; + // Global error handler + } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { + $mode = $GLOBALS['_PEAR_default_error_mode']; + $options = $GLOBALS['_PEAR_default_error_options']; + } + } + + if ($error_class !== null) { + $ec = $error_class; + } elseif (isset($this) && isset($this->_error_class)) { + $ec = $this->_error_class; + } else { + $ec = 'PEAR_Error'; + } + + if (intval(PHP_VERSION) < 5) { + // little non-eval hack to fix bug #12147 + include 'PEAR/FixPHP5PEARWarnings.php'; + return $a; + } + + if ($skipmsg) { + $a = new $ec($code, $mode, $options, $userinfo); + } else { + $a = new $ec($message, $code, $mode, $options, $userinfo); + } + + return $a; + } + + /** + * Simpler form of raiseError with fewer options. In most cases + * message, code and userinfo are enough. + * + * @param mixed $message a text error message or a PEAR error object + * + * @param int $code a numeric error code (it is up to your class + * to define these if you want to use codes) + * + * @param string $userinfo If you need to pass along for example debug + * information, this parameter is meant for that. + * + * @access public + * @return object a PEAR error object + * @see PEAR::raiseError + */ + function &throwError($message = null, $code = null, $userinfo = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + $a = &$this->raiseError($message, $code, null, null, $userinfo); + return $a; + } + + $a = &PEAR::raiseError($message, $code, null, null, $userinfo); + return $a; + } + + function staticPushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + $stack[] = array($def_mode, $def_options); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $def_mode = $mode; + $def_options = $options; + break; + + case PEAR_ERROR_CALLBACK: + $def_mode = $mode; + // class/object method callback + if (is_callable($options)) { + $def_options = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + $stack[] = array($mode, $options); + return true; + } + + function staticPopErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + return true; + } + + /** + * Push a new error handler on top of the error handler options stack. With this + * you can easily override the actual error handler for some code and restore + * it later with popErrorHandling. + * + * @param mixed $mode (same as setErrorHandling) + * @param mixed $options (same as setErrorHandling) + * + * @return bool Always true + * + * @see PEAR::setErrorHandling + */ + function pushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + if (isset($this) && is_a($this, 'PEAR')) { + $def_mode = &$this->_default_error_mode; + $def_options = &$this->_default_error_options; + } else { + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + } + $stack[] = array($def_mode, $def_options); + + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + $stack[] = array($mode, $options); + return true; + } + + /** + * Pop the last error handler used + * + * @return bool Always true + * + * @see PEAR::pushErrorHandling + */ + function popErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + return true; + } + + /** + * OS independant PHP extension load. Remember to take care + * on the correct extension name for case sensitive OSes. + * + * @param string $ext The extension name + * @return bool Success or not on the dl() call + */ + function loadExtension($ext) + { + if (extension_loaded($ext)) { + return true; + } + + // if either returns true dl() will produce a FATAL error, stop that + if ( + function_exists('dl') === false || + ini_get('enable_dl') != 1 || + ini_get('safe_mode') == 1 + ) { + return false; + } + + if (OS_WINDOWS) { + $suffix = '.dll'; + } elseif (PHP_OS == 'HP-UX') { + $suffix = '.sl'; + } elseif (PHP_OS == 'AIX') { + $suffix = '.a'; + } elseif (PHP_OS == 'OSX') { + $suffix = '.bundle'; + } else { + $suffix = '.so'; + } + + return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); + } +} + +if (PEAR_ZE2) { + include_once 'PEAR5.php'; +} + +function _PEAR_call_destructors() +{ + global $_PEAR_destructor_object_list; + if (is_array($_PEAR_destructor_object_list) && + sizeof($_PEAR_destructor_object_list)) + { + reset($_PEAR_destructor_object_list); + if (PEAR_ZE2) { + $destructLifoExists = PEAR5::getStaticProperty('PEAR', 'destructlifo'); + } else { + $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo'); + } + + if ($destructLifoExists) { + $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); + } + + while (list($k, $objref) = each($_PEAR_destructor_object_list)) { + $classname = get_class($objref); + while ($classname) { + $destructor = "_$classname"; + if (method_exists($objref, $destructor)) { + $objref->$destructor(); + break; + } else { + $classname = get_parent_class($classname); + } + } + } + // Empty the object list to ensure that destructors are + // not called more than once. + $_PEAR_destructor_object_list = array(); + } + + // Now call the shutdown functions + if ( + isset($GLOBALS['_PEAR_shutdown_funcs']) && + is_array($GLOBALS['_PEAR_shutdown_funcs']) && + !empty($GLOBALS['_PEAR_shutdown_funcs']) + ) { + foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { + call_user_func_array($value[0], $value[1]); + } + } +} + +/** + * Standard PEAR error class for PHP 4 + * + * This class is supserseded by {@link PEAR_Exception} in PHP 5 + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V.V. Cox + * @author Gregory Beaver + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/manual/en/core.pear.pear-error.php + * @see PEAR::raiseError(), PEAR::throwError() + * @since Class available since PHP 4.0.2 + */ +class PEAR_Error +{ + var $error_message_prefix = ''; + var $mode = PEAR_ERROR_RETURN; + var $level = E_USER_NOTICE; + var $code = -1; + var $message = ''; + var $userinfo = ''; + var $backtrace = null; + + /** + * PEAR_Error constructor + * + * @param string $message message + * + * @param int $code (optional) error code + * + * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, + * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION + * + * @param mixed $options (optional) error level, _OR_ in the case of + * PEAR_ERROR_CALLBACK, the callback function or object/method + * tuple. + * + * @param string $userinfo (optional) additional user/debug info + * + * @access public + * + */ + function PEAR_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + if ($mode === null) { + $mode = PEAR_ERROR_RETURN; + } + $this->message = $message; + $this->code = $code; + $this->mode = $mode; + $this->userinfo = $userinfo; + + if (PEAR_ZE2) { + $skiptrace = PEAR5::getStaticProperty('PEAR_Error', 'skiptrace'); + } else { + $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace'); + } + + if (!$skiptrace) { + $this->backtrace = debug_backtrace(); + if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) { + unset($this->backtrace[0]['object']); + } + } + + if ($mode & PEAR_ERROR_CALLBACK) { + $this->level = E_USER_NOTICE; + $this->callback = $options; + } else { + if ($options === null) { + $options = E_USER_NOTICE; + } + + $this->level = $options; + $this->callback = null; + } + + if ($this->mode & PEAR_ERROR_PRINT) { + if (is_null($options) || is_int($options)) { + $format = "%s"; + } else { + $format = $options; + } + + printf($format, $this->getMessage()); + } + + if ($this->mode & PEAR_ERROR_TRIGGER) { + trigger_error($this->getMessage(), $this->level); + } + + if ($this->mode & PEAR_ERROR_DIE) { + $msg = $this->getMessage(); + if (is_null($options) || is_int($options)) { + $format = "%s"; + if (substr($msg, -1) != "\n") { + $msg .= "\n"; + } + } else { + $format = $options; + } + die(sprintf($format, $msg)); + } + + if ($this->mode & PEAR_ERROR_CALLBACK && is_callable($this->callback)) { + call_user_func($this->callback, $this); + } + + if ($this->mode & PEAR_ERROR_EXCEPTION) { + trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING); + eval('$e = new Exception($this->message, $this->code);throw($e);'); + } + } + + /** + * Get the error mode from an error object. + * + * @return int error mode + * @access public + */ + function getMode() + { + return $this->mode; + } + + /** + * Get the callback function/method from an error object. + * + * @return mixed callback function or object/method array + * @access public + */ + function getCallback() + { + return $this->callback; + } + + /** + * Get the error message from an error object. + * + * @return string full error message + * @access public + */ + function getMessage() + { + return ($this->error_message_prefix . $this->message); + } + + /** + * Get error code from an error object + * + * @return int error code + * @access public + */ + function getCode() + { + return $this->code; + } + + /** + * Get the name of this error/exception. + * + * @return string error/exception name (type) + * @access public + */ + function getType() + { + return get_class($this); + } + + /** + * Get additional user-supplied information. + * + * @return string user-supplied information + * @access public + */ + function getUserInfo() + { + return $this->userinfo; + } + + /** + * Get additional debug information supplied by the application. + * + * @return string debug information + * @access public + */ + function getDebugInfo() + { + return $this->getUserInfo(); + } + + /** + * Get the call backtrace from where the error was generated. + * Supported with PHP 4.3.0 or newer. + * + * @param int $frame (optional) what frame to fetch + * @return array Backtrace, or NULL if not available. + * @access public + */ + function getBacktrace($frame = null) + { + if (defined('PEAR_IGNORE_BACKTRACE')) { + return null; + } + if ($frame === null) { + return $this->backtrace; + } + return $this->backtrace[$frame]; + } + + function addUserInfo($info) + { + if (empty($this->userinfo)) { + $this->userinfo = $info; + } else { + $this->userinfo .= " ** $info"; + } + } + + function __toString() + { + return $this->getMessage(); + } + + /** + * Make a string representation of this object. + * + * @return string a string with an object summary + * @access public + */ + function toString() + { + $modes = array(); + $levels = array(E_USER_NOTICE => 'notice', + E_USER_WARNING => 'warning', + E_USER_ERROR => 'error'); + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_array($this->callback)) { + $callback = (is_object($this->callback[0]) ? + strtolower(get_class($this->callback[0])) : + $this->callback[0]) . '::' . + $this->callback[1]; + } else { + $callback = $this->callback; + } + return sprintf('[%s: message="%s" code=%d mode=callback '. + 'callback=%s prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + $callback, $this->error_message_prefix, + $this->userinfo); + } + if ($this->mode & PEAR_ERROR_PRINT) { + $modes[] = 'print'; + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + $modes[] = 'trigger'; + } + if ($this->mode & PEAR_ERROR_DIE) { + $modes[] = 'die'; + } + if ($this->mode & PEAR_ERROR_RETURN) { + $modes[] = 'return'; + } + return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. + 'prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + implode("|", $modes), $levels[$this->level], + $this->error_message_prefix, + $this->userinfo); + } +} + +/* + * Local Variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Autoloader.php b/typo3conf/ext/phpunit/PEAR/PEAR/Autoloader.php new file mode 100644 index 0000000..19af86e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Autoloader.php @@ -0,0 +1,218 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Autoloader.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/manual/en/core.ppm.php#core.ppm.pear-autoloader + * @since File available since Release 0.1 + * @deprecated File deprecated in Release 1.4.0a1 + */ + +// /* vim: set expandtab tabstop=4 shiftwidth=4: */ + +if (!extension_loaded("overload")) { + // die hard without ext/overload + die("Rebuild PHP with the `overload' extension to use PEAR_Autoloader"); +} + +/** + * Include for PEAR_Error and PEAR classes + */ +require_once "PEAR.php"; + +/** + * This class is for objects where you want to separate the code for + * some methods into separate classes. This is useful if you have a + * class with not-frequently-used methods that contain lots of code + * that you would like to avoid always parsing. + * + * The PEAR_Autoloader class provides autoloading and aggregation. + * The autoloading lets you set up in which classes the separated + * methods are found. Aggregation is the technique used to import new + * methods, an instance of each class providing separated methods is + * stored and called every time the aggregated method is called. + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/manual/en/core.ppm.php#core.ppm.pear-autoloader + * @since File available since Release 0.1 + * @deprecated File deprecated in Release 1.4.0a1 + */ +class PEAR_Autoloader extends PEAR +{ + // {{{ properties + + /** + * Map of methods and classes where they are defined + * + * @var array + * + * @access private + */ + var $_autoload_map = array(); + + /** + * Map of methods and aggregate objects + * + * @var array + * + * @access private + */ + var $_method_map = array(); + + // }}} + // {{{ addAutoload() + + /** + * Add one or more autoload entries. + * + * @param string $method which method to autoload + * + * @param string $classname (optional) which class to find the method in. + * If the $method parameter is an array, this + * parameter may be omitted (and will be ignored + * if not), and the $method parameter will be + * treated as an associative array with method + * names as keys and class names as values. + * + * @return void + * + * @access public + */ + function addAutoload($method, $classname = null) + { + if (is_array($method)) { + array_walk($method, create_function('$a,&$b', '$b = strtolower($b);')); + $this->_autoload_map = array_merge($this->_autoload_map, $method); + } else { + $this->_autoload_map[strtolower($method)] = $classname; + } + } + + // }}} + // {{{ removeAutoload() + + /** + * Remove an autoload entry. + * + * @param string $method which method to remove the autoload entry for + * + * @return bool TRUE if an entry was removed, FALSE if not + * + * @access public + */ + function removeAutoload($method) + { + $method = strtolower($method); + $ok = isset($this->_autoload_map[$method]); + unset($this->_autoload_map[$method]); + return $ok; + } + + // }}} + // {{{ addAggregateObject() + + /** + * Add an aggregate object to this object. If the specified class + * is not defined, loading it will be attempted following PEAR's + * file naming scheme. All the methods in the class will be + * aggregated, except private ones (name starting with an + * underscore) and constructors. + * + * @param string $classname what class to instantiate for the object. + * + * @return void + * + * @access public + */ + function addAggregateObject($classname) + { + $classname = strtolower($classname); + if (!class_exists($classname)) { + $include_file = preg_replace('/[^a-z0-9]/i', '_', $classname); + include_once $include_file; + } + $obj =& new $classname; + $methods = get_class_methods($classname); + foreach ($methods as $method) { + // don't import priviate methods and constructors + if ($method{0} != '_' && $method != $classname) { + $this->_method_map[$method] = $obj; + } + } + } + + // }}} + // {{{ removeAggregateObject() + + /** + * Remove an aggregate object. + * + * @param string $classname the class of the object to remove + * + * @return bool TRUE if an object was removed, FALSE if not + * + * @access public + */ + function removeAggregateObject($classname) + { + $ok = false; + $classname = strtolower($classname); + reset($this->_method_map); + while (list($method, $obj) = each($this->_method_map)) { + if (is_a($obj, $classname)) { + unset($this->_method_map[$method]); + $ok = true; + } + } + return $ok; + } + + // }}} + // {{{ __call() + + /** + * Overloaded object call handler, called each time an + * undefined/aggregated method is invoked. This method repeats + * the call in the right aggregate object and passes on the return + * value. + * + * @param string $method which method that was called + * + * @param string $args An array of the parameters passed in the + * original call + * + * @return mixed The return value from the aggregated method, or a PEAR + * error if the called method was unknown. + */ + function __call($method, $args, &$retval) + { + $method = strtolower($method); + if (empty($this->_method_map[$method]) && isset($this->_autoload_map[$method])) { + $this->addAggregateObject($this->_autoload_map[$method]); + } + if (isset($this->_method_map[$method])) { + $retval = call_user_func_array(array($this->_method_map[$method], $method), $args); + return true; + } + return false; + } + + // }}} +} + +overload("PEAR_Autoloader"); + +?> diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Builder.php b/typo3conf/ext/phpunit/PEAR/PEAR/Builder.php new file mode 100644 index 0000000..16a8253 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Builder.php @@ -0,0 +1,489 @@ + + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Builder.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + * + * TODO: log output parameters in PECL command line + * TODO: msdev path in configuration + */ + +/** + * Needed for extending PEAR_Builder + */ +require_once 'PEAR/Common.php'; +require_once 'PEAR/PackageFile.php'; + +/** + * Class to handle building (compiling) extensions. + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since PHP 4.0.2 + * @see http://pear.php.net/manual/en/core.ppm.pear-builder.php + */ +class PEAR_Builder extends PEAR_Common +{ + var $php_api_version = 0; + var $zend_module_api_no = 0; + var $zend_extension_api_no = 0; + + var $extensions_built = array(); + + /** + * @var string Used for reporting when it is not possible to pass function + * via extra parameter, e.g. log, msdevCallback + */ + var $current_callback = null; + + // used for msdev builds + var $_lastline = null; + var $_firstline = null; + + /** + * PEAR_Builder constructor. + * + * @param object $ui user interface object (instance of PEAR_Frontend_*) + * + * @access public + */ + function PEAR_Builder(&$ui) + { + parent::PEAR_Common(); + $this->setFrontendObject($ui); + } + + /** + * Build an extension from source on windows. + * requires msdev + */ + function _build_win32($descfile, $callback = null) + { + if (is_object($descfile)) { + $pkg = $descfile; + $descfile = $pkg->getPackageFile(); + } else { + $pf = &new PEAR_PackageFile($this->config, $this->debug); + $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($pkg)) { + return $pkg; + } + } + $dir = dirname($descfile); + $old_cwd = getcwd(); + + if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) { + return $this->raiseError("could not chdir to $dir"); + } + + // packages that were in a .tar have the packagefile in this directory + $vdir = $pkg->getPackage() . '-' . $pkg->getVersion(); + if (file_exists($dir) && is_dir($vdir)) { + if (!chdir($vdir)) { + return $this->raiseError("could not chdir to " . realpath($vdir)); + } + + $dir = getcwd(); + } + + $this->log(2, "building in $dir"); + + $dsp = $pkg->getPackage().'.dsp'; + if (!file_exists("$dir/$dsp")) { + return $this->raiseError("The DSP $dsp does not exist."); + } + // XXX TODO: make release build type configurable + $command = 'msdev '.$dsp.' /MAKE "'.$pkg->getPackage(). ' - Release"'; + + $err = $this->_runCommand($command, array(&$this, 'msdevCallback')); + if (PEAR::isError($err)) { + return $err; + } + + // figure out the build platform and type + $platform = 'Win32'; + $buildtype = 'Release'; + if (preg_match('/.*?'.$pkg->getPackage().'\s-\s(\w+)\s(.*?)-+/i',$this->_firstline,$matches)) { + $platform = $matches[1]; + $buildtype = $matches[2]; + } + + if (preg_match('/(.*)?\s-\s(\d+).*?(\d+)/', $this->_lastline, $matches)) { + if ($matches[2]) { + // there were errors in the build + return $this->raiseError("There were errors during compilation."); + } + $out = $matches[1]; + } else { + return $this->raiseError("Did not understand the completion status returned from msdev.exe."); + } + + // msdev doesn't tell us the output directory :/ + // open the dsp, find /out and use that directory + $dsptext = join(file($dsp),''); + + // this regex depends on the build platform and type having been + // correctly identified above. + $regex ='/.*?!IF\s+"\$\(CFG\)"\s+==\s+("'. + $pkg->getPackage().'\s-\s'. + $platform.'\s'. + $buildtype.'").*?'. + '\/out:"(.*?)"/is'; + + if ($dsptext && preg_match($regex, $dsptext, $matches)) { + // what we get back is a relative path to the output file itself. + $outfile = realpath($matches[2]); + } else { + return $this->raiseError("Could not retrieve output information from $dsp."); + } + // realpath returns false if the file doesn't exist + if ($outfile && copy($outfile, "$dir/$out")) { + $outfile = "$dir/$out"; + } + + $built_files[] = array( + 'file' => "$outfile", + 'php_api' => $this->php_api_version, + 'zend_mod_api' => $this->zend_module_api_no, + 'zend_ext_api' => $this->zend_extension_api_no, + ); + + return $built_files; + } + // }}} + + // {{{ msdevCallback() + function msdevCallback($what, $data) + { + if (!$this->_firstline) + $this->_firstline = $data; + $this->_lastline = $data; + call_user_func($this->current_callback, $what, $data); + } + + /** + * @param string + * @param string + * @param array + * @access private + */ + function _harvestInstDir($dest_prefix, $dirname, &$built_files) + { + $d = opendir($dirname); + if (!$d) + return false; + + $ret = true; + while (($ent = readdir($d)) !== false) { + if ($ent{0} == '.') + continue; + + $full = $dirname . DIRECTORY_SEPARATOR . $ent; + if (is_dir($full)) { + if (!$this->_harvestInstDir( + $dest_prefix . DIRECTORY_SEPARATOR . $ent, + $full, $built_files)) { + $ret = false; + break; + } + } else { + $dest = $dest_prefix . DIRECTORY_SEPARATOR . $ent; + $built_files[] = array( + 'file' => $full, + 'dest' => $dest, + 'php_api' => $this->php_api_version, + 'zend_mod_api' => $this->zend_module_api_no, + 'zend_ext_api' => $this->zend_extension_api_no, + ); + } + } + closedir($d); + return $ret; + } + + /** + * Build an extension from source. Runs "phpize" in the source + * directory, but compiles in a temporary directory + * (TMPDIR/pear-build-USER/PACKAGE-VERSION). + * + * @param string|PEAR_PackageFile_v* $descfile path to XML package description file, or + * a PEAR_PackageFile object + * + * @param mixed $callback callback function used to report output, + * see PEAR_Builder::_runCommand for details + * + * @return array an array of associative arrays with built files, + * format: + * array( array( 'file' => '/path/to/ext.so', + * 'php_api' => YYYYMMDD, + * 'zend_mod_api' => YYYYMMDD, + * 'zend_ext_api' => YYYYMMDD ), + * ... ) + * + * @access public + * + * @see PEAR_Builder::_runCommand + */ + function build($descfile, $callback = null) + { + if (preg_match('/(\\/|\\\\|^)([^\\/\\\\]+)?php(.+)?$/', + $this->config->get('php_bin'), $matches)) { + if (isset($matches[2]) && strlen($matches[2]) && + trim($matches[2]) != trim($this->config->get('php_prefix'))) { + $this->log(0, 'WARNING: php_bin ' . $this->config->get('php_bin') . + ' appears to have a prefix ' . $matches[2] . ', but' . + ' config variable php_prefix does not match'); + } + + if (isset($matches[3]) && strlen($matches[3]) && + trim($matches[3]) != trim($this->config->get('php_suffix'))) { + $this->log(0, 'WARNING: php_bin ' . $this->config->get('php_bin') . + ' appears to have a suffix ' . $matches[3] . ', but' . + ' config variable php_suffix does not match'); + } + } + + $this->current_callback = $callback; + if (PEAR_OS == "Windows") { + return $this->_build_win32($descfile, $callback); + } + + if (PEAR_OS != 'Unix') { + return $this->raiseError("building extensions not supported on this platform"); + } + + if (is_object($descfile)) { + $pkg = $descfile; + $descfile = $pkg->getPackageFile(); + if (is_a($pkg, 'PEAR_PackageFile_v1')) { + $dir = dirname($descfile); + } else { + $dir = $pkg->_config->get('temp_dir') . '/' . $pkg->getName(); + // automatically delete at session end + $this->addTempFile($dir); + } + } else { + $pf = &new PEAR_PackageFile($this->config); + $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($pkg)) { + return $pkg; + } + $dir = dirname($descfile); + } + + // Find config. outside of normal path - e.g. config.m4 + foreach (array_keys($pkg->getInstallationFileList()) as $item) { + if (stristr($item, 'config.')) { + $dir .= DIRECTORY_SEPARATOR . dirname($item); + break; + } + } + + $old_cwd = getcwd(); + if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) { + return $this->raiseError("could not chdir to $dir"); + } + + $vdir = $pkg->getPackage() . '-' . $pkg->getVersion(); + if (is_dir($vdir)) { + chdir($vdir); + } + + $dir = getcwd(); + $this->log(2, "building in $dir"); + putenv('PATH=' . $this->config->get('bin_dir') . ':' . getenv('PATH')); + $err = $this->_runCommand($this->config->get('php_prefix') + . "phpize" . + $this->config->get('php_suffix'), + array(&$this, 'phpizeCallback')); + if (PEAR::isError($err)) { + return $err; + } + + if (!$err) { + return $this->raiseError("`phpize' failed"); + } + + // {{{ start of interactive part + $configure_command = "$dir/configure"; + $configure_options = $pkg->getConfigureOptions(); + if ($configure_options) { + foreach ($configure_options as $o) { + $default = array_key_exists('default', $o) ? $o['default'] : null; + list($r) = $this->ui->userDialog('build', + array($o['prompt']), + array('text'), + array($default)); + if (substr($o['name'], 0, 5) == 'with-' && + ($r == 'yes' || $r == 'autodetect')) { + $configure_command .= " --$o[name]"; + } else { + $configure_command .= " --$o[name]=".trim($r); + } + } + } + // }}} end of interactive part + + // FIXME make configurable + if (!$user=getenv('USER')) { + $user='defaultuser'; + } + + $tmpdir = $this->config->get('temp_dir'); + $build_basedir = System::mktemp(" -t $tmpdir -d pear-build-$user"); + $build_dir = "$build_basedir/$vdir"; + $inst_dir = "$build_basedir/install-$vdir"; + $this->log(1, "building in $build_dir"); + if (is_dir($build_dir)) { + System::rm(array('-rf', $build_dir)); + } + + if (!System::mkDir(array('-p', $build_dir))) { + return $this->raiseError("could not create build dir: $build_dir"); + } + + $this->addTempFile($build_dir); + if (!System::mkDir(array('-p', $inst_dir))) { + return $this->raiseError("could not create temporary install dir: $inst_dir"); + } + $this->addTempFile($inst_dir); + + $make_command = getenv('MAKE') ? getenv('MAKE') : 'make'; + + $to_run = array( + $configure_command, + $make_command, + "$make_command INSTALL_ROOT=\"$inst_dir\" install", + "find \"$inst_dir\" | xargs ls -dils" + ); + if (!file_exists($build_dir) || !is_dir($build_dir) || !chdir($build_dir)) { + return $this->raiseError("could not chdir to $build_dir"); + } + putenv('PHP_PEAR_VERSION=1.9.3'); + foreach ($to_run as $cmd) { + $err = $this->_runCommand($cmd, $callback); + if (PEAR::isError($err)) { + chdir($old_cwd); + return $err; + } + if (!$err) { + chdir($old_cwd); + return $this->raiseError("`$cmd' failed"); + } + } + if (!($dp = opendir("modules"))) { + chdir($old_cwd); + return $this->raiseError("no `modules' directory found"); + } + $built_files = array(); + $prefix = exec($this->config->get('php_prefix') + . "php-config" . + $this->config->get('php_suffix') . " --prefix"); + $this->_harvestInstDir($prefix, $inst_dir . DIRECTORY_SEPARATOR . $prefix, $built_files); + chdir($old_cwd); + return $built_files; + } + + /** + * Message callback function used when running the "phpize" + * program. Extracts the API numbers used. Ignores other message + * types than "cmdoutput". + * + * @param string $what the type of message + * @param mixed $data the message + * + * @return void + * + * @access public + */ + function phpizeCallback($what, $data) + { + if ($what != 'cmdoutput') { + return; + } + $this->log(1, rtrim($data)); + if (preg_match('/You should update your .aclocal.m4/', $data)) { + return; + } + $matches = array(); + if (preg_match('/^\s+(\S[^:]+):\s+(\d{8})/', $data, $matches)) { + $member = preg_replace('/[^a-z]/', '_', strtolower($matches[1])); + $apino = (int)$matches[2]; + if (isset($this->$member)) { + $this->$member = $apino; + //$msg = sprintf("%-22s : %d", $matches[1], $apino); + //$this->log(1, $msg); + } + } + } + + /** + * Run an external command, using a message callback to report + * output. The command will be run through popen and output is + * reported for every line with a "cmdoutput" message with the + * line string, including newlines, as payload. + * + * @param string $command the command to run + * + * @param mixed $callback (optional) function to use as message + * callback + * + * @return bool whether the command was successful (exit code 0 + * means success, any other means failure) + * + * @access private + */ + function _runCommand($command, $callback = null) + { + $this->log(1, "running: $command"); + $pp = popen("$command 2>&1", "r"); + if (!$pp) { + return $this->raiseError("failed to run `$command'"); + } + if ($callback && $callback[0]->debug == 1) { + $olddbg = $callback[0]->debug; + $callback[0]->debug = 2; + } + + while ($line = fgets($pp, 1024)) { + if ($callback) { + call_user_func($callback, 'cmdoutput', $line); + } else { + $this->log(2, rtrim($line)); + } + } + if ($callback && isset($olddbg)) { + $callback[0]->debug = $olddbg; + } + + $exitcode = is_resource($pp) ? pclose($pp) : -1; + return ($exitcode == 0); + } + + function log($level, $msg) + { + if ($this->current_callback) { + if ($this->debug >= $level) { + call_user_func($this->current_callback, 'output', $msg); + } + return; + } + return PEAR_Common::log($level, $msg); + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/ChannelFile.php b/typo3conf/ext/phpunit/PEAR/PEAR/ChannelFile.php new file mode 100644 index 0000000..4460823 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/ChannelFile.php @@ -0,0 +1,1559 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: ChannelFile.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Needed for error handling + */ +require_once 'PEAR/ErrorStack.php'; +require_once 'PEAR/XMLParser.php'; +require_once 'PEAR/Common.php'; + +/** + * Error code if the channel.xml tag does not contain a valid version + */ +define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1); +/** + * Error code if the channel.xml tag version is not supported (version 1.0 is the only supported version, + * currently + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2); + +/** + * Error code if parsing is attempted with no xml extension + */ +define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3); + +/** + * Error code if creating the xml parser resource fails + */ +define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4); + +/** + * Error code used for all sax xml parsing errors + */ +define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5); + +/**#@+ + * Validation errors + */ +/** + * Error code when channel name is missing + */ +define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6); +/** + * Error code when channel name is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7); +/** + * Error code when channel summary is missing + */ +define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8); +/** + * Error code when channel summary is multi-line + */ +define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9); +/** + * Error code when channel server is missing for protocol + */ +define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10); +/** + * Error code when channel server is invalid for protocol + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11); +/** + * Error code when a mirror name is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21); +/** + * Error code when a mirror type is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22); +/** + * Error code when an attempt is made to generate xml, but the parsed content is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID', 23); +/** + * Error code when an empty package name validate regex is passed in + */ +define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24); +/** + * Error code when a tag has no version + */ +define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25); +/** + * Error code when a tag has no name + */ +define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26); +/** + * Error code when a tag has no name + */ +define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27); +/** + * Error code when a tag has no version attribute + */ +define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28); +/** + * Error code when a mirror does not exist but is called for in one of the set* + * methods. + */ +define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32); +/** + * Error code when a server port is not numeric + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33); +/** + * Error code when contains no version attribute + */ +define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34); +/** + * Error code when contains no type attribute in a protocol definition + */ +define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35); +/** + * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel + */ +define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36); +/** + * Error code when ssl attribute is present and is not "yes" + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37); +/**#@-*/ + +/** + * Mirror types allowed. Currently only internet servers are recognized. + */ +$GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] = array('server'); + + +/** + * The Channel handling class + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_ChannelFile +{ + /** + * @access private + * @var PEAR_ErrorStack + * @access private + */ + var $_stack; + + /** + * Supported channel.xml versions, for parsing + * @var array + * @access private + */ + var $_supportedVersions = array('1.0'); + + /** + * Parsed channel information + * @var array + * @access private + */ + var $_channelInfo; + + /** + * index into the subchannels array, used for parsing xml + * @var int + * @access private + */ + var $_subchannelIndex; + + /** + * index into the mirrors array, used for parsing xml + * @var int + * @access private + */ + var $_mirrorIndex; + + /** + * Flag used to determine the validity of parsed content + * @var boolean + * @access private + */ + var $_isValid = false; + + function PEAR_ChannelFile() + { + $this->_stack = &new PEAR_ErrorStack('PEAR_ChannelFile'); + $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); + $this->_isValid = false; + } + + /** + * @return array + * @access protected + */ + function _getErrorMessage() + { + return + array( + PEAR_CHANNELFILE_ERROR_INVALID_VERSION => + 'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%', + PEAR_CHANNELFILE_ERROR_NO_VERSION => + 'No version number found in tag', + PEAR_CHANNELFILE_ERROR_NO_XML_EXT => + '%error%', + PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER => + 'Unable to create XML parser', + PEAR_CHANNELFILE_ERROR_PARSER_ERROR => + '%error%', + PEAR_CHANNELFILE_ERROR_NO_NAME => + 'Missing channel name', + PEAR_CHANNELFILE_ERROR_INVALID_NAME => + 'Invalid channel %tag% "%name%"', + PEAR_CHANNELFILE_ERROR_NO_SUMMARY => + 'Missing channel summary', + PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY => + 'Channel summary should be on one line, but is multi-line', + PEAR_CHANNELFILE_ERROR_NO_HOST => + 'Missing channel server for %type% server', + PEAR_CHANNELFILE_ERROR_INVALID_HOST => + 'Server name "%server%" is invalid for %type% server', + PEAR_CHANNELFILE_ERROR_INVALID_MIRROR => + 'Invalid mirror name "%name%", mirror type %type%', + PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE => + 'Invalid mirror type "%type%"', + PEAR_CHANNELFILE_ERROR_INVALID => + 'Cannot generate xml, contents are invalid', + PEAR_CHANNELFILE_ERROR_EMPTY_REGEX => + 'packagenameregex cannot be empty', + PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION => + '%parent% %protocol% function has no version', + PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME => + '%parent% %protocol% function has no name', + PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE => + '%parent% rest baseurl has no type', + PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME => + 'Validation package has no name in tag', + PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION => + 'Validation package "%package%" has no version', + PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND => + 'Mirror "%mirror%" does not exist', + PEAR_CHANNELFILE_ERROR_INVALID_PORT => + 'Port "%port%" must be numeric', + PEAR_CHANNELFILE_ERROR_NO_STATICVERSION => + ' tag must contain version attribute', + PEAR_CHANNELFILE_URI_CANT_MIRROR => + 'The __uri pseudo-channel cannot have mirrors', + PEAR_CHANNELFILE_ERROR_INVALID_SSL => + '%server% has invalid ssl attribute "%ssl%" can only be yes or not present', + ); + } + + /** + * @param string contents of package.xml file + * @return bool success of parsing + */ + function fromXmlString($data) + { + if (preg_match('/_supportedVersions)) { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error', + array('version' => $channelversion[1])); + return false; + } + $parser = new PEAR_XMLParser; + $result = $parser->parse($data); + if ($result !== true) { + if ($result->getCode() == 1) { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error', + array('error' => $result->getMessage())); + } else { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error'); + } + return false; + } + $this->_channelInfo = $parser->getData(); + return true; + } else { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data)); + return false; + } + } + + /** + * @return array + */ + function toArray() + { + if (!$this->_isValid && !$this->validate()) { + return false; + } + return $this->_channelInfo; + } + + /** + * @param array + * @static + * @return PEAR_ChannelFile|false false if invalid + */ + function &fromArray($data, $compatibility = false, $stackClass = 'PEAR_ErrorStack') + { + $a = new PEAR_ChannelFile($compatibility, $stackClass); + $a->_fromArray($data); + if (!$a->validate()) { + $a = false; + return $a; + } + return $a; + } + + /** + * Unlike {@link fromArray()} this does not do any validation + * @param array + * @static + * @return PEAR_ChannelFile + */ + function &fromArrayWithErrors($data, $compatibility = false, + $stackClass = 'PEAR_ErrorStack') + { + $a = new PEAR_ChannelFile($compatibility, $stackClass); + $a->_fromArray($data); + return $a; + } + + /** + * @param array + * @access private + */ + function _fromArray($data) + { + $this->_channelInfo = $data; + } + + /** + * Wrapper to {@link PEAR_ErrorStack::getErrors()} + * @param boolean determines whether to purge the error stack after retrieving + * @return array + */ + function getErrors($purge = false) + { + return $this->_stack->getErrors($purge); + } + + /** + * Unindent given string (?) + * + * @param string $str The string that has to be unindented. + * @return string + * @access private + */ + function _unIndent($str) + { + // remove leading newlines + $str = preg_replace('/^[\r\n]+/', '', $str); + // find whitespace at the beginning of the first line + $indent_len = strspn($str, " \t"); + $indent = substr($str, 0, $indent_len); + $data = ''; + // remove the same amount of whitespace from following lines + foreach (explode("\n", $str) as $line) { + if (substr($line, 0, $indent_len) == $indent) { + $data .= substr($line, $indent_len) . "\n"; + } + } + return $data; + } + + /** + * Parse a channel.xml file. Expects the name of + * a channel xml file as input. + * + * @param string $descfile name of channel xml file + * @return bool success of parsing + */ + function fromXmlFile($descfile) + { + if (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) || + (!$fp = fopen($descfile, 'r'))) { + require_once 'PEAR.php'; + return PEAR::raiseError("Unable to open $descfile"); + } + + // read the whole thing so we only get one cdata callback + // for each block of cdata + fclose($fp); + $data = file_get_contents($descfile); + return $this->fromXmlString($data); + } + + /** + * Parse channel information from different sources + * + * This method is able to extract information about a channel + * from an .xml file or a string + * + * @access public + * @param string Filename of the source or the source itself + * @return bool + */ + function fromAny($info) + { + if (is_string($info) && file_exists($info) && strlen($info) < 255) { + $tmp = substr($info, -4); + if ($tmp == '.xml') { + $info = $this->fromXmlFile($info); + } else { + $fp = fopen($info, "r"); + $test = fread($fp, 5); + fclose($fp); + if ($test == "fromXmlFile($info); + } + } + if (PEAR::isError($info)) { + require_once 'PEAR.php'; + return PEAR::raiseError($info); + } + } + if (is_string($info)) { + $info = $this->fromXmlString($info); + } + return $info; + } + + /** + * Return an XML document based on previous parsing and modifications + * + * @return string XML data + * + * @access public + */ + function toXml() + { + if (!$this->_isValid && !$this->validate()) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID); + return false; + } + if (!isset($this->_channelInfo['attribs']['version'])) { + $this->_channelInfo['attribs']['version'] = '1.0'; + } + $channelInfo = $this->_channelInfo; + $ret = "\n"; + $ret .= " + $channelInfo[name] + " . htmlspecialchars($channelInfo['summary'])." +"; + if (isset($channelInfo['suggestedalias'])) { + $ret .= ' ' . $channelInfo['suggestedalias'] . "\n"; + } + if (isset($channelInfo['validatepackage'])) { + $ret .= ' ' . + htmlspecialchars($channelInfo['validatepackage']['_content']) . + "\n"; + } + $ret .= " \n"; + $ret .= ' _makeRestXml($channelInfo['servers']['primary']['rest'], ' '); + } + $ret .= " \n"; + if (isset($channelInfo['servers']['mirror'])) { + $ret .= $this->_makeMirrorsXml($channelInfo); + } + $ret .= " \n"; + $ret .= ""; + return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret)); + } + + /** + * Generate the tag + * @access private + */ + function _makeRestXml($info, $indent) + { + $ret = $indent . "\n"; + if (isset($info['baseurl']) && !isset($info['baseurl'][0])) { + $info['baseurl'] = array($info['baseurl']); + } + + if (isset($info['baseurl'])) { + foreach ($info['baseurl'] as $url) { + $ret .= "$indent \n"; + } + } + $ret .= $indent . "\n"; + return $ret; + } + + /** + * Generate the tag + * @access private + */ + function _makeMirrorsXml($channelInfo) + { + $ret = ""; + if (!isset($channelInfo['servers']['mirror'][0])) { + $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']); + } + foreach ($channelInfo['servers']['mirror'] as $mirror) { + $ret .= ' _makeRestXml($mirror['rest'], ' '); + } + $ret .= " \n"; + } else { + $ret .= "/>\n"; + } + } + return $ret; + } + + /** + * Generate the tag + * @access private + */ + function _makeFunctionsXml($functions, $indent, $rest = false) + { + $ret = ''; + if (!isset($functions[0])) { + $functions = array($functions); + } + foreach ($functions as $function) { + $ret .= "$indent\n"; + } + return $ret; + } + + /** + * Validation error. Also marks the object contents as invalid + * @param error code + * @param array error information + * @access private + */ + function _validateError($code, $params = array()) + { + $this->_stack->push($code, 'error', $params); + $this->_isValid = false; + } + + /** + * Validation warning. Does not mark the object contents invalid. + * @param error code + * @param array error information + * @access private + */ + function _validateWarning($code, $params = array()) + { + $this->_stack->push($code, 'warning', $params); + } + + /** + * Validate parsed file. + * + * @access public + * @return boolean + */ + function validate() + { + $this->_isValid = true; + $info = $this->_channelInfo; + if (empty($info['name'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME); + } elseif (!$this->validChannelServer($info['name'])) { + if ($info['name'] != '__uri') { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name', + 'name' => $info['name'])); + } + } + if (empty($info['summary'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); + } elseif (strpos(trim($info['summary']), "\n") !== false) { + $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, + array('summary' => $info['summary'])); + } + if (isset($info['suggestedalias'])) { + if (!$this->validChannelServer($info['suggestedalias'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias'])); + } + } + if (isset($info['localalias'])) { + if (!$this->validChannelServer($info['localalias'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'localalias', 'name' =>$info['localalias'])); + } + } + if (isset($info['validatepackage'])) { + if (!isset($info['validatepackage']['_content'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME); + } + if (!isset($info['validatepackage']['attribs']['version'])) { + $content = isset($info['validatepackage']['_content']) ? + $info['validatepackage']['_content'] : + null; + $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION, + array('package' => $content)); + } + } + + if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['port']) && + !is_numeric($info['servers']['primary']['attribs']['port'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT, + array('port' => $info['servers']['primary']['attribs']['port'])); + } + + if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['ssl']) && + $info['servers']['primary']['attribs']['ssl'] != 'yes') { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, + array('ssl' => $info['servers']['primary']['attribs']['ssl'], + 'server' => $info['name'])); + } + + if (isset($info['servers']['primary']['rest']) && + isset($info['servers']['primary']['rest']['baseurl'])) { + $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']); + } + if (isset($info['servers']['mirror'])) { + if ($this->_channelInfo['name'] == '__uri') { + $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR); + } + if (!isset($info['servers']['mirror'][0])) { + $info['servers']['mirror'] = array($info['servers']['mirror']); + } + foreach ($info['servers']['mirror'] as $mirror) { + if (!isset($mirror['attribs']['host'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST, + array('type' => 'mirror')); + } elseif (!$this->validChannelServer($mirror['attribs']['host'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST, + array('server' => $mirror['attribs']['host'], 'type' => 'mirror')); + } + if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, + array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host'])); + } + if (isset($mirror['rest'])) { + $this->_validateFunctions('rest', $mirror['rest']['baseurl'], + $mirror['attribs']['host']); + } + } + } + return $this->_isValid; + } + + /** + * @param string rest - protocol name this function applies to + * @param array the functions + * @param string the name of the parent element (mirror name, for instance) + */ + function _validateFunctions($protocol, $functions, $parent = '') + { + if (!isset($functions[0])) { + $functions = array($functions); + } + + foreach ($functions as $function) { + if (!isset($function['_content']) || empty($function['_content'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME, + array('parent' => $parent, 'protocol' => $protocol)); + } + + if ($protocol == 'rest') { + if (!isset($function['attribs']['type']) || + empty($function['attribs']['type'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE, + array('parent' => $parent, 'protocol' => $protocol)); + } + } else { + if (!isset($function['attribs']['version']) || + empty($function['attribs']['version'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION, + array('parent' => $parent, 'protocol' => $protocol)); + } + } + } + } + + /** + * Test whether a string contains a valid channel server. + * @param string $ver the package version to test + * @return bool + */ + function validChannelServer($server) + { + if ($server == '__uri') { + return true; + } + return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server); + } + + /** + * @return string|false + */ + function getName() + { + if (isset($this->_channelInfo['name'])) { + return $this->_channelInfo['name']; + } + + return false; + } + + /** + * @return string|false + */ + function getServer() + { + if (isset($this->_channelInfo['name'])) { + return $this->_channelInfo['name']; + } + + return false; + } + + /** + * @return int|80 port number to connect to + */ + function getPort($mirror = false) + { + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + if (isset($mir['attribs']['port'])) { + return $mir['attribs']['port']; + } + + if ($this->getSSL($mirror)) { + return 443; + } + + return 80; + } + + return false; + } + + if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) { + return $this->_channelInfo['servers']['primary']['attribs']['port']; + } + + if ($this->getSSL()) { + return 443; + } + + return 80; + } + + /** + * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel + */ + function getSSL($mirror = false) + { + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + if (isset($mir['attribs']['ssl'])) { + return true; + } + + return false; + } + + return false; + } + + if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { + return true; + } + + return false; + } + + /** + * @return string|false + */ + function getSummary() + { + if (isset($this->_channelInfo['summary'])) { + return $this->_channelInfo['summary']; + } + + return false; + } + + /** + * @param string protocol type + * @param string Mirror name + * @return array|false + */ + function getFunctions($protocol, $mirror = false) + { + if ($this->getName() == '__uri') { + return false; + } + + $function = $protocol == 'rest' ? 'baseurl' : 'function'; + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + if (isset($mir[$protocol][$function])) { + return $mir[$protocol][$function]; + } + } + + return false; + } + + if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) { + return $this->_channelInfo['servers']['primary'][$protocol][$function]; + } + + return false; + } + + /** + * @param string Protocol type + * @param string Function name (null to return the + * first protocol of the type requested) + * @param string Mirror name, if any + * @return array + */ + function getFunction($type, $name = null, $mirror = false) + { + $protocols = $this->getFunctions($type, $mirror); + if (!$protocols) { + return false; + } + + foreach ($protocols as $protocol) { + if ($name === null) { + return $protocol; + } + + if ($protocol['_content'] != $name) { + continue; + } + + return $protocol; + } + + return false; + } + + /** + * @param string protocol type + * @param string protocol name + * @param string version + * @param string mirror name + * @return boolean + */ + function supports($type, $name = null, $mirror = false, $version = '1.0') + { + $protocols = $this->getFunctions($type, $mirror); + if (!$protocols) { + return false; + } + + foreach ($protocols as $protocol) { + if ($protocol['attribs']['version'] != $version) { + continue; + } + + if ($name === null) { + return true; + } + + if ($protocol['_content'] != $name) { + continue; + } + + return true; + } + + return false; + } + + /** + * Determines whether a channel supports Representational State Transfer (REST) protocols + * for retrieving channel information + * @param string + * @return bool + */ + function supportsREST($mirror = false) + { + if ($mirror == $this->_channelInfo['name']) { + $mirror = false; + } + + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + return isset($mir['rest']); + } + + return false; + } + + return isset($this->_channelInfo['servers']['primary']['rest']); + } + + /** + * Get the URL to access a base resource. + * + * Hyperlinks in the returned xml will be used to retrieve the proper information + * needed. This allows extreme extensibility and flexibility in implementation + * @param string Resource Type to retrieve + */ + function getBaseURL($resourceType, $mirror = false) + { + if ($mirror == $this->_channelInfo['name']) { + $mirror = false; + } + + if ($mirror) { + $mir = $this->getMirror($mirror); + if (!$mir) { + return false; + } + + $rest = $mir['rest']; + } else { + $rest = $this->_channelInfo['servers']['primary']['rest']; + } + + if (!isset($rest['baseurl'][0])) { + $rest['baseurl'] = array($rest['baseurl']); + } + + foreach ($rest['baseurl'] as $baseurl) { + if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) { + return $baseurl['_content']; + } + } + + return false; + } + + /** + * Since REST does not implement RPC, provide this as a logical wrapper around + * resetFunctions for REST + * @param string|false mirror name, if any + */ + function resetREST($mirror = false) + { + return $this->resetFunctions('rest', $mirror); + } + + /** + * Empty all protocol definitions + * @param string protocol type + * @param string|false mirror name, if any + */ + function resetFunctions($type, $mirror = false) + { + if ($mirror) { + if (isset($this->_channelInfo['servers']['mirror'])) { + $mirrors = $this->_channelInfo['servers']['mirror']; + if (!isset($mirrors[0])) { + $mirrors = array($mirrors); + } + + foreach ($mirrors as $i => $mir) { + if ($mir['attribs']['host'] == $mirror) { + if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) { + unset($this->_channelInfo['servers']['mirror'][$i][$type]); + } + + return true; + } + } + + return false; + } + + return false; + } + + if (isset($this->_channelInfo['servers']['primary'][$type])) { + unset($this->_channelInfo['servers']['primary'][$type]); + } + + return true; + } + + /** + * Set a channel's protocols to the protocols supported by pearweb + */ + function setDefaultPEARProtocols($version = '1.0', $mirror = false) + { + switch ($version) { + case '1.0' : + $this->resetREST($mirror); + + if (!isset($this->_channelInfo['servers'])) { + $this->_channelInfo['servers'] = array('primary' => + array('rest' => array())); + } elseif (!isset($this->_channelInfo['servers']['primary'])) { + $this->_channelInfo['servers']['primary'] = array('rest' => array()); + } + + return true; + break; + default : + return false; + break; + } + } + + /** + * @return array + */ + function getMirrors() + { + if (isset($this->_channelInfo['servers']['mirror'])) { + $mirrors = $this->_channelInfo['servers']['mirror']; + if (!isset($mirrors[0])) { + $mirrors = array($mirrors); + } + + return $mirrors; + } + + return array(); + } + + /** + * Get the unserialized XML representing a mirror + * @return array|false + */ + function getMirror($server) + { + foreach ($this->getMirrors() as $mirror) { + if ($mirror['attribs']['host'] == $server) { + return $mirror; + } + } + + return false; + } + + /** + * @param string + * @return string|false + * @error PEAR_CHANNELFILE_ERROR_NO_NAME + * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME + */ + function setName($name) + { + return $this->setServer($name); + } + + /** + * Set the socket number (port) that is used to connect to this channel + * @param integer + * @param string|false name of the mirror server, or false for the primary + */ + function setPort($port, $mirror = false) + { + if ($mirror) { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port; + return true; + } + } + + return false; + } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port; + $this->_isValid = false; + return true; + } + } + + $this->_channelInfo['servers']['primary']['attribs']['port'] = $port; + $this->_isValid = false; + return true; + } + + /** + * Set the socket number (port) that is used to connect to this channel + * @param bool Determines whether to turn on SSL support or turn it off + * @param string|false name of the mirror server, or false for the primary + */ + function setSSL($ssl = true, $mirror = false) + { + if ($mirror) { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + if (!$ssl) { + if (isset($this->_channelInfo['servers']['mirror'][$i] + ['attribs']['ssl'])) { + unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']); + } + } else { + $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes'; + } + + return true; + } + } + + return false; + } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + if (!$ssl) { + if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) { + unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']); + } + } else { + $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes'; + } + + $this->_isValid = false; + return true; + } + } + + if ($ssl) { + $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes'; + } else { + if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { + unset($this->_channelInfo['servers']['primary']['attribs']['ssl']); + } + } + + $this->_isValid = false; + return true; + } + + /** + * @param string + * @return string|false + * @error PEAR_CHANNELFILE_ERROR_NO_SERVER + * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER + */ + function setServer($server, $mirror = false) + { + if (empty($server)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER); + return false; + } elseif (!$this->validChannelServer($server)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'name', 'name' => $server)); + return false; + } + + if ($mirror) { + $found = false; + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $found = true; + break; + } + } + + if (!$found) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + + $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server; + return true; + } + + $this->_channelInfo['name'] = $server; + return true; + } + + /** + * @param string + * @return boolean success + * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY + * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY + */ + function setSummary($summary) + { + if (empty($summary)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); + return false; + } elseif (strpos(trim($summary), "\n") !== false) { + $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, + array('summary' => $summary)); + } + + $this->_channelInfo['summary'] = $summary; + return true; + } + + /** + * @param string + * @param boolean determines whether the alias is in channel.xml or local + * @return boolean success + */ + function setAlias($alias, $local = false) + { + if (!$this->validChannelServer($alias)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'suggestedalias', 'name' => $alias)); + return false; + } + + if ($local) { + $this->_channelInfo['localalias'] = $alias; + } else { + $this->_channelInfo['suggestedalias'] = $alias; + } + + return true; + } + + /** + * @return string + */ + function getAlias() + { + if (isset($this->_channelInfo['localalias'])) { + return $this->_channelInfo['localalias']; + } + if (isset($this->_channelInfo['suggestedalias'])) { + return $this->_channelInfo['suggestedalias']; + } + if (isset($this->_channelInfo['name'])) { + return $this->_channelInfo['name']; + } + return ''; + } + + /** + * Set the package validation object if it differs from PEAR's default + * The class must be includeable via changing _ in the classname to path separator, + * but no checking of this is made. + * @param string|false pass in false to reset to the default packagename regex + * @return boolean success + */ + function setValidationPackage($validateclass, $version) + { + if (empty($validateclass)) { + unset($this->_channelInfo['validatepackage']); + } + $this->_channelInfo['validatepackage'] = array('_content' => $validateclass); + $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version); + } + + /** + * Add a protocol to the provides section + * @param string protocol type + * @param string protocol version + * @param string protocol name, if any + * @param string mirror name, if this is a mirror's protocol + * @return bool + */ + function addFunction($type, $version, $name = '', $mirror = false) + { + if ($mirror) { + return $this->addMirrorFunction($mirror, $type, $version, $name); + } + + $set = array('attribs' => array('version' => $version), '_content' => $name); + if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) { + if (!isset($this->_channelInfo['servers'])) { + $this->_channelInfo['servers'] = array('primary' => + array($type => array())); + } elseif (!isset($this->_channelInfo['servers']['primary'])) { + $this->_channelInfo['servers']['primary'] = array($type => array()); + } + + $this->_channelInfo['servers']['primary'][$type]['function'] = $set; + $this->_isValid = false; + return true; + } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) { + $this->_channelInfo['servers']['primary'][$type]['function'] = array( + $this->_channelInfo['servers']['primary'][$type]['function']); + } + + $this->_channelInfo['servers']['primary'][$type]['function'][] = $set; + return true; + } + /** + * Add a protocol to a mirror's provides section + * @param string mirror name (server) + * @param string protocol type + * @param string protocol version + * @param string protocol name, if any + */ + function addMirrorFunction($mirror, $type, $version, $name = '') + { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + + $setmirror = false; + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; + break; + } + } + } else { + if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + $setmirror = &$this->_channelInfo['servers']['mirror']; + } + } + + if (!$setmirror) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + + $set = array('attribs' => array('version' => $version), '_content' => $name); + if (!isset($setmirror[$type]['function'])) { + $setmirror[$type]['function'] = $set; + $this->_isValid = false; + return true; + } elseif (!isset($setmirror[$type]['function'][0])) { + $setmirror[$type]['function'] = array($setmirror[$type]['function']); + } + + $setmirror[$type]['function'][] = $set; + $this->_isValid = false; + return true; + } + + /** + * @param string Resource Type this url links to + * @param string URL + * @param string|false mirror name, if this is not a primary server REST base URL + */ + function setBaseURL($resourceType, $url, $mirror = false) + { + if ($mirror) { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + + $setmirror = false; + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; + break; + } + } + } else { + if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + $setmirror = &$this->_channelInfo['servers']['mirror']; + } + } + } else { + $setmirror = &$this->_channelInfo['servers']['primary']; + } + + $set = array('attribs' => array('type' => $resourceType), '_content' => $url); + if (!isset($setmirror['rest'])) { + $setmirror['rest'] = array(); + } + + if (!isset($setmirror['rest']['baseurl'])) { + $setmirror['rest']['baseurl'] = $set; + $this->_isValid = false; + return true; + } elseif (!isset($setmirror['rest']['baseurl'][0])) { + $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']); + } + + foreach ($setmirror['rest']['baseurl'] as $i => $url) { + if ($url['attribs']['type'] == $resourceType) { + $this->_isValid = false; + $setmirror['rest']['baseurl'][$i] = $set; + return true; + } + } + + $setmirror['rest']['baseurl'][] = $set; + $this->_isValid = false; + return true; + } + + /** + * @param string mirror server + * @param int mirror http port + * @return boolean + */ + function addMirror($server, $port = null) + { + if ($this->_channelInfo['name'] == '__uri') { + return false; // the __uri channel cannot have mirrors by definition + } + + $set = array('attribs' => array('host' => $server)); + if (is_numeric($port)) { + $set['attribs']['port'] = $port; + } + + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_channelInfo['servers']['mirror'] = $set; + return true; + } + + if (!isset($this->_channelInfo['servers']['mirror'][0])) { + $this->_channelInfo['servers']['mirror'] = + array($this->_channelInfo['servers']['mirror']); + } + + $this->_channelInfo['servers']['mirror'][] = $set; + return true; + } + + /** + * Retrieve the name of the validation package for this channel + * @return string|false + */ + function getValidationPackage() + { + if (!$this->_isValid && !$this->validate()) { + return false; + } + + if (!isset($this->_channelInfo['validatepackage'])) { + return array('attribs' => array('version' => 'default'), + '_content' => 'PEAR_Validate'); + } + + return $this->_channelInfo['validatepackage']; + } + + /** + * Retrieve the object that can be used for custom validation + * @param string|false the name of the package to validate. If the package is + * the channel validation package, PEAR_Validate is returned + * @return PEAR_Validate|false false is returned if the validation package + * cannot be located + */ + function &getValidationObject($package = false) + { + if (!class_exists('PEAR_Validate')) { + require_once 'PEAR/Validate.php'; + } + + if (!$this->_isValid) { + if (!$this->validate()) { + $a = false; + return $a; + } + } + + if (isset($this->_channelInfo['validatepackage'])) { + if ($package == $this->_channelInfo['validatepackage']) { + // channel validation packages are always validated by PEAR_Validate + $val = &new PEAR_Validate; + return $val; + } + + if (!class_exists(str_replace('.', '_', + $this->_channelInfo['validatepackage']['_content']))) { + if ($this->isIncludeable(str_replace('_', '/', + $this->_channelInfo['validatepackage']['_content']) . '.php')) { + include_once str_replace('_', '/', + $this->_channelInfo['validatepackage']['_content']) . '.php'; + $vclass = str_replace('.', '_', + $this->_channelInfo['validatepackage']['_content']); + $val = &new $vclass; + } else { + $a = false; + return $a; + } + } else { + $vclass = str_replace('.', '_', + $this->_channelInfo['validatepackage']['_content']); + $val = &new $vclass; + } + } else { + $val = &new PEAR_Validate; + } + + return $val; + } + + function isIncludeable($path) + { + $possibilities = explode(PATH_SEPARATOR, ini_get('include_path')); + foreach ($possibilities as $dir) { + if (file_exists($dir . DIRECTORY_SEPARATOR . $path) + && is_readable($dir . DIRECTORY_SEPARATOR . $path)) { + return true; + } + } + + return false; + } + + /** + * This function is used by the channel updater and retrieves a value set by + * the registry, or the current time if it has not been set + * @return string + */ + function lastModified() + { + if (isset($this->_channelInfo['_lastmodified'])) { + return $this->_channelInfo['_lastmodified']; + } + + return time(); + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/ChannelFile/Parser.php b/typo3conf/ext/phpunit/PEAR/PEAR/ChannelFile/Parser.php new file mode 100644 index 0000000..69cd57a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/ChannelFile/Parser.php @@ -0,0 +1,68 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Parser.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * base xml parser class + */ +require_once 'PEAR/XMLParser.php'; +require_once 'PEAR/ChannelFile.php'; +/** + * Parser for channel.xml + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_ChannelFile_Parser extends PEAR_XMLParser +{ + var $_config; + var $_logger; + var $_registry; + + function setConfig(&$c) + { + $this->_config = &$c; + $this->_registry = &$c->getRegistry(); + } + + function setLogger(&$l) + { + $this->_logger = &$l; + } + + function parse($data, $file) + { + if (PEAR::isError($err = parent::parse($data, $file))) { + return $err; + } + + $ret = new PEAR_ChannelFile; + $ret->setConfig($this->_config); + if (isset($this->_logger)) { + $ret->setLogger($this->_logger); + } + + $ret->fromArray($this->_unserializedData); + // make sure the filelist is in the easy to read format needed + $ret->flattenFilelist(); + $ret->setPackagefile($file, $archive); + return $ret; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command.php b/typo3conf/ext/phpunit/PEAR/PEAR/Command.php new file mode 100644 index 0000000..487bb0d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command.php @@ -0,0 +1,414 @@ + + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Command.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * Needed for error handling + */ +require_once 'PEAR.php'; +require_once 'PEAR/Frontend.php'; +require_once 'PEAR/XMLParser.php'; + +/** + * List of commands and what classes they are implemented in. + * @var array command => implementing class + */ +$GLOBALS['_PEAR_Command_commandlist'] = array(); + +/** + * List of commands and their descriptions + * @var array command => description + */ +$GLOBALS['_PEAR_Command_commanddesc'] = array(); + +/** + * List of shortcuts to common commands. + * @var array shortcut => command + */ +$GLOBALS['_PEAR_Command_shortcuts'] = array(); + +/** + * Array of command objects + * @var array class => object + */ +$GLOBALS['_PEAR_Command_objects'] = array(); + +/** + * PEAR command class, a simple factory class for administrative + * commands. + * + * How to implement command classes: + * + * - The class must be called PEAR_Command_Nnn, installed in the + * "PEAR/Common" subdir, with a method called getCommands() that + * returns an array of the commands implemented by the class (see + * PEAR/Command/Install.php for an example). + * + * - The class must implement a run() function that is called with three + * params: + * + * (string) command name + * (array) assoc array with options, freely defined by each + * command, for example: + * array('force' => true) + * (array) list of the other parameters + * + * The run() function returns a PEAR_CommandResponse object. Use + * these methods to get information: + * + * int getStatus() Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL) + * *_PARTIAL means that you need to issue at least + * one more command to complete the operation + * (used for example for validation steps). + * + * string getMessage() Returns a message for the user. Remember, + * no HTML or other interface-specific markup. + * + * If something unexpected happens, run() returns a PEAR error. + * + * - DON'T OUTPUT ANYTHING! Return text for output instead. + * + * - DON'T USE HTML! The text you return will be used from both Gtk, + * web and command-line interfaces, so for now, keep everything to + * plain text. + * + * - DON'T USE EXIT OR DIE! Always use pear errors. From static + * classes do PEAR::raiseError(), from other classes do + * $this->raiseError(). + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command +{ + // {{{ factory() + + /** + * Get the right object for executing a command. + * + * @param string $command The name of the command + * @param object $config Instance of PEAR_Config object + * + * @return object the command object or a PEAR error + * + * @access public + * @static + */ + function &factory($command, &$config) + { + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); + } + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { + $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; + } + if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { + $a = PEAR::raiseError("unknown command `$command'"); + return $a; + } + $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; + if (!class_exists($class)) { + require_once $GLOBALS['_PEAR_Command_objects'][$class]; + } + if (!class_exists($class)) { + $a = PEAR::raiseError("unknown command `$command'"); + return $a; + } + $ui =& PEAR_Command::getFrontendObject(); + $obj = &new $class($ui, $config); + return $obj; + } + + // }}} + // {{{ & getObject() + function &getObject($command) + { + $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; + if (!class_exists($class)) { + require_once $GLOBALS['_PEAR_Command_objects'][$class]; + } + if (!class_exists($class)) { + return PEAR::raiseError("unknown command `$command'"); + } + $ui =& PEAR_Command::getFrontendObject(); + $config = &PEAR_Config::singleton(); + $obj = &new $class($ui, $config); + return $obj; + } + + // }}} + // {{{ & getFrontendObject() + + /** + * Get instance of frontend object. + * + * @return object|PEAR_Error + * @static + */ + function &getFrontendObject() + { + $a = &PEAR_Frontend::singleton(); + return $a; + } + + // }}} + // {{{ & setFrontendClass() + + /** + * Load current frontend class. + * + * @param string $uiclass Name of class implementing the frontend + * + * @return object the frontend object, or a PEAR error + * @static + */ + function &setFrontendClass($uiclass) + { + $a = &PEAR_Frontend::setFrontendClass($uiclass); + return $a; + } + + // }}} + // {{{ setFrontendType() + + /** + * Set current frontend. + * + * @param string $uitype Name of the frontend type (for example "CLI") + * + * @return object the frontend object, or a PEAR error + * @static + */ + function setFrontendType($uitype) + { + $uiclass = 'PEAR_Frontend_' . $uitype; + return PEAR_Command::setFrontendClass($uiclass); + } + + // }}} + // {{{ registerCommands() + + /** + * Scan through the Command directory looking for classes + * and see what commands they implement. + * + * @param bool (optional) if FALSE (default), the new list of + * commands should replace the current one. If TRUE, + * new entries will be merged with old. + * + * @param string (optional) where (what directory) to look for + * classes, defaults to the Command subdirectory of + * the directory from where this file (__FILE__) is + * included. + * + * @return bool TRUE on success, a PEAR error on failure + * + * @access public + * @static + */ + function registerCommands($merge = false, $dir = null) + { + $parser = new PEAR_XMLParser; + if ($dir === null) { + $dir = dirname(__FILE__) . '/Command'; + } + if (!is_dir($dir)) { + return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory"); + } + $dp = @opendir($dir); + if (empty($dp)) { + return PEAR::raiseError("registerCommands: opendir($dir) failed"); + } + if (!$merge) { + $GLOBALS['_PEAR_Command_commandlist'] = array(); + } + + while ($file = readdir($dp)) { + if ($file{0} == '.' || substr($file, -4) != '.xml') { + continue; + } + + $f = substr($file, 0, -4); + $class = "PEAR_Command_" . $f; + // List of commands + if (empty($GLOBALS['_PEAR_Command_objects'][$class])) { + $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . $f . '.php'; + } + + $parser->parse(file_get_contents("$dir/$file")); + $implements = $parser->getData(); + foreach ($implements as $command => $desc) { + if ($command == 'attribs') { + continue; + } + + if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { + return PEAR::raiseError('Command "' . $command . '" already registered in ' . + 'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); + } + + $GLOBALS['_PEAR_Command_commandlist'][$command] = $class; + $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary']; + if (isset($desc['shortcut'])) { + $shortcut = $desc['shortcut']; + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) { + return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' . + 'registered to command "' . $command . '" in class "' . + $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); + } + $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command; + } + + if (isset($desc['options']) && $desc['options']) { + foreach ($desc['options'] as $oname => $option) { + if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) { + return PEAR::raiseError('Option "' . $oname . '" short option "' . + $option['shortopt'] . '" must be ' . + 'only 1 character in Command "' . $command . '" in class "' . + $class . '"'); + } + } + } + } + } + + ksort($GLOBALS['_PEAR_Command_shortcuts']); + ksort($GLOBALS['_PEAR_Command_commandlist']); + @closedir($dp); + return true; + } + + // }}} + // {{{ getCommands() + + /** + * Get the list of currently supported commands, and what + * classes implement them. + * + * @return array command => implementing class + * + * @access public + * @static + */ + function getCommands() + { + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); + } + return $GLOBALS['_PEAR_Command_commandlist']; + } + + // }}} + // {{{ getShortcuts() + + /** + * Get the list of command shortcuts. + * + * @return array shortcut => command + * + * @access public + * @static + */ + function getShortcuts() + { + if (empty($GLOBALS['_PEAR_Command_shortcuts'])) { + PEAR_Command::registerCommands(); + } + return $GLOBALS['_PEAR_Command_shortcuts']; + } + + // }}} + // {{{ getGetoptArgs() + + /** + * Compiles arguments for getopt. + * + * @param string $command command to get optstring for + * @param string $short_args (reference) short getopt format + * @param array $long_args (reference) long getopt format + * + * @return void + * + * @access public + * @static + */ + function getGetoptArgs($command, &$short_args, &$long_args) + { + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); + } + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { + $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; + } + if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { + return null; + } + $obj = &PEAR_Command::getObject($command); + return $obj->getGetoptArgs($command, $short_args, $long_args); + } + + // }}} + // {{{ getDescription() + + /** + * Get description for a command. + * + * @param string $command Name of the command + * + * @return string command description + * + * @access public + * @static + */ + function getDescription($command) + { + if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) { + return null; + } + return $GLOBALS['_PEAR_Command_commanddesc'][$command]; + } + + // }}} + // {{{ getHelp() + + /** + * Get help for command. + * + * @param string $command Name of the command to return help for + * + * @access public + * @static + */ + function getHelp($command) + { + $cmds = PEAR_Command::getCommands(); + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { + $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; + } + if (isset($cmds[$command])) { + $obj = &PEAR_Command::getObject($command); + return $obj->getHelp($command); + } + return false; + } + // }}} +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Auth.php b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Auth.php new file mode 100644 index 0000000..2bdb4af --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Auth.php @@ -0,0 +1,81 @@ + + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Auth.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + * @deprecated since 1.8.0alpha1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Channels.php'; + +/** + * PEAR commands for login/logout + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + * @deprecated since 1.8.0alpha1 + */ +class PEAR_Command_Auth extends PEAR_Command_Channels +{ + var $commands = array( + 'login' => array( + 'summary' => 'Connects and authenticates to remote server [Deprecated in favor of channel-login]', + 'shortcut' => 'li', + 'function' => 'doLogin', + 'options' => array(), + 'doc' => ' +WARNING: This function is deprecated in favor of using channel-login + +Log in to a remote channel server. If is not supplied, +the default channel is used. To use remote functions in the installer +that require any kind of privileges, you need to log in first. The +username and password you enter here will be stored in your per-user +PEAR configuration (~/.pearrc on Unix-like systems). After logging +in, your username and password will be sent along in subsequent +operations on the remote server.', + ), + 'logout' => array( + 'summary' => 'Logs out from the remote server [Deprecated in favor of channel-logout]', + 'shortcut' => 'lo', + 'function' => 'doLogout', + 'options' => array(), + 'doc' => ' +WARNING: This function is deprecated in favor of using channel-logout + +Logs out from the remote server. This command does not actually +connect to the remote server, it only deletes the stored username and +password from your user configuration.', + ) + + ); + + /** + * PEAR_Command_Auth constructor. + * + * @access public + */ + function PEAR_Command_Auth(&$ui, &$config) + { + parent::PEAR_Command_Channels($ui, $config); + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Auth.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Auth.xml new file mode 100644 index 0000000..590193d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Auth.xml @@ -0,0 +1,30 @@ + + + Connects and authenticates to remote server [Deprecated in favor of channel-login] + doLogin + li + + <channel name> +WARNING: This function is deprecated in favor of using channel-login + +Log in to a remote channel server. If <channel name> is not supplied, +the default channel is used. To use remote functions in the installer +that require any kind of privileges, you need to log in first. The +username and password you enter here will be stored in your per-user +PEAR configuration (~/.pearrc on Unix-like systems). After logging +in, your username and password will be sent along in subsequent +operations on the remote server. + + + Logs out from the remote server [Deprecated in favor of channel-logout] + doLogout + lo + + +WARNING: This function is deprecated in favor of using channel-logout + +Logs out from the remote server. This command does not actually +connect to the remote server, it only deletes the stored username and +password from your user configuration. + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Build.php b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Build.php new file mode 100644 index 0000000..b8bbf7d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Build.php @@ -0,0 +1,85 @@ + + * @author Tomas V.V.Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Build.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for building extensions. + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V.V.Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Build extends PEAR_Command_Common +{ + var $commands = array( + 'build' => array( + 'summary' => 'Build an Extension From C Source', + 'function' => 'doBuild', + 'shortcut' => 'b', + 'options' => array(), + 'doc' => '[package.xml] +Builds one or more extensions contained in a package.' + ), + ); + + /** + * PEAR_Command_Build constructor. + * + * @access public + */ + function PEAR_Command_Build(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + function doBuild($command, $options, $params) + { + require_once 'PEAR/Builder.php'; + if (sizeof($params) < 1) { + $params[0] = 'package.xml'; + } + + $builder = &new PEAR_Builder($this->ui); + $this->debug = $this->config->get('verbose'); + $err = $builder->build($params[0], array(&$this, 'buildCallback')); + if (PEAR::isError($err)) { + return $err; + } + + return true; + } + + function buildCallback($what, $data) + { + if (($what == 'cmdoutput' && $this->debug > 1) || + ($what == 'output' && $this->debug > 0)) { + $this->ui->outputData(rtrim($data), 'build'); + } + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Build.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Build.xml new file mode 100644 index 0000000..ec4e6f5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Build.xml @@ -0,0 +1,10 @@ + + + Build an Extension From C Source + doBuild + b + + [package.xml] +Builds one or more extensions contained in a package. + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Channels.php b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Channels.php new file mode 100644 index 0000000..0742e8e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Channels.php @@ -0,0 +1,883 @@ + + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Channels.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +define('PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS', -500); + +/** + * PEAR commands for managing channels. + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Command_Channels extends PEAR_Command_Common +{ + var $commands = array( + 'list-channels' => array( + 'summary' => 'List Available Channels', + 'function' => 'doList', + 'shortcut' => 'lc', + 'options' => array(), + 'doc' => ' +List all available channels for installation. +', + ), + 'update-channels' => array( + 'summary' => 'Update the Channel List', + 'function' => 'doUpdateAll', + 'shortcut' => 'uc', + 'options' => array(), + 'doc' => ' +List all installed packages in all channels. +' + ), + 'channel-delete' => array( + 'summary' => 'Remove a Channel From the List', + 'function' => 'doDelete', + 'shortcut' => 'cde', + 'options' => array(), + 'doc' => ' +Delete a channel from the registry. You may not +remove any channel that has installed packages. +' + ), + 'channel-add' => array( + 'summary' => 'Add a Channel', + 'function' => 'doAdd', + 'shortcut' => 'ca', + 'options' => array(), + 'doc' => ' +Add a private channel to the channel list. Note that all +public channels should be synced using "update-channels". +Parameter may be either a local file or remote URL to a +channel.xml. +' + ), + 'channel-update' => array( + 'summary' => 'Update an Existing Channel', + 'function' => 'doUpdate', + 'shortcut' => 'cu', + 'options' => array( + 'force' => array( + 'shortopt' => 'f', + 'doc' => 'will force download of new channel.xml if an existing channel name is used', + ), + 'channel' => array( + 'shortopt' => 'c', + 'arg' => 'CHANNEL', + 'doc' => 'will force download of new channel.xml if an existing channel name is used', + ), +), + 'doc' => '[|] +Update a channel in the channel list directly. Note that all +public channels can be synced using "update-channels". +Parameter may be a local or remote channel.xml, or the name of +an existing channel. +' + ), + 'channel-info' => array( + 'summary' => 'Retrieve Information on a Channel', + 'function' => 'doInfo', + 'shortcut' => 'ci', + 'options' => array(), + 'doc' => ' +List the files in an installed package. +' + ), + 'channel-alias' => array( + 'summary' => 'Specify an alias to a channel name', + 'function' => 'doAlias', + 'shortcut' => 'cha', + 'options' => array(), + 'doc' => ' +Specify a specific alias to use for a channel name. +The alias may not be an existing channel name or +alias. +' + ), + 'channel-discover' => array( + 'summary' => 'Initialize a Channel from its server', + 'function' => 'doDiscover', + 'shortcut' => 'di', + 'options' => array(), + 'doc' => '[|] +Initialize a channel from its server and create a local channel.xml. +If is in the format ":@" then + and will be set as the login username/password for +. Use caution when passing the username/password in this way, as +it may allow other users on your computer to briefly view your username/ +password via the system\'s process list. +' + ), + 'channel-login' => array( + 'summary' => 'Connects and authenticates to remote channel server', + 'shortcut' => 'cli', + 'function' => 'doLogin', + 'options' => array(), + 'doc' => ' +Log in to a remote channel server. If is not supplied, +the default channel is used. To use remote functions in the installer +that require any kind of privileges, you need to log in first. The +username and password you enter here will be stored in your per-user +PEAR configuration (~/.pearrc on Unix-like systems). After logging +in, your username and password will be sent along in subsequent +operations on the remote server.', + ), + 'channel-logout' => array( + 'summary' => 'Logs out from the remote channel server', + 'shortcut' => 'clo', + 'function' => 'doLogout', + 'options' => array(), + 'doc' => ' +Logs out from a remote channel server. If is not supplied, +the default channel is used. This command does not actually connect to the +remote server, it only deletes the stored username and password from your user +configuration.', + ), + ); + + /** + * PEAR_Command_Registry constructor. + * + * @access public + */ + function PEAR_Command_Channels(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + function _sortChannels($a, $b) + { + return strnatcasecmp($a->getName(), $b->getName()); + } + + function doList($command, $options, $params) + { + $reg = &$this->config->getRegistry(); + $registered = $reg->getChannels(); + usort($registered, array(&$this, '_sortchannels')); + $i = $j = 0; + $data = array( + 'caption' => 'Registered Channels:', + 'border' => true, + 'headline' => array('Channel', 'Alias', 'Summary') + ); + foreach ($registered as $channel) { + $data['data'][] = array($channel->getName(), + $channel->getAlias(), + $channel->getSummary()); + } + + if (count($registered) === 0) { + $data = '(no registered channels)'; + } + $this->ui->outputData($data, $command); + return true; + } + + function doUpdateAll($command, $options, $params) + { + $reg = &$this->config->getRegistry(); + $channels = $reg->getChannels(); + + $success = true; + foreach ($channels as $channel) { + if ($channel->getName() != '__uri') { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->doUpdate('channel-update', + $options, + array($channel->getName())); + if (PEAR::isError($err)) { + $this->ui->outputData($err->getMessage(), $command); + $success = false; + } else { + $success &= $err; + } + } + } + return $success; + } + + function doInfo($command, $options, $params) + { + if (count($params) !== 1) { + return $this->raiseError("No channel specified"); + } + + $reg = &$this->config->getRegistry(); + $channel = strtolower($params[0]); + if ($reg->channelExists($channel)) { + $chan = $reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $this->raiseError($chan); + } + } else { + if (strpos($channel, '://')) { + $downloader = &$this->getDownloader(); + $tmpdir = $this->config->get('temp_dir'); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $loc = $downloader->downloadHttp($channel, $this->ui, $tmpdir); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($loc)) { + return $this->raiseError('Cannot open "' . $channel . + '" (' . $loc->getMessage() . ')'); + } else { + $contents = implode('', file($loc)); + } + } else { + if (!file_exists($params[0])) { + return $this->raiseError('Unknown channel "' . $channel . '"'); + } + + $fp = fopen($params[0], 'r'); + if (!$fp) { + return $this->raiseError('Cannot open "' . $params[0] . '"'); + } + + $contents = ''; + while (!feof($fp)) { + $contents .= fread($fp, 1024); + } + fclose($fp); + } + + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $chan = new PEAR_ChannelFile; + $chan->fromXmlString($contents); + $chan->validate(); + if ($errs = $chan->getErrors(true)) { + foreach ($errs as $err) { + $this->ui->outputData($err['level'] . ': ' . $err['message']); + } + return $this->raiseError('Channel file "' . $params[0] . '" is not valid'); + } + } + + if (!$chan) { + return $this->raiseError('Serious error: Channel "' . $params[0] . + '" has a corrupted registry entry'); + } + + $channel = $chan->getName(); + $caption = 'Channel ' . $channel . ' Information:'; + $data1 = array( + 'caption' => $caption, + 'border' => true); + $data1['data']['server'] = array('Name and Server', $chan->getName()); + if ($chan->getAlias() != $chan->getName()) { + $data1['data']['alias'] = array('Alias', $chan->getAlias()); + } + + $data1['data']['summary'] = array('Summary', $chan->getSummary()); + $validate = $chan->getValidationPackage(); + $data1['data']['vpackage'] = array('Validation Package Name', $validate['_content']); + $data1['data']['vpackageversion'] = + array('Validation Package Version', $validate['attribs']['version']); + $d = array(); + $d['main'] = $data1; + + $data['data'] = array(); + $data['caption'] = 'Server Capabilities'; + $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base'); + if ($chan->supportsREST()) { + if ($chan->supportsREST()) { + $funcs = $chan->getFunctions('rest'); + if (!isset($funcs[0])) { + $funcs = array($funcs); + } + foreach ($funcs as $protocol) { + $data['data'][] = array('rest', $protocol['attribs']['type'], + $protocol['_content']); + } + } + } else { + $data['data'][] = array('No supported protocols'); + } + + $d['protocols'] = $data; + $data['data'] = array(); + $mirrors = $chan->getMirrors(); + if ($mirrors) { + $data['caption'] = 'Channel ' . $channel . ' Mirrors:'; + unset($data['headline']); + foreach ($mirrors as $mirror) { + $data['data'][] = array($mirror['attribs']['host']); + $d['mirrors'] = $data; + } + + foreach ($mirrors as $i => $mirror) { + $data['data'] = array(); + $data['caption'] = 'Mirror ' . $mirror['attribs']['host'] . ' Capabilities'; + $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base'); + if ($chan->supportsREST($mirror['attribs']['host'])) { + if ($chan->supportsREST($mirror['attribs']['host'])) { + $funcs = $chan->getFunctions('rest', $mirror['attribs']['host']); + if (!isset($funcs[0])) { + $funcs = array($funcs); + } + + foreach ($funcs as $protocol) { + $data['data'][] = array('rest', $protocol['attribs']['type'], + $protocol['_content']); + } + } + } else { + $data['data'][] = array('No supported protocols'); + } + $d['mirrorprotocols' . $i] = $data; + } + } + $this->ui->outputData($d, 'channel-info'); + } + + // }}} + + function doDelete($command, $options, $params) + { + if (count($params) !== 1) { + return $this->raiseError('channel-delete: no channel specified'); + } + + $reg = &$this->config->getRegistry(); + if (!$reg->channelExists($params[0])) { + return $this->raiseError('channel-delete: channel "' . $params[0] . '" does not exist'); + } + + $channel = $reg->channelName($params[0]); + if ($channel == 'pear.php.net') { + return $this->raiseError('Cannot delete the pear.php.net channel'); + } + + if ($channel == 'pecl.php.net') { + return $this->raiseError('Cannot delete the pecl.php.net channel'); + } + + if ($channel == 'doc.php.net') { + return $this->raiseError('Cannot delete the doc.php.net channel'); + } + + if ($channel == '__uri') { + return $this->raiseError('Cannot delete the __uri pseudo-channel'); + } + + if (PEAR::isError($err = $reg->listPackages($channel))) { + return $err; + } + + if (count($err)) { + return $this->raiseError('Channel "' . $channel . + '" has installed packages, cannot delete'); + } + + if (!$reg->deleteChannel($channel)) { + return $this->raiseError('Channel "' . $channel . '" deletion failed'); + } else { + $this->config->deleteChannel($channel); + $this->ui->outputData('Channel "' . $channel . '" deleted', $command); + } + } + + function doAdd($command, $options, $params) + { + if (count($params) !== 1) { + return $this->raiseError('channel-add: no channel file specified'); + } + + if (strpos($params[0], '://')) { + $downloader = &$this->getDownloader(); + $tmpdir = $this->config->get('temp_dir'); + if (!file_exists($tmpdir)) { + require_once 'System.php'; + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = System::mkdir(array('-p', $tmpdir)); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($err)) { + return $this->raiseError('channel-add: temp_dir does not exist: "' . + $tmpdir . + '" - You can change this location with "pear config-set temp_dir"'); + } + } + + if (!is_writable($tmpdir)) { + return $this->raiseError('channel-add: temp_dir is not writable: "' . + $tmpdir . + '" - You can change this location with "pear config-set temp_dir"'); + } + + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $loc = $downloader->downloadHttp($params[0], $this->ui, $tmpdir, null, false); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($loc)) { + return $this->raiseError('channel-add: Cannot open "' . $params[0] . + '" (' . $loc->getMessage() . ')'); + } + + list($loc, $lastmodified) = $loc; + $contents = implode('', file($loc)); + } else { + $lastmodified = $fp = false; + if (file_exists($params[0])) { + $fp = fopen($params[0], 'r'); + } + + if (!$fp) { + return $this->raiseError('channel-add: cannot open "' . $params[0] . '"'); + } + + $contents = ''; + while (!feof($fp)) { + $contents .= fread($fp, 1024); + } + fclose($fp); + } + + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $channel = new PEAR_ChannelFile; + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $result = $channel->fromXmlString($contents); + PEAR::staticPopErrorHandling(); + if (!$result) { + $exit = false; + if (count($errors = $channel->getErrors(true))) { + foreach ($errors as $error) { + $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message'])); + if (!$exit) { + $exit = $error['level'] == 'error' ? true : false; + } + } + if ($exit) { + return $this->raiseError('channel-add: invalid channel.xml file'); + } + } + } + + $reg = &$this->config->getRegistry(); + if ($reg->channelExists($channel->getName())) { + return $this->raiseError('channel-add: Channel "' . $channel->getName() . + '" exists, use channel-update to update entry', PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS); + } + + $ret = $reg->addChannel($channel, $lastmodified); + if (PEAR::isError($ret)) { + return $ret; + } + + if (!$ret) { + return $this->raiseError('channel-add: adding Channel "' . $channel->getName() . + '" to registry failed'); + } + + $this->config->setChannels($reg->listChannels()); + $this->config->writeConfigFile(); + $this->ui->outputData('Adding Channel "' . $channel->getName() . '" succeeded', $command); + } + + function doUpdate($command, $options, $params) + { + if (count($params) !== 1) { + return $this->raiseError("No channel file specified"); + } + + $tmpdir = $this->config->get('temp_dir'); + if (!file_exists($tmpdir)) { + require_once 'System.php'; + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = System::mkdir(array('-p', $tmpdir)); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($err)) { + return $this->raiseError('channel-add: temp_dir does not exist: "' . + $tmpdir . + '" - You can change this location with "pear config-set temp_dir"'); + } + } + + if (!is_writable($tmpdir)) { + return $this->raiseError('channel-add: temp_dir is not writable: "' . + $tmpdir . + '" - You can change this location with "pear config-set temp_dir"'); + } + + $reg = &$this->config->getRegistry(); + $lastmodified = false; + if ((!file_exists($params[0]) || is_dir($params[0])) + && $reg->channelExists(strtolower($params[0]))) { + $c = $reg->getChannel(strtolower($params[0])); + if (PEAR::isError($c)) { + return $this->raiseError($c); + } + + $this->ui->outputData("Updating channel \"$params[0]\"", $command); + $dl = &$this->getDownloader(array()); + // if force is specified, use a timestamp of "1" to force retrieval + $lastmodified = isset($options['force']) ? false : $c->lastModified(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $contents = $dl->downloadHttp('http://' . $c->getName() . '/channel.xml', + $this->ui, $tmpdir, null, $lastmodified); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($contents)) { + // Attempt to fall back to https + $this->ui->outputData("Channel \"$params[0]\" is not responding over http://, failed with message: " . $contents->getMessage()); + $this->ui->outputData("Trying channel \"$params[0]\" over https:// instead"); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $contents = $dl->downloadHttp('https://' . $c->getName() . '/channel.xml', + $this->ui, $tmpdir, null, $lastmodified); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($contents)) { + return $this->raiseError('Cannot retrieve channel.xml for channel "' . + $c->getName() . '" (' . $contents->getMessage() . ')'); + } + } + + list($contents, $lastmodified) = $contents; + if (!$contents) { + $this->ui->outputData("Channel \"$params[0]\" is up to date"); + return; + } + + $contents = implode('', file($contents)); + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $channel = new PEAR_ChannelFile; + $channel->fromXmlString($contents); + if (!$channel->getErrors()) { + // security check: is the downloaded file for the channel we got it from? + if (strtolower($channel->getName()) != strtolower($c->getName())) { + if (!isset($options['force'])) { + return $this->raiseError('ERROR: downloaded channel definition file' . + ' for channel "' . $channel->getName() . '" from channel "' . + strtolower($c->getName()) . '"'); + } + + $this->ui->log(0, 'WARNING: downloaded channel definition file' . + ' for channel "' . $channel->getName() . '" from channel "' . + strtolower($c->getName()) . '"'); + } + } + } else { + if (strpos($params[0], '://')) { + $dl = &$this->getDownloader(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $loc = $dl->downloadHttp($params[0], + $this->ui, $tmpdir, null, $lastmodified); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($loc)) { + return $this->raiseError("Cannot open " . $params[0] . + ' (' . $loc->getMessage() . ')'); + } + + list($loc, $lastmodified) = $loc; + $contents = implode('', file($loc)); + } else { + $fp = false; + if (file_exists($params[0])) { + $fp = fopen($params[0], 'r'); + } + + if (!$fp) { + return $this->raiseError("Cannot open " . $params[0]); + } + + $contents = ''; + while (!feof($fp)) { + $contents .= fread($fp, 1024); + } + fclose($fp); + } + + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $channel = new PEAR_ChannelFile; + $channel->fromXmlString($contents); + } + + $exit = false; + if (count($errors = $channel->getErrors(true))) { + foreach ($errors as $error) { + $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message'])); + if (!$exit) { + $exit = $error['level'] == 'error' ? true : false; + } + } + if ($exit) { + return $this->raiseError('Invalid channel.xml file'); + } + } + + if (!$reg->channelExists($channel->getName())) { + return $this->raiseError('Error: Channel "' . $channel->getName() . + '" does not exist, use channel-add to add an entry'); + } + + $ret = $reg->updateChannel($channel, $lastmodified); + if (PEAR::isError($ret)) { + return $ret; + } + + if (!$ret) { + return $this->raiseError('Updating Channel "' . $channel->getName() . + '" in registry failed'); + } + + $this->config->setChannels($reg->listChannels()); + $this->config->writeConfigFile(); + $this->ui->outputData('Update of Channel "' . $channel->getName() . '" succeeded'); + } + + function &getDownloader() + { + if (!class_exists('PEAR_Downloader')) { + require_once 'PEAR/Downloader.php'; + } + $a = new PEAR_Downloader($this->ui, array(), $this->config); + return $a; + } + + function doAlias($command, $options, $params) + { + if (count($params) === 1) { + return $this->raiseError('No channel alias specified'); + } + + if (count($params) !== 2 || (!empty($params[1]) && $params[1]{0} == '-')) { + return $this->raiseError( + 'Invalid format, correct is: channel-alias channel alias'); + } + + $reg = &$this->config->getRegistry(); + if (!$reg->channelExists($params[0], true)) { + $extra = ''; + if ($reg->isAlias($params[0])) { + $extra = ' (use "channel-alias ' . $reg->channelName($params[0]) . ' ' . + strtolower($params[1]) . '")'; + } + + return $this->raiseError('"' . $params[0] . '" is not a valid channel' . $extra); + } + + if ($reg->isAlias($params[1])) { + return $this->raiseError('Channel "' . $reg->channelName($params[1]) . '" is ' . + 'already aliased to "' . strtolower($params[1]) . '", cannot re-alias'); + } + + $chan = &$reg->getChannel($params[0]); + if (PEAR::isError($chan)) { + return $this->raiseError('Corrupt registry? Error retrieving channel "' . $params[0] . + '" information (' . $chan->getMessage() . ')'); + } + + // make it a local alias + if (!$chan->setAlias(strtolower($params[1]), true)) { + return $this->raiseError('Alias "' . strtolower($params[1]) . + '" is not a valid channel alias'); + } + + $reg->updateChannel($chan); + $this->ui->outputData('Channel "' . $chan->getName() . '" aliased successfully to "' . + strtolower($params[1]) . '"'); + } + + /** + * The channel-discover command + * + * @param string $command command name + * @param array $options option_name => value + * @param array $params list of additional parameters. + * $params[0] should contain a string with either: + * - or + * - :@ + * @return null|PEAR_Error + */ + function doDiscover($command, $options, $params) + { + if (count($params) !== 1) { + return $this->raiseError("No channel server specified"); + } + + // Look for the possible input format ":@" + if (preg_match('/^(.+):(.+)@(.+)\\z/', $params[0], $matches)) { + $username = $matches[1]; + $password = $matches[2]; + $channel = $matches[3]; + } else { + $channel = $params[0]; + } + + $reg = &$this->config->getRegistry(); + if ($reg->channelExists($channel)) { + if (!$reg->isAlias($channel)) { + return $this->raiseError("Channel \"$channel\" is already initialized", PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS); + } + + return $this->raiseError("A channel alias named \"$channel\" " . + 'already exists, aliasing channel "' . $reg->channelName($channel) + . '"'); + } + + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->doAdd($command, $options, array('http://' . $channel . '/channel.xml')); + $this->popErrorHandling(); + if (PEAR::isError($err)) { + if ($err->getCode() === PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS) { + return $this->raiseError("Discovery of channel \"$channel\" failed (" . + $err->getMessage() . ')'); + } + // Attempt fetch via https + $this->ui->outputData("Discovering channel $channel over http:// failed with message: " . $err->getMessage()); + $this->ui->outputData("Trying to discover channel $channel over https:// instead"); + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->doAdd($command, $options, array('https://' . $channel . '/channel.xml')); + $this->popErrorHandling(); + if (PEAR::isError($err)) { + return $this->raiseError("Discovery of channel \"$channel\" failed (" . + $err->getMessage() . ')'); + } + } + + // Store username/password if they were given + // Arguably we should do a logintest on the channel here, but since + // that's awkward on a REST-based channel (even "pear login" doesn't + // do it for those), and XML-RPC is deprecated, it's fairly pointless. + if (isset($username)) { + $this->config->set('username', $username, 'user', $channel); + $this->config->set('password', $password, 'user', $channel); + $this->config->store(); + $this->ui->outputData("Stored login for channel \"$channel\" using username \"$username\"", $command); + } + + $this->ui->outputData("Discovery of channel \"$channel\" succeeded", $command); + } + + /** + * Execute the 'login' command. + * + * @param string $command command name + * @param array $options option_name => value + * @param array $params list of additional parameters + * + * @return bool TRUE on success or + * a PEAR error on failure + * + * @access public + */ + function doLogin($command, $options, $params) + { + $reg = &$this->config->getRegistry(); + + // If a parameter is supplied, use that as the channel to log in to + $channel = isset($params[0]) ? $params[0] : $this->config->get('default_channel'); + + $chan = $reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $this->raiseError($chan); + } + + $server = $this->config->get('preferred_mirror', null, $channel); + $username = $this->config->get('username', null, $channel); + if (empty($username)) { + $username = isset($_ENV['USER']) ? $_ENV['USER'] : null; + } + $this->ui->outputData("Logging in to $server.", $command); + + list($username, $password) = $this->ui->userDialog( + $command, + array('Username', 'Password'), + array('text', 'password'), + array($username, '') + ); + $username = trim($username); + $password = trim($password); + + $ourfile = $this->config->getConfFile('user'); + if (!$ourfile) { + $ourfile = $this->config->getConfFile('system'); + } + + $this->config->set('username', $username, 'user', $channel); + $this->config->set('password', $password, 'user', $channel); + + if ($chan->supportsREST()) { + $ok = true; + } + + if ($ok !== true) { + return $this->raiseError('Login failed!'); + } + + $this->ui->outputData("Logged in.", $command); + // avoid changing any temporary settings changed with -d + $ourconfig = new PEAR_Config($ourfile, $ourfile); + $ourconfig->set('username', $username, 'user', $channel); + $ourconfig->set('password', $password, 'user', $channel); + $ourconfig->store(); + + return true; + } + + /** + * Execute the 'logout' command. + * + * @param string $command command name + * @param array $options option_name => value + * @param array $params list of additional parameters + * + * @return bool TRUE on success or + * a PEAR error on failure + * + * @access public + */ + function doLogout($command, $options, $params) + { + $reg = &$this->config->getRegistry(); + + // If a parameter is supplied, use that as the channel to log in to + $channel = isset($params[0]) ? $params[0] : $this->config->get('default_channel'); + + $chan = $reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $this->raiseError($chan); + } + + $server = $this->config->get('preferred_mirror', null, $channel); + $this->ui->outputData("Logging out from $server.", $command); + $this->config->remove('username', 'user', $channel); + $this->config->remove('password', 'user', $channel); + $this->config->store(); + return true; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Channels.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Channels.xml new file mode 100644 index 0000000..47b7206 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Channels.xml @@ -0,0 +1,123 @@ + + + List Available Channels + doList + lc + + +List all available channels for installation. + + + + Update the Channel List + doUpdateAll + uc + + +List all installed packages in all channels. + + + + Remove a Channel From the List + doDelete + cde + + <channel name> +Delete a channel from the registry. You may not +remove any channel that has installed packages. + + + + Add a Channel + doAdd + ca + + <channel.xml> +Add a private channel to the channel list. Note that all +public channels should be synced using "update-channels". +Parameter may be either a local file or remote URL to a +channel.xml. + + + + Update an Existing Channel + doUpdate + cu + + + f + will force download of new channel.xml if an existing channel name is used + + + c + will force download of new channel.xml if an existing channel name is used + CHANNEL + + + [<channel.xml>|<channel name>] +Update a channel in the channel list directly. Note that all +public channels can be synced using "update-channels". +Parameter may be a local or remote channel.xml, or the name of +an existing channel. + + + + Retrieve Information on a Channel + doInfo + ci + + <package> +List the files in an installed package. + + + + Specify an alias to a channel name + doAlias + cha + + <channel> <alias> +Specify a specific alias to use for a channel name. +The alias may not be an existing channel name or +alias. + + + + Initialize a Channel from its server + doDiscover + di + + [<channel.xml>|<channel name>] +Initialize a channel from its server and create a local channel.xml. +If <channel name> is in the format "<username>:<password>@<channel>" then +<username> and <password> will be set as the login username/password for +<channel>. Use caution when passing the username/password in this way, as +it may allow other users on your computer to briefly view your username/ +password via the system's process list. + + + + Connects and authenticates to remote channel server + doLogin + cli + + <channel name> +Log in to a remote channel server. If <channel name> is not supplied, +the default channel is used. To use remote functions in the installer +that require any kind of privileges, you need to log in first. The +username and password you enter here will be stored in your per-user +PEAR configuration (~/.pearrc on Unix-like systems). After logging +in, your username and password will be sent along in subsequent +operations on the remote server. + + + Logs out from the remote channel server + doLogout + clo + + <channel name> +Logs out from a remote channel server. If <channel name> is not supplied, +the default channel is used. This command does not actually connect to the +remote server, it only deletes the stored username and password from your user +configuration. + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Common.php b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Common.php new file mode 100644 index 0000000..38097a5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Common.php @@ -0,0 +1,273 @@ + + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Common.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR.php'; + +/** + * PEAR commands base class + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Common extends PEAR +{ + /** + * PEAR_Config object used to pass user system and configuration + * on when executing commands + * + * @var PEAR_Config + */ + var $config; + /** + * @var PEAR_Registry + * @access protected + */ + var $_registry; + + /** + * User Interface object, for all interaction with the user. + * @var object + */ + var $ui; + + var $_deps_rel_trans = array( + 'lt' => '<', + 'le' => '<=', + 'eq' => '=', + 'ne' => '!=', + 'gt' => '>', + 'ge' => '>=', + 'has' => '==' + ); + + var $_deps_type_trans = array( + 'pkg' => 'package', + 'ext' => 'extension', + 'php' => 'PHP', + 'prog' => 'external program', + 'ldlib' => 'external library for linking', + 'rtlib' => 'external runtime library', + 'os' => 'operating system', + 'websrv' => 'web server', + 'sapi' => 'SAPI backend' + ); + + /** + * PEAR_Command_Common constructor. + * + * @access public + */ + function PEAR_Command_Common(&$ui, &$config) + { + parent::PEAR(); + $this->config = &$config; + $this->ui = &$ui; + } + + /** + * Return a list of all the commands defined by this class. + * @return array list of commands + * @access public + */ + function getCommands() + { + $ret = array(); + foreach (array_keys($this->commands) as $command) { + $ret[$command] = $this->commands[$command]['summary']; + } + + return $ret; + } + + /** + * Return a list of all the command shortcuts defined by this class. + * @return array shortcut => command + * @access public + */ + function getShortcuts() + { + $ret = array(); + foreach (array_keys($this->commands) as $command) { + if (isset($this->commands[$command]['shortcut'])) { + $ret[$this->commands[$command]['shortcut']] = $command; + } + } + + return $ret; + } + + function getOptions($command) + { + $shortcuts = $this->getShortcuts(); + if (isset($shortcuts[$command])) { + $command = $shortcuts[$command]; + } + + if (isset($this->commands[$command]) && + isset($this->commands[$command]['options'])) { + return $this->commands[$command]['options']; + } + + return null; + } + + function getGetoptArgs($command, &$short_args, &$long_args) + { + $short_args = ''; + $long_args = array(); + if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) { + return; + } + + reset($this->commands[$command]['options']); + while (list($option, $info) = each($this->commands[$command]['options'])) { + $larg = $sarg = ''; + if (isset($info['arg'])) { + if ($info['arg']{0} == '(') { + $larg = '=='; + $sarg = '::'; + $arg = substr($info['arg'], 1, -1); + } else { + $larg = '='; + $sarg = ':'; + $arg = $info['arg']; + } + } + + if (isset($info['shortopt'])) { + $short_args .= $info['shortopt'] . $sarg; + } + + $long_args[] = $option . $larg; + } + } + + /** + * Returns the help message for the given command + * + * @param string $command The command + * @return mixed A fail string if the command does not have help or + * a two elements array containing [0]=>help string, + * [1]=> help string for the accepted cmd args + */ + function getHelp($command) + { + $config = &PEAR_Config::singleton(); + if (!isset($this->commands[$command])) { + return "No such command \"$command\""; + } + + $help = null; + if (isset($this->commands[$command]['doc'])) { + $help = $this->commands[$command]['doc']; + } + + if (empty($help)) { + // XXX (cox) Fallback to summary if there is no doc (show both?) + if (!isset($this->commands[$command]['summary'])) { + return "No help for command \"$command\""; + } + $help = $this->commands[$command]['summary']; + } + + if (preg_match_all('/{config\s+([^\}]+)}/e', $help, $matches)) { + foreach($matches[0] as $k => $v) { + $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help); + } + } + + return array($help, $this->getHelpArgs($command)); + } + + /** + * Returns the help for the accepted arguments of a command + * + * @param string $command + * @return string The help string + */ + function getHelpArgs($command) + { + if (isset($this->commands[$command]['options']) && + count($this->commands[$command]['options'])) + { + $help = "Options:\n"; + foreach ($this->commands[$command]['options'] as $k => $v) { + if (isset($v['arg'])) { + if ($v['arg'][0] == '(') { + $arg = substr($v['arg'], 1, -1); + $sapp = " [$arg]"; + $lapp = "[=$arg]"; + } else { + $sapp = " $v[arg]"; + $lapp = "=$v[arg]"; + } + } else { + $sapp = $lapp = ""; + } + + if (isset($v['shortopt'])) { + $s = $v['shortopt']; + $help .= " -$s$sapp, --$k$lapp\n"; + } else { + $help .= " --$k$lapp\n"; + } + + $p = " "; + $doc = rtrim(str_replace("\n", "\n$p", $v['doc'])); + $help .= " $doc\n"; + } + + return $help; + } + + return null; + } + + function run($command, $options, $params) + { + if (empty($this->commands[$command]['function'])) { + // look for shortcuts + foreach (array_keys($this->commands) as $cmd) { + if (isset($this->commands[$cmd]['shortcut']) && $this->commands[$cmd]['shortcut'] == $command) { + if (empty($this->commands[$cmd]['function'])) { + return $this->raiseError("unknown command `$command'"); + } else { + $func = $this->commands[$cmd]['function']; + } + $command = $cmd; + + //$command = $this->commands[$cmd]['function']; + break; + } + } + } else { + $func = $this->commands[$command]['function']; + } + + return $this->$func($command, $options, $params); + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Config.php b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Config.php new file mode 100644 index 0000000..428488f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Config.php @@ -0,0 +1,413 @@ + + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Config.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for managing configuration data. + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Config extends PEAR_Command_Common +{ + var $commands = array( + 'config-show' => array( + 'summary' => 'Show All Settings', + 'function' => 'doConfigShow', + 'shortcut' => 'csh', + 'options' => array( + 'channel' => array( + 'shortopt' => 'c', + 'doc' => 'show configuration variables for another channel', + 'arg' => 'CHAN', + ), +), + 'doc' => '[layer] +Displays all configuration values. An optional argument +may be used to tell which configuration layer to display. Valid +configuration layers are "user", "system" and "default". To display +configurations for different channels, set the default_channel +configuration variable and run config-show again. +', + ), + 'config-get' => array( + 'summary' => 'Show One Setting', + 'function' => 'doConfigGet', + 'shortcut' => 'cg', + 'options' => array( + 'channel' => array( + 'shortopt' => 'c', + 'doc' => 'show configuration variables for another channel', + 'arg' => 'CHAN', + ), +), + 'doc' => ' [layer] +Displays the value of one configuration parameter. The +first argument is the name of the parameter, an optional second argument +may be used to tell which configuration layer to look in. Valid configuration +layers are "user", "system" and "default". If no layer is specified, a value +will be picked from the first layer that defines the parameter, in the order +just specified. The configuration value will be retrieved for the channel +specified by the default_channel configuration variable. +', + ), + 'config-set' => array( + 'summary' => 'Change Setting', + 'function' => 'doConfigSet', + 'shortcut' => 'cs', + 'options' => array( + 'channel' => array( + 'shortopt' => 'c', + 'doc' => 'show configuration variables for another channel', + 'arg' => 'CHAN', + ), +), + 'doc' => ' [layer] +Sets the value of one configuration parameter. The first argument is +the name of the parameter, the second argument is the new value. Some +parameters are subject to validation, and the command will fail with +an error message if the new value does not make sense. An optional +third argument may be used to specify in which layer to set the +configuration parameter. The default layer is "user". The +configuration value will be set for the current channel, which +is controlled by the default_channel configuration variable. +', + ), + 'config-help' => array( + 'summary' => 'Show Information About Setting', + 'function' => 'doConfigHelp', + 'shortcut' => 'ch', + 'options' => array(), + 'doc' => '[parameter] +Displays help for a configuration parameter. Without arguments it +displays help for all configuration parameters. +', + ), + 'config-create' => array( + 'summary' => 'Create a Default configuration file', + 'function' => 'doConfigCreate', + 'shortcut' => 'coc', + 'options' => array( + 'windows' => array( + 'shortopt' => 'w', + 'doc' => 'create a config file for a windows install', + ), + ), + 'doc' => ' +Create a default configuration file with all directory configuration +variables set to subdirectories of , and save it as . +This is useful especially for creating a configuration file for a remote +PEAR installation (using the --remoteconfig option of install, upgrade, +and uninstall). +', + ), + ); + + /** + * PEAR_Command_Config constructor. + * + * @access public + */ + function PEAR_Command_Config(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + function doConfigShow($command, $options, $params) + { + $layer = null; + if (is_array($params)) { + $layer = isset($params[0]) ? $params[0] : null; + } + + // $params[0] -> the layer + if ($error = $this->_checkLayer($layer)) { + return $this->raiseError("config-show:$error"); + } + + $keys = $this->config->getKeys(); + sort($keys); + $channel = isset($options['channel']) ? $options['channel'] : + $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + if (!$reg->channelExists($channel)) { + return $this->raiseError('Channel "' . $channel . '" does not exist'); + } + + $channel = $reg->channelName($channel); + $data = array('caption' => 'Configuration (channel ' . $channel . '):'); + foreach ($keys as $key) { + $type = $this->config->getType($key); + $value = $this->config->get($key, $layer, $channel); + if ($type == 'password' && $value) { + $value = '********'; + } + + if ($value === false) { + $value = 'false'; + } elseif ($value === true) { + $value = 'true'; + } + + $data['data'][$this->config->getGroup($key)][] = array($this->config->getPrompt($key) , $key, $value); + } + + foreach ($this->config->getLayers() as $layer) { + $data['data']['Config Files'][] = array(ucfirst($layer) . ' Configuration File', 'Filename' , $this->config->getConfFile($layer)); + } + + $this->ui->outputData($data, $command); + return true; + } + + function doConfigGet($command, $options, $params) + { + $args_cnt = is_array($params) ? count($params) : 0; + switch ($args_cnt) { + case 1: + $config_key = $params[0]; + $layer = null; + break; + case 2: + $config_key = $params[0]; + $layer = $params[1]; + if ($error = $this->_checkLayer($layer)) { + return $this->raiseError("config-get:$error"); + } + break; + case 0: + default: + return $this->raiseError("config-get expects 1 or 2 parameters"); + } + + $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + if (!$reg->channelExists($channel)) { + return $this->raiseError('Channel "' . $channel . '" does not exist'); + } + + $this->ui->outputData($this->config->get($config_key, $layer, $channel), $command); + return true; + } + + function doConfigSet($command, $options, $params) + { + // $param[0] -> a parameter to set + // $param[1] -> the value for the parameter + // $param[2] -> the layer + $failmsg = ''; + if (count($params) < 2 || count($params) > 3) { + $failmsg .= "config-set expects 2 or 3 parameters"; + return PEAR::raiseError($failmsg); + } + + if (isset($params[2]) && ($error = $this->_checkLayer($params[2]))) { + $failmsg .= $error; + return PEAR::raiseError("config-set:$failmsg"); + } + + $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + if (!$reg->channelExists($channel)) { + return $this->raiseError('Channel "' . $channel . '" does not exist'); + } + + $channel = $reg->channelName($channel); + if ($params[0] == 'default_channel' && !$reg->channelExists($params[1])) { + return $this->raiseError('Channel "' . $params[1] . '" does not exist'); + } + + if ($params[0] == 'preferred_mirror' + && ( + !$reg->mirrorExists($channel, $params[1]) && + (!$reg->channelExists($params[1]) || $channel != $params[1]) + ) + ) { + $msg = 'Channel Mirror "' . $params[1] . '" does not exist'; + $msg .= ' in your registry for channel "' . $channel . '".'; + $msg .= "\n" . 'Attempt to run "pear channel-update ' . $channel .'"'; + $msg .= ' if you believe this mirror should exist as you may'; + $msg .= ' have outdated channel information.'; + return $this->raiseError($msg); + } + + if (count($params) == 2) { + array_push($params, 'user'); + $layer = 'user'; + } else { + $layer = $params[2]; + } + + array_push($params, $channel); + if (!call_user_func_array(array(&$this->config, 'set'), $params)) { + array_pop($params); + $failmsg = "config-set (" . implode(", ", $params) . ") failed, channel $channel"; + } else { + $this->config->store($layer); + } + + if ($failmsg) { + return $this->raiseError($failmsg); + } + + $this->ui->outputData('config-set succeeded', $command); + return true; + } + + function doConfigHelp($command, $options, $params) + { + if (empty($params)) { + $params = $this->config->getKeys(); + } + + $data['caption'] = "Config help" . ((count($params) == 1) ? " for $params[0]" : ''); + $data['headline'] = array('Name', 'Type', 'Description'); + $data['border'] = true; + foreach ($params as $name) { + $type = $this->config->getType($name); + $docs = $this->config->getDocs($name); + if ($type == 'set') { + $docs = rtrim($docs) . "\nValid set: " . + implode(' ', $this->config->getSetValues($name)); + } + + $data['data'][] = array($name, $type, $docs); + } + + $this->ui->outputData($data, $command); + } + + function doConfigCreate($command, $options, $params) + { + if (count($params) != 2) { + return PEAR::raiseError('config-create: must have 2 parameters, root path and ' . + 'filename to save as'); + } + + $root = $params[0]; + // Clean up the DIRECTORY_SEPARATOR mess + $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; + $root = preg_replace(array('!\\\\+!', '!/+!', "!$ds2+!"), + array('/', '/', '/'), + $root); + if ($root{0} != '/') { + if (!isset($options['windows'])) { + return PEAR::raiseError('Root directory must be an absolute path beginning ' . + 'with "/", was: "' . $root . '"'); + } + + if (!preg_match('/^[A-Za-z]:/', $root)) { + return PEAR::raiseError('Root directory must be an absolute path beginning ' . + 'with "\\" or "C:\\", was: "' . $root . '"'); + } + } + + $windows = isset($options['windows']); + if ($windows) { + $root = str_replace('/', '\\', $root); + } + + if (!file_exists($params[1]) && !@touch($params[1])) { + return PEAR::raiseError('Could not create "' . $params[1] . '"'); + } + + $params[1] = realpath($params[1]); + $config = &new PEAR_Config($params[1], '#no#system#config#', false, false); + if ($root{strlen($root) - 1} == '/') { + $root = substr($root, 0, strlen($root) - 1); + } + + $config->noRegistry(); + $config->set('php_dir', $windows ? "$root\\pear\\php" : "$root/pear/php", 'user'); + $config->set('data_dir', $windows ? "$root\\pear\\data" : "$root/pear/data"); + $config->set('www_dir', $windows ? "$root\\pear\\www" : "$root/pear/www"); + $config->set('cfg_dir', $windows ? "$root\\pear\\cfg" : "$root/pear/cfg"); + $config->set('ext_dir', $windows ? "$root\\pear\\ext" : "$root/pear/ext"); + $config->set('doc_dir', $windows ? "$root\\pear\\docs" : "$root/pear/docs"); + $config->set('test_dir', $windows ? "$root\\pear\\tests" : "$root/pear/tests"); + $config->set('cache_dir', $windows ? "$root\\pear\\cache" : "$root/pear/cache"); + $config->set('download_dir', $windows ? "$root\\pear\\download" : "$root/pear/download"); + $config->set('temp_dir', $windows ? "$root\\pear\\temp" : "$root/pear/temp"); + $config->set('bin_dir', $windows ? "$root\\pear" : "$root/pear"); + $config->writeConfigFile(); + $this->_showConfig($config); + $this->ui->outputData('Successfully created default configuration file "' . $params[1] . '"', + $command); + } + + function _showConfig(&$config) + { + $params = array('user'); + $keys = $config->getKeys(); + sort($keys); + $channel = 'pear.php.net'; + $data = array('caption' => 'Configuration (channel ' . $channel . '):'); + foreach ($keys as $key) { + $type = $config->getType($key); + $value = $config->get($key, 'user', $channel); + if ($type == 'password' && $value) { + $value = '********'; + } + + if ($value === false) { + $value = 'false'; + } elseif ($value === true) { + $value = 'true'; + } + $data['data'][$config->getGroup($key)][] = + array($config->getPrompt($key) , $key, $value); + } + + foreach ($config->getLayers() as $layer) { + $data['data']['Config Files'][] = + array(ucfirst($layer) . ' Configuration File', 'Filename' , + $config->getConfFile($layer)); + } + + $this->ui->outputData($data, 'config-show'); + return true; + } + + /** + * Checks if a layer is defined or not + * + * @param string $layer The layer to search for + * @return mixed False on no error or the error message + */ + function _checkLayer($layer = null) + { + if (!empty($layer) && $layer != 'default') { + $layers = $this->config->getLayers(); + if (!in_array($layer, $layers)) { + return " only the layers: \"" . implode('" or "', $layers) . "\" are supported"; + } + } + + return false; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Config.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Config.xml new file mode 100644 index 0000000..f64a925 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Config.xml @@ -0,0 +1,92 @@ + + + Show All Settings + doConfigShow + csh + + + c + show configuration variables for another channel + CHAN + + + [layer] +Displays all configuration values. An optional argument +may be used to tell which configuration layer to display. Valid +configuration layers are "user", "system" and "default". To display +configurations for different channels, set the default_channel +configuration variable and run config-show again. + + + + Show One Setting + doConfigGet + cg + + + c + show configuration variables for another channel + CHAN + + + <parameter> [layer] +Displays the value of one configuration parameter. The +first argument is the name of the parameter, an optional second argument +may be used to tell which configuration layer to look in. Valid configuration +layers are "user", "system" and "default". If no layer is specified, a value +will be picked from the first layer that defines the parameter, in the order +just specified. The configuration value will be retrieved for the channel +specified by the default_channel configuration variable. + + + + Change Setting + doConfigSet + cs + + + c + show configuration variables for another channel + CHAN + + + <parameter> <value> [layer] +Sets the value of one configuration parameter. The first argument is +the name of the parameter, the second argument is the new value. Some +parameters are subject to validation, and the command will fail with +an error message if the new value does not make sense. An optional +third argument may be used to specify in which layer to set the +configuration parameter. The default layer is "user". The +configuration value will be set for the current channel, which +is controlled by the default_channel configuration variable. + + + + Show Information About Setting + doConfigHelp + ch + + [parameter] +Displays help for a configuration parameter. Without arguments it +displays help for all configuration parameters. + + + + Create a Default configuration file + doConfigCreate + coc + + + w + create a config file for a windows install + + + <root path> <filename> +Create a default configuration file with all directory configuration +variables set to subdirectories of <root path>, and save it as <filename>. +This is useful especially for creating a configuration file for a remote +PEAR installation (using the --remoteconfig option of install, upgrade, +and uninstall). + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Install.php b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Install.php new file mode 100644 index 0000000..0d5b014 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Install.php @@ -0,0 +1,1268 @@ + + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Install.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for installation or deinstallation/upgrading of + * packages. + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Install extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'install' => array( + 'summary' => 'Install Package', + 'function' => 'doInstall', + 'shortcut' => 'i', + 'options' => array( + 'force' => array( + 'shortopt' => 'f', + 'doc' => 'will overwrite newer installed packages', + ), + 'loose' => array( + 'shortopt' => 'l', + 'doc' => 'do not check for recommended dependency version', + ), + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, install anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not install files, only register the package as installed', + ), + 'soft' => array( + 'shortopt' => 's', + 'doc' => 'soft install, fail silently, or upgrade if already installed', + ), + 'nobuild' => array( + 'shortopt' => 'B', + 'doc' => 'don\'t build C extensions', + ), + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'request uncompressed files when downloading', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM', + ), + 'packagingroot' => array( + 'shortopt' => 'P', + 'arg' => 'DIR', + 'doc' => 'root directory used when packaging files, like RPM packaging', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + 'alldeps' => array( + 'shortopt' => 'a', + 'doc' => 'install all required and optional dependencies', + ), + 'onlyreqdeps' => array( + 'shortopt' => 'o', + 'doc' => 'install all required dependencies', + ), + 'offline' => array( + 'shortopt' => 'O', + 'doc' => 'do not attempt to download any urls or contact channels', + ), + 'pretend' => array( + 'shortopt' => 'p', + 'doc' => 'Only list the packages that would be downloaded', + ), + ), + 'doc' => '[channel/] ... +Installs one or more PEAR packages. You can specify a package to +install in four ways: + +"Package-1.0.tgz" : installs from a local file + +"http://example.com/Package-1.0.tgz" : installs from +anywhere on the net. + +"package.xml" : installs the package described in +package.xml. Useful for testing, or for wrapping a PEAR package in +another package manager such as RPM. + +"Package[-version/state][.tar]" : queries your default channel\'s server +({config master_server}) and downloads the newest package with +the preferred quality/state ({config preferred_state}). + +To retrieve Package version 1.1, use "Package-1.1," to retrieve +Package state beta, use "Package-beta." To retrieve an uncompressed +file, append .tar (make sure there is no file by the same name first) + +To download a package from another channel, prefix with the channel name like +"channel/Package" + +More than one package may be specified at once. It is ok to mix these +four ways of specifying packages. +'), + 'upgrade' => array( + 'summary' => 'Upgrade Package', + 'function' => 'doInstall', + 'shortcut' => 'up', + 'options' => array( + 'channel' => array( + 'shortopt' => 'c', + 'doc' => 'upgrade packages from a specific channel', + 'arg' => 'CHAN', + ), + 'force' => array( + 'shortopt' => 'f', + 'doc' => 'overwrite newer installed packages', + ), + 'loose' => array( + 'shortopt' => 'l', + 'doc' => 'do not check for recommended dependency version', + ), + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, upgrade anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not install files, only register the package as upgraded', + ), + 'nobuild' => array( + 'shortopt' => 'B', + 'doc' => 'don\'t build C extensions', + ), + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'request uncompressed files when downloading', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + 'alldeps' => array( + 'shortopt' => 'a', + 'doc' => 'install all required and optional dependencies', + ), + 'onlyreqdeps' => array( + 'shortopt' => 'o', + 'doc' => 'install all required dependencies', + ), + 'offline' => array( + 'shortopt' => 'O', + 'doc' => 'do not attempt to download any urls or contact channels', + ), + 'pretend' => array( + 'shortopt' => 'p', + 'doc' => 'Only list the packages that would be downloaded', + ), + ), + 'doc' => ' ... +Upgrades one or more PEAR packages. See documentation for the +"install" command for ways to specify a package. + +When upgrading, your package will be updated if the provided new +package has a higher version number (use the -f option if you need to +upgrade anyway). + +More than one package may be specified at once. +'), + 'upgrade-all' => array( + 'summary' => 'Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters]', + 'function' => 'doUpgradeAll', + 'shortcut' => 'ua', + 'options' => array( + 'channel' => array( + 'shortopt' => 'c', + 'doc' => 'upgrade packages from a specific channel', + 'arg' => 'CHAN', + ), + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, upgrade anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not install files, only register the package as upgraded', + ), + 'nobuild' => array( + 'shortopt' => 'B', + 'doc' => 'don\'t build C extensions', + ), + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'request uncompressed files when downloading', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + 'loose' => array( + 'doc' => 'do not check for recommended dependency version', + ), + ), + 'doc' => ' +WARNING: This function is deprecated in favor of using the upgrade command with no params + +Upgrades all packages that have a newer release available. Upgrades are +done only if there is a release available of the state specified in +"preferred_state" (currently {config preferred_state}), or a state considered +more stable. +'), + 'uninstall' => array( + 'summary' => 'Un-install Package', + 'function' => 'doUninstall', + 'shortcut' => 'un', + 'options' => array( + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, uninstall anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not remove files, only register the packages as not installed', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + 'offline' => array( + 'shortopt' => 'O', + 'doc' => 'do not attempt to uninstall remotely', + ), + ), + 'doc' => '[channel/] ... +Uninstalls one or more PEAR packages. More than one package may be +specified at once. Prefix with channel name to uninstall from a +channel not in your default channel ({config default_channel}) +'), + 'bundle' => array( + 'summary' => 'Unpacks a Pecl Package', + 'function' => 'doBundle', + 'shortcut' => 'bun', + 'options' => array( + 'destination' => array( + 'shortopt' => 'd', + 'arg' => 'DIR', + 'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)', + ), + 'force' => array( + 'shortopt' => 'f', + 'doc' => 'Force the unpacking even if there were errors in the package', + ), + ), + 'doc' => ' +Unpacks a Pecl Package into the selected location. It will download the +package if needed. +'), + 'run-scripts' => array( + 'summary' => 'Run Post-Install Scripts bundled with a package', + 'function' => 'doRunScripts', + 'shortcut' => 'rs', + 'options' => array( + ), + 'doc' => ' +Run post-installation scripts in package , if any exist. +'), + ); + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Install constructor. + * + * @access public + */ + function PEAR_Command_Install(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + /** + * For unit testing purposes + */ + function &getDownloader(&$ui, $options, &$config) + { + if (!class_exists('PEAR_Downloader')) { + require_once 'PEAR/Downloader.php'; + } + $a = &new PEAR_Downloader($ui, $options, $config); + return $a; + } + + /** + * For unit testing purposes + */ + function &getInstaller(&$ui) + { + if (!class_exists('PEAR_Installer')) { + require_once 'PEAR/Installer.php'; + } + $a = &new PEAR_Installer($ui); + return $a; + } + + function enableExtension($binaries, $type) + { + if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) { + return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location'); + } + $ini = $this->_parseIni($phpini); + if (PEAR::isError($ini)) { + return $ini; + } + $line = 0; + if ($type == 'extsrc' || $type == 'extbin') { + $search = 'extensions'; + $enable = 'extension'; + } else { + $search = 'zend_extensions'; + ob_start(); + phpinfo(INFO_GENERAL); + $info = ob_get_contents(); + ob_end_clean(); + $debug = function_exists('leak') ? '_debug' : ''; + $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : ''; + $enable = 'zend_extension' . $debug . $ts; + } + foreach ($ini[$search] as $line => $extension) { + if (in_array($extension, $binaries, true) || in_array( + $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) { + // already enabled - assume if one is, all are + return true; + } + } + if ($line) { + $newini = array_slice($ini['all'], 0, $line); + } else { + $newini = array(); + } + foreach ($binaries as $binary) { + if ($ini['extension_dir']) { + $binary = basename($binary); + } + $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n"); + } + $newini = array_merge($newini, array_slice($ini['all'], $line)); + $fp = @fopen($phpini, 'wb'); + if (!$fp) { + return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing'); + } + foreach ($newini as $line) { + fwrite($fp, $line); + } + fclose($fp); + return true; + } + + function disableExtension($binaries, $type) + { + if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) { + return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location'); + } + $ini = $this->_parseIni($phpini); + if (PEAR::isError($ini)) { + return $ini; + } + $line = 0; + if ($type == 'extsrc' || $type == 'extbin') { + $search = 'extensions'; + $enable = 'extension'; + } else { + $search = 'zend_extensions'; + ob_start(); + phpinfo(INFO_GENERAL); + $info = ob_get_contents(); + ob_end_clean(); + $debug = function_exists('leak') ? '_debug' : ''; + $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : ''; + $enable = 'zend_extension' . $debug . $ts; + } + $found = false; + foreach ($ini[$search] as $line => $extension) { + if (in_array($extension, $binaries, true) || in_array( + $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) { + $found = true; + break; + } + } + if (!$found) { + // not enabled + return true; + } + $fp = @fopen($phpini, 'wb'); + if (!$fp) { + return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing'); + } + if ($line) { + $newini = array_slice($ini['all'], 0, $line); + // delete the enable line + $newini = array_merge($newini, array_slice($ini['all'], $line + 1)); + } else { + $newini = array_slice($ini['all'], 1); + } + foreach ($newini as $line) { + fwrite($fp, $line); + } + fclose($fp); + return true; + } + + function _parseIni($filename) + { + if (!file_exists($filename)) { + return PEAR::raiseError('php.ini "' . $filename . '" does not exist'); + } + + if (filesize($filename) > 300000) { + return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting'); + } + + ob_start(); + phpinfo(INFO_GENERAL); + $info = ob_get_contents(); + ob_end_clean(); + $debug = function_exists('leak') ? '_debug' : ''; + $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : ''; + $zend_extension_line = 'zend_extension' . $debug . $ts; + $all = @file($filename); + if (!$all) { + return PEAR::raiseError('php.ini "' . $filename .'" could not be read'); + } + $zend_extensions = $extensions = array(); + // assume this is right, but pull from the php.ini if it is found + $extension_dir = ini_get('extension_dir'); + foreach ($all as $linenum => $line) { + $line = trim($line); + if (!$line) { + continue; + } + if ($line[0] == ';') { + continue; + } + if (strtolower(substr($line, 0, 13)) == 'extension_dir') { + $line = trim(substr($line, 13)); + if ($line[0] == '=') { + $x = trim(substr($line, 1)); + $x = explode(';', $x); + $extension_dir = str_replace('"', '', array_shift($x)); + continue; + } + } + if (strtolower(substr($line, 0, 9)) == 'extension') { + $line = trim(substr($line, 9)); + if ($line[0] == '=') { + $x = trim(substr($line, 1)); + $x = explode(';', $x); + $extensions[$linenum] = str_replace('"', '', array_shift($x)); + continue; + } + } + if (strtolower(substr($line, 0, strlen($zend_extension_line))) == + $zend_extension_line) { + $line = trim(substr($line, strlen($zend_extension_line))); + if ($line[0] == '=') { + $x = trim(substr($line, 1)); + $x = explode(';', $x); + $zend_extensions[$linenum] = str_replace('"', '', array_shift($x)); + continue; + } + } + } + return array( + 'extensions' => $extensions, + 'zend_extensions' => $zend_extensions, + 'extension_dir' => $extension_dir, + 'all' => $all, + ); + } + + // {{{ doInstall() + + function doInstall($command, $options, $params) + { + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } + + if (isset($options['installroot']) && isset($options['packagingroot'])) { + return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot'); + } + + $reg = &$this->config->getRegistry(); + $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel'); + if (!$reg->channelExists($channel)) { + return $this->raiseError('Channel "' . $channel . '" does not exist'); + } + + if (empty($this->installer)) { + $this->installer = &$this->getInstaller($this->ui); + } + + if ($command == 'upgrade' || $command == 'upgrade-all') { + // If people run the upgrade command but pass nothing, emulate a upgrade-all + if ($command == 'upgrade' && empty($params)) { + return $this->doUpgradeAll($command, $options, $params); + } + $options['upgrade'] = true; + } else { + $packages = $params; + } + + $instreg = &$reg; // instreg used to check if package is installed + if (isset($options['packagingroot']) && !isset($options['upgrade'])) { + $packrootphp_dir = $this->installer->_prependPath( + $this->config->get('php_dir', null, 'pear.php.net'), + $options['packagingroot']); + $instreg = new PEAR_Registry($packrootphp_dir); // other instreg! + + if ($this->config->get('verbose') > 2) { + $this->ui->outputData('using package root: ' . $options['packagingroot']); + } + } + + $abstractpackages = $otherpackages = array(); + // parse params + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + + foreach ($params as $param) { + if (strpos($param, 'http://') === 0) { + $otherpackages[] = $param; + continue; + } + + if (strpos($param, 'channel://') === false && @file_exists($param)) { + if (isset($options['force'])) { + $otherpackages[] = $param; + continue; + } + + $pkg = new PEAR_PackageFile($this->config); + $pf = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING); + if (PEAR::isError($pf)) { + $otherpackages[] = $param; + continue; + } + + $exists = $reg->packageExists($pf->getPackage(), $pf->getChannel()); + $pversion = $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel()); + $version_compare = version_compare($pf->getVersion(), $pversion, '<='); + if ($exists && $version_compare) { + if ($this->config->get('verbose')) { + $this->ui->outputData('Ignoring installed package ' . + $reg->parsedPackageNameToString( + array('package' => $pf->getPackage(), + 'channel' => $pf->getChannel()), true)); + } + continue; + } + $otherpackages[] = $param; + continue; + } + + $e = $reg->parsePackageName($param, $channel); + if (PEAR::isError($e)) { + $otherpackages[] = $param; + } else { + $abstractpackages[] = $e; + } + } + PEAR::staticPopErrorHandling(); + + // if there are any local package .tgz or remote static url, we can't + // filter. The filter only works for abstract packages + if (count($abstractpackages) && !isset($options['force'])) { + // when not being forced, only do necessary upgrades/installs + if (isset($options['upgrade'])) { + $abstractpackages = $this->_filterUptodatePackages($abstractpackages, $command); + } else { + $count = count($abstractpackages); + foreach ($abstractpackages as $i => $package) { + if (isset($package['group'])) { + // do not filter out install groups + continue; + } + + if ($instreg->packageExists($package['package'], $package['channel'])) { + if ($count > 1) { + if ($this->config->get('verbose')) { + $this->ui->outputData('Ignoring installed package ' . + $reg->parsedPackageNameToString($package, true)); + } + unset($abstractpackages[$i]); + } elseif ($count === 1) { + // Lets try to upgrade it since it's already installed + $options['upgrade'] = true; + } + } + } + } + $abstractpackages = + array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages); + } elseif (count($abstractpackages)) { + $abstractpackages = + array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages); + } + + $packages = array_merge($abstractpackages, $otherpackages); + if (!count($packages)) { + $c = ''; + if (isset($options['channel'])){ + $c .= ' in channel "' . $options['channel'] . '"'; + } + $this->ui->outputData('Nothing to ' . $command . $c); + return true; + } + + $this->downloader = &$this->getDownloader($this->ui, $options, $this->config); + $errors = $downloaded = $binaries = array(); + $downloaded = &$this->downloader->download($packages); + if (PEAR::isError($downloaded)) { + return $this->raiseError($downloaded); + } + + $errors = $this->downloader->getErrorMsgs(); + if (count($errors)) { + $err = array(); + $err['data'] = array(); + foreach ($errors as $error) { + if ($error !== null) { + $err['data'][] = array($error); + } + } + + if (!empty($err['data'])) { + $err['headline'] = 'Install Errors'; + $this->ui->outputData($err); + } + + if (!count($downloaded)) { + return $this->raiseError("$command failed"); + } + } + + $data = array( + 'headline' => 'Packages that would be Installed' + ); + + if (isset($options['pretend'])) { + foreach ($downloaded as $package) { + $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage())); + } + $this->ui->outputData($data, 'pretend'); + return true; + } + + $this->installer->setOptions($options); + $this->installer->sortPackagesForInstall($downloaded); + if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) { + $this->raiseError($err->getMessage()); + return true; + } + + $binaries = $extrainfo = array(); + foreach ($downloaded as $param) { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $info = $this->installer->install($param, $options); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($info)) { + $oldinfo = $info; + $pkg = &$param->getPackageFile(); + if ($info->getCode() != PEAR_INSTALLER_NOBINARY) { + if (!($info = $pkg->installBinary($this->installer))) { + $this->ui->outputData('ERROR: ' .$oldinfo->getMessage()); + continue; + } + + // we just installed a different package than requested, + // let's change the param and info so that the rest of this works + $param = $info[0]; + $info = $info[1]; + } + } + + if (!is_array($info)) { + return $this->raiseError("$command failed"); + } + + if ($param->getPackageType() == 'extsrc' || + $param->getPackageType() == 'extbin' || + $param->getPackageType() == 'zendextsrc' || + $param->getPackageType() == 'zendextbin' + ) { + $pkg = &$param->getPackageFile(); + if ($instbin = $pkg->getInstalledBinary()) { + $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel()); + } else { + $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel()); + } + + foreach ($instpkg->getFilelist() as $name => $atts) { + $pinfo = pathinfo($atts['installed_as']); + if (!isset($pinfo['extension']) || + in_array($pinfo['extension'], array('c', 'h')) + ) { + continue; // make sure we don't match php_blah.h + } + + if ((strpos($pinfo['basename'], 'php_') === 0 && + $pinfo['extension'] == 'dll') || + // most unices + $pinfo['extension'] == 'so' || + // hp-ux + $pinfo['extension'] == 'sl') { + $binaries[] = array($atts['installed_as'], $pinfo); + break; + } + } + + if (count($binaries)) { + foreach ($binaries as $pinfo) { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType()); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($ret)) { + $extrainfo[] = $ret->getMessage(); + if ($param->getPackageType() == 'extsrc' || + $param->getPackageType() == 'extbin') { + $exttype = 'extension'; + } else { + ob_start(); + phpinfo(INFO_GENERAL); + $info = ob_get_contents(); + ob_end_clean(); + $debug = function_exists('leak') ? '_debug' : ''; + $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : ''; + $exttype = 'zend_extension' . $debug . $ts; + } + $extrainfo[] = 'You should add "' . $exttype . '=' . + $pinfo[1]['basename'] . '" to php.ini'; + } else { + $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() . + ' enabled in php.ini'; + } + } + } + } + + if ($this->config->get('verbose') > 0) { + $chan = $param->getChannel(); + $label = $reg->parsedPackageNameToString( + array( + 'channel' => $chan, + 'package' => $param->getPackage(), + 'version' => $param->getVersion(), + )); + $out = array('data' => "$command ok: $label"); + if (isset($info['release_warnings'])) { + $out['release_warnings'] = $info['release_warnings']; + } + $this->ui->outputData($out, $command); + + if (!isset($options['register-only']) && !isset($options['offline'])) { + if ($this->config->isDefinedLayer('ftp')) { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $info = $this->installer->ftpInstall($param); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($info)) { + $this->ui->outputData($info->getMessage()); + $this->ui->outputData("remote install failed: $label"); + } else { + $this->ui->outputData("remote install ok: $label"); + } + } + } + } + + $deps = $param->getDeps(); + if ($deps) { + if (isset($deps['group'])) { + $groups = $deps['group']; + if (!isset($groups[0])) { + $groups = array($groups); + } + + foreach ($groups as $group) { + if ($group['attribs']['name'] == 'default') { + // default group is always installed, unless the user + // explicitly chooses to install another group + continue; + } + $extrainfo[] = $param->getPackage() . ': Optional feature ' . + $group['attribs']['name'] . ' available (' . + $group['attribs']['hint'] . ')'; + } + + $extrainfo[] = $param->getPackage() . + ': To install optional features use "pear install ' . + $reg->parsedPackageNameToString( + array('package' => $param->getPackage(), + 'channel' => $param->getChannel()), true) . + '#featurename"'; + } + } + + $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel()); + // $pkg may be NULL if install is a 'fake' install via --packagingroot + if (is_object($pkg)) { + $pkg->setConfig($this->config); + if ($list = $pkg->listPostinstallScripts()) { + $pn = $reg->parsedPackageNameToString(array('channel' => + $param->getChannel(), 'package' => $param->getPackage()), true); + $extrainfo[] = $pn . ' has post-install scripts:'; + foreach ($list as $file) { + $extrainfo[] = $file; + } + $extrainfo[] = $param->getPackage() . + ': Use "pear run-scripts ' . $pn . '" to finish setup.'; + $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES'; + } + } + } + + if (count($extrainfo)) { + foreach ($extrainfo as $info) { + $this->ui->outputData($info); + } + } + + return true; + } + + // }}} + // {{{ doUpgradeAll() + + function doUpgradeAll($command, $options, $params) + { + $reg = &$this->config->getRegistry(); + $upgrade = array(); + + if (isset($options['channel'])) { + $channels = array($options['channel']); + } else { + $channels = $reg->listChannels(); + } + + foreach ($channels as $channel) { + if ($channel == '__uri') { + continue; + } + + // parse name with channel + foreach ($reg->listPackages($channel) as $name) { + $upgrade[] = $reg->parsedPackageNameToString(array( + 'channel' => $channel, + 'package' => $name + )); + } + } + + $err = $this->doInstall($command, $options, $upgrade); + if (PEAR::isError($err)) { + $this->ui->outputData($err->getMessage(), $command); + } + } + + // }}} + // {{{ doUninstall() + + function doUninstall($command, $options, $params) + { + if (count($params) < 1) { + return $this->raiseError("Please supply the package(s) you want to uninstall"); + } + + if (empty($this->installer)) { + $this->installer = &$this->getInstaller($this->ui); + } + + if (isset($options['remoteconfig'])) { + $e = $this->config->readFTPConfigFile($options['remoteconfig']); + if (!PEAR::isError($e)) { + $this->installer->setConfig($this->config); + } + } + + $reg = &$this->config->getRegistry(); + $newparams = array(); + $binaries = array(); + $badparams = array(); + foreach ($params as $pkg) { + $channel = $this->config->get('default_channel'); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $parsed = $reg->parsePackageName($pkg, $channel); + PEAR::staticPopErrorHandling(); + if (!$parsed || PEAR::isError($parsed)) { + $badparams[] = $pkg; + continue; + } + $package = $parsed['package']; + $channel = $parsed['channel']; + $info = &$reg->getPackage($package, $channel); + if ($info === null && + ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) { + // make sure this isn't a package that has flipped from pear to pecl but + // used a package.xml 1.0 + $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net'; + $info = &$reg->getPackage($package, $testc); + if ($info !== null) { + $channel = $testc; + } + } + if ($info === null) { + $badparams[] = $pkg; + } else { + $newparams[] = &$info; + // check for binary packages (this is an alias for those packages if so) + if ($installedbinary = $info->getInstalledBinary()) { + $this->ui->log('adding binary package ' . + $reg->parsedPackageNameToString(array('channel' => $channel, + 'package' => $installedbinary), true)); + $newparams[] = &$reg->getPackage($installedbinary, $channel); + } + // add the contents of a dependency group to the list of installed packages + if (isset($parsed['group'])) { + $group = $info->getDependencyGroup($parsed['group']); + if ($group) { + $installed = $reg->getInstalledGroup($group); + if ($installed) { + foreach ($installed as $i => $p) { + $newparams[] = &$installed[$i]; + } + } + } + } + } + } + $err = $this->installer->sortPackagesForUninstall($newparams); + if (PEAR::isError($err)) { + $this->ui->outputData($err->getMessage(), $command); + return true; + } + $params = $newparams; + // twist this to use it to check on whether dependent packages are also being uninstalled + // for circular dependencies like subpackages + $this->installer->setUninstallPackages($newparams); + $params = array_merge($params, $badparams); + $binaries = array(); + foreach ($params as $pkg) { + $this->installer->pushErrorHandling(PEAR_ERROR_RETURN); + if ($err = $this->installer->uninstall($pkg, $options)) { + $this->installer->popErrorHandling(); + if (PEAR::isError($err)) { + $this->ui->outputData($err->getMessage(), $command); + continue; + } + if ($pkg->getPackageType() == 'extsrc' || + $pkg->getPackageType() == 'extbin' || + $pkg->getPackageType() == 'zendextsrc' || + $pkg->getPackageType() == 'zendextbin') { + if ($instbin = $pkg->getInstalledBinary()) { + continue; // this will be uninstalled later + } + + foreach ($pkg->getFilelist() as $name => $atts) { + $pinfo = pathinfo($atts['installed_as']); + if (!isset($pinfo['extension']) || + in_array($pinfo['extension'], array('c', 'h'))) { + continue; // make sure we don't match php_blah.h + } + if ((strpos($pinfo['basename'], 'php_') === 0 && + $pinfo['extension'] == 'dll') || + // most unices + $pinfo['extension'] == 'so' || + // hp-ux + $pinfo['extension'] == 'sl') { + $binaries[] = array($atts['installed_as'], $pinfo); + break; + } + } + if (count($binaries)) { + foreach ($binaries as $pinfo) { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType()); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($ret)) { + $extrainfo[] = $ret->getMessage(); + if ($pkg->getPackageType() == 'extsrc' || + $pkg->getPackageType() == 'extbin') { + $exttype = 'extension'; + } else { + ob_start(); + phpinfo(INFO_GENERAL); + $info = ob_get_contents(); + ob_end_clean(); + $debug = function_exists('leak') ? '_debug' : ''; + $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : ''; + $exttype = 'zend_extension' . $debug . $ts; + } + $this->ui->outputData('Unable to remove "' . $exttype . '=' . + $pinfo[1]['basename'] . '" from php.ini', $command); + } else { + $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() . + ' disabled in php.ini', $command); + } + } + } + } + $savepkg = $pkg; + if ($this->config->get('verbose') > 0) { + if (is_object($pkg)) { + $pkg = $reg->parsedPackageNameToString($pkg); + } + $this->ui->outputData("uninstall ok: $pkg", $command); + } + if (!isset($options['offline']) && is_object($savepkg) && + defined('PEAR_REMOTEINSTALL_OK')) { + if ($this->config->isDefinedLayer('ftp')) { + $this->installer->pushErrorHandling(PEAR_ERROR_RETURN); + $info = $this->installer->ftpUninstall($savepkg); + $this->installer->popErrorHandling(); + if (PEAR::isError($info)) { + $this->ui->outputData($info->getMessage()); + $this->ui->outputData("remote uninstall failed: $pkg"); + } else { + $this->ui->outputData("remote uninstall ok: $pkg"); + } + } + } + } else { + $this->installer->popErrorHandling(); + if (!is_object($pkg)) { + return $this->raiseError("uninstall failed: $pkg"); + } + $pkg = $reg->parsedPackageNameToString($pkg); + } + } + + return true; + } + + // }}} + + + // }}} + // {{{ doBundle() + /* + (cox) It just downloads and untars the package, does not do + any check that the PEAR_Installer::_installFile() does. + */ + + function doBundle($command, $options, $params) + { + $opts = array( + 'force' => true, + 'nodeps' => true, + 'soft' => true, + 'downloadonly' => true + ); + $downloader = &$this->getDownloader($this->ui, $opts, $this->config); + $reg = &$this->config->getRegistry(); + if (count($params) < 1) { + return $this->raiseError("Please supply the package you want to bundle"); + } + + if (isset($options['destination'])) { + if (!is_dir($options['destination'])) { + System::mkdir('-p ' . $options['destination']); + } + $dest = realpath($options['destination']); + } else { + $pwd = getcwd(); + $dir = $pwd . DIRECTORY_SEPARATOR . 'ext'; + $dest = is_dir($dir) ? $dir : $pwd; + } + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = $downloader->setDownloadDir($dest); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($err)) { + return PEAR::raiseError('download directory "' . $dest . + '" is not writeable.'); + } + $result = &$downloader->download(array($params[0])); + if (PEAR::isError($result)) { + return $result; + } + if (!isset($result[0])) { + return $this->raiseError('unable to unpack ' . $params[0]); + } + $pkgfile = &$result[0]->getPackageFile(); + $pkgname = $pkgfile->getName(); + $pkgversion = $pkgfile->getVersion(); + + // Unpacking ------------------------------------------------- + $dest .= DIRECTORY_SEPARATOR . $pkgname; + $orig = $pkgname . '-' . $pkgversion; + + $tar = &new Archive_Tar($pkgfile->getArchiveFile()); + if (!$tar->extractModify($dest, $orig)) { + return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile()); + } + $this->ui->outputData("Package ready at '$dest'"); + // }}} + } + + // }}} + + function doRunScripts($command, $options, $params) + { + if (!isset($params[0])) { + return $this->raiseError('run-scripts expects 1 parameter: a package name'); + } + + $reg = &$this->config->getRegistry(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel')); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($parsed)) { + return $this->raiseError($parsed); + } + + $package = &$reg->getPackage($parsed['package'], $parsed['channel']); + if (!is_object($package)) { + return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry'); + } + + $package->setConfig($this->config); + $package->runPostinstallScripts(); + $this->ui->outputData('Install scripts complete', $command); + return true; + } + + /** + * Given a list of packages, filter out those ones that are already up to date + * + * @param $packages: packages, in parsed array format ! + * @return list of packages that can be upgraded + */ + function _filterUptodatePackages($packages, $command) + { + $reg = &$this->config->getRegistry(); + $latestReleases = array(); + + $ret = array(); + foreach ($packages as $package) { + if (isset($package['group'])) { + $ret[] = $package; + continue; + } + + $channel = $package['channel']; + $name = $package['package']; + if (!$reg->packageExists($name, $channel)) { + $ret[] = $package; + continue; + } + + if (!isset($latestReleases[$channel])) { + // fill in cache for this channel + $chan = &$reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $this->raiseError($chan); + } + + $base2 = false; + $preferred_mirror = $this->config->get('preferred_mirror', null, $channel); + if ($chan->supportsREST($preferred_mirror) && + ( + //($base2 = $chan->getBaseURL('REST1.4', $preferred_mirror)) || + ($base = $chan->getBaseURL('REST1.0', $preferred_mirror)) + ) + ) { + $dorest = true; + } + + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (!isset($package['state'])) { + $state = $this->config->get('preferred_state', null, $channel); + } else { + $state = $package['state']; + } + + if ($dorest) { + if ($base2) { + $rest = &$this->config->getREST('1.4', array()); + $base = $base2; + } else { + $rest = &$this->config->getREST('1.0', array()); + } + + $installed = array_flip($reg->listPackages($channel)); + $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg); + } + + PEAR::staticPopErrorHandling(); + if (PEAR::isError($latest)) { + $this->ui->outputData('Error getting channel info from ' . $channel . + ': ' . $latest->getMessage()); + continue; + } + + $latestReleases[$channel] = array_change_key_case($latest); + } + + // check package for latest release + $name_lower = strtolower($name); + if (isset($latestReleases[$channel][$name_lower])) { + // if not set, up to date + $inst_version = $reg->packageInfo($name, 'version', $channel); + $channel_version = $latestReleases[$channel][$name_lower]['version']; + if (version_compare($channel_version, $inst_version, 'le')) { + // installed version is up-to-date + continue; + } + + // maintain BC + if ($command == 'upgrade-all') { + $this->ui->outputData(array('data' => 'Will upgrade ' . + $reg->parsedPackageNameToString($package)), $command); + } + $ret[] = $package; + } + } + + return $ret; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Install.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Install.xml new file mode 100644 index 0000000..1b1e933 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Install.xml @@ -0,0 +1,276 @@ + + + Install Package + doInstall + i + + + f + will overwrite newer installed packages + + + l + do not check for recommended dependency version + + + n + ignore dependencies, install anyway + + + r + do not install files, only register the package as installed + + + s + soft install, fail silently, or upgrade if already installed + + + B + don't build C extensions + + + Z + request uncompressed files when downloading + + + R + root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM + DIR + + + P + root directory used when packaging files, like RPM packaging + DIR + + + + force install even if there were errors + + + a + install all required and optional dependencies + + + o + install all required dependencies + + + O + do not attempt to download any urls or contact channels + + + p + Only list the packages that would be downloaded + + + [channel/]<package> ... +Installs one or more PEAR packages. You can specify a package to +install in four ways: + +"Package-1.0.tgz" : installs from a local file + +"http://example.com/Package-1.0.tgz" : installs from +anywhere on the net. + +"package.xml" : installs the package described in +package.xml. Useful for testing, or for wrapping a PEAR package in +another package manager such as RPM. + +"Package[-version/state][.tar]" : queries your default channel's server +({config master_server}) and downloads the newest package with +the preferred quality/state ({config preferred_state}). + +To retrieve Package version 1.1, use "Package-1.1," to retrieve +Package state beta, use "Package-beta." To retrieve an uncompressed +file, append .tar (make sure there is no file by the same name first) + +To download a package from another channel, prefix with the channel name like +"channel/Package" + +More than one package may be specified at once. It is ok to mix these +four ways of specifying packages. + + + + Upgrade Package + doInstall + up + + + c + upgrade packages from a specific channel + CHAN + + + f + overwrite newer installed packages + + + l + do not check for recommended dependency version + + + n + ignore dependencies, upgrade anyway + + + r + do not install files, only register the package as upgraded + + + B + don't build C extensions + + + Z + request uncompressed files when downloading + + + R + root directory used when installing files (ala PHP's INSTALL_ROOT) + DIR + + + + force install even if there were errors + + + a + install all required and optional dependencies + + + o + install all required dependencies + + + O + do not attempt to download any urls or contact channels + + + p + Only list the packages that would be downloaded + + + <package> ... +Upgrades one or more PEAR packages. See documentation for the +"install" command for ways to specify a package. + +When upgrading, your package will be updated if the provided new +package has a higher version number (use the -f option if you need to +upgrade anyway). + +More than one package may be specified at once. + + + + Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters] + doUpgradeAll + ua + + + c + upgrade packages from a specific channel + CHAN + + + n + ignore dependencies, upgrade anyway + + + r + do not install files, only register the package as upgraded + + + B + don't build C extensions + + + Z + request uncompressed files when downloading + + + R + root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM + DIR + + + + force install even if there were errors + + + + do not check for recommended dependency version + + + +WARNING: This function is deprecated in favor of using the upgrade command with no params + +Upgrades all packages that have a newer release available. Upgrades are +done only if there is a release available of the state specified in +"preferred_state" (currently {config preferred_state}), or a state considered +more stable. + + + + Un-install Package + doUninstall + un + + + n + ignore dependencies, uninstall anyway + + + r + do not remove files, only register the packages as not installed + + + R + root directory used when installing files (ala PHP's INSTALL_ROOT) + DIR + + + + force install even if there were errors + + + O + do not attempt to uninstall remotely + + + [channel/]<package> ... +Uninstalls one or more PEAR packages. More than one package may be +specified at once. Prefix with channel name to uninstall from a +channel not in your default channel ({config default_channel}) + + + + Unpacks a Pecl Package + doBundle + bun + + + d + Optional destination directory for unpacking (defaults to current path or "ext" if exists) + DIR + + + f + Force the unpacking even if there were errors in the package + + + <package> +Unpacks a Pecl Package into the selected location. It will download the +package if needed. + + + + Run Post-Install Scripts bundled with a package + doRunScripts + rs + + <package> +Run post-installation scripts in package <package>, if any exist. + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Mirror.php b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Mirror.php new file mode 100644 index 0000000..a8ffb48 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Mirror.php @@ -0,0 +1,139 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Mirror.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.2.0 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for providing file mirrors + * + * @category pear + * @package PEAR + * @author Alexander Merz + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.2.0 + */ +class PEAR_Command_Mirror extends PEAR_Command_Common +{ + var $commands = array( + 'download-all' => array( + 'summary' => 'Downloads each available package from the default channel', + 'function' => 'doDownloadAll', + 'shortcut' => 'da', + 'options' => array( + 'channel' => + array( + 'shortopt' => 'c', + 'doc' => 'specify a channel other than the default channel', + 'arg' => 'CHAN', + ), + ), + 'doc' => ' +Requests a list of available packages from the default channel ({config default_channel}) +and downloads them to current working directory. Note: only +packages within preferred_state ({config preferred_state}) will be downloaded' + ), + ); + + /** + * PEAR_Command_Mirror constructor. + * + * @access public + * @param object PEAR_Frontend a reference to an frontend + * @param object PEAR_Config a reference to the configuration data + */ + function PEAR_Command_Mirror(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + /** + * For unit-testing + */ + function &factory($a) + { + $a = &PEAR_Command::factory($a, $this->config); + return $a; + } + + /** + * retrieves a list of avaible Packages from master server + * and downloads them + * + * @access public + * @param string $command the command + * @param array $options the command options before the command + * @param array $params the stuff after the command name + * @return bool true if succesful + * @throw PEAR_Error + */ + function doDownloadAll($command, $options, $params) + { + $savechannel = $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + $channel = isset($options['channel']) ? $options['channel'] : + $this->config->get('default_channel'); + if (!$reg->channelExists($channel)) { + $this->config->set('default_channel', $savechannel); + return $this->raiseError('Channel "' . $channel . '" does not exist'); + } + $this->config->set('default_channel', $channel); + + $this->ui->outputData('Using Channel ' . $this->config->get('default_channel')); + $chan = $reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $this->raiseError($chan); + } + + if ($chan->supportsREST($this->config->get('preferred_mirror')) && + $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { + $rest = &$this->config->getREST('1.0', array()); + $remoteInfo = array_flip($rest->listPackages($base, $channel)); + } + + if (PEAR::isError($remoteInfo)) { + return $remoteInfo; + } + + $cmd = &$this->factory("download"); + if (PEAR::isError($cmd)) { + return $cmd; + } + + $this->ui->outputData('Using Preferred State of ' . + $this->config->get('preferred_state')); + $this->ui->outputData('Gathering release information, please wait...'); + + /** + * Error handling not necessary, because already done by + * the download command + */ + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = $cmd->run('download', array('downloadonly' => true), array_keys($remoteInfo)); + PEAR::staticPopErrorHandling(); + $this->config->set('default_channel', $savechannel); + if (PEAR::isError($err)) { + $this->ui->outputData($err->getMessage()); + } + + return true; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Mirror.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Mirror.xml new file mode 100644 index 0000000..fe8be9d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Mirror.xml @@ -0,0 +1,18 @@ + + + Downloads each available package from the default channel + doDownloadAll + da + + + c + specify a channel other than the default channel + CHAN + + + +Requests a list of available packages from the default channel ({config default_channel}) +and downloads them to current working directory. Note: only +packages within preferred_state ({config preferred_state}) will be downloaded + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Package.php b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Package.php new file mode 100644 index 0000000..7029841 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Package.php @@ -0,0 +1,1124 @@ + + * @author Martin Jansen + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Package.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for login/logout + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Martin Jansen + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ + +class PEAR_Command_Package extends PEAR_Command_Common +{ + var $commands = array( + 'package' => array( + 'summary' => 'Build Package', + 'function' => 'doPackage', + 'shortcut' => 'p', + 'options' => array( + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'Do not gzip the package file' + ), + 'showname' => array( + 'shortopt' => 'n', + 'doc' => 'Print the name of the packaged file.', + ), + ), + 'doc' => '[descfile] [descfile2] +Creates a PEAR package from its description file (usually called +package.xml). If a second packagefile is passed in, then +the packager will check to make sure that one is a package.xml +version 1.0, and the other is a package.xml version 2.0. The +package.xml version 1.0 will be saved as "package.xml" in the archive, +and the other as "package2.xml" in the archive" +' + ), + 'package-validate' => array( + 'summary' => 'Validate Package Consistency', + 'function' => 'doPackageValidate', + 'shortcut' => 'pv', + 'options' => array(), + 'doc' => ' +', + ), + 'cvsdiff' => array( + 'summary' => 'Run a "cvs diff" for all files in a package', + 'function' => 'doCvsDiff', + 'shortcut' => 'cd', + 'options' => array( + 'quiet' => array( + 'shortopt' => 'q', + 'doc' => 'Be quiet', + ), + 'reallyquiet' => array( + 'shortopt' => 'Q', + 'doc' => 'Be really quiet', + ), + 'date' => array( + 'shortopt' => 'D', + 'doc' => 'Diff against revision of DATE', + 'arg' => 'DATE', + ), + 'release' => array( + 'shortopt' => 'R', + 'doc' => 'Diff against tag for package release REL', + 'arg' => 'REL', + ), + 'revision' => array( + 'shortopt' => 'r', + 'doc' => 'Diff against revision REV', + 'arg' => 'REV', + ), + 'context' => array( + 'shortopt' => 'c', + 'doc' => 'Generate context diff', + ), + 'unified' => array( + 'shortopt' => 'u', + 'doc' => 'Generate unified diff', + ), + 'ignore-case' => array( + 'shortopt' => 'i', + 'doc' => 'Ignore case, consider upper- and lower-case letters equivalent', + ), + 'ignore-whitespace' => array( + 'shortopt' => 'b', + 'doc' => 'Ignore changes in amount of white space', + ), + 'ignore-blank-lines' => array( + 'shortopt' => 'B', + 'doc' => 'Ignore changes that insert or delete blank lines', + ), + 'brief' => array( + 'doc' => 'Report only whether the files differ, no details', + ), + 'dry-run' => array( + 'shortopt' => 'n', + 'doc' => 'Don\'t do anything, just pretend', + ), + ), + 'doc' => ' +Compares all the files in a package. Without any options, this +command will compare the current code with the last checked-in code. +Using the -r or -R option you may compare the current code with that +of a specific release. +', + ), + 'svntag' => array( + 'summary' => 'Set SVN Release Tag', + 'function' => 'doSvnTag', + 'shortcut' => 'sv', + 'options' => array( + 'quiet' => array( + 'shortopt' => 'q', + 'doc' => 'Be quiet', + ), + 'slide' => array( + 'shortopt' => 'F', + 'doc' => 'Move (slide) tag if it exists', + ), + 'delete' => array( + 'shortopt' => 'd', + 'doc' => 'Remove tag', + ), + 'dry-run' => array( + 'shortopt' => 'n', + 'doc' => 'Don\'t do anything, just pretend', + ), + ), + 'doc' => ' [files...] + Sets a SVN tag on all files in a package. Use this command after you have + packaged a distribution tarball with the "package" command to tag what + revisions of what files were in that release. If need to fix something + after running svngtag once, but before the tarball is released to the public, + use the "slide" option to move the release tag. + + to include files (such as a second package.xml, or tests not included in the + release), pass them as additional parameters. + ', + ), + 'cvstag' => array( + 'summary' => 'Set CVS Release Tag', + 'function' => 'doCvsTag', + 'shortcut' => 'ct', + 'options' => array( + 'quiet' => array( + 'shortopt' => 'q', + 'doc' => 'Be quiet', + ), + 'reallyquiet' => array( + 'shortopt' => 'Q', + 'doc' => 'Be really quiet', + ), + 'slide' => array( + 'shortopt' => 'F', + 'doc' => 'Move (slide) tag if it exists', + ), + 'delete' => array( + 'shortopt' => 'd', + 'doc' => 'Remove tag', + ), + 'dry-run' => array( + 'shortopt' => 'n', + 'doc' => 'Don\'t do anything, just pretend', + ), + ), + 'doc' => ' [files...] +Sets a CVS tag on all files in a package. Use this command after you have +packaged a distribution tarball with the "package" command to tag what +revisions of what files were in that release. If need to fix something +after running cvstag once, but before the tarball is released to the public, +use the "slide" option to move the release tag. + +to include files (such as a second package.xml, or tests not included in the +release), pass them as additional parameters. +', + ), + 'package-dependencies' => array( + 'summary' => 'Show package dependencies', + 'function' => 'doPackageDependencies', + 'shortcut' => 'pd', + 'options' => array(), + 'doc' => ' or or +List all dependencies the package has. +Can take a tgz / tar file, package.xml or a package name of an installed package.' + ), + 'sign' => array( + 'summary' => 'Sign a package distribution file', + 'function' => 'doSign', + 'shortcut' => 'si', + 'options' => array( + 'verbose' => array( + 'shortopt' => 'v', + 'doc' => 'Display GnuPG output', + ), + ), + 'doc' => ' +Signs a package distribution (.tar or .tgz) file with GnuPG.', + ), + 'makerpm' => array( + 'summary' => 'Builds an RPM spec file from a PEAR package', + 'function' => 'doMakeRPM', + 'shortcut' => 'rpm', + 'options' => array( + 'spec-template' => array( + 'shortopt' => 't', + 'arg' => 'FILE', + 'doc' => 'Use FILE as RPM spec file template' + ), + 'rpm-pkgname' => array( + 'shortopt' => 'p', + 'arg' => 'FORMAT', + 'doc' => 'Use FORMAT as format string for RPM package name, %s is replaced +by the PEAR package name, defaults to "PEAR::%s".', + ), + ), + 'doc' => ' + +Creates an RPM .spec file for wrapping a PEAR package inside an RPM +package. Intended to be used from the SPECS directory, with the PEAR +package tarball in the SOURCES directory: + +$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz +Wrote RPM spec file PEAR::Net_Geo-1.0.spec +$ rpm -bb PEAR::Net_Socket-1.0.spec +... +Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm +', + ), + 'convert' => array( + 'summary' => 'Convert a package.xml 1.0 to package.xml 2.0 format', + 'function' => 'doConvert', + 'shortcut' => 'c2', + 'options' => array( + 'flat' => array( + 'shortopt' => 'f', + 'doc' => 'do not beautify the filelist.', + ), + ), + 'doc' => '[descfile] [descfile2] +Converts a package.xml in 1.0 format into a package.xml +in 2.0 format. The new file will be named package2.xml by default, +and package.xml will be used as the old file by default. +This is not the most intelligent conversion, and should only be +used for automated conversion or learning the format. +' + ), + ); + + var $output; + + /** + * PEAR_Command_Package constructor. + * + * @access public + */ + function PEAR_Command_Package(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + function _displayValidationResults($err, $warn, $strict = false) + { + foreach ($err as $e) { + $this->output .= "Error: $e\n"; + } + foreach ($warn as $w) { + $this->output .= "Warning: $w\n"; + } + $this->output .= sprintf('Validation: %d error(s), %d warning(s)'."\n", + sizeof($err), sizeof($warn)); + if ($strict && count($err) > 0) { + $this->output .= "Fix these errors and try again."; + return false; + } + return true; + } + + function &getPackager() + { + if (!class_exists('PEAR_Packager')) { + require_once 'PEAR/Packager.php'; + } + $a = &new PEAR_Packager; + return $a; + } + + function &getPackageFile($config, $debug = false) + { + if (!class_exists('PEAR_Common')) { + require_once 'PEAR/Common.php'; + } + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } + $a = &new PEAR_PackageFile($config, $debug); + $common = new PEAR_Common; + $common->ui = $this->ui; + $a->setLogger($common); + return $a; + } + + function doPackage($command, $options, $params) + { + $this->output = ''; + $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml'; + $pkg2 = isset($params[1]) ? $params[1] : null; + if (!$pkg2 && !isset($params[0]) && file_exists('package2.xml')) { + $pkg2 = 'package2.xml'; + } + + $packager = &$this->getPackager(); + $compress = empty($options['nocompress']) ? true : false; + $result = $packager->package($pkginfofile, $compress, $pkg2); + if (PEAR::isError($result)) { + return $this->raiseError($result); + } + + // Don't want output, only the package file name just created + if (isset($options['showname'])) { + $this->output = $result; + } + + if ($this->output) { + $this->ui->outputData($this->output, $command); + } + + return true; + } + + function doPackageValidate($command, $options, $params) + { + $this->output = ''; + if (count($params) < 1) { + $params[0] = 'package.xml'; + } + + $obj = &$this->getPackageFile($this->config, $this->_debug); + $obj->rawReturn(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL); + if (PEAR::isError($info)) { + $info = $obj->fromPackageFile($params[0], PEAR_VALIDATE_NORMAL); + } else { + $archive = $info->getArchiveFile(); + $tar = &new Archive_Tar($archive); + $tar->extract(dirname($info->getPackageFile())); + $info->setPackageFile(dirname($info->getPackageFile()) . DIRECTORY_SEPARATOR . + $info->getPackage() . '-' . $info->getVersion() . DIRECTORY_SEPARATOR . + basename($info->getPackageFile())); + } + + PEAR::staticPopErrorHandling(); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + + $valid = false; + if ($info->getPackagexmlVersion() == '2.0') { + if ($valid = $info->validate(PEAR_VALIDATE_NORMAL)) { + $info->flattenFileList(); + $valid = $info->validate(PEAR_VALIDATE_PACKAGING); + } + } else { + $valid = $info->validate(PEAR_VALIDATE_PACKAGING); + } + + $err = $warn = array(); + if ($errors = $info->getValidationWarnings()) { + foreach ($errors as $error) { + if ($error['level'] == 'warning') { + $warn[] = $error['message']; + } else { + $err[] = $error['message']; + } + } + } + + $this->_displayValidationResults($err, $warn); + $this->ui->outputData($this->output, $command); + return true; + } + + function doSvnTag($command, $options, $params) + { + $this->output = ''; + $_cmd = $command; + if (count($params) < 1) { + $help = $this->getHelp($command); + return $this->raiseError("$command: missing parameter: $help[0]"); + } + + $packageFile = realpath($params[0]); + $dir = dirname($packageFile); + $dir = substr($dir, strrpos($dir, DIRECTORY_SEPARATOR) + 1); + $obj = &$this->getPackageFile($this->config, $this->_debug); + $info = $obj->fromAnyFile($packageFile, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + + $err = $warn = array(); + if (!$info->validate()) { + foreach ($info->getValidationWarnings() as $error) { + if ($error['level'] == 'warning') { + $warn[] = $error['message']; + } else { + $err[] = $error['message']; + } + } + } + + if (!$this->_displayValidationResults($err, $warn, true)) { + $this->ui->outputData($this->output, $command); + return $this->raiseError('SVN tag failed'); + } + + $version = $info->getVersion(); + $package = $info->getName(); + $svntag = "$package-$version"; + + if (isset($options['delete'])) { + return $this->_svnRemoveTag($version, $package, $svntag, $packageFile, $options); + } + + $path = $this->_svnFindPath($packageFile); + + // Check if there are any modified files + $fp = popen('svn st --xml ' . dirname($packageFile), "r"); + $out = ''; + while ($line = fgets($fp, 1024)) { + $out .= rtrim($line)."\n"; + } + pclose($fp); + + if (!isset($options['quiet']) && strpos($out, 'item="modified"')) { + $params = array(array( + 'name' => 'modified', + 'type' => 'yesno', + 'default' => 'no', + 'prompt' => 'You have files in your SVN checkout (' . $path['from'] . ') that have been modified but not commited, do you still want to tag ' . $version . '?', + )); + $answers = $this->ui->confirmDialog($params); + + if (!in_array($answers['modified'], array('y', 'yes', 'on', '1'))) { + return true; + } + } + + if (isset($options['slide'])) { + $this->_svnRemoveTag($version, $package, $svntag, $packageFile, $options); + } + + // Check if tag already exists + $releaseTag = $path['local']['base'] . 'tags' . DIRECTORY_SEPARATOR . $svntag; + $existsCommand = 'svn ls ' . $path['base'] . 'tags/'; + + $fp = popen($existsCommand, "r"); + $out = ''; + while ($line = fgets($fp, 1024)) { + $out .= rtrim($line)."\n"; + } + pclose($fp); + + if (in_array($svntag . DIRECTORY_SEPARATOR, explode("\n", $out))) { + $this->ui->outputData($this->output, $command); + return $this->raiseError('SVN tag ' . $svntag . ' for ' . $package . ' already exists.'); + } elseif (file_exists($path['local']['base'] . 'tags') === false) { + return $this->raiseError('Can not locate the tags directory at ' . $path['local']['base'] . 'tags'); + } elseif (is_writeable($path['local']['base'] . 'tags') === false) { + return $this->raiseError('Can not write to the tag directory at ' . $path['local']['base'] . 'tags'); + } else { + $makeCommand = 'svn mkdir ' . $releaseTag; + $this->output .= "+ $makeCommand\n"; + if (empty($options['dry-run'])) { + // We need to create the tag dir. + $fp = popen($makeCommand, "r"); + $out = ''; + while ($line = fgets($fp, 1024)) { + $out .= rtrim($line)."\n"; + } + pclose($fp); + $this->output .= "$out\n"; + } + } + + $command = 'svn'; + if (isset($options['quiet'])) { + $command .= ' -q'; + } + + $command .= ' copy --parents '; + + $dir = dirname($packageFile); + $dir = substr($dir, strrpos($dir, DIRECTORY_SEPARATOR) + 1); + $files = array_keys($info->getFilelist()); + if (!in_array(basename($packageFile), $files)) { + $files[] = basename($packageFile); + } + + array_shift($params); + if (count($params)) { + // add in additional files to be tagged (package files and such) + $files = array_merge($files, $params); + } + + $commands = array(); + foreach ($files as $file) { + if (!file_exists($file)) { + $file = $dir . DIRECTORY_SEPARATOR . $file; + } + $commands[] = $command . ' ' . escapeshellarg($file) . ' ' . + escapeshellarg($releaseTag . DIRECTORY_SEPARATOR . $file); + } + + $this->output .= implode("\n", $commands) . "\n"; + if (empty($options['dry-run'])) { + foreach ($commands as $command) { + $fp = popen($command, "r"); + while ($line = fgets($fp, 1024)) { + $this->output .= rtrim($line)."\n"; + } + pclose($fp); + } + } + + $command = 'svn ci -m "Tagging the ' . $version . ' release" ' . $releaseTag . "\n"; + $this->output .= "+ $command\n"; + if (empty($options['dry-run'])) { + $fp = popen($command, "r"); + while ($line = fgets($fp, 1024)) { + $this->output .= rtrim($line)."\n"; + } + pclose($fp); + } + + $this->ui->outputData($this->output, $_cmd); + return true; + } + + function _svnFindPath($file) + { + $xml = ''; + $command = "svn info --xml $file"; + $fp = popen($command, "r"); + while ($line = fgets($fp, 1024)) { + $xml .= rtrim($line)."\n"; + } + pclose($fp); + $url_tag = strpos($xml, ''); + $url = substr($xml, $url_tag + 5, strpos($xml, '', $url_tag + 5) - ($url_tag + 5)); + + $path = array(); + $path['from'] = substr($url, 0, strrpos($url, '/')); + $path['base'] = substr($path['from'], 0, strrpos($path['from'], '/') + 1); + + // Figure out the local paths - see http://pear.php.net/bugs/17463 + $pos = strpos($file, DIRECTORY_SEPARATOR . 'trunk' . DIRECTORY_SEPARATOR); + if ($pos === false) { + $pos = strpos($file, DIRECTORY_SEPARATOR . 'branches' . DIRECTORY_SEPARATOR); + } + $path['local']['base'] = substr($file, 0, $pos + 1); + + return $path; + } + + function _svnRemoveTag($version, $package, $tag, $packageFile, $options) + { + $command = 'svn'; + + if (isset($options['quiet'])) { + $command .= ' -q'; + } + + $command .= ' remove'; + $command .= ' -m "Removing tag for the ' . $version . ' release."'; + + $path = $this->_svnFindPath($packageFile); + $command .= ' ' . $path['base'] . 'tags/' . $tag; + + + if ($this->config->get('verbose') > 1) { + $this->output .= "+ $command\n"; + } + + $this->output .= "+ $command\n"; + if (empty($options['dry-run'])) { + $fp = popen($command, "r"); + while ($line = fgets($fp, 1024)) { + $this->output .= rtrim($line)."\n"; + } + pclose($fp); + } + + $this->ui->outputData($this->output, $command); + return true; + } + + function doCvsTag($command, $options, $params) + { + $this->output = ''; + $_cmd = $command; + if (count($params) < 1) { + $help = $this->getHelp($command); + return $this->raiseError("$command: missing parameter: $help[0]"); + } + + $packageFile = realpath($params[0]); + $obj = &$this->getPackageFile($this->config, $this->_debug); + $info = $obj->fromAnyFile($packageFile, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + + $err = $warn = array(); + if (!$info->validate()) { + foreach ($info->getValidationWarnings() as $error) { + if ($error['level'] == 'warning') { + $warn[] = $error['message']; + } else { + $err[] = $error['message']; + } + } + } + + if (!$this->_displayValidationResults($err, $warn, true)) { + $this->ui->outputData($this->output, $command); + return $this->raiseError('CVS tag failed'); + } + + $version = $info->getVersion(); + $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version); + $cvstag = "RELEASE_$cvsversion"; + $files = array_keys($info->getFilelist()); + $command = 'cvs'; + if (isset($options['quiet'])) { + $command .= ' -q'; + } + + if (isset($options['reallyquiet'])) { + $command .= ' -Q'; + } + + $command .= ' tag'; + if (isset($options['slide'])) { + $command .= ' -F'; + } + + if (isset($options['delete'])) { + $command .= ' -d'; + } + + $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]); + array_shift($params); + if (count($params)) { + // add in additional files to be tagged + $files = array_merge($files, $params); + } + + $dir = dirname($packageFile); + $dir = substr($dir, strrpos($dir, '/') + 1); + foreach ($files as $file) { + if (!file_exists($file)) { + $file = $dir . DIRECTORY_SEPARATOR . $file; + } + $command .= ' ' . escapeshellarg($file); + } + + if ($this->config->get('verbose') > 1) { + $this->output .= "+ $command\n"; + } + + $this->output .= "+ $command\n"; + if (empty($options['dry-run'])) { + $fp = popen($command, "r"); + while ($line = fgets($fp, 1024)) { + $this->output .= rtrim($line)."\n"; + } + pclose($fp); + } + + $this->ui->outputData($this->output, $_cmd); + return true; + } + + function doCvsDiff($command, $options, $params) + { + $this->output = ''; + if (sizeof($params) < 1) { + $help = $this->getHelp($command); + return $this->raiseError("$command: missing parameter: $help[0]"); + } + + $file = realpath($params[0]); + $obj = &$this->getPackageFile($this->config, $this->_debug); + $info = $obj->fromAnyFile($file, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + + $err = $warn = array(); + if (!$info->validate()) { + foreach ($info->getValidationWarnings() as $error) { + if ($error['level'] == 'warning') { + $warn[] = $error['message']; + } else { + $err[] = $error['message']; + } + } + } + + if (!$this->_displayValidationResults($err, $warn, true)) { + $this->ui->outputData($this->output, $command); + return $this->raiseError('CVS diff failed'); + } + + $info1 = $info->getFilelist(); + $files = $info1; + $cmd = "cvs"; + if (isset($options['quiet'])) { + $cmd .= ' -q'; + unset($options['quiet']); + } + + if (isset($options['reallyquiet'])) { + $cmd .= ' -Q'; + unset($options['reallyquiet']); + } + + if (isset($options['release'])) { + $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $options['release']); + $cvstag = "RELEASE_$cvsversion"; + $options['revision'] = $cvstag; + unset($options['release']); + } + + $execute = true; + if (isset($options['dry-run'])) { + $execute = false; + unset($options['dry-run']); + } + + $cmd .= ' diff'; + // the rest of the options are passed right on to "cvs diff" + foreach ($options as $option => $optarg) { + $arg = $short = false; + if (isset($this->commands[$command]['options'][$option])) { + $arg = $this->commands[$command]['options'][$option]['arg']; + $short = $this->commands[$command]['options'][$option]['shortopt']; + } + $cmd .= $short ? " -$short" : " --$option"; + if ($arg && $optarg) { + $cmd .= ($short ? '' : '=') . escapeshellarg($optarg); + } + } + + foreach ($files as $file) { + $cmd .= ' ' . escapeshellarg($file['name']); + } + + if ($this->config->get('verbose') > 1) { + $this->output .= "+ $cmd\n"; + } + + if ($execute) { + $fp = popen($cmd, "r"); + while ($line = fgets($fp, 1024)) { + $this->output .= rtrim($line)."\n"; + } + pclose($fp); + } + + $this->ui->outputData($this->output, $command); + return true; + } + + function doPackageDependencies($command, $options, $params) + { + // $params[0] -> the PEAR package to list its information + if (count($params) !== 1) { + return $this->raiseError("bad parameter(s), try \"help $command\""); + } + + $obj = &$this->getPackageFile($this->config, $this->_debug); + if (is_file($params[0]) || strpos($params[0], '.xml') > 0) { + $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL); + } else { + $reg = $this->config->getRegistry(); + $info = $obj->fromArray($reg->packageInfo($params[0])); + } + + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + + $deps = $info->getDeps(); + if (is_array($deps)) { + if ($info->getPackagexmlVersion() == '1.0') { + $data = array( + 'caption' => 'Dependencies for pear/' . $info->getPackage(), + 'border' => true, + 'headline' => array("Required?", "Type", "Name", "Relation", "Version"), + ); + + foreach ($deps as $d) { + if (isset($d['optional'])) { + if ($d['optional'] == 'yes') { + $req = 'No'; + } else { + $req = 'Yes'; + } + } else { + $req = 'Yes'; + } + + if (isset($this->_deps_rel_trans[$d['rel']])) { + $rel = $this->_deps_rel_trans[$d['rel']]; + } else { + $rel = $d['rel']; + } + + if (isset($this->_deps_type_trans[$d['type']])) { + $type = ucfirst($this->_deps_type_trans[$d['type']]); + } else { + $type = $d['type']; + } + + if (isset($d['name'])) { + $name = $d['name']; + } else { + $name = ''; + } + + if (isset($d['version'])) { + $version = $d['version']; + } else { + $version = ''; + } + + $data['data'][] = array($req, $type, $name, $rel, $version); + } + } else { // package.xml 2.0 dependencies display + require_once 'PEAR/Dependency2.php'; + $deps = $info->getDependencies(); + $reg = &$this->config->getRegistry(); + if (is_array($deps)) { + $d = new PEAR_Dependency2($this->config, array(), ''); + $data = array( + 'caption' => 'Dependencies for ' . $info->getPackage(), + 'border' => true, + 'headline' => array("Required?", "Type", "Name", 'Versioning', 'Group'), + ); + foreach ($deps as $type => $subd) { + $req = ($type == 'required') ? 'Yes' : 'No'; + if ($type == 'group') { + $group = $subd['attribs']['name']; + } else { + $group = ''; + } + + if (!isset($subd[0])) { + $subd = array($subd); + } + + foreach ($subd as $groupa) { + foreach ($groupa as $deptype => $depinfo) { + if ($deptype == 'attribs') { + continue; + } + + if ($deptype == 'pearinstaller') { + $deptype = 'pear Installer'; + } + + if (!isset($depinfo[0])) { + $depinfo = array($depinfo); + } + + foreach ($depinfo as $inf) { + $name = ''; + if (isset($inf['channel'])) { + $alias = $reg->channelAlias($inf['channel']); + if (!$alias) { + $alias = '(channel?) ' .$inf['channel']; + } + $name = $alias . '/'; + + } + if (isset($inf['name'])) { + $name .= $inf['name']; + } elseif (isset($inf['pattern'])) { + $name .= $inf['pattern']; + } else { + $name .= ''; + } + + if (isset($inf['uri'])) { + $name .= ' [' . $inf['uri'] . ']'; + } + + if (isset($inf['conflicts'])) { + $ver = 'conflicts'; + } else { + $ver = $d->_getExtraString($inf); + } + + $data['data'][] = array($req, ucfirst($deptype), $name, + $ver, $group); + } + } + } + } + } + } + + $this->ui->outputData($data, $command); + return true; + } + + // Fallback + $this->ui->outputData("This package does not have any dependencies.", $command); + } + + function doSign($command, $options, $params) + { + // should move most of this code into PEAR_Packager + // so it'll be easy to implement "pear package --sign" + if (count($params) !== 1) { + return $this->raiseError("bad parameter(s), try \"help $command\""); + } + + require_once 'System.php'; + require_once 'Archive/Tar.php'; + + if (!file_exists($params[0])) { + return $this->raiseError("file does not exist: $params[0]"); + } + + $obj = $this->getPackageFile($this->config, $this->_debug); + $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + + $tar = new Archive_Tar($params[0]); + + $tmpdir = $this->config->get('temp_dir'); + $tmpdir = System::mktemp(" -t $tmpdir -d pearsign"); + if (!$tar->extractList('package2.xml package.xml package.sig', $tmpdir)) { + return $this->raiseError("failed to extract tar file"); + } + + if (file_exists("$tmpdir/package.sig")) { + return $this->raiseError("package already signed"); + } + + $packagexml = 'package.xml'; + if (file_exists("$tmpdir/package2.xml")) { + $packagexml = 'package2.xml'; + } + + if (file_exists("$tmpdir/package.sig")) { + unlink("$tmpdir/package.sig"); + } + + if (!file_exists("$tmpdir/$packagexml")) { + return $this->raiseError("Extracted file $tmpdir/$packagexml not found."); + } + + $input = $this->ui->userDialog($command, + array('GnuPG Passphrase'), + array('password')); + if (!isset($input[0])) { + //use empty passphrase + $input[0] = ''; + } + + $devnull = (isset($options['verbose'])) ? '' : ' 2>/dev/null'; + $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/$packagexml" . $devnull, "w"); + if (!$gpg) { + return $this->raiseError("gpg command failed"); + } + + fwrite($gpg, "$input[0]\n"); + if (pclose($gpg) || !file_exists("$tmpdir/package.sig")) { + return $this->raiseError("gpg sign failed"); + } + + if (!$tar->addModify("$tmpdir/package.sig", '', $tmpdir)) { + return $this->raiseError('failed adding signature to file'); + } + + $this->ui->outputData("Package signed.", $command); + return true; + } + + /** + * For unit testing purposes + */ + function &getInstaller(&$ui) + { + if (!class_exists('PEAR_Installer')) { + require_once 'PEAR/Installer.php'; + } + $a = &new PEAR_Installer($ui); + return $a; + } + + /** + * For unit testing purposes + */ + function &getCommandPackaging(&$ui, &$config) + { + if (!class_exists('PEAR_Command_Packaging')) { + if ($fp = @fopen('PEAR/Command/Packaging.php', 'r', true)) { + fclose($fp); + include_once 'PEAR/Command/Packaging.php'; + } + } + + if (class_exists('PEAR_Command_Packaging')) { + $a = &new PEAR_Command_Packaging($ui, $config); + } else { + $a = null; + } + + return $a; + } + + function doMakeRPM($command, $options, $params) + { + + // Check to see if PEAR_Command_Packaging is installed, and + // transparently switch to use the "make-rpm-spec" command from it + // instead, if it does. Otherwise, continue to use the old version + // of "makerpm" supplied with this package (PEAR). + $packaging_cmd = $this->getCommandPackaging($this->ui, $this->config); + if ($packaging_cmd !== null) { + $this->ui->outputData('PEAR_Command_Packaging is installed; using '. + 'newer "make-rpm-spec" command instead'); + return $packaging_cmd->run('make-rpm-spec', $options, $params); + } + + $this->ui->outputData('WARNING: "pear makerpm" is no longer available; an '. + 'improved version is available via "pear make-rpm-spec", which '. + 'is available by installing PEAR_Command_Packaging'); + return true; + } + + function doConvert($command, $options, $params) + { + $packagexml = isset($params[0]) ? $params[0] : 'package.xml'; + $newpackagexml = isset($params[1]) ? $params[1] : dirname($packagexml) . + DIRECTORY_SEPARATOR . 'package2.xml'; + $pkg = &$this->getPackageFile($this->config, $this->_debug); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $pf = $pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($pf)) { + if (is_array($pf->getUserInfo())) { + foreach ($pf->getUserInfo() as $warning) { + $this->ui->outputData($warning['message']); + } + } + return $this->raiseError($pf); + } + + if (is_a($pf, 'PEAR_PackageFile_v2')) { + $this->ui->outputData($packagexml . ' is already a package.xml version 2.0'); + return true; + } + + $gen = &$pf->getDefaultGenerator(); + $newpf = &$gen->toV2(); + $newpf->setPackagefile($newpackagexml); + $gen = &$newpf->getDefaultGenerator(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $state = (isset($options['flat']) ? PEAR_VALIDATE_PACKAGING : PEAR_VALIDATE_NORMAL); + $saved = $gen->toPackageFile(dirname($newpackagexml), $state, basename($newpackagexml)); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($saved)) { + if (is_array($saved->getUserInfo())) { + foreach ($saved->getUserInfo() as $warning) { + $this->ui->outputData($warning['message']); + } + } + + $this->ui->outputData($saved->getMessage()); + return true; + } + + $this->ui->outputData('Wrote new version 2.0 package.xml to "' . $saved . '"'); + return true; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Package.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Package.xml new file mode 100644 index 0000000..d1aff9d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Package.xml @@ -0,0 +1,237 @@ + + + Build Package + doPackage + p + + + Z + Do not gzip the package file + + + n + Print the name of the packaged file. + + + [descfile] [descfile2] +Creates a PEAR package from its description file (usually called +package.xml). If a second packagefile is passed in, then +the packager will check to make sure that one is a package.xml +version 1.0, and the other is a package.xml version 2.0. The +package.xml version 1.0 will be saved as "package.xml" in the archive, +and the other as "package2.xml" in the archive" + + + + Validate Package Consistency + doPackageValidate + pv + + + + + + Run a "cvs diff" for all files in a package + doCvsDiff + cd + + + q + Be quiet + + + Q + Be really quiet + + + D + Diff against revision of DATE + DATE + + + R + Diff against tag for package release REL + REL + + + r + Diff against revision REV + REV + + + c + Generate context diff + + + u + Generate unified diff + + + i + Ignore case, consider upper- and lower-case letters equivalent + + + b + Ignore changes in amount of white space + + + B + Ignore changes that insert or delete blank lines + + + + Report only whether the files differ, no details + + + n + Don't do anything, just pretend + + + <package.xml> +Compares all the files in a package. Without any options, this +command will compare the current code with the last checked-in code. +Using the -r or -R option you may compare the current code with that +of a specific release. + + + + Set SVN Release Tag + doSvnTag + sv + + + q + Be quiet + + + F + Move (slide) tag if it exists + + + d + Remove tag + + + n + Don't do anything, just pretend + + + <package.xml> [files...] + Sets a SVN tag on all files in a package. Use this command after you have + packaged a distribution tarball with the "package" command to tag what + revisions of what files were in that release. If need to fix something + after running svntag once, but before the tarball is released to the public, + use the "slide" option to move the release tag. + + to include files (such as a second package.xml, or tests not included in the + release), pass them as additional parameters. + + + + Set CVS Release Tag + doCvsTag + ct + + + q + Be quiet + + + Q + Be really quiet + + + F + Move (slide) tag if it exists + + + d + Remove tag + + + n + Don't do anything, just pretend + + + <package.xml> [files...] +Sets a CVS tag on all files in a package. Use this command after you have +packaged a distribution tarball with the "package" command to tag what +revisions of what files were in that release. If need to fix something +after running cvstag once, but before the tarball is released to the public, +use the "slide" option to move the release tag. + +to include files (such as a second package.xml, or tests not included in the +release), pass them as additional parameters. + + + + Show package dependencies + doPackageDependencies + pd + + <package-file> or <package.xml> or <install-package-name> +List all dependencies the package has. +Can take a tgz / tar file, package.xml or a package name of an installed package. + + + Sign a package distribution file + doSign + si + + + v + Display GnuPG output + + + <package-file> +Signs a package distribution (.tar or .tgz) file with GnuPG. + + + Builds an RPM spec file from a PEAR package + doMakeRPM + rpm + + + t + Use FILE as RPM spec file template + FILE + + + p + Use FORMAT as format string for RPM package name, %s is replaced +by the PEAR package name, defaults to "PEAR::%s". + FORMAT + + + <package-file> + +Creates an RPM .spec file for wrapping a PEAR package inside an RPM +package. Intended to be used from the SPECS directory, with the PEAR +package tarball in the SOURCES directory: + +$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz +Wrote RPM spec file PEAR::Net_Geo-1.0.spec +$ rpm -bb PEAR::Net_Socket-1.0.spec +... +Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm + + + + Convert a package.xml 1.0 to package.xml 2.0 format + doConvert + c2 + + + f + do not beautify the filelist. + + + [descfile] [descfile2] +Converts a package.xml in 1.0 format into a package.xml +in 2.0 format. The new file will be named package2.xml by default, +and package.xml will be used as the old file by default. +This is not the most intelligent conversion, and should only be +used for automated conversion or learning the format. + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Pickle.php b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Pickle.php new file mode 100644 index 0000000..3e81eee --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Pickle.php @@ -0,0 +1,421 @@ + + * @copyright 2005-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Pickle.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for login/logout + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 2005-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.1 + */ + +class PEAR_Command_Pickle extends PEAR_Command_Common +{ + var $commands = array( + 'pickle' => array( + 'summary' => 'Build PECL Package', + 'function' => 'doPackage', + 'shortcut' => 'pi', + 'options' => array( + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'Do not gzip the package file' + ), + 'showname' => array( + 'shortopt' => 'n', + 'doc' => 'Print the name of the packaged file.', + ), + ), + 'doc' => '[descfile] +Creates a PECL package from its package2.xml file. + +An automatic conversion will be made to a package.xml 1.0 and written out to +disk in the current directory as "package.xml". Note that +only simple package.xml 2.0 will be converted. package.xml 2.0 with: + + - dependency types other than required/optional PECL package/ext/php/pearinstaller + - more than one extsrcrelease or zendextsrcrelease + - zendextbinrelease, extbinrelease, phprelease, or bundle release type + - dependency groups + - ignore tags in release filelist + - tasks other than replace + - custom roles + +will cause pickle to fail, and output an error message. If your package2.xml +uses any of these features, you are best off using PEAR_PackageFileManager to +generate both package.xml. +' + ), + ); + + /** + * PEAR_Command_Package constructor. + * + * @access public + */ + function PEAR_Command_Pickle(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + /** + * For unit-testing ease + * + * @return PEAR_Packager + */ + function &getPackager() + { + if (!class_exists('PEAR_Packager')) { + require_once 'PEAR/Packager.php'; + } + + $a = &new PEAR_Packager; + return $a; + } + + /** + * For unit-testing ease + * + * @param PEAR_Config $config + * @param bool $debug + * @param string|null $tmpdir + * @return PEAR_PackageFile + */ + function &getPackageFile($config, $debug = false) + { + if (!class_exists('PEAR_Common')) { + require_once 'PEAR/Common.php'; + } + + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } + + $a = &new PEAR_PackageFile($config, $debug); + $common = new PEAR_Common; + $common->ui = $this->ui; + $a->setLogger($common); + return $a; + } + + function doPackage($command, $options, $params) + { + $this->output = ''; + $pkginfofile = isset($params[0]) ? $params[0] : 'package2.xml'; + $packager = &$this->getPackager(); + if (PEAR::isError($err = $this->_convertPackage($pkginfofile))) { + return $err; + } + + $compress = empty($options['nocompress']) ? true : false; + $result = $packager->package($pkginfofile, $compress, 'package.xml'); + if (PEAR::isError($result)) { + return $this->raiseError($result); + } + + // Don't want output, only the package file name just created + if (isset($options['showname'])) { + $this->ui->outputData($result, $command); + } + + return true; + } + + function _convertPackage($packagexml) + { + $pkg = &$this->getPackageFile($this->config); + $pf2 = &$pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL); + if (!is_a($pf2, 'PEAR_PackageFile_v2')) { + return $this->raiseError('Cannot process "' . + $packagexml . '", is not a package.xml 2.0'); + } + + require_once 'PEAR/PackageFile/v1.php'; + $pf = new PEAR_PackageFile_v1; + $pf->setConfig($this->config); + if ($pf2->getPackageType() != 'extsrc' && $pf2->getPackageType() != 'zendextsrc') { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", is not an extension source package. Using a PEAR_PackageFileManager-based ' . + 'script is an option'); + } + + if (is_array($pf2->getUsesRole())) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains custom roles. Using a PEAR_PackageFileManager-based script or ' . + 'the convert command is an option'); + } + + if (is_array($pf2->getUsesTask())) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains custom tasks. Using a PEAR_PackageFileManager-based script or ' . + 'the convert command is an option'); + } + + $deps = $pf2->getDependencies(); + if (isset($deps['group'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains dependency groups. Using a PEAR_PackageFileManager-based script ' . + 'or the convert command is an option'); + } + + if (isset($deps['required']['subpackage']) || + isset($deps['optional']['subpackage'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains subpackage dependencies. Using a PEAR_PackageFileManager-based '. + 'script is an option'); + } + + if (isset($deps['required']['os'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains os dependencies. Using a PEAR_PackageFileManager-based '. + 'script is an option'); + } + + if (isset($deps['required']['arch'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains arch dependencies. Using a PEAR_PackageFileManager-based '. + 'script is an option'); + } + + $pf->setPackage($pf2->getPackage()); + $pf->setSummary($pf2->getSummary()); + $pf->setDescription($pf2->getDescription()); + foreach ($pf2->getMaintainers() as $maintainer) { + $pf->addMaintainer($maintainer['role'], $maintainer['handle'], + $maintainer['name'], $maintainer['email']); + } + + $pf->setVersion($pf2->getVersion()); + $pf->setDate($pf2->getDate()); + $pf->setLicense($pf2->getLicense()); + $pf->setState($pf2->getState()); + $pf->setNotes($pf2->getNotes()); + $pf->addPhpDep($deps['required']['php']['min'], 'ge'); + if (isset($deps['required']['php']['max'])) { + $pf->addPhpDep($deps['required']['php']['max'], 'le'); + } + + if (isset($deps['required']['package'])) { + if (!isset($deps['required']['package'][0])) { + $deps['required']['package'] = array($deps['required']['package']); + } + + foreach ($deps['required']['package'] as $dep) { + if (!isset($dep['channel'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains uri-based dependency on a package. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + + if ($dep['channel'] != 'pear.php.net' + && $dep['channel'] != 'pecl.php.net' + && $dep['channel'] != 'doc.php.net') { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains dependency on a non-standard channel package. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + + if (isset($dep['conflicts'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains conflicts dependency. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + + if (isset($dep['exclude'])) { + $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); + } + + if (isset($dep['min'])) { + $pf->addPackageDep($dep['name'], $dep['min'], 'ge'); + } + + if (isset($dep['max'])) { + $pf->addPackageDep($dep['name'], $dep['max'], 'le'); + } + } + } + + if (isset($deps['required']['extension'])) { + if (!isset($deps['required']['extension'][0])) { + $deps['required']['extension'] = array($deps['required']['extension']); + } + + foreach ($deps['required']['extension'] as $dep) { + if (isset($dep['conflicts'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains conflicts dependency. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + + if (isset($dep['exclude'])) { + $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); + } + + if (isset($dep['min'])) { + $pf->addExtensionDep($dep['name'], $dep['min'], 'ge'); + } + + if (isset($dep['max'])) { + $pf->addExtensionDep($dep['name'], $dep['max'], 'le'); + } + } + } + + if (isset($deps['optional']['package'])) { + if (!isset($deps['optional']['package'][0])) { + $deps['optional']['package'] = array($deps['optional']['package']); + } + + foreach ($deps['optional']['package'] as $dep) { + if (!isset($dep['channel'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains uri-based dependency on a package. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + + if ($dep['channel'] != 'pear.php.net' + && $dep['channel'] != 'pecl.php.net' + && $dep['channel'] != 'doc.php.net') { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains dependency on a non-standard channel package. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + + if (isset($dep['exclude'])) { + $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); + } + + if (isset($dep['min'])) { + $pf->addPackageDep($dep['name'], $dep['min'], 'ge', 'yes'); + } + + if (isset($dep['max'])) { + $pf->addPackageDep($dep['name'], $dep['max'], 'le', 'yes'); + } + } + } + + if (isset($deps['optional']['extension'])) { + if (!isset($deps['optional']['extension'][0])) { + $deps['optional']['extension'] = array($deps['optional']['extension']); + } + + foreach ($deps['optional']['extension'] as $dep) { + if (isset($dep['exclude'])) { + $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); + } + + if (isset($dep['min'])) { + $pf->addExtensionDep($dep['name'], $dep['min'], 'ge', 'yes'); + } + + if (isset($dep['max'])) { + $pf->addExtensionDep($dep['name'], $dep['max'], 'le', 'yes'); + } + } + } + + $contents = $pf2->getContents(); + $release = $pf2->getReleases(); + if (isset($releases[0])) { + return $this->raiseError('Cannot safely process "' . $packagexml . '" contains ' + . 'multiple extsrcrelease/zendextsrcrelease tags. Using a PEAR_PackageFileManager-based script ' . + 'or the convert command is an option'); + } + + if ($configoptions = $pf2->getConfigureOptions()) { + foreach ($configoptions as $option) { + $default = isset($option['default']) ? $option['default'] : false; + $pf->addConfigureOption($option['name'], $option['prompt'], $default); + } + } + + if (isset($release['filelist']['ignore'])) { + return $this->raiseError('Cannot safely process "' . $packagexml . '" contains ' + . 'ignore tags. Using a PEAR_PackageFileManager-based script or the convert' . + ' command is an option'); + } + + if (isset($release['filelist']['install']) && + !isset($release['filelist']['install'][0])) { + $release['filelist']['install'] = array($release['filelist']['install']); + } + + if (isset($contents['dir']['attribs']['baseinstalldir'])) { + $baseinstalldir = $contents['dir']['attribs']['baseinstalldir']; + } else { + $baseinstalldir = false; + } + + if (!isset($contents['dir']['file'][0])) { + $contents['dir']['file'] = array($contents['dir']['file']); + } + + foreach ($contents['dir']['file'] as $file) { + if ($baseinstalldir && !isset($file['attribs']['baseinstalldir'])) { + $file['attribs']['baseinstalldir'] = $baseinstalldir; + } + + $processFile = $file; + unset($processFile['attribs']); + if (count($processFile)) { + foreach ($processFile as $name => $task) { + if ($name != $pf2->getTasksNs() . ':replace') { + return $this->raiseError('Cannot safely process "' . $packagexml . + '" contains tasks other than replace. Using a ' . + 'PEAR_PackageFileManager-based script is an option.'); + } + $file['attribs']['replace'][] = $task; + } + } + + if (!in_array($file['attribs']['role'], PEAR_Common::getFileRoles())) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains custom roles. Using a PEAR_PackageFileManager-based script ' . + 'or the convert command is an option'); + } + + if (isset($release['filelist']['install'])) { + foreach ($release['filelist']['install'] as $installas) { + if ($installas['attribs']['name'] == $file['attribs']['name']) { + $file['attribs']['install-as'] = $installas['attribs']['as']; + } + } + } + + $pf->addFile('/', $file['attribs']['name'], $file['attribs']); + } + + if ($pf2->getChangeLog()) { + $this->ui->outputData('WARNING: changelog is not translated to package.xml ' . + '1.0, use PEAR_PackageFileManager-based script if you need changelog-' . + 'translation for package.xml 1.0'); + } + + $gen = &$pf->getDefaultGenerator(); + $gen->toPackageFile('.'); + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Pickle.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Pickle.xml new file mode 100644 index 0000000..721ecea --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Pickle.xml @@ -0,0 +1,36 @@ + + + Build PECL Package + doPackage + pi + + + Z + Do not gzip the package file + + + n + Print the name of the packaged file. + + + [descfile] +Creates a PECL package from its package2.xml file. + +An automatic conversion will be made to a package.xml 1.0 and written out to +disk in the current directory as "package.xml". Note that +only simple package.xml 2.0 will be converted. package.xml 2.0 with: + + - dependency types other than required/optional PECL package/ext/php/pearinstaller + - more than one extsrcrelease or zendextsrcrelease + - zendextbinrelease, extbinrelease, phprelease, or bundle release type + - dependency groups + - ignore tags in release filelist + - tasks other than replace + - custom roles + +will cause pickle to fail, and output an error message. If your package2.xml +uses any of these features, you are best off using PEAR_PackageFileManager to +generate both package.xml. + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Registry.php b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Registry.php new file mode 100644 index 0000000..bd9ca2d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Registry.php @@ -0,0 +1,1145 @@ + + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Registry.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for registry manipulation + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Registry extends PEAR_Command_Common +{ + var $commands = array( + 'list' => array( + 'summary' => 'List Installed Packages In The Default Channel', + 'function' => 'doList', + 'shortcut' => 'l', + 'options' => array( + 'channel' => array( + 'shortopt' => 'c', + 'doc' => 'list installed packages from this channel', + 'arg' => 'CHAN', + ), + 'allchannels' => array( + 'shortopt' => 'a', + 'doc' => 'list installed packages from all channels', + ), + 'channelinfo' => array( + 'shortopt' => 'i', + 'doc' => 'output fully channel-aware data, even on failure', + ), + ), + 'doc' => ' +If invoked without parameters, this command lists the PEAR packages +installed in your php_dir ({config php_dir}). With a parameter, it +lists the files in a package. +', + ), + 'list-files' => array( + 'summary' => 'List Files In Installed Package', + 'function' => 'doFileList', + 'shortcut' => 'fl', + 'options' => array(), + 'doc' => ' +List the files in an installed package. +' + ), + 'shell-test' => array( + 'summary' => 'Shell Script Test', + 'function' => 'doShellTest', + 'shortcut' => 'st', + 'options' => array(), + 'doc' => ' [[relation] version] +Tests if a package is installed in the system. Will exit(1) if it is not. + The version comparison operator. One of: + <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne + The version to compare with +'), + 'info' => array( + 'summary' => 'Display information about a package', + 'function' => 'doInfo', + 'shortcut' => 'in', + 'options' => array(), + 'doc' => ' +Displays information about a package. The package argument may be a +local package file, an URL to a package file, or the name of an +installed package.' + ) + ); + + /** + * PEAR_Command_Registry constructor. + * + * @access public + */ + function PEAR_Command_Registry(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + function _sortinfo($a, $b) + { + $apackage = isset($a['package']) ? $a['package'] : $a['name']; + $bpackage = isset($b['package']) ? $b['package'] : $b['name']; + return strcmp($apackage, $bpackage); + } + + function doList($command, $options, $params) + { + $reg = &$this->config->getRegistry(); + $channelinfo = isset($options['channelinfo']); + if (isset($options['allchannels']) && !$channelinfo) { + return $this->doListAll($command, array(), $params); + } + + if (isset($options['allchannels']) && $channelinfo) { + // allchannels with $channelinfo + unset($options['allchannels']); + $channels = $reg->getChannels(); + $errors = array(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + foreach ($channels as $channel) { + $options['channel'] = $channel->getName(); + $ret = $this->doList($command, $options, $params); + + if (PEAR::isError($ret)) { + $errors[] = $ret; + } + } + + PEAR::staticPopErrorHandling(); + if (count($errors)) { + // for now, only give first error + return PEAR::raiseError($errors[0]); + } + + return true; + } + + if (count($params) === 1) { + return $this->doFileList($command, $options, $params); + } + + if (isset($options['channel'])) { + if (!$reg->channelExists($options['channel'])) { + return $this->raiseError('Channel "' . $options['channel'] .'" does not exist'); + } + + $channel = $reg->channelName($options['channel']); + } else { + $channel = $this->config->get('default_channel'); + } + + $installed = $reg->packageInfo(null, null, $channel); + usort($installed, array(&$this, '_sortinfo')); + + $data = array( + 'caption' => 'Installed packages, channel ' . + $channel . ':', + 'border' => true, + 'headline' => array('Package', 'Version', 'State'), + 'channel' => $channel, + ); + if ($channelinfo) { + $data['headline'] = array('Channel', 'Package', 'Version', 'State'); + } + + if (count($installed) && !isset($data['data'])) { + $data['data'] = array(); + } + + foreach ($installed as $package) { + $pobj = $reg->getPackage(isset($package['package']) ? + $package['package'] : $package['name'], $channel); + if ($channelinfo) { + $packageinfo = array($pobj->getChannel(), $pobj->getPackage(), $pobj->getVersion(), + $pobj->getState() ? $pobj->getState() : null); + } else { + $packageinfo = array($pobj->getPackage(), $pobj->getVersion(), + $pobj->getState() ? $pobj->getState() : null); + } + $data['data'][] = $packageinfo; + } + + if (count($installed) === 0) { + if (!$channelinfo) { + $data = '(no packages installed from channel ' . $channel . ')'; + } else { + $data = array( + 'caption' => 'Installed packages, channel ' . + $channel . ':', + 'border' => true, + 'channel' => $channel, + 'data' => array(array('(no packages installed)')), + ); + } + } + + $this->ui->outputData($data, $command); + return true; + } + + function doListAll($command, $options, $params) + { + // This duplicate code is deprecated over + // list --channelinfo, which gives identical + // output for list and list --allchannels. + $reg = &$this->config->getRegistry(); + $installed = $reg->packageInfo(null, null, null); + foreach ($installed as $channel => $packages) { + usort($packages, array($this, '_sortinfo')); + $data = array( + 'caption' => 'Installed packages, channel ' . $channel . ':', + 'border' => true, + 'headline' => array('Package', 'Version', 'State'), + 'channel' => $channel + ); + + foreach ($packages as $package) { + $p = isset($package['package']) ? $package['package'] : $package['name']; + $pobj = $reg->getPackage($p, $channel); + $data['data'][] = array($pobj->getPackage(), $pobj->getVersion(), + $pobj->getState() ? $pobj->getState() : null); + } + + // Adds a blank line after each section + $data['data'][] = array(); + + if (count($packages) === 0) { + $data = array( + 'caption' => 'Installed packages, channel ' . $channel . ':', + 'border' => true, + 'data' => array(array('(no packages installed)'), array()), + 'channel' => $channel + ); + } + $this->ui->outputData($data, $command); + } + return true; + } + + function doFileList($command, $options, $params) + { + if (count($params) !== 1) { + return $this->raiseError('list-files expects 1 parameter'); + } + + $reg = &$this->config->getRegistry(); + $fp = false; + if (!is_dir($params[0]) && (file_exists($params[0]) || $fp = @fopen($params[0], 'r'))) { + if ($fp) { + fclose($fp); + } + + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } + + $pkg = &new PEAR_PackageFile($this->config, $this->_debug); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $info = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL); + PEAR::staticPopErrorHandling(); + $headings = array('Package File', 'Install Path'); + $installed = false; + } else { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel')); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($parsed)) { + return $this->raiseError($parsed); + } + + $info = &$reg->getPackage($parsed['package'], $parsed['channel']); + $headings = array('Type', 'Install Path'); + $installed = true; + } + + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + + if ($info === null) { + return $this->raiseError("`$params[0]' not installed"); + } + + $list = ($info->getPackagexmlVersion() == '1.0' || $installed) ? + $info->getFilelist() : $info->getContents(); + if ($installed) { + $caption = 'Installed Files For ' . $params[0]; + } else { + $caption = 'Contents of ' . basename($params[0]); + } + + $data = array( + 'caption' => $caption, + 'border' => true, + 'headline' => $headings); + if ($info->getPackagexmlVersion() == '1.0' || $installed) { + foreach ($list as $file => $att) { + if ($installed) { + if (empty($att['installed_as'])) { + continue; + } + $data['data'][] = array($att['role'], $att['installed_as']); + } else { + if (isset($att['baseinstalldir']) && !in_array($att['role'], + array('test', 'data', 'doc'))) { + $dest = $att['baseinstalldir'] . DIRECTORY_SEPARATOR . + $file; + } else { + $dest = $file; + } + switch ($att['role']) { + case 'test': + case 'data': + case 'doc': + $role = $att['role']; + if ($role == 'test') { + $role .= 's'; + } + $dest = $this->config->get($role . '_dir') . DIRECTORY_SEPARATOR . + $info->getPackage() . DIRECTORY_SEPARATOR . $dest; + break; + case 'php': + default: + $dest = $this->config->get('php_dir') . DIRECTORY_SEPARATOR . + $dest; + } + $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; + $dest = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), + array(DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR), + $dest); + $file = preg_replace('!/+!', '/', $file); + $data['data'][] = array($file, $dest); + } + } + } else { // package.xml 2.0, not installed + if (!isset($list['dir']['file'][0])) { + $list['dir']['file'] = array($list['dir']['file']); + } + + foreach ($list['dir']['file'] as $att) { + $att = $att['attribs']; + $file = $att['name']; + $role = &PEAR_Installer_Role::factory($info, $att['role'], $this->config); + $role->setup($this, $info, $att, $file); + if (!$role->isInstallable()) { + $dest = '(not installable)'; + } else { + $dest = $role->processInstallation($info, $att, $file, ''); + if (PEAR::isError($dest)) { + $dest = '(Unknown role "' . $att['role'] . ')'; + } else { + list(,, $dest) = $dest; + } + } + $data['data'][] = array($file, $dest); + } + } + + $this->ui->outputData($data, $command); + return true; + } + + function doShellTest($command, $options, $params) + { + if (count($params) < 1) { + return PEAR::raiseError('ERROR, usage: pear shell-test packagename [[relation] version]'); + } + + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $reg = &$this->config->getRegistry(); + $info = $reg->parsePackageName($params[0], $this->config->get('default_channel')); + if (PEAR::isError($info)) { + exit(1); // invalid package name + } + + $package = $info['package']; + $channel = $info['channel']; + // "pear shell-test Foo" + if (!$reg->packageExists($package, $channel)) { + if ($channel == 'pecl.php.net') { + if ($reg->packageExists($package, 'pear.php.net')) { + $channel = 'pear.php.net'; // magically change channels for extensions + } + } + } + + if (count($params) === 1) { + if (!$reg->packageExists($package, $channel)) { + exit(1); + } + // "pear shell-test Foo 1.0" + } elseif (count($params) === 2) { + $v = $reg->packageInfo($package, 'version', $channel); + if (!$v || !version_compare("$v", "{$params[1]}", "ge")) { + exit(1); + } + // "pear shell-test Foo ge 1.0" + } elseif (count($params) === 3) { + $v = $reg->packageInfo($package, 'version', $channel); + if (!$v || !version_compare("$v", "{$params[2]}", $params[1])) { + exit(1); + } + } else { + PEAR::staticPopErrorHandling(); + $this->raiseError("$command: expects 1 to 3 parameters"); + exit(1); + } + } + + function doInfo($command, $options, $params) + { + if (count($params) !== 1) { + return $this->raiseError('pear info expects 1 parameter'); + } + + $info = $fp = false; + $reg = &$this->config->getRegistry(); + if (is_file($params[0]) && !is_dir($params[0]) && + (file_exists($params[0]) || $fp = @fopen($params[0], 'r')) + ) { + if ($fp) { + fclose($fp); + } + + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } + + $pkg = &new PEAR_PackageFile($this->config, $this->_debug); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $obj = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($obj)) { + $uinfo = $obj->getUserInfo(); + if (is_array($uinfo)) { + foreach ($uinfo as $message) { + if (is_array($message)) { + $message = $message['message']; + } + $this->ui->outputData($message); + } + } + + return $this->raiseError($obj); + } + + if ($obj->getPackagexmlVersion() != '1.0') { + return $this->_doInfo2($command, $options, $params, $obj, false); + } + + $info = $obj->toArray(); + } else { + $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel')); + if (PEAR::isError($parsed)) { + return $this->raiseError($parsed); + } + + $package = $parsed['package']; + $channel = $parsed['channel']; + $info = $reg->packageInfo($package, null, $channel); + if (isset($info['old'])) { + $obj = $reg->getPackage($package, $channel); + return $this->_doInfo2($command, $options, $params, $obj, true); + } + } + + if (PEAR::isError($info)) { + return $info; + } + + if (empty($info)) { + $this->raiseError("No information found for `$params[0]'"); + return; + } + + unset($info['filelist']); + unset($info['dirtree']); + unset($info['changelog']); + if (isset($info['xsdversion'])) { + $info['package.xml version'] = $info['xsdversion']; + unset($info['xsdversion']); + } + + if (isset($info['packagerversion'])) { + $info['packaged with PEAR version'] = $info['packagerversion']; + unset($info['packagerversion']); + } + + $keys = array_keys($info); + $longtext = array('description', 'summary'); + foreach ($keys as $key) { + if (is_array($info[$key])) { + switch ($key) { + case 'maintainers': { + $i = 0; + $mstr = ''; + foreach ($info[$key] as $m) { + if ($i++ > 0) { + $mstr .= "\n"; + } + $mstr .= $m['name'] . " <"; + if (isset($m['email'])) { + $mstr .= $m['email']; + } else { + $mstr .= $m['handle'] . '@php.net'; + } + $mstr .= "> ($m[role])"; + } + $info[$key] = $mstr; + break; + } + case 'release_deps': { + $i = 0; + $dstr = ''; + foreach ($info[$key] as $d) { + if (isset($this->_deps_rel_trans[$d['rel']])) { + $rel = $this->_deps_rel_trans[$d['rel']]; + } else { + $rel = $d['rel']; + } + if (isset($this->_deps_type_trans[$d['type']])) { + $type = ucfirst($this->_deps_type_trans[$d['type']]); + } else { + $type = $d['type']; + } + if (isset($d['name'])) { + $name = $d['name'] . ' '; + } else { + $name = ''; + } + if (isset($d['version'])) { + $version = $d['version'] . ' '; + } else { + $version = ''; + } + if (isset($d['optional']) && $d['optional'] == 'yes') { + $optional = ' (optional)'; + } else { + $optional = ''; + } + $dstr .= "$type $name$rel $version$optional\n"; + } + $info[$key] = $dstr; + break; + } + case 'provides' : { + $debug = $this->config->get('verbose'); + if ($debug < 2) { + $pstr = 'Classes: '; + } else { + $pstr = ''; + } + $i = 0; + foreach ($info[$key] as $p) { + if ($debug < 2 && $p['type'] != "class") { + continue; + } + // Only print classes when verbosity mode is < 2 + if ($debug < 2) { + if ($i++ > 0) { + $pstr .= ", "; + } + $pstr .= $p['name']; + } else { + if ($i++ > 0) { + $pstr .= "\n"; + } + $pstr .= ucfirst($p['type']) . " " . $p['name']; + if (isset($p['explicit']) && $p['explicit'] == 1) { + $pstr .= " (explicit)"; + } + } + } + $info[$key] = $pstr; + break; + } + case 'configure_options' : { + foreach ($info[$key] as $i => $p) { + $info[$key][$i] = array_map(null, array_keys($p), array_values($p)); + $info[$key][$i] = array_map(create_function('$a', + 'return join(" = ",$a);'), $info[$key][$i]); + $info[$key][$i] = implode(', ', $info[$key][$i]); + } + $info[$key] = implode("\n", $info[$key]); + break; + } + default: { + $info[$key] = implode(", ", $info[$key]); + break; + } + } + } + + if ($key == '_lastmodified') { + $hdate = date('Y-m-d', $info[$key]); + unset($info[$key]); + $info['Last Modified'] = $hdate; + } elseif ($key == '_lastversion') { + $info['Previous Installed Version'] = $info[$key] ? $info[$key] : '- None -'; + unset($info[$key]); + } else { + $info[$key] = trim($info[$key]); + if (in_array($key, $longtext)) { + $info[$key] = preg_replace('/ +/', ' ', $info[$key]); + } + } + } + + $caption = 'About ' . $info['package'] . '-' . $info['version']; + $data = array( + 'caption' => $caption, + 'border' => true); + foreach ($info as $key => $value) { + $key = ucwords(trim(str_replace('_', ' ', $key))); + $data['data'][] = array($key, $value); + } + $data['raw'] = $info; + + $this->ui->outputData($data, 'package-info'); + } + + /** + * @access private + */ + function _doInfo2($command, $options, $params, &$obj, $installed) + { + $reg = &$this->config->getRegistry(); + $caption = 'About ' . $obj->getChannel() . '/' .$obj->getPackage() . '-' . + $obj->getVersion(); + $data = array( + 'caption' => $caption, + 'border' => true); + switch ($obj->getPackageType()) { + case 'php' : + $release = 'PEAR-style PHP-based Package'; + break; + case 'extsrc' : + $release = 'PECL-style PHP extension (source code)'; + break; + case 'zendextsrc' : + $release = 'PECL-style Zend extension (source code)'; + break; + case 'extbin' : + $release = 'PECL-style PHP extension (binary)'; + break; + case 'zendextbin' : + $release = 'PECL-style Zend extension (binary)'; + break; + case 'bundle' : + $release = 'Package bundle (collection of packages)'; + break; + } + $extends = $obj->getExtends(); + $extends = $extends ? + $obj->getPackage() . ' (extends ' . $extends . ')' : $obj->getPackage(); + if ($src = $obj->getSourcePackage()) { + $extends .= ' (source package ' . $src['channel'] . '/' . $src['package'] . ')'; + } + + $info = array( + 'Release Type' => $release, + 'Name' => $extends, + 'Channel' => $obj->getChannel(), + 'Summary' => preg_replace('/ +/', ' ', $obj->getSummary()), + 'Description' => preg_replace('/ +/', ' ', $obj->getDescription()), + ); + $info['Maintainers'] = ''; + foreach (array('lead', 'developer', 'contributor', 'helper') as $role) { + $leads = $obj->{"get{$role}s"}(); + if (!$leads) { + continue; + } + + if (isset($leads['active'])) { + $leads = array($leads); + } + + foreach ($leads as $lead) { + if (!empty($info['Maintainers'])) { + $info['Maintainers'] .= "\n"; + } + + $active = $lead['active'] == 'no' ? ', inactive' : ''; + $info['Maintainers'] .= $lead['name'] . ' <'; + $info['Maintainers'] .= $lead['email'] . "> ($role$active)"; + } + } + + $info['Release Date'] = $obj->getDate(); + if ($time = $obj->getTime()) { + $info['Release Date'] .= ' ' . $time; + } + + $info['Release Version'] = $obj->getVersion() . ' (' . $obj->getState() . ')'; + $info['API Version'] = $obj->getVersion('api') . ' (' . $obj->getState('api') . ')'; + $info['License'] = $obj->getLicense(); + $uri = $obj->getLicenseLocation(); + if ($uri) { + if (isset($uri['uri'])) { + $info['License'] .= ' (' . $uri['uri'] . ')'; + } else { + $extra = $obj->getInstalledLocation($info['filesource']); + if ($extra) { + $info['License'] .= ' (' . $uri['filesource'] . ')'; + } + } + } + + $info['Release Notes'] = $obj->getNotes(); + if ($compat = $obj->getCompatible()) { + if (!isset($compat[0])) { + $compat = array($compat); + } + + $info['Compatible with'] = ''; + foreach ($compat as $package) { + $info['Compatible with'] .= $package['channel'] . '/' . $package['name'] . + "\nVersions >= " . $package['min'] . ', <= ' . $package['max']; + if (isset($package['exclude'])) { + if (is_array($package['exclude'])) { + $package['exclude'] = implode(', ', $package['exclude']); + } + + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + $info['Not Compatible with'] .= $package['channel'] . '/' . + $package['name'] . "\nVersions " . $package['exclude']; + } + } + } + + $usesrole = $obj->getUsesrole(); + if ($usesrole) { + if (!isset($usesrole[0])) { + $usesrole = array($usesrole); + } + + foreach ($usesrole as $roledata) { + if (isset($info['Uses Custom Roles'])) { + $info['Uses Custom Roles'] .= "\n"; + } else { + $info['Uses Custom Roles'] = ''; + } + + if (isset($roledata['package'])) { + $rolepackage = $reg->parsedPackageNameToString($roledata, true); + } else { + $rolepackage = $roledata['uri']; + } + $info['Uses Custom Roles'] .= $roledata['role'] . ' (' . $rolepackage . ')'; + } + } + + $usestask = $obj->getUsestask(); + if ($usestask) { + if (!isset($usestask[0])) { + $usestask = array($usestask); + } + + foreach ($usestask as $taskdata) { + if (isset($info['Uses Custom Tasks'])) { + $info['Uses Custom Tasks'] .= "\n"; + } else { + $info['Uses Custom Tasks'] = ''; + } + + if (isset($taskdata['package'])) { + $taskpackage = $reg->parsedPackageNameToString($taskdata, true); + } else { + $taskpackage = $taskdata['uri']; + } + $info['Uses Custom Tasks'] .= $taskdata['task'] . ' (' . $taskpackage . ')'; + } + } + + $deps = $obj->getDependencies(); + $info['Required Dependencies'] = 'PHP version ' . $deps['required']['php']['min']; + if (isset($deps['required']['php']['max'])) { + $info['Required Dependencies'] .= '-' . $deps['required']['php']['max'] . "\n"; + } else { + $info['Required Dependencies'] .= "\n"; + } + + if (isset($deps['required']['php']['exclude'])) { + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + + if (is_array($deps['required']['php']['exclude'])) { + $deps['required']['php']['exclude'] = + implode(', ', $deps['required']['php']['exclude']); + } + $info['Not Compatible with'] .= "PHP versions\n " . + $deps['required']['php']['exclude']; + } + + $info['Required Dependencies'] .= 'PEAR installer version'; + if (isset($deps['required']['pearinstaller']['max'])) { + $info['Required Dependencies'] .= 's ' . + $deps['required']['pearinstaller']['min'] . '-' . + $deps['required']['pearinstaller']['max']; + } else { + $info['Required Dependencies'] .= ' ' . + $deps['required']['pearinstaller']['min'] . ' or newer'; + } + + if (isset($deps['required']['pearinstaller']['exclude'])) { + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + + if (is_array($deps['required']['pearinstaller']['exclude'])) { + $deps['required']['pearinstaller']['exclude'] = + implode(', ', $deps['required']['pearinstaller']['exclude']); + } + $info['Not Compatible with'] .= "PEAR installer\n Versions " . + $deps['required']['pearinstaller']['exclude']; + } + + foreach (array('Package', 'Extension') as $type) { + $index = strtolower($type); + if (isset($deps['required'][$index])) { + if (isset($deps['required'][$index]['name'])) { + $deps['required'][$index] = array($deps['required'][$index]); + } + + foreach ($deps['required'][$index] as $package) { + if (isset($package['conflicts'])) { + $infoindex = 'Not Compatible with'; + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + } else { + $infoindex = 'Required Dependencies'; + $info[$infoindex] .= "\n"; + } + + if ($index == 'extension') { + $name = $package['name']; + } else { + if (isset($package['channel'])) { + $name = $package['channel'] . '/' . $package['name']; + } else { + $name = '__uri/' . $package['name'] . ' (static URI)'; + } + } + + $info[$infoindex] .= "$type $name"; + if (isset($package['uri'])) { + $info[$infoindex] .= "\n Download URI: $package[uri]"; + continue; + } + + if (isset($package['max']) && isset($package['min'])) { + $info[$infoindex] .= " \n Versions " . + $package['min'] . '-' . $package['max']; + } elseif (isset($package['min'])) { + $info[$infoindex] .= " \n Version " . + $package['min'] . ' or newer'; + } elseif (isset($package['max'])) { + $info[$infoindex] .= " \n Version " . + $package['max'] . ' or older'; + } + + if (isset($package['recommended'])) { + $info[$infoindex] .= "\n Recommended version: $package[recommended]"; + } + + if (isset($package['exclude'])) { + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + + if (is_array($package['exclude'])) { + $package['exclude'] = implode(', ', $package['exclude']); + } + + $package['package'] = $package['name']; // for parsedPackageNameToString + if (isset($package['conflicts'])) { + $info['Not Compatible with'] .= '=> except '; + } + $info['Not Compatible with'] .= 'Package ' . + $reg->parsedPackageNameToString($package, true); + $info['Not Compatible with'] .= "\n Versions " . $package['exclude']; + } + } + } + } + + if (isset($deps['required']['os'])) { + if (isset($deps['required']['os']['name'])) { + $dep['required']['os']['name'] = array($dep['required']['os']['name']); + } + + foreach ($dep['required']['os'] as $os) { + if (isset($os['conflicts']) && $os['conflicts'] == 'yes') { + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + $info['Not Compatible with'] .= "$os[name] Operating System"; + } else { + $info['Required Dependencies'] .= "\n"; + $info['Required Dependencies'] .= "$os[name] Operating System"; + } + } + } + + if (isset($deps['required']['arch'])) { + if (isset($deps['required']['arch']['pattern'])) { + $dep['required']['arch']['pattern'] = array($dep['required']['os']['pattern']); + } + + foreach ($dep['required']['arch'] as $os) { + if (isset($os['conflicts']) && $os['conflicts'] == 'yes') { + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + $info['Not Compatible with'] .= "OS/Arch matching pattern '/$os[pattern]/'"; + } else { + $info['Required Dependencies'] .= "\n"; + $info['Required Dependencies'] .= "OS/Arch matching pattern '/$os[pattern]/'"; + } + } + } + + if (isset($deps['optional'])) { + foreach (array('Package', 'Extension') as $type) { + $index = strtolower($type); + if (isset($deps['optional'][$index])) { + if (isset($deps['optional'][$index]['name'])) { + $deps['optional'][$index] = array($deps['optional'][$index]); + } + + foreach ($deps['optional'][$index] as $package) { + if (isset($package['conflicts']) && $package['conflicts'] == 'yes') { + $infoindex = 'Not Compatible with'; + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + } else { + $infoindex = 'Optional Dependencies'; + if (!isset($info['Optional Dependencies'])) { + $info['Optional Dependencies'] = ''; + } else { + $info['Optional Dependencies'] .= "\n"; + } + } + + if ($index == 'extension') { + $name = $package['name']; + } else { + if (isset($package['channel'])) { + $name = $package['channel'] . '/' . $package['name']; + } else { + $name = '__uri/' . $package['name'] . ' (static URI)'; + } + } + + $info[$infoindex] .= "$type $name"; + if (isset($package['uri'])) { + $info[$infoindex] .= "\n Download URI: $package[uri]"; + continue; + } + + if ($infoindex == 'Not Compatible with') { + // conflicts is only used to say that all versions conflict + continue; + } + + if (isset($package['max']) && isset($package['min'])) { + $info[$infoindex] .= " \n Versions " . + $package['min'] . '-' . $package['max']; + } elseif (isset($package['min'])) { + $info[$infoindex] .= " \n Version " . + $package['min'] . ' or newer'; + } elseif (isset($package['max'])) { + $info[$infoindex] .= " \n Version " . + $package['min'] . ' or older'; + } + + if (isset($package['recommended'])) { + $info[$infoindex] .= "\n Recommended version: $package[recommended]"; + } + + if (isset($package['exclude'])) { + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info['Not Compatible with'] .= "\n"; + } + + if (is_array($package['exclude'])) { + $package['exclude'] = implode(', ', $package['exclude']); + } + + $info['Not Compatible with'] .= "Package $package\n Versions " . + $package['exclude']; + } + } + } + } + } + + if (isset($deps['group'])) { + if (!isset($deps['group'][0])) { + $deps['group'] = array($deps['group']); + } + + foreach ($deps['group'] as $group) { + $info['Dependency Group ' . $group['attribs']['name']] = $group['attribs']['hint']; + $groupindex = $group['attribs']['name'] . ' Contents'; + $info[$groupindex] = ''; + foreach (array('Package', 'Extension') as $type) { + $index = strtolower($type); + if (isset($group[$index])) { + if (isset($group[$index]['name'])) { + $group[$index] = array($group[$index]); + } + + foreach ($group[$index] as $package) { + if (!empty($info[$groupindex])) { + $info[$groupindex] .= "\n"; + } + + if ($index == 'extension') { + $name = $package['name']; + } else { + if (isset($package['channel'])) { + $name = $package['channel'] . '/' . $package['name']; + } else { + $name = '__uri/' . $package['name'] . ' (static URI)'; + } + } + + if (isset($package['uri'])) { + if (isset($package['conflicts']) && $package['conflicts'] == 'yes') { + $info[$groupindex] .= "Not Compatible with $type $name"; + } else { + $info[$groupindex] .= "$type $name"; + } + + $info[$groupindex] .= "\n Download URI: $package[uri]"; + continue; + } + + if (isset($package['conflicts']) && $package['conflicts'] == 'yes') { + $info[$groupindex] .= "Not Compatible with $type $name"; + continue; + } + + $info[$groupindex] .= "$type $name"; + if (isset($package['max']) && isset($package['min'])) { + $info[$groupindex] .= " \n Versions " . + $package['min'] . '-' . $package['max']; + } elseif (isset($package['min'])) { + $info[$groupindex] .= " \n Version " . + $package['min'] . ' or newer'; + } elseif (isset($package['max'])) { + $info[$groupindex] .= " \n Version " . + $package['min'] . ' or older'; + } + + if (isset($package['recommended'])) { + $info[$groupindex] .= "\n Recommended version: $package[recommended]"; + } + + if (isset($package['exclude'])) { + if (!isset($info['Not Compatible with'])) { + $info['Not Compatible with'] = ''; + } else { + $info[$groupindex] .= "Not Compatible with\n"; + } + + if (is_array($package['exclude'])) { + $package['exclude'] = implode(', ', $package['exclude']); + } + $info[$groupindex] .= " Package $package\n Versions " . + $package['exclude']; + } + } + } + } + } + } + + if ($obj->getPackageType() == 'bundle') { + $info['Bundled Packages'] = ''; + foreach ($obj->getBundledPackages() as $package) { + if (!empty($info['Bundled Packages'])) { + $info['Bundled Packages'] .= "\n"; + } + + if (isset($package['uri'])) { + $info['Bundled Packages'] .= '__uri/' . $package['name']; + $info['Bundled Packages'] .= "\n (URI: $package[uri]"; + } else { + $info['Bundled Packages'] .= $package['channel'] . '/' . $package['name']; + } + } + } + + $info['package.xml version'] = '2.0'; + if ($installed) { + if ($obj->getLastModified()) { + $info['Last Modified'] = date('Y-m-d H:i', $obj->getLastModified()); + } + + $v = $obj->getLastInstalledVersion(); + $info['Previous Installed Version'] = $v ? $v : '- None -'; + } + + foreach ($info as $key => $value) { + $data['data'][] = array($key, $value); + } + + $data['raw'] = $obj->getArray(); // no validation needed + $this->ui->outputData($data, 'package-info'); + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Registry.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Registry.xml new file mode 100644 index 0000000..9f4e214 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Registry.xml @@ -0,0 +1,58 @@ + + + List Installed Packages In The Default Channel + doList + l + + + c + list installed packages from this channel + CHAN + + + a + list installed packages from all channels + + + i + output fully channel-aware data, even on failure + + + <package> +If invoked without parameters, this command lists the PEAR packages +installed in your php_dir ({config php_dir}). With a parameter, it +lists the files in a package. + + + + List Files In Installed Package + doFileList + fl + + <package> +List the files in an installed package. + + + + Shell Script Test + doShellTest + st + + <package> [[relation] version] +Tests if a package is installed in the system. Will exit(1) if it is not. + <relation> The version comparison operator. One of: + <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne + <version> The version to compare with + + + + Display information about a package + doInfo + in + + <package> +Displays information about a package. The package argument may be a +local package file, an URL to a package file, or the name of an +installed package. + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Remote.php b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Remote.php new file mode 100644 index 0000000..619f57d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Remote.php @@ -0,0 +1,810 @@ + + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Remote.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; +require_once 'PEAR/REST.php'; + +/** + * PEAR commands for remote server querying + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Remote extends PEAR_Command_Common +{ + var $commands = array( + 'remote-info' => array( + 'summary' => 'Information About Remote Packages', + 'function' => 'doRemoteInfo', + 'shortcut' => 'ri', + 'options' => array(), + 'doc' => ' +Get details on a package from the server.', + ), + 'list-upgrades' => array( + 'summary' => 'List Available Upgrades', + 'function' => 'doListUpgrades', + 'shortcut' => 'lu', + 'options' => array( + 'channelinfo' => array( + 'shortopt' => 'i', + 'doc' => 'output fully channel-aware data, even on failure', + ), + ), + 'doc' => '[preferred_state] +List releases on the server of packages you have installed where +a newer version is available with the same release state (stable etc.) +or the state passed as the second parameter.' + ), + 'remote-list' => array( + 'summary' => 'List Remote Packages', + 'function' => 'doRemoteList', + 'shortcut' => 'rl', + 'options' => array( + 'channel' => + array( + 'shortopt' => 'c', + 'doc' => 'specify a channel other than the default channel', + 'arg' => 'CHAN', + ) + ), + 'doc' => ' +Lists the packages available on the configured server along with the +latest stable release of each package.', + ), + 'search' => array( + 'summary' => 'Search remote package database', + 'function' => 'doSearch', + 'shortcut' => 'sp', + 'options' => array( + 'channel' => + array( + 'shortopt' => 'c', + 'doc' => 'specify a channel other than the default channel', + 'arg' => 'CHAN', + ), + 'allchannels' => array( + 'shortopt' => 'a', + 'doc' => 'search packages from all known channels', + ), + 'channelinfo' => array( + 'shortopt' => 'i', + 'doc' => 'output fully channel-aware data, even on failure', + ), + ), + 'doc' => '[packagename] [packageinfo] +Lists all packages which match the search parameters. The first +parameter is a fragment of a packagename. The default channel +will be used unless explicitly overridden. The second parameter +will be used to match any portion of the summary/description', + ), + 'list-all' => array( + 'summary' => 'List All Packages', + 'function' => 'doListAll', + 'shortcut' => 'la', + 'options' => array( + 'channel' => + array( + 'shortopt' => 'c', + 'doc' => 'specify a channel other than the default channel', + 'arg' => 'CHAN', + ), + 'channelinfo' => array( + 'shortopt' => 'i', + 'doc' => 'output fully channel-aware data, even on failure', + ), + ), + 'doc' => ' +Lists the packages available on the configured server along with the +latest stable release of each package.', + ), + 'download' => array( + 'summary' => 'Download Package', + 'function' => 'doDownload', + 'shortcut' => 'd', + 'options' => array( + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'download an uncompressed (.tar) file', + ), + ), + 'doc' => '... +Download package tarballs. The files will be named as suggested by the +server, for example if you download the DB package and the latest stable +version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz.', + ), + 'clear-cache' => array( + 'summary' => 'Clear Web Services Cache', + 'function' => 'doClearCache', + 'shortcut' => 'cc', + 'options' => array(), + 'doc' => ' +Clear the REST cache. See also the cache_ttl configuration +parameter. +', + ), + ); + + /** + * PEAR_Command_Remote constructor. + * + * @access public + */ + function PEAR_Command_Remote(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + function _checkChannelForStatus($channel, $chan) + { + if (PEAR::isError($chan)) { + $this->raiseError($chan); + } + if (!is_a($chan, 'PEAR_ChannelFile')) { + return $this->raiseError('Internal corruption error: invalid channel "' . + $channel . '"'); + } + $rest = new PEAR_REST($this->config); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $mirror = $this->config->get('preferred_mirror', null, + $channel); + $a = $rest->downloadHttp('http://' . $channel . + '/channel.xml', $chan->lastModified()); + PEAR::staticPopErrorHandling(); + if (!PEAR::isError($a) && $a) { + $this->ui->outputData('WARNING: channel "' . $channel . '" has ' . + 'updated its protocols, use "' . PEAR_RUNTYPE . ' channel-update ' . $channel . + '" to update'); + } + } + + function doRemoteInfo($command, $options, $params) + { + if (sizeof($params) != 1) { + return $this->raiseError("$command expects one param: the remote package name"); + } + $savechannel = $channel = $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + $package = $params[0]; + $parsed = $reg->parsePackageName($package, $channel); + if (PEAR::isError($parsed)) { + return $this->raiseError('Invalid package name "' . $package . '"'); + } + + $channel = $parsed['channel']; + $this->config->set('default_channel', $channel); + $chan = $reg->getChannel($channel); + if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) { + return $e; + } + + $mirror = $this->config->get('preferred_mirror'); + if ($chan->supportsREST($mirror) && $base = $chan->getBaseURL('REST1.0', $mirror)) { + $rest = &$this->config->getREST('1.0', array()); + $info = $rest->packageInfo($base, $parsed['package'], $channel); + } + + if (!isset($info)) { + return $this->raiseError('No supported protocol was found'); + } + + if (PEAR::isError($info)) { + $this->config->set('default_channel', $savechannel); + return $this->raiseError($info); + } + + if (!isset($info['name'])) { + return $this->raiseError('No remote package "' . $package . '" was found'); + } + + $installed = $reg->packageInfo($info['name'], null, $channel); + $info['installed'] = $installed['version'] ? $installed['version'] : '- no -'; + if (is_array($info['installed'])) { + $info['installed'] = $info['installed']['release']; + } + + $this->ui->outputData($info, $command); + $this->config->set('default_channel', $savechannel); + + return true; + } + + function doRemoteList($command, $options, $params) + { + $savechannel = $channel = $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + if (isset($options['channel'])) { + $channel = $options['channel']; + if (!$reg->channelExists($channel)) { + return $this->raiseError('Channel "' . $channel . '" does not exist'); + } + + $this->config->set('default_channel', $channel); + } + + $chan = $reg->getChannel($channel); + if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) { + return $e; + } + + $list_options = false; + if ($this->config->get('preferred_state') == 'stable') { + $list_options = true; + } + + $available = array(); + if ($chan->supportsREST($this->config->get('preferred_mirror')) && + $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror')) + ) { + // use faster list-all if available + $rest = &$this->config->getREST('1.1', array()); + $available = $rest->listAll($base, $list_options, true, false, false, $chan->getName()); + } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) && + $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { + $rest = &$this->config->getREST('1.0', array()); + $available = $rest->listAll($base, $list_options, true, false, false, $chan->getName()); + } + + if (PEAR::isError($available)) { + $this->config->set('default_channel', $savechannel); + return $this->raiseError($available); + } + + $i = $j = 0; + $data = array( + 'caption' => 'Channel ' . $channel . ' Available packages:', + 'border' => true, + 'headline' => array('Package', 'Version'), + 'channel' => $channel + ); + + if (count($available) == 0) { + $data = '(no packages available yet)'; + } else { + foreach ($available as $name => $info) { + $version = (isset($info['stable']) && $info['stable']) ? $info['stable'] : '-n/a-'; + $data['data'][] = array($name, $version); + } + } + $this->ui->outputData($data, $command); + $this->config->set('default_channel', $savechannel); + return true; + } + + function doListAll($command, $options, $params) + { + $savechannel = $channel = $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + if (isset($options['channel'])) { + $channel = $options['channel']; + if (!$reg->channelExists($channel)) { + return $this->raiseError("Channel \"$channel\" does not exist"); + } + + $this->config->set('default_channel', $channel); + } + + $list_options = false; + if ($this->config->get('preferred_state') == 'stable') { + $list_options = true; + } + + $chan = $reg->getChannel($channel); + if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) { + return $e; + } + + if ($chan->supportsREST($this->config->get('preferred_mirror')) && + $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror'))) { + // use faster list-all if available + $rest = &$this->config->getREST('1.1', array()); + $available = $rest->listAll($base, $list_options, false, false, false, $chan->getName()); + } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) && + $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { + $rest = &$this->config->getREST('1.0', array()); + $available = $rest->listAll($base, $list_options, false, false, false, $chan->getName()); + } + + if (PEAR::isError($available)) { + $this->config->set('default_channel', $savechannel); + return $this->raiseError('The package list could not be fetched from the remote server. Please try again. (Debug info: "' . $available->getMessage() . '")'); + } + + $data = array( + 'caption' => 'All packages [Channel ' . $channel . ']:', + 'border' => true, + 'headline' => array('Package', 'Latest', 'Local'), + 'channel' => $channel, + ); + + if (isset($options['channelinfo'])) { + // add full channelinfo + $data['caption'] = 'Channel ' . $channel . ' All packages:'; + $data['headline'] = array('Channel', 'Package', 'Latest', 'Local', + 'Description', 'Dependencies'); + } + $local_pkgs = $reg->listPackages($channel); + + foreach ($available as $name => $info) { + $installed = $reg->packageInfo($name, null, $channel); + if (is_array($installed['version'])) { + $installed['version'] = $installed['version']['release']; + } + $desc = $info['summary']; + if (isset($params[$name])) { + $desc .= "\n\n".$info['description']; + } + if (isset($options['mode'])) + { + if ($options['mode'] == 'installed' && !isset($installed['version'])) { + continue; + } + if ($options['mode'] == 'notinstalled' && isset($installed['version'])) { + continue; + } + if ($options['mode'] == 'upgrades' + && (!isset($installed['version']) || version_compare($installed['version'], + $info['stable'], '>='))) { + continue; + } + } + $pos = array_search(strtolower($name), $local_pkgs); + if ($pos !== false) { + unset($local_pkgs[$pos]); + } + + if (isset($info['stable']) && !$info['stable']) { + $info['stable'] = null; + } + + if (isset($options['channelinfo'])) { + // add full channelinfo + if ($info['stable'] === $info['unstable']) { + $state = $info['state']; + } else { + $state = 'stable'; + } + $latest = $info['stable'].' ('.$state.')'; + $local = ''; + if (isset($installed['version'])) { + $inst_state = $reg->packageInfo($name, 'release_state', $channel); + $local = $installed['version'].' ('.$inst_state.')'; + } + + $packageinfo = array( + $channel, + $name, + $latest, + $local, + isset($desc) ? $desc : null, + isset($info['deps']) ? $info['deps'] : null, + ); + } else { + $packageinfo = array( + $reg->channelAlias($channel) . '/' . $name, + isset($info['stable']) ? $info['stable'] : null, + isset($installed['version']) ? $installed['version'] : null, + isset($desc) ? $desc : null, + isset($info['deps']) ? $info['deps'] : null, + ); + } + $data['data'][$info['category']][] = $packageinfo; + } + + if (isset($options['mode']) && in_array($options['mode'], array('notinstalled', 'upgrades'))) { + $this->config->set('default_channel', $savechannel); + $this->ui->outputData($data, $command); + return true; + } + + foreach ($local_pkgs as $name) { + $info = &$reg->getPackage($name, $channel); + $data['data']['Local'][] = array( + $reg->channelAlias($channel) . '/' . $info->getPackage(), + '', + $info->getVersion(), + $info->getSummary(), + $info->getDeps() + ); + } + + $this->config->set('default_channel', $savechannel); + $this->ui->outputData($data, $command); + return true; + } + + function doSearch($command, $options, $params) + { + if ((!isset($params[0]) || empty($params[0])) + && (!isset($params[1]) || empty($params[1]))) + { + return $this->raiseError('no valid search string supplied'); + } + + $channelinfo = isset($options['channelinfo']); + $reg = &$this->config->getRegistry(); + if (isset($options['allchannels'])) { + // search all channels + unset($options['allchannels']); + $channels = $reg->getChannels(); + $errors = array(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + foreach ($channels as $channel) { + if ($channel->getName() != '__uri') { + $options['channel'] = $channel->getName(); + $ret = $this->doSearch($command, $options, $params); + if (PEAR::isError($ret)) { + $errors[] = $ret; + } + } + } + + PEAR::staticPopErrorHandling(); + if (count($errors) !== 0) { + // for now, only give first error + return PEAR::raiseError($errors[0]); + } + + return true; + } + + $savechannel = $channel = $this->config->get('default_channel'); + $package = strtolower($params[0]); + $summary = isset($params[1]) ? $params[1] : false; + if (isset($options['channel'])) { + $reg = &$this->config->getRegistry(); + $channel = $options['channel']; + if (!$reg->channelExists($channel)) { + return $this->raiseError('Channel "' . $channel . '" does not exist'); + } + + $this->config->set('default_channel', $channel); + } + + $chan = $reg->getChannel($channel); + if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) { + return $e; + } + + if ($chan->supportsREST($this->config->get('preferred_mirror')) && + $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { + $rest = &$this->config->getREST('1.0', array()); + $available = $rest->listAll($base, false, false, $package, $summary, $chan->getName()); + } + + if (PEAR::isError($available)) { + $this->config->set('default_channel', $savechannel); + return $this->raiseError($available); + } + + if (!$available && !$channelinfo) { + // clean exit when not found, no error ! + $data = 'no packages found that match pattern "' . $package . '", for channel '.$channel.'.'; + $this->ui->outputData($data); + $this->config->set('default_channel', $channel); + return true; + } + + if ($channelinfo) { + $data = array( + 'caption' => 'Matched packages, channel ' . $channel . ':', + 'border' => true, + 'headline' => array('Channel', 'Package', 'Stable/(Latest)', 'Local'), + 'channel' => $channel + ); + } else { + $data = array( + 'caption' => 'Matched packages, channel ' . $channel . ':', + 'border' => true, + 'headline' => array('Package', 'Stable/(Latest)', 'Local'), + 'channel' => $channel + ); + } + + if (!$available && $channelinfo) { + unset($data['headline']); + $data['data'] = 'No packages found that match pattern "' . $package . '".'; + $available = array(); + } + + foreach ($available as $name => $info) { + $installed = $reg->packageInfo($name, null, $channel); + $desc = $info['summary']; + if (isset($params[$name])) + $desc .= "\n\n".$info['description']; + + if (!isset($info['stable']) || !$info['stable']) { + $version_remote = 'none'; + } else { + if ($info['unstable']) { + $version_remote = $info['unstable']; + } else { + $version_remote = $info['stable']; + } + $version_remote .= ' ('.$info['state'].')'; + } + $version = is_array($installed['version']) ? $installed['version']['release'] : + $installed['version']; + if ($channelinfo) { + $packageinfo = array( + $channel, + $name, + $version_remote, + $version, + $desc, + ); + } else { + $packageinfo = array( + $name, + $version_remote, + $version, + $desc, + ); + } + $data['data'][$info['category']][] = $packageinfo; + } + + $this->ui->outputData($data, $command); + $this->config->set('default_channel', $channel); + return true; + } + + function &getDownloader($options) + { + if (!class_exists('PEAR_Downloader')) { + require_once 'PEAR/Downloader.php'; + } + $a = &new PEAR_Downloader($this->ui, $options, $this->config); + return $a; + } + + function doDownload($command, $options, $params) + { + // make certain that dependencies are ignored + $options['downloadonly'] = 1; + + // eliminate error messages for preferred_state-related errors + /* TODO: Should be an option, but until now download does respect + prefered state */ + /* $options['ignorepreferred_state'] = 1; */ + // eliminate error messages for preferred_state-related errors + + $downloader = &$this->getDownloader($options); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $e = $downloader->setDownloadDir(getcwd()); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($e)) { + return $this->raiseError('Current directory is not writeable, cannot download'); + } + + $errors = array(); + $downloaded = array(); + $err = $downloader->download($params); + if (PEAR::isError($err)) { + return $err; + } + + $errors = $downloader->getErrorMsgs(); + if (count($errors)) { + foreach ($errors as $error) { + if ($error !== null) { + $this->ui->outputData($error); + } + } + + return $this->raiseError("$command failed"); + } + + $downloaded = $downloader->getDownloadedPackages(); + foreach ($downloaded as $pkg) { + $this->ui->outputData("File $pkg[file] downloaded", $command); + } + + return true; + } + + function downloadCallback($msg, $params = null) + { + if ($msg == 'done') { + $this->bytes_downloaded = $params; + } + } + + function doListUpgrades($command, $options, $params) + { + require_once 'PEAR/Common.php'; + if (isset($params[0]) && !is_array(PEAR_Common::betterStates($params[0]))) { + return $this->raiseError($params[0] . ' is not a valid state (stable/beta/alpha/devel/etc.) try "pear help list-upgrades"'); + } + + $savechannel = $channel = $this->config->get('default_channel'); + $reg = &$this->config->getRegistry(); + foreach ($reg->listChannels() as $channel) { + $inst = array_flip($reg->listPackages($channel)); + if (!count($inst)) { + continue; + } + + if ($channel == '__uri') { + continue; + } + + $this->config->set('default_channel', $channel); + $state = empty($params[0]) ? $this->config->get('preferred_state') : $params[0]; + + $caption = $channel . ' Available Upgrades'; + $chan = $reg->getChannel($channel); + if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) { + return $e; + } + + $latest = array(); + $base2 = false; + $preferred_mirror = $this->config->get('preferred_mirror'); + if ($chan->supportsREST($preferred_mirror) && + ( + //($base2 = $chan->getBaseURL('REST1.4', $preferred_mirror)) || + ($base = $chan->getBaseURL('REST1.0', $preferred_mirror)) + ) + + ) { + if ($base2) { + $rest = &$this->config->getREST('1.4', array()); + $base = $base2; + } else { + $rest = &$this->config->getREST('1.0', array()); + } + + if (empty($state) || $state == 'any') { + $state = false; + } else { + $caption .= ' (' . implode(', ', PEAR_Common::betterStates($state, true)) . ')'; + } + + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $latest = $rest->listLatestUpgrades($base, $state, $inst, $channel, $reg); + PEAR::staticPopErrorHandling(); + } + + if (PEAR::isError($latest)) { + $this->ui->outputData($latest->getMessage()); + continue; + } + + $caption .= ':'; + if (PEAR::isError($latest)) { + $this->config->set('default_channel', $savechannel); + return $latest; + } + + $data = array( + 'caption' => $caption, + 'border' => 1, + 'headline' => array('Channel', 'Package', 'Local', 'Remote', 'Size'), + 'channel' => $channel + ); + + foreach ((array)$latest as $pkg => $info) { + $package = strtolower($pkg); + if (!isset($inst[$package])) { + // skip packages we don't have installed + continue; + } + + extract($info); + $inst_version = $reg->packageInfo($package, 'version', $channel); + $inst_state = $reg->packageInfo($package, 'release_state', $channel); + if (version_compare("$version", "$inst_version", "le")) { + // installed version is up-to-date + continue; + } + + if ($filesize >= 20480) { + $filesize += 1024 - ($filesize % 1024); + $fs = sprintf("%dkB", $filesize / 1024); + } elseif ($filesize > 0) { + $filesize += 103 - ($filesize % 103); + $fs = sprintf("%.1fkB", $filesize / 1024.0); + } else { + $fs = " -"; // XXX center instead + } + + $data['data'][] = array($channel, $pkg, "$inst_version ($inst_state)", "$version ($state)", $fs); + } + + if (isset($options['channelinfo'])) { + if (empty($data['data'])) { + unset($data['headline']); + if (count($inst) == 0) { + $data['data'] = '(no packages installed)'; + } else { + $data['data'] = '(no upgrades available)'; + } + } + $this->ui->outputData($data, $command); + } else { + if (empty($data['data'])) { + $this->ui->outputData('Channel ' . $channel . ': No upgrades available'); + } else { + $this->ui->outputData($data, $command); + } + } + } + + $this->config->set('default_channel', $savechannel); + return true; + } + + function doClearCache($command, $options, $params) + { + $cache_dir = $this->config->get('cache_dir'); + $verbose = $this->config->get('verbose'); + $output = ''; + if (!file_exists($cache_dir) || !is_dir($cache_dir)) { + return $this->raiseError("$cache_dir does not exist or is not a directory"); + } + + if (!($dp = @opendir($cache_dir))) { + return $this->raiseError("opendir($cache_dir) failed: $php_errormsg"); + } + + if ($verbose >= 1) { + $output .= "reading directory $cache_dir\n"; + } + + $num = 0; + while ($ent = readdir($dp)) { + if (preg_match('/rest.cache(file|id)\\z/', $ent)) { + $path = $cache_dir . DIRECTORY_SEPARATOR . $ent; + if (file_exists($path)) { + $ok = @unlink($path); + } else { + $ok = false; + $php_errormsg = ''; + } + + if ($ok) { + if ($verbose >= 2) { + $output .= "deleted $path\n"; + } + $num++; + } elseif ($verbose >= 1) { + $output .= "failed to delete $path $php_errormsg\n"; + } + } + } + + closedir($dp); + if ($verbose >= 1) { + $output .= "$num cache entries cleared\n"; + } + + $this->ui->outputData(rtrim($output), $command); + return $num; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Remote.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Remote.xml new file mode 100644 index 0000000..b4f6100 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Remote.xml @@ -0,0 +1,109 @@ + + + Information About Remote Packages + doRemoteInfo + ri + + <package> +Get details on a package from the server. + + + List Available Upgrades + doListUpgrades + lu + + + i + output fully channel-aware data, even on failure + + + [preferred_state] +List releases on the server of packages you have installed where +a newer version is available with the same release state (stable etc.) +or the state passed as the second parameter. + + + List Remote Packages + doRemoteList + rl + + + c + specify a channel other than the default channel + CHAN + + + +Lists the packages available on the configured server along with the +latest stable release of each package. + + + Search remote package database + doSearch + sp + + + c + specify a channel other than the default channel + CHAN + + + a + search packages from all known channels + + + i + output fully channel-aware data, even on failure + + + [packagename] [packageinfo] +Lists all packages which match the search parameters. The first +parameter is a fragment of a packagename. The default channel +will be used unless explicitly overridden. The second parameter +will be used to match any portion of the summary/description + + + List All Packages + doListAll + la + + + c + specify a channel other than the default channel + CHAN + + + i + output fully channel-aware data, even on failure + + + +Lists the packages available on the configured server along with the +latest stable release of each package. + + + Download Package + doDownload + d + + + Z + download an uncompressed (.tar) file + + + <package>... +Download package tarballs. The files will be named as suggested by the +server, for example if you download the DB package and the latest stable +version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz. + + + Clear Web Services Cache + doClearCache + cc + + +Clear the XML-RPC/REST cache. See also the cache_ttl configuration +parameter. + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Test.php b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Test.php new file mode 100644 index 0000000..591e89a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Test.php @@ -0,0 +1,337 @@ + + * @author Martin Jansen + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Test.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for login/logout + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Martin Jansen + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ + +class PEAR_Command_Test extends PEAR_Command_Common +{ + var $commands = array( + 'run-tests' => array( + 'summary' => 'Run Regression Tests', + 'function' => 'doRunTests', + 'shortcut' => 'rt', + 'options' => array( + 'recur' => array( + 'shortopt' => 'r', + 'doc' => 'Run tests in child directories, recursively. 4 dirs deep maximum', + ), + 'ini' => array( + 'shortopt' => 'i', + 'doc' => 'actual string of settings to pass to php in format " -d setting=blah"', + 'arg' => 'SETTINGS' + ), + 'realtimelog' => array( + 'shortopt' => 'l', + 'doc' => 'Log test runs/results as they are run', + ), + 'quiet' => array( + 'shortopt' => 'q', + 'doc' => 'Only display detail for failed tests', + ), + 'simple' => array( + 'shortopt' => 's', + 'doc' => 'Display simple output for all tests', + ), + 'package' => array( + 'shortopt' => 'p', + 'doc' => 'Treat parameters as installed packages from which to run tests', + ), + 'phpunit' => array( + 'shortopt' => 'u', + 'doc' => 'Search parameters for AllTests.php, and use that to run phpunit-based tests +If none is found, all .phpt tests will be tried instead.', + ), + 'tapoutput' => array( + 'shortopt' => 't', + 'doc' => 'Output run-tests.log in TAP-compliant format', + ), + 'cgi' => array( + 'shortopt' => 'c', + 'doc' => 'CGI php executable (needed for tests with POST/GET section)', + 'arg' => 'PHPCGI', + ), + 'coverage' => array( + 'shortopt' => 'x', + 'doc' => 'Generate a code coverage report (requires Xdebug 2.0.0+)', + ), + ), + 'doc' => '[testfile|dir ...] +Run regression tests with PHP\'s regression testing script (run-tests.php).', + ), + ); + + var $output; + + /** + * PEAR_Command_Test constructor. + * + * @access public + */ + function PEAR_Command_Test(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + function doRunTests($command, $options, $params) + { + if (isset($options['phpunit']) && isset($options['tapoutput'])) { + return $this->raiseError('ERROR: cannot use both --phpunit and --tapoutput at the same time'); + } + + require_once 'PEAR/Common.php'; + require_once 'System.php'; + $log = new PEAR_Common; + $log->ui = &$this->ui; // slightly hacky, but it will work + $tests = array(); + $depth = isset($options['recur']) ? 14 : 1; + + if (!count($params)) { + $params[] = '.'; + } + + if (isset($options['package'])) { + $oldparams = $params; + $params = array(); + $reg = &$this->config->getRegistry(); + foreach ($oldparams as $param) { + $pname = $reg->parsePackageName($param, $this->config->get('default_channel')); + if (PEAR::isError($pname)) { + return $this->raiseError($pname); + } + + $package = &$reg->getPackage($pname['package'], $pname['channel']); + if (!$package) { + return PEAR::raiseError('Unknown package "' . + $reg->parsedPackageNameToString($pname) . '"'); + } + + $filelist = $package->getFilelist(); + foreach ($filelist as $name => $atts) { + if (isset($atts['role']) && $atts['role'] != 'test') { + continue; + } + + if (isset($options['phpunit']) && preg_match('/AllTests\.php\\z/i', $name)) { + $params[] = $atts['installed_as']; + continue; + } elseif (!preg_match('/\.phpt\\z/', $name)) { + continue; + } + $params[] = $atts['installed_as']; + } + } + } + + foreach ($params as $p) { + if (is_dir($p)) { + if (isset($options['phpunit'])) { + $dir = System::find(array($p, '-type', 'f', + '-maxdepth', $depth, + '-name', 'AllTests.php')); + if (count($dir)) { + foreach ($dir as $p) { + $p = realpath($p); + if (!count($tests) || + (count($tests) && strlen($p) < strlen($tests[0]))) { + // this is in a higher-level directory, use this one instead. + $tests = array($p); + } + } + } + continue; + } + + $args = array($p, '-type', 'f', '-name', '*.phpt'); + } else { + if (isset($options['phpunit'])) { + if (preg_match('/AllTests\.php\\z/i', $p)) { + $p = realpath($p); + if (!count($tests) || + (count($tests) && strlen($p) < strlen($tests[0]))) { + // this is in a higher-level directory, use this one instead. + $tests = array($p); + } + } + continue; + } + + if (file_exists($p) && preg_match('/\.phpt$/', $p)) { + $tests[] = $p; + continue; + } + + if (!preg_match('/\.phpt\\z/', $p)) { + $p .= '.phpt'; + } + + $args = array(dirname($p), '-type', 'f', '-name', $p); + } + + if (!isset($options['recur'])) { + $args[] = '-maxdepth'; + $args[] = 1; + } + + $dir = System::find($args); + $tests = array_merge($tests, $dir); + } + + $ini_settings = ''; + if (isset($options['ini'])) { + $ini_settings .= $options['ini']; + } + + if (isset($_ENV['TEST_PHP_INCLUDE_PATH'])) { + $ini_settings .= " -d include_path={$_ENV['TEST_PHP_INCLUDE_PATH']}"; + } + + if ($ini_settings) { + $this->ui->outputData('Using INI settings: "' . $ini_settings . '"'); + } + + $skipped = $passed = $failed = array(); + $tests_count = count($tests); + $this->ui->outputData('Running ' . $tests_count . ' tests', $command); + $start = time(); + if (isset($options['realtimelog']) && file_exists('run-tests.log')) { + unlink('run-tests.log'); + } + + if (isset($options['tapoutput'])) { + $tap = '1..' . $tests_count . "\n"; + } + + require_once 'PEAR/RunTest.php'; + $run = new PEAR_RunTest($log, $options); + $run->tests_count = $tests_count; + + if (isset($options['coverage']) && extension_loaded('xdebug')){ + $run->xdebug_loaded = true; + } else { + $run->xdebug_loaded = false; + } + + $j = $i = 1; + foreach ($tests as $t) { + if (isset($options['realtimelog'])) { + $fp = @fopen('run-tests.log', 'a'); + if ($fp) { + fwrite($fp, "Running test [$i / $tests_count] $t..."); + fclose($fp); + } + } + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (isset($options['phpunit'])) { + $result = $run->runPHPUnit($t, $ini_settings); + } else { + $result = $run->run($t, $ini_settings, $j); + } + PEAR::staticPopErrorHandling(); + if (PEAR::isError($result)) { + $this->ui->log($result->getMessage()); + continue; + } + + if (isset($options['tapoutput'])) { + $tap .= $result[0] . ' ' . $i . $result[1] . "\n"; + continue; + } + + if (isset($options['realtimelog'])) { + $fp = @fopen('run-tests.log', 'a'); + if ($fp) { + fwrite($fp, "$result\n"); + fclose($fp); + } + } + + if ($result == 'FAILED') { + $failed[] = $t; + } + if ($result == 'PASSED') { + $passed[] = $t; + } + if ($result == 'SKIPPED') { + $skipped[] = $t; + } + + $j++; + } + + $total = date('i:s', time() - $start); + if (isset($options['tapoutput'])) { + $fp = @fopen('run-tests.log', 'w'); + if ($fp) { + fwrite($fp, $tap, strlen($tap)); + fclose($fp); + $this->ui->outputData('wrote TAP-format log to "' .realpath('run-tests.log') . + '"', $command); + } + } else { + if (count($failed)) { + $output = "TOTAL TIME: $total\n"; + $output .= count($passed) . " PASSED TESTS\n"; + $output .= count($skipped) . " SKIPPED TESTS\n"; + $output .= count($failed) . " FAILED TESTS:\n"; + foreach ($failed as $failure) { + $output .= $failure . "\n"; + } + + $mode = isset($options['realtimelog']) ? 'a' : 'w'; + $fp = @fopen('run-tests.log', $mode); + + if ($fp) { + fwrite($fp, $output, strlen($output)); + fclose($fp); + $this->ui->outputData('wrote log to "' . realpath('run-tests.log') . '"', $command); + } + } elseif (file_exists('run-tests.log') && !is_dir('run-tests.log')) { + @unlink('run-tests.log'); + } + } + $this->ui->outputData('TOTAL TIME: ' . $total); + $this->ui->outputData(count($passed) . ' PASSED TESTS', $command); + $this->ui->outputData(count($skipped) . ' SKIPPED TESTS', $command); + if (count($failed)) { + $this->ui->outputData(count($failed) . ' FAILED TESTS:', $command); + foreach ($failed as $failure) { + $this->ui->outputData($failure, $command); + } + } + + return true; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Command/Test.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Test.xml new file mode 100644 index 0000000..bbe9fcc --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Command/Test.xml @@ -0,0 +1,54 @@ + + + Run Regression Tests + doRunTests + rt + + + r + Run tests in child directories, recursively. 4 dirs deep maximum + + + i + actual string of settings to pass to php in format " -d setting=blah" + SETTINGS + + + l + Log test runs/results as they are run + + + q + Only display detail for failed tests + + + s + Display simple output for all tests + + + p + Treat parameters as installed packages from which to run tests + + + u + Search parameters for AllTests.php, and use that to run phpunit-based tests +If none is found, all .phpt tests will be tried instead. + + + t + Output run-tests.log in TAP-compliant format + + + c + CGI php executable (needed for tests with POST/GET section) + PHPCGI + + + x + Generate a code coverage report (requires Xdebug 2.0.0+) + + + [testfile|dir ...] +Run regression tests with PHP's regression testing script (run-tests.php). + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Common.php b/typo3conf/ext/phpunit/PEAR/PEAR/Common.php new file mode 100644 index 0000000..3d20842 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Common.php @@ -0,0 +1,837 @@ + + * @author Tomas V. V. Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Common.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1.0 + * @deprecated File deprecated since Release 1.4.0a1 + */ + +/** + * Include error handling + */ +require_once 'PEAR.php'; + +/** + * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode() + */ +define('PEAR_COMMON_ERROR_INVALIDPHP', 1); +define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+'); +define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/'); + +// this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1 +define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?'); +define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '\\z/i'); + +// XXX far from perfect :-) +define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG . + ')(-([.0-9a-zA-Z]+))?'); +define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG . + '\\z/'); + +define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+'); +define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '\\z/'); + +// this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED +define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*'); +define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '\\z/i'); + +define('_PEAR_CHANNELS_PACKAGE_PREG', '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/(' + . _PEAR_COMMON_PACKAGE_NAME_PREG . ')'); +define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '\\z/i'); + +define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::(' + . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?'); +define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '\\z/'); + +/** + * List of temporary files and directories registered by + * PEAR_Common::addTempFile(). + * @var array + */ +$GLOBALS['_PEAR_Common_tempfiles'] = array(); + +/** + * Valid maintainer roles + * @var array + */ +$GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper'); + +/** + * Valid release states + * @var array + */ +$GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel'); + +/** + * Valid dependency types + * @var array + */ +$GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi'); + +/** + * Valid dependency relations + * @var array + */ +$GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne'); + +/** + * Valid file roles + * @var array + */ +$GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script'); + +/** + * Valid replacement types + * @var array + */ +$GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info'); + +/** + * Valid "provide" types + * @var array + */ +$GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api'); + +/** + * Valid "provide" types + * @var array + */ +$GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup'); + +/** + * Class providing common functionality for PEAR administration classes. + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V. V. Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + * @deprecated This class will disappear, and its components will be spread + * into smaller classes, like the AT&T breakup, as of Release 1.4.0a1 + */ +class PEAR_Common extends PEAR +{ + /** + * User Interface object (PEAR_Frontend_* class). If null, + * the log() method uses print. + * @var object + */ + var $ui = null; + + /** + * Configuration object (PEAR_Config). + * @var PEAR_Config + */ + var $config = null; + + /** stack of elements, gives some sort of XML context */ + var $element_stack = array(); + + /** name of currently parsed XML element */ + var $current_element; + + /** array of attributes of the currently parsed XML element */ + var $current_attributes = array(); + + /** assoc with information about a package */ + var $pkginfo = array(); + + var $current_path = null; + + /** + * Flag variable used to mark a valid package file + * @var boolean + * @access private + */ + var $_validPackageFile; + + /** + * PEAR_Common constructor + * + * @access public + */ + function PEAR_Common() + { + parent::PEAR(); + $this->config = &PEAR_Config::singleton(); + $this->debug = $this->config->get('verbose'); + } + + /** + * PEAR_Common destructor + * + * @access private + */ + function _PEAR_Common() + { + // doesn't work due to bug #14744 + //$tempfiles = $this->_tempfiles; + $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles']; + while ($file = array_shift($tempfiles)) { + if (@is_dir($file)) { + if (!class_exists('System')) { + require_once 'System.php'; + } + + System::rm(array('-rf', $file)); + } elseif (file_exists($file)) { + unlink($file); + } + } + } + + /** + * Register a temporary file or directory. When the destructor is + * executed, all registered temporary files and directories are + * removed. + * + * @param string $file name of file or directory + * + * @return void + * + * @access public + */ + function addTempFile($file) + { + if (!class_exists('PEAR_Frontend')) { + require_once 'PEAR/Frontend.php'; + } + PEAR_Frontend::addTempFile($file); + } + + /** + * Wrapper to System::mkDir(), creates a directory as well as + * any necessary parent directories. + * + * @param string $dir directory name + * + * @return bool TRUE on success, or a PEAR error + * + * @access public + */ + function mkDirHier($dir) + { + // Only used in Installer - move it there ? + $this->log(2, "+ create dir $dir"); + if (!class_exists('System')) { + require_once 'System.php'; + } + return System::mkDir(array('-p', $dir)); + } + + /** + * Logging method. + * + * @param int $level log level (0 is quiet, higher is noisier) + * @param string $msg message to write to the log + * + * @return void + * + * @access public + * @static + */ + function log($level, $msg, $append_crlf = true) + { + if ($this->debug >= $level) { + if (!class_exists('PEAR_Frontend')) { + require_once 'PEAR/Frontend.php'; + } + + $ui = &PEAR_Frontend::singleton(); + if (is_a($ui, 'PEAR_Frontend')) { + $ui->log($msg, $append_crlf); + } else { + print "$msg\n"; + } + } + } + + /** + * Create and register a temporary directory. + * + * @param string $tmpdir (optional) Directory to use as tmpdir. + * Will use system defaults (for example + * /tmp or c:\windows\temp) if not specified + * + * @return string name of created directory + * + * @access public + */ + function mkTempDir($tmpdir = '') + { + $topt = $tmpdir ? array('-t', $tmpdir) : array(); + $topt = array_merge($topt, array('-d', 'pear')); + if (!class_exists('System')) { + require_once 'System.php'; + } + + if (!$tmpdir = System::mktemp($topt)) { + return false; + } + + $this->addTempFile($tmpdir); + return $tmpdir; + } + + /** + * Set object that represents the frontend to be used. + * + * @param object Reference of the frontend object + * @return void + * @access public + */ + function setFrontendObject(&$ui) + { + $this->ui = &$ui; + } + + /** + * Return an array containing all of the states that are more stable than + * or equal to the passed in state + * + * @param string Release state + * @param boolean Determines whether to include $state in the list + * @return false|array False if $state is not a valid release state + */ + function betterStates($state, $include = false) + { + static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); + $i = array_search($state, $states); + if ($i === false) { + return false; + } + if ($include) { + $i--; + } + return array_slice($states, $i + 1); + } + + /** + * Get the valid roles for a PEAR package maintainer + * + * @return array + * @static + */ + function getUserRoles() + { + return $GLOBALS['_PEAR_Common_maintainer_roles']; + } + + /** + * Get the valid package release states of packages + * + * @return array + * @static + */ + function getReleaseStates() + { + return $GLOBALS['_PEAR_Common_release_states']; + } + + /** + * Get the implemented dependency types (php, ext, pkg etc.) + * + * @return array + * @static + */ + function getDependencyTypes() + { + return $GLOBALS['_PEAR_Common_dependency_types']; + } + + /** + * Get the implemented dependency relations (has, lt, ge etc.) + * + * @return array + * @static + */ + function getDependencyRelations() + { + return $GLOBALS['_PEAR_Common_dependency_relations']; + } + + /** + * Get the implemented file roles + * + * @return array + * @static + */ + function getFileRoles() + { + return $GLOBALS['_PEAR_Common_file_roles']; + } + + /** + * Get the implemented file replacement types in + * + * @return array + * @static + */ + function getReplacementTypes() + { + return $GLOBALS['_PEAR_Common_replacement_types']; + } + + /** + * Get the implemented file replacement types in + * + * @return array + * @static + */ + function getProvideTypes() + { + return $GLOBALS['_PEAR_Common_provide_types']; + } + + /** + * Get the implemented file replacement types in + * + * @return array + * @static + */ + function getScriptPhases() + { + return $GLOBALS['_PEAR_Common_script_phases']; + } + + /** + * Test whether a string contains a valid package name. + * + * @param string $name the package name to test + * + * @return bool + * + * @access public + */ + function validPackageName($name) + { + return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name); + } + + /** + * Test whether a string contains a valid package version. + * + * @param string $ver the package version to test + * + * @return bool + * + * @access public + */ + function validPackageVersion($ver) + { + return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); + } + + /** + * @param string $path relative or absolute include path + * @return boolean + * @static + */ + function isIncludeable($path) + { + if (file_exists($path) && is_readable($path)) { + return true; + } + + $ipath = explode(PATH_SEPARATOR, ini_get('include_path')); + foreach ($ipath as $include) { + $test = realpath($include . DIRECTORY_SEPARATOR . $path); + if (file_exists($test) && is_readable($test)) { + return true; + } + } + + return false; + } + + function _postProcessChecks($pf) + { + if (!PEAR::isError($pf)) { + return $this->_postProcessValidPackagexml($pf); + } + + $errs = $pf->getUserinfo(); + if (is_array($errs)) { + foreach ($errs as $error) { + $e = $this->raiseError($error['message'], $error['code'], null, null, $error); + } + } + + return $pf; + } + + /** + * Returns information about a package file. Expects the name of + * a gzipped tar file as input. + * + * @param string $file name of .tgz file + * + * @return array array with package information + * + * @access public + * @deprecated use PEAR_PackageFile->fromTgzFile() instead + * + */ + function infoFromTgzFile($file) + { + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL); + return $this->_postProcessChecks($pf); + } + + /** + * Returns information about a package file. Expects the name of + * a package xml file as input. + * + * @param string $descfile name of package xml file + * + * @return array array with package information + * + * @access public + * @deprecated use PEAR_PackageFile->fromPackageFile() instead + * + */ + function infoFromDescriptionFile($descfile) + { + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); + return $this->_postProcessChecks($pf); + } + + /** + * Returns information about a package file. Expects the contents + * of a package xml file as input. + * + * @param string $data contents of package.xml file + * + * @return array array with package information + * + * @access public + * @deprecated use PEAR_PackageFile->fromXmlstring() instead + * + */ + function infoFromString($data) + { + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false); + return $this->_postProcessChecks($pf); + } + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @return array + */ + function _postProcessValidPackagexml(&$pf) + { + if (!is_a($pf, 'PEAR_PackageFile_v2')) { + $this->pkginfo = $pf->toArray(); + return $this->pkginfo; + } + + // sort of make this into a package.xml 1.0-style array + // changelog is not converted to old format. + $arr = $pf->toArray(true); + $arr = array_merge($arr, $arr['old']); + unset($arr['old'], $arr['xsdversion'], $arr['contents'], $arr['compatible'], + $arr['channel'], $arr['uri'], $arr['dependencies'], $arr['phprelease'], + $arr['extsrcrelease'], $arr['zendextsrcrelease'], $arr['extbinrelease'], + $arr['zendextbinrelease'], $arr['bundle'], $arr['lead'], $arr['developer'], + $arr['helper'], $arr['contributor']); + $arr['filelist'] = $pf->getFilelist(); + $this->pkginfo = $arr; + return $arr; + } + + /** + * Returns package information from different sources + * + * This method is able to extract information about a package + * from a .tgz archive or from a XML package definition file. + * + * @access public + * @param string Filename of the source ('package.xml', '.tgz') + * @return string + * @deprecated use PEAR_PackageFile->fromAnyFile() instead + */ + function infoFromAny($info) + { + if (is_string($info) && file_exists($info)) { + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($pf)) { + $errs = $pf->getUserinfo(); + if (is_array($errs)) { + foreach ($errs as $error) { + $e = $this->raiseError($error['message'], $error['code'], null, null, $error); + } + } + + return $pf; + } + + return $this->_postProcessValidPackagexml($pf); + } + + return $info; + } + + /** + * Return an XML document based on the package info (as returned + * by the PEAR_Common::infoFrom* methods). + * + * @param array $pkginfo package info + * + * @return string XML data + * + * @access public + * @deprecated use a PEAR_PackageFile_v* object's generator instead + */ + function xmlFromInfo($pkginfo) + { + $config = &PEAR_Config::singleton(); + $packagefile = &new PEAR_PackageFile($config); + $pf = &$packagefile->fromArray($pkginfo); + $gen = &$pf->getDefaultGenerator(); + return $gen->toXml(PEAR_VALIDATE_PACKAGING); + } + + /** + * Validate XML package definition file. + * + * @param string $info Filename of the package archive or of the + * package definition file + * @param array $errors Array that will contain the errors + * @param array $warnings Array that will contain the warnings + * @param string $dir_prefix (optional) directory where source files + * may be found, or empty if they are not available + * @access public + * @return boolean + * @deprecated use the validation of PEAR_PackageFile objects + */ + function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '') + { + $config = &PEAR_Config::singleton(); + $packagefile = &new PEAR_PackageFile($config); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (strpos($info, 'fromXmlString($info, PEAR_VALIDATE_NORMAL, ''); + } else { + $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); + } + + PEAR::staticPopErrorHandling(); + if (PEAR::isError($pf)) { + $errs = $pf->getUserinfo(); + if (is_array($errs)) { + foreach ($errs as $error) { + if ($error['level'] == 'error') { + $errors[] = $error['message']; + } else { + $warnings[] = $error['message']; + } + } + } + + return false; + } + + return true; + } + + /** + * Build a "provides" array from data returned by + * analyzeSourceCode(). The format of the built array is like + * this: + * + * array( + * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), + * ... + * ) + * + * + * @param array $srcinfo array with information about a source file + * as returned by the analyzeSourceCode() method. + * + * @return void + * + * @access public + * + */ + function buildProvidesArray($srcinfo) + { + $file = basename($srcinfo['source_file']); + $pn = ''; + if (isset($this->_packageName)) { + $pn = $this->_packageName; + } + + $pnl = strlen($pn); + foreach ($srcinfo['declared_classes'] as $class) { + $key = "class;$class"; + if (isset($this->pkginfo['provides'][$key])) { + continue; + } + + $this->pkginfo['provides'][$key] = + array('file'=> $file, 'type' => 'class', 'name' => $class); + if (isset($srcinfo['inheritance'][$class])) { + $this->pkginfo['provides'][$key]['extends'] = + $srcinfo['inheritance'][$class]; + } + } + + foreach ($srcinfo['declared_methods'] as $class => $methods) { + foreach ($methods as $method) { + $function = "$class::$method"; + $key = "function;$function"; + if ($method{0} == '_' || !strcasecmp($method, $class) || + isset($this->pkginfo['provides'][$key])) { + continue; + } + + $this->pkginfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } + } + + foreach ($srcinfo['declared_functions'] as $function) { + $key = "function;$function"; + if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) { + continue; + } + + if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { + $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; + } + + $this->pkginfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } + } + + /** + * Analyze the source code of the given PHP file + * + * @param string Filename of the PHP file + * @return mixed + * @access public + */ + function analyzeSourceCode($file) + { + if (!class_exists('PEAR_PackageFile_v2_Validator')) { + require_once 'PEAR/PackageFile/v2/Validator.php'; + } + + $a = new PEAR_PackageFile_v2_Validator; + return $a->analyzeSourceCode($file); + } + + function detectDependencies($any, $status_callback = null) + { + if (!function_exists("token_get_all")) { + return false; + } + + if (PEAR::isError($info = $this->infoFromAny($any))) { + return $this->raiseError($info); + } + + if (!is_array($info)) { + return false; + } + + $deps = array(); + $used_c = $decl_c = $decl_f = $decl_m = array(); + foreach ($info['filelist'] as $file => $fa) { + $tmp = $this->analyzeSourceCode($file); + $used_c = @array_merge($used_c, $tmp['used_classes']); + $decl_c = @array_merge($decl_c, $tmp['declared_classes']); + $decl_f = @array_merge($decl_f, $tmp['declared_functions']); + $decl_m = @array_merge($decl_m, $tmp['declared_methods']); + $inheri = @array_merge($inheri, $tmp['inheritance']); + } + + $used_c = array_unique($used_c); + $decl_c = array_unique($decl_c); + $undecl_c = array_diff($used_c, $decl_c); + + return array('used_classes' => $used_c, + 'declared_classes' => $decl_c, + 'declared_methods' => $decl_m, + 'declared_functions' => $decl_f, + 'undeclared_classes' => $undecl_c, + 'inheritance' => $inheri, + ); + } + + /** + * Download a file through HTTP. Considers suggested file name in + * Content-disposition: header and can run a callback function for + * different events. The callback will be called with two + * parameters: the callback type, and parameters. The implemented + * callback types are: + * + * 'setup' called at the very beginning, parameter is a UI object + * that should be used for all output + * 'message' the parameter is a string with an informational message + * 'saveas' may be used to save with a different file name, the + * parameter is the filename that is about to be used. + * If a 'saveas' callback returns a non-empty string, + * that file name will be used as the filename instead. + * Note that $save_dir will not be affected by this, only + * the basename of the file. + * 'start' download is starting, parameter is number of bytes + * that are expected, or -1 if unknown + * 'bytesread' parameter is the number of bytes read so far + * 'done' download is complete, parameter is the total number + * of bytes read + * 'connfailed' if the TCP connection fails, this callback is called + * with array(host,port,errno,errmsg) + * 'writefailed' if writing to disk fails, this callback is called + * with array(destfile,errmsg) + * + * If an HTTP proxy has been configured (http_proxy PEAR_Config + * setting), the proxy will be used. + * + * @param string $url the URL to download + * @param object $ui PEAR_Frontend_* instance + * @param object $config PEAR_Config instance + * @param string $save_dir (optional) directory to save file in + * @param mixed $callback (optional) function/method to call for status + * updates + * + * @return string Returns the full path of the downloaded file or a PEAR + * error on failure. If the error is caused by + * socket-related errors, the error object will + * have the fsockopen error code available through + * getCode(). + * + * @access public + * @deprecated in favor of PEAR_Downloader::downloadHttp() + */ + function downloadHttp($url, &$ui, $save_dir = '.', $callback = null) + { + if (!class_exists('PEAR_Downloader')) { + require_once 'PEAR/Downloader.php'; + } + return PEAR_Downloader::downloadHttp($url, $ui, $save_dir, $callback); + } +} + +require_once 'PEAR/Config.php'; +require_once 'PEAR/PackageFile.php'; \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Config.php b/typo3conf/ext/phpunit/PEAR/PEAR/Config.php new file mode 100644 index 0000000..eade943 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Config.php @@ -0,0 +1,2097 @@ + + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Config.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * Required for error handling + */ +require_once 'PEAR.php'; +require_once 'PEAR/Registry.php'; +require_once 'PEAR/Installer/Role.php'; +require_once 'System.php'; + +/** + * Last created PEAR_Config instance. + * @var object + */ +$GLOBALS['_PEAR_Config_instance'] = null; +if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) { + $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear'; +} else { + $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR; +} + +// Below we define constants with default values for all configuration +// parameters except username/password. All of them can have their +// defaults set through environment variables. The reason we use the +// PHP_ prefix is for some security, PHP protects environment +// variables starting with PHP_*. + +// default channel and preferred mirror is based on whether we are invoked through +// the "pear" or the "pecl" command +if (!defined('PEAR_RUNTYPE')) { + define('PEAR_RUNTYPE', 'pear'); +} + +if (PEAR_RUNTYPE == 'pear') { + define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net'); +} else { + define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net'); +} + +if (getenv('PHP_PEAR_SYSCONF_DIR')) { + define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR')); +} elseif (getenv('SystemRoot')) { + define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot')); +} else { + define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR); +} + +// Default for master_server +if (getenv('PHP_PEAR_MASTER_SERVER')) { + define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER')); +} else { + define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net'); +} + +// Default for http_proxy +if (getenv('PHP_PEAR_HTTP_PROXY')) { + define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY')); +} elseif (getenv('http_proxy')) { + define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy')); +} else { + define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', ''); +} + +// Default for php_dir +if (getenv('PHP_PEAR_INSTALL_DIR')) { + define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR')); +} else { + if (@file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) { + define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); + } else { + define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); + } +} + +// Default for ext_dir +if (getenv('PHP_PEAR_EXTENSION_DIR')) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR')); +} else { + if (ini_get('extension_dir')) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir')); + } elseif (defined('PEAR_EXTENSION_DIR') && + file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR); + } elseif (defined('PHP_EXTENSION_DIR')) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR); + } else { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.'); + } +} + +// Default for doc_dir +if (getenv('PHP_PEAR_DOC_DIR')) { + define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_DOC_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs'); +} + +// Default for bin_dir +if (getenv('PHP_PEAR_BIN_DIR')) { + define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR); +} + +// Default for data_dir +if (getenv('PHP_PEAR_DATA_DIR')) { + define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_DATA_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data'); +} + +// Default for cfg_dir +if (getenv('PHP_PEAR_CFG_DIR')) { + define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_CFG_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg'); +} + +// Default for www_dir +if (getenv('PHP_PEAR_WWW_DIR')) { + define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_WWW_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www'); +} + +// Default for test_dir +if (getenv('PHP_PEAR_TEST_DIR')) { + define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_TEST_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests'); +} + +// Default for temp_dir +if (getenv('PHP_PEAR_TEMP_DIR')) { + define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_TEMP_DIR', + System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . + DIRECTORY_SEPARATOR . 'temp'); +} + +// Default for cache_dir +if (getenv('PHP_PEAR_CACHE_DIR')) { + define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_CACHE_DIR', + System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . + DIRECTORY_SEPARATOR . 'cache'); +} + +// Default for download_dir +if (getenv('PHP_PEAR_DOWNLOAD_DIR')) { + define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', + System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . + DIRECTORY_SEPARATOR . 'download'); +} + +// Default for php_bin +if (getenv('PHP_PEAR_PHP_BIN')) { + define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN')); +} else { + define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR. + DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : '')); +} + +// Default for verbose +if (getenv('PHP_PEAR_VERBOSE')) { + define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE')); +} else { + define('PEAR_CONFIG_DEFAULT_VERBOSE', 1); +} + +// Default for preferred_state +if (getenv('PHP_PEAR_PREFERRED_STATE')) { + define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE')); +} else { + define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable'); +} + +// Default for umask +if (getenv('PHP_PEAR_UMASK')) { + define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK')); +} else { + define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask())); +} + +// Default for cache_ttl +if (getenv('PHP_PEAR_CACHE_TTL')) { + define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL')); +} else { + define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600); +} + +// Default for sig_type +if (getenv('PHP_PEAR_SIG_TYPE')) { + define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE')); +} else { + define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg'); +} + +// Default for sig_bin +if (getenv('PHP_PEAR_SIG_BIN')) { + define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN')); +} else { + define('PEAR_CONFIG_DEFAULT_SIG_BIN', + System::which( + 'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg')); +} + +// Default for sig_keydir +if (getenv('PHP_PEAR_SIG_KEYDIR')) { + define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR')); +} else { + define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', + PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys'); +} + +/** + * This is a class for storing configuration data, keeping track of + * which are system-defined, user-defined or defaulted. + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Config extends PEAR +{ + /** + * Array of config files used. + * + * @var array layer => config file + */ + var $files = array( + 'system' => '', + 'user' => '', + ); + + var $layers = array(); + + /** + * Configuration data, two-dimensional array where the first + * dimension is the config layer ('user', 'system' and 'default'), + * and the second dimension is keyname => value. + * + * The order in the first dimension is important! Earlier + * layers will shadow later ones when a config value is + * requested (if a 'user' value exists, it will be returned first, + * then 'system' and finally 'default'). + * + * @var array layer => array(keyname => value, ...) + */ + var $configuration = array( + 'user' => array(), + 'system' => array(), + 'default' => array(), + ); + + /** + * Configuration values that can be set for a channel + * + * All other configuration values can only have a global value + * @var array + * @access private + */ + var $_channelConfigInfo = array( + 'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'cfg_dir', + 'test_dir', 'www_dir', 'php_bin', 'php_prefix', 'php_suffix', 'username', + 'password', 'verbose', 'preferred_state', 'umask', 'preferred_mirror', 'php_ini' + ); + + /** + * Channels that can be accessed + * @see setChannels() + * @var array + * @access private + */ + var $_channels = array('pear.php.net', 'pecl.php.net', '__uri'); + + /** + * This variable is used to control the directory values returned + * @see setInstallRoot(); + * @var string|false + * @access private + */ + var $_installRoot = false; + + /** + * If requested, this will always refer to the registry + * contained in php_dir + * @var PEAR_Registry + */ + var $_registry = array(); + + /** + * @var array + * @access private + */ + var $_regInitialized = array(); + + /** + * @var bool + * @access private + */ + var $_noRegistry = false; + + /** + * amount of errors found while parsing config + * @var integer + * @access private + */ + var $_errorsFound = 0; + var $_lastError = null; + + /** + * Information about the configuration data. Stores the type, + * default value and a documentation string for each configuration + * value. + * + * @var array layer => array(infotype => value, ...) + */ + var $configuration_info = array( + // Channels/Internet Access + 'default_channel' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, + 'doc' => 'the default channel to use for all non explicit commands', + 'prompt' => 'Default Channel', + 'group' => 'Internet Access', + ), + 'preferred_mirror' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, + 'doc' => 'the default server or mirror to use for channel actions', + 'prompt' => 'Default Channel Mirror', + 'group' => 'Internet Access', + ), + 'remote_config' => array( + 'type' => 'password', + 'default' => '', + 'doc' => 'ftp url of remote configuration file to use for synchronized install', + 'prompt' => 'Remote Configuration File', + 'group' => 'Internet Access', + ), + 'auto_discover' => array( + 'type' => 'integer', + 'default' => 0, + 'doc' => 'whether to automatically discover new channels', + 'prompt' => 'Auto-discover new Channels', + 'group' => 'Internet Access', + ), + // Internet Access + 'master_server' => array( + 'type' => 'string', + 'default' => 'pear.php.net', + 'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]', + 'prompt' => 'PEAR server [DEPRECATED]', + 'group' => 'Internet Access', + ), + 'http_proxy' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY, + 'doc' => 'HTTP proxy (host:port) to use when downloading packages', + 'prompt' => 'HTTP Proxy Server Address', + 'group' => 'Internet Access', + ), + // File Locations + 'php_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_PHP_DIR, + 'doc' => 'directory where .php files are installed', + 'prompt' => 'PEAR directory', + 'group' => 'File Locations', + ), + 'ext_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_EXT_DIR, + 'doc' => 'directory where loadable extensions are installed', + 'prompt' => 'PHP extension directory', + 'group' => 'File Locations', + ), + 'doc_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_DOC_DIR, + 'doc' => 'directory where documentation is installed', + 'prompt' => 'PEAR documentation directory', + 'group' => 'File Locations', + ), + 'bin_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_BIN_DIR, + 'doc' => 'directory where executables are installed', + 'prompt' => 'PEAR executables directory', + 'group' => 'File Locations', + ), + 'data_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_DATA_DIR, + 'doc' => 'directory where data files are installed', + 'prompt' => 'PEAR data directory', + 'group' => 'File Locations (Advanced)', + ), + 'cfg_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_CFG_DIR, + 'doc' => 'directory where modifiable configuration files are installed', + 'prompt' => 'PEAR configuration file directory', + 'group' => 'File Locations (Advanced)', + ), + 'www_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_WWW_DIR, + 'doc' => 'directory where www frontend files (html/js) are installed', + 'prompt' => 'PEAR www files directory', + 'group' => 'File Locations (Advanced)', + ), + 'test_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_TEST_DIR, + 'doc' => 'directory where regression tests are installed', + 'prompt' => 'PEAR test directory', + 'group' => 'File Locations (Advanced)', + ), + 'cache_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR, + 'doc' => 'directory which is used for web service cache', + 'prompt' => 'PEAR Installer cache directory', + 'group' => 'File Locations (Advanced)', + ), + 'temp_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR, + 'doc' => 'directory which is used for all temp files', + 'prompt' => 'PEAR Installer temp directory', + 'group' => 'File Locations (Advanced)', + ), + 'download_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR, + 'doc' => 'directory which is used for all downloaded files', + 'prompt' => 'PEAR Installer download directory', + 'group' => 'File Locations (Advanced)', + ), + 'php_bin' => array( + 'type' => 'file', + 'default' => PEAR_CONFIG_DEFAULT_PHP_BIN, + 'doc' => 'PHP CLI/CGI binary for executing scripts', + 'prompt' => 'PHP CLI/CGI binary', + 'group' => 'File Locations (Advanced)', + ), + 'php_prefix' => array( + 'type' => 'string', + 'default' => '', + 'doc' => '--program-prefix for php_bin\'s ./configure, used for pecl installs', + 'prompt' => '--program-prefix passed to PHP\'s ./configure', + 'group' => 'File Locations (Advanced)', + ), + 'php_suffix' => array( + 'type' => 'string', + 'default' => '', + 'doc' => '--program-suffix for php_bin\'s ./configure, used for pecl installs', + 'prompt' => '--program-suffix passed to PHP\'s ./configure', + 'group' => 'File Locations (Advanced)', + ), + 'php_ini' => array( + 'type' => 'file', + 'default' => '', + 'doc' => 'location of php.ini in which to enable PECL extensions on install', + 'prompt' => 'php.ini location', + 'group' => 'File Locations (Advanced)', + ), + // Maintainers + 'username' => array( + 'type' => 'string', + 'default' => '', + 'doc' => '(maintainers) your PEAR account name', + 'prompt' => 'PEAR username (for maintainers)', + 'group' => 'Maintainers', + ), + 'password' => array( + 'type' => 'password', + 'default' => '', + 'doc' => '(maintainers) your PEAR account password', + 'prompt' => 'PEAR password (for maintainers)', + 'group' => 'Maintainers', + ), + // Advanced + 'verbose' => array( + 'type' => 'integer', + 'default' => PEAR_CONFIG_DEFAULT_VERBOSE, + 'doc' => 'verbosity level +0: really quiet +1: somewhat quiet +2: verbose +3: debug', + 'prompt' => 'Debug Log Level', + 'group' => 'Advanced', + ), + 'preferred_state' => array( + 'type' => 'set', + 'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE, + 'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified', + 'valid_set' => array( + 'stable', 'beta', 'alpha', 'devel', 'snapshot'), + 'prompt' => 'Preferred Package State', + 'group' => 'Advanced', + ), + 'umask' => array( + 'type' => 'mask', + 'default' => PEAR_CONFIG_DEFAULT_UMASK, + 'doc' => 'umask used when creating files (Unix-like systems only)', + 'prompt' => 'Unix file mask', + 'group' => 'Advanced', + ), + 'cache_ttl' => array( + 'type' => 'integer', + 'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL, + 'doc' => 'amount of secs where the local cache is used and not updated', + 'prompt' => 'Cache TimeToLive', + 'group' => 'Advanced', + ), + 'sig_type' => array( + 'type' => 'set', + 'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE, + 'doc' => 'which package signature mechanism to use', + 'valid_set' => array('gpg'), + 'prompt' => 'Package Signature Type', + 'group' => 'Maintainers', + ), + 'sig_bin' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_SIG_BIN, + 'doc' => 'which package signature mechanism to use', + 'prompt' => 'Signature Handling Program', + 'group' => 'Maintainers', + ), + 'sig_keyid' => array( + 'type' => 'string', + 'default' => '', + 'doc' => 'which key to use for signing with', + 'prompt' => 'Signature Key Id', + 'group' => 'Maintainers', + ), + 'sig_keydir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR, + 'doc' => 'directory where signature keys are located', + 'prompt' => 'Signature Key Directory', + 'group' => 'Maintainers', + ), + // __channels is reserved - used for channel-specific configuration + ); + + /** + * Constructor. + * + * @param string file to read user-defined options from + * @param string file to read system-wide defaults from + * @param bool determines whether a registry object "follows" + * the value of php_dir (is automatically created + * and moved when php_dir is changed) + * @param bool if true, fails if configuration files cannot be loaded + * + * @access public + * + * @see PEAR_Config::singleton + */ + function PEAR_Config($user_file = '', $system_file = '', $ftp_file = false, + $strict = true) + { + $this->PEAR(); + PEAR_Installer_Role::initializeConfig($this); + $sl = DIRECTORY_SEPARATOR; + if (empty($user_file)) { + if (OS_WINDOWS) { + $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini'; + } else { + $user_file = getenv('HOME') . $sl . '.pearrc'; + } + } + + if (empty($system_file)) { + $system_file = PEAR_CONFIG_SYSCONFDIR . $sl; + if (OS_WINDOWS) { + $system_file .= 'pearsys.ini'; + } else { + $system_file .= 'pear.conf'; + } + } + + $this->layers = array_keys($this->configuration); + $this->files['user'] = $user_file; + $this->files['system'] = $system_file; + if ($user_file && file_exists($user_file)) { + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $this->readConfigFile($user_file, 'user', $strict); + $this->popErrorHandling(); + if ($this->_errorsFound > 0) { + return; + } + } + + if ($system_file && @file_exists($system_file)) { + $this->mergeConfigFile($system_file, false, 'system', $strict); + if ($this->_errorsFound > 0) { + return; + } + + } + + if (!$ftp_file) { + $ftp_file = $this->get('remote_config'); + } + + if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) { + $this->readFTPConfigFile($ftp_file); + } + + foreach ($this->configuration_info as $key => $info) { + $this->configuration['default'][$key] = $info['default']; + } + + $this->_registry['default'] = &new PEAR_Registry($this->configuration['default']['php_dir']); + $this->_registry['default']->setConfig($this, false); + $this->_regInitialized['default'] = false; + //$GLOBALS['_PEAR_Config_instance'] = &$this; + } + + /** + * Return the default locations of user and system configuration files + * @static + */ + function getDefaultConfigFiles() + { + $sl = DIRECTORY_SEPARATOR; + if (OS_WINDOWS) { + return array( + 'user' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini', + 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini' + ); + } + + return array( + 'user' => getenv('HOME') . $sl . '.pearrc', + 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf' + ); + } + + /** + * Static singleton method. If you want to keep only one instance + * of this class in use, this method will give you a reference to + * the last created PEAR_Config object if one exists, or create a + * new object. + * + * @param string (optional) file to read user-defined options from + * @param string (optional) file to read system-wide defaults from + * + * @return object an existing or new PEAR_Config instance + * + * @access public + * + * @see PEAR_Config::PEAR_Config + */ + function &singleton($user_file = '', $system_file = '', $strict = true) + { + if (is_object($GLOBALS['_PEAR_Config_instance'])) { + return $GLOBALS['_PEAR_Config_instance']; + } + + $t_conf = &new PEAR_Config($user_file, $system_file, false, $strict); + if ($t_conf->_errorsFound > 0) { + return $t_conf->lastError; + } + + $GLOBALS['_PEAR_Config_instance'] = &$t_conf; + return $GLOBALS['_PEAR_Config_instance']; + } + + /** + * Determine whether any configuration files have been detected, and whether a + * registry object can be retrieved from this configuration. + * @return bool + * @since PEAR 1.4.0a1 + */ + function validConfiguration() + { + if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) { + return true; + } + + return false; + } + + /** + * Reads configuration data from a file. All existing values in + * the config layer are discarded and replaced with data from the + * file. + * @param string file to read from, if NULL or not specified, the + * last-used file for the same layer (second param) is used + * @param string config layer to insert data into ('user' or 'system') + * @return bool TRUE on success or a PEAR error on failure + */ + function readConfigFile($file = null, $layer = 'user', $strict = true) + { + if (empty($this->files[$layer])) { + return $this->raiseError("unknown config layer `$layer'"); + } + + if ($file === null) { + $file = $this->files[$layer]; + } + + $data = $this->_readConfigDataFrom($file); + if (PEAR::isError($data)) { + if (!$strict) { + return true; + } + + $this->_errorsFound++; + $this->lastError = $data; + + return $data; + } + + $this->files[$layer] = $file; + $this->_decodeInput($data); + $this->configuration[$layer] = $data; + $this->_setupChannels(); + if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { + $this->_registry[$layer] = &new PEAR_Registry($phpdir); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; + } else { + unset($this->_registry[$layer]); + } + return true; + } + + /** + * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini + * @return true|PEAR_Error + */ + function readFTPConfigFile($path) + { + do { // poor man's try + if (!class_exists('PEAR_FTP')) { + if (!class_exists('PEAR_Common')) { + require_once 'PEAR/Common.php'; + } + if (PEAR_Common::isIncludeable('PEAR/FTP.php')) { + require_once 'PEAR/FTP.php'; + } + } + + if (!class_exists('PEAR_FTP')) { + return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config'); + } + + $this->_ftp = &new PEAR_FTP; + $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN); + $e = $this->_ftp->init($path); + if (PEAR::isError($e)) { + $this->_ftp->popErrorHandling(); + return $e; + } + + $tmp = System::mktemp('-d'); + PEAR_Common::addTempFile($tmp); + $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR . + 'pear.ini', false, FTP_BINARY); + if (PEAR::isError($e)) { + $this->_ftp->popErrorHandling(); + return $e; + } + + PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini'); + $this->_ftp->disconnect(); + $this->_ftp->popErrorHandling(); + $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini'; + $e = $this->readConfigFile(null, 'ftp'); + if (PEAR::isError($e)) { + return $e; + } + + $fail = array(); + foreach ($this->configuration_info as $key => $val) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + // any directory configs must be set for this to work + if (!isset($this->configuration['ftp'][$key])) { + $fail[] = $key; + } + } + } + + if (!count($fail)) { + return true; + } + + $fail = '"' . implode('", "', $fail) . '"'; + unset($this->files['ftp']); + unset($this->configuration['ftp']); + return PEAR::raiseError('ERROR: Ftp configuration file must set all ' . + 'directory configuration variables. These variables were not set: ' . + $fail); + } while (false); // poor man's catch + unset($this->files['ftp']); + return PEAR::raiseError('no remote host specified'); + } + + /** + * Reads the existing configurations and creates the _channels array from it + */ + function _setupChannels() + { + $set = array_flip(array_values($this->_channels)); + foreach ($this->configuration as $layer => $data) { + $i = 1000; + if (isset($data['__channels']) && is_array($data['__channels'])) { + foreach ($data['__channels'] as $channel => $info) { + $set[$channel] = $i++; + } + } + } + $this->_channels = array_values(array_flip($set)); + $this->setChannels($this->_channels); + } + + function deleteChannel($channel) + { + $ch = strtolower($channel); + foreach ($this->configuration as $layer => $data) { + if (isset($data['__channels']) && isset($data['__channels'][$ch])) { + unset($this->configuration[$layer]['__channels'][$ch]); + } + } + + $this->_channels = array_flip($this->_channels); + unset($this->_channels[$ch]); + $this->_channels = array_flip($this->_channels); + } + + /** + * Merges data into a config layer from a file. Does the same + * thing as readConfigFile, except it does not replace all + * existing values in the config layer. + * @param string file to read from + * @param bool whether to overwrite existing data (default TRUE) + * @param string config layer to insert data into ('user' or 'system') + * @param string if true, errors are returned if file opening fails + * @return bool TRUE on success or a PEAR error on failure + */ + function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true) + { + if (empty($this->files[$layer])) { + return $this->raiseError("unknown config layer `$layer'"); + } + + if ($file === null) { + $file = $this->files[$layer]; + } + + $data = $this->_readConfigDataFrom($file); + if (PEAR::isError($data)) { + if (!$strict) { + return true; + } + + $this->_errorsFound++; + $this->lastError = $data; + + return $data; + } + + $this->_decodeInput($data); + if ($override) { + $this->configuration[$layer] = + PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data); + } else { + $this->configuration[$layer] = + PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]); + } + + $this->_setupChannels(); + if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { + $this->_registry[$layer] = &new PEAR_Registry($phpdir); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; + } else { + unset($this->_registry[$layer]); + } + return true; + } + + /** + * @param array + * @param array + * @return array + * @static + */ + function arrayMergeRecursive($arr2, $arr1) + { + $ret = array(); + foreach ($arr2 as $key => $data) { + if (!isset($arr1[$key])) { + $ret[$key] = $data; + unset($arr1[$key]); + continue; + } + if (is_array($data)) { + if (!is_array($arr1[$key])) { + $ret[$key] = $arr1[$key]; + unset($arr1[$key]); + continue; + } + $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]); + unset($arr1[$key]); + } + } + + return array_merge($ret, $arr1); + } + + /** + * Writes data into a config layer from a file. + * + * @param string|null file to read from, or null for default + * @param string config layer to insert data into ('user' or + * 'system') + * @param string|null data to write to config file or null for internal data [DEPRECATED] + * @return bool TRUE on success or a PEAR error on failure + */ + function writeConfigFile($file = null, $layer = 'user', $data = null) + { + $this->_lazyChannelSetup($layer); + if ($layer == 'both' || $layer == 'all') { + foreach ($this->files as $type => $file) { + $err = $this->writeConfigFile($file, $type, $data); + if (PEAR::isError($err)) { + return $err; + } + } + return true; + } + + if (empty($this->files[$layer])) { + return $this->raiseError("unknown config file type `$layer'"); + } + + if ($file === null) { + $file = $this->files[$layer]; + } + + $data = ($data === null) ? $this->configuration[$layer] : $data; + $this->_encodeOutput($data); + $opt = array('-p', dirname($file)); + if (!@System::mkDir($opt)) { + return $this->raiseError("could not create directory: " . dirname($file)); + } + + if (file_exists($file) && is_file($file) && !is_writeable($file)) { + return $this->raiseError("no write access to $file!"); + } + + $fp = @fopen($file, "w"); + if (!$fp) { + return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)"); + } + + $contents = "#PEAR_Config 0.9\n" . serialize($data); + if (!@fwrite($fp, $contents)) { + return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)"); + } + return true; + } + + /** + * Reads configuration data from a file and returns the parsed data + * in an array. + * + * @param string file to read from + * @return array configuration data or a PEAR error on failure + * @access private + */ + function _readConfigDataFrom($file) + { + $fp = false; + if (file_exists($file)) { + $fp = @fopen($file, "r"); + } + + if (!$fp) { + return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed"); + } + + $size = filesize($file); + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + fclose($fp); + $contents = file_get_contents($file); + if (empty($contents)) { + return $this->raiseError('Configuration file "' . $file . '" is empty'); + } + + set_magic_quotes_runtime($rt); + + $version = false; + if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) { + $version = $matches[1]; + $contents = substr($contents, strlen($matches[0])); + } else { + // Museum config file + if (substr($contents,0,2) == 'a:') { + $version = '0.1'; + } + } + + if ($version && version_compare("$version", '1', '<')) { + // no '@', it is possible that unserialize + // raises a notice but it seems to block IO to + // STDOUT if a '@' is used and a notice is raise + $data = unserialize($contents); + + if (!is_array($data) && !$data) { + if ($contents == serialize(false)) { + $data = array(); + } else { + $err = $this->raiseError("PEAR_Config: bad data in $file"); + return $err; + } + } + if (!is_array($data)) { + if (strlen(trim($contents)) > 0) { + $error = "PEAR_Config: bad data in $file"; + $err = $this->raiseError($error); + return $err; + } + + $data = array(); + } + // add parsing of newer formats here... + } else { + $err = $this->raiseError("$file: unknown version `$version'"); + return $err; + } + + return $data; + } + + /** + * Gets the file used for storing the config for a layer + * + * @param string $layer 'user' or 'system' + */ + function getConfFile($layer) + { + return $this->files[$layer]; + } + + /** + * @param string Configuration class name, used for detecting duplicate calls + * @param array information on a role as parsed from its xml file + * @return true|PEAR_Error + * @access private + */ + function _addConfigVars($class, $vars) + { + static $called = array(); + if (isset($called[$class])) { + return; + } + + $called[$class] = 1; + if (count($vars) > 3) { + return $this->raiseError('Roles can only define 3 new config variables or less'); + } + + foreach ($vars as $name => $var) { + if (!is_array($var)) { + return $this->raiseError('Configuration information must be an array'); + } + + if (!isset($var['type'])) { + return $this->raiseError('Configuration information must contain a type'); + } elseif (!in_array($var['type'], + array('string', 'mask', 'password', 'directory', 'file', 'set'))) { + return $this->raiseError( + 'Configuration type must be one of directory, file, string, ' . + 'mask, set, or password'); + } + if (!isset($var['default'])) { + return $this->raiseError( + 'Configuration information must contain a default value ("default" index)'); + } + + if (is_array($var['default'])) { + $real_default = ''; + foreach ($var['default'] as $config_var => $val) { + if (strpos($config_var, 'text') === 0) { + $real_default .= $val; + } elseif (strpos($config_var, 'constant') === 0) { + if (!defined($val)) { + return $this->raiseError( + 'Unknown constant "' . $val . '" requested in ' . + 'default value for configuration variable "' . + $name . '"'); + } + + $real_default .= constant($val); + } elseif (isset($this->configuration_info[$config_var])) { + $real_default .= + $this->configuration_info[$config_var]['default']; + } else { + return $this->raiseError( + 'Unknown request for "' . $config_var . '" value in ' . + 'default value for configuration variable "' . + $name . '"'); + } + } + $var['default'] = $real_default; + } + + if ($var['type'] == 'integer') { + $var['default'] = (integer) $var['default']; + } + + if (!isset($var['doc'])) { + return $this->raiseError( + 'Configuration information must contain a summary ("doc" index)'); + } + + if (!isset($var['prompt'])) { + return $this->raiseError( + 'Configuration information must contain a simple prompt ("prompt" index)'); + } + + if (!isset($var['group'])) { + return $this->raiseError( + 'Configuration information must contain a simple group ("group" index)'); + } + + if (isset($this->configuration_info[$name])) { + return $this->raiseError('Configuration variable "' . $name . + '" already exists'); + } + + $this->configuration_info[$name] = $var; + // fix bug #7351: setting custom config variable in a channel fails + $this->_channelConfigInfo[] = $name; + } + + return true; + } + + /** + * Encodes/scrambles configuration data before writing to files. + * Currently, 'password' values will be base64-encoded as to avoid + * that people spot cleartext passwords by accident. + * + * @param array (reference) array to encode values in + * @return bool TRUE on success + * @access private + */ + function _encodeOutput(&$data) + { + foreach ($data as $key => $value) { + if ($key == '__channels') { + foreach ($data['__channels'] as $channel => $blah) { + $this->_encodeOutput($data['__channels'][$channel]); + } + } + + if (!isset($this->configuration_info[$key])) { + continue; + } + + $type = $this->configuration_info[$key]['type']; + switch ($type) { + // we base64-encode passwords so they are at least + // not shown in plain by accident + case 'password': { + $data[$key] = base64_encode($data[$key]); + break; + } + case 'mask': { + $data[$key] = octdec($data[$key]); + break; + } + } + } + + return true; + } + + /** + * Decodes/unscrambles configuration data after reading from files. + * + * @param array (reference) array to encode values in + * @return bool TRUE on success + * @access private + * + * @see PEAR_Config::_encodeOutput + */ + function _decodeInput(&$data) + { + if (!is_array($data)) { + return true; + } + + foreach ($data as $key => $value) { + if ($key == '__channels') { + foreach ($data['__channels'] as $channel => $blah) { + $this->_decodeInput($data['__channels'][$channel]); + } + } + + if (!isset($this->configuration_info[$key])) { + continue; + } + + $type = $this->configuration_info[$key]['type']; + switch ($type) { + case 'password': { + $data[$key] = base64_decode($data[$key]); + break; + } + case 'mask': { + $data[$key] = decoct($data[$key]); + break; + } + } + } + + return true; + } + + /** + * Retrieve the default channel. + * + * On startup, channels are not initialized, so if the default channel is not + * pear.php.net, then initialize the config. + * @param string registry layer + * @return string|false + */ + function getDefaultChannel($layer = null) + { + $ret = false; + if ($layer === null) { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer]['default_channel'])) { + $ret = $this->configuration[$layer]['default_channel']; + break; + } + } + } elseif (isset($this->configuration[$layer]['default_channel'])) { + $ret = $this->configuration[$layer]['default_channel']; + } + + if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') { + $ret = 'pecl.php.net'; + } + + if ($ret) { + if ($ret != 'pear.php.net') { + $this->_lazyChannelSetup(); + } + + return $ret; + } + + return PEAR_CONFIG_DEFAULT_CHANNEL; + } + + /** + * Returns a configuration value, prioritizing layers as per the + * layers property. + * + * @param string config key + * @return mixed the config value, or NULL if not found + * @access public + */ + function get($key, $layer = null, $channel = false) + { + if (!isset($this->configuration_info[$key])) { + return null; + } + + if ($key == '__channels') { + return null; + } + + if ($key == 'default_channel') { + return $this->getDefaultChannel($layer); + } + + if (!$channel) { + $channel = $this->getDefaultChannel(); + } elseif ($channel != 'pear.php.net') { + $this->_lazyChannelSetup(); + } + $channel = strtolower($channel); + + $test = (in_array($key, $this->_channelConfigInfo)) ? + $this->_getChannelValue($key, $layer, $channel) : + null; + if ($test !== null) { + if ($this->_installRoot) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + return $this->_prependPath($test, $this->_installRoot); + } + } + return $test; + } + + if ($layer === null) { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer][$key])) { + $test = $this->configuration[$layer][$key]; + if ($this->_installRoot) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + return $this->_prependPath($test, $this->_installRoot); + } + } + + if ($key == 'preferred_mirror') { + $reg = &$this->getRegistry(); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $channel; + } + + if (!$chan->getMirror($test) && $chan->getName() != $test) { + return $channel; // mirror does not exist + } + } + } + return $test; + } + } + } elseif (isset($this->configuration[$layer][$key])) { + $test = $this->configuration[$layer][$key]; + if ($this->_installRoot) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + return $this->_prependPath($test, $this->_installRoot); + } + } + + if ($key == 'preferred_mirror') { + $reg = &$this->getRegistry(); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $channel; + } + + if (!$chan->getMirror($test) && $chan->getName() != $test) { + return $channel; // mirror does not exist + } + } + } + + return $test; + } + + return null; + } + + /** + * Returns a channel-specific configuration value, prioritizing layers as per the + * layers property. + * + * @param string config key + * @return mixed the config value, or NULL if not found + * @access private + */ + function _getChannelValue($key, $layer, $channel) + { + if ($key == '__channels' || $channel == 'pear.php.net') { + return null; + } + + $ret = null; + if ($layer === null) { + foreach ($this->layers as $ilayer) { + if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) { + $ret = $this->configuration[$ilayer]['__channels'][$channel][$key]; + break; + } + } + } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) { + $ret = $this->configuration[$layer]['__channels'][$channel][$key]; + } + + if ($key != 'preferred_mirror') { + return $ret; + } + + + if ($ret !== null) { + $reg = &$this->getRegistry($layer); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $channel; + } + + if (!$chan->getMirror($ret) && $chan->getName() != $ret) { + return $channel; // mirror does not exist + } + } + + return $ret; + } + + if ($channel != $this->getDefaultChannel($layer)) { + return $channel; // we must use the channel name as the preferred mirror + // if the user has not chosen an alternate + } + + return $this->getDefaultChannel($layer); + } + + /** + * Set a config value in a specific layer (defaults to 'user'). + * Enforces the types defined in the configuration_info array. An + * integer config variable will be cast to int, and a set config + * variable will be validated against its legal values. + * + * @param string config key + * @param string config value + * @param string (optional) config layer + * @param string channel to set this value for, or null for global value + * @return bool TRUE on success, FALSE on failure + */ + function set($key, $value, $layer = 'user', $channel = false) + { + if ($key == '__channels') { + return false; + } + + if (!isset($this->configuration[$layer])) { + return false; + } + + if ($key == 'default_channel') { + // can only set this value globally + $channel = 'pear.php.net'; + if ($value != 'pear.php.net') { + $this->_lazyChannelSetup($layer); + } + } + + if ($key == 'preferred_mirror') { + if ($channel == '__uri') { + return false; // can't set the __uri pseudo-channel's mirror + } + + $reg = &$this->getRegistry($layer); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel ? $channel : 'pear.php.net'); + if (PEAR::isError($chan)) { + return false; + } + + if (!$chan->getMirror($value) && $chan->getName() != $value) { + return false; // mirror does not exist + } + } + } + + if (!isset($this->configuration_info[$key])) { + return false; + } + + extract($this->configuration_info[$key]); + switch ($type) { + case 'integer': + $value = (int)$value; + break; + case 'set': { + // If a valid_set is specified, require the value to + // be in the set. If there is no valid_set, accept + // any value. + if ($valid_set) { + reset($valid_set); + if ((key($valid_set) === 0 && !in_array($value, $valid_set)) || + (key($valid_set) !== 0 && empty($valid_set[$value]))) + { + return false; + } + } + break; + } + } + + if (!$channel) { + $channel = $this->get('default_channel', null, 'pear.php.net'); + } + + if (!in_array($channel, $this->_channels)) { + $this->_lazyChannelSetup($layer); + $reg = &$this->getRegistry($layer); + if ($reg) { + $channel = $reg->channelName($channel); + } + + if (!in_array($channel, $this->_channels)) { + return false; + } + } + + if ($channel != 'pear.php.net') { + if (in_array($key, $this->_channelConfigInfo)) { + $this->configuration[$layer]['__channels'][$channel][$key] = $value; + return true; + } + + return false; + } + + if ($key == 'default_channel') { + if (!isset($reg)) { + $reg = &$this->getRegistry($layer); + if (!$reg) { + $reg = &$this->getRegistry(); + } + } + + if ($reg) { + $value = $reg->channelName($value); + } + + if (!$value) { + return false; + } + } + + $this->configuration[$layer][$key] = $value; + if ($key == 'php_dir' && !$this->_noRegistry) { + if (!isset($this->_registry[$layer]) || + $value != $this->_registry[$layer]->install_dir) { + $this->_registry[$layer] = &new PEAR_Registry($value); + $this->_regInitialized[$layer] = false; + $this->_registry[$layer]->setConfig($this, false); + } + } + + return true; + } + + function _lazyChannelSetup($uselayer = false) + { + if ($this->_noRegistry) { + return; + } + + $merge = false; + foreach ($this->_registry as $layer => $p) { + if ($uselayer && $uselayer != $layer) { + continue; + } + + if (!$this->_regInitialized[$layer]) { + if ($layer == 'default' && isset($this->_registry['user']) || + isset($this->_registry['system'])) { + // only use the default registry if there are no alternatives + continue; + } + + if (!is_object($this->_registry[$layer])) { + if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) { + $this->_registry[$layer] = &new PEAR_Registry($phpdir); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; + } else { + unset($this->_registry[$layer]); + return; + } + } + + $this->setChannels($this->_registry[$layer]->listChannels(), $merge); + $this->_regInitialized[$layer] = true; + $merge = true; + } + } + } + + /** + * Set the list of channels. + * + * This should be set via a call to {@link PEAR_Registry::listChannels()} + * @param array + * @param bool + * @return bool success of operation + */ + function setChannels($channels, $merge = false) + { + if (!is_array($channels)) { + return false; + } + + if ($merge) { + $this->_channels = array_merge($this->_channels, $channels); + } else { + $this->_channels = $channels; + } + + foreach ($channels as $channel) { + $channel = strtolower($channel); + if ($channel == 'pear.php.net') { + continue; + } + + foreach ($this->layers as $layer) { + if (!isset($this->configuration[$layer]['__channels'])) { + $this->configuration[$layer]['__channels'] = array(); + } + if (!isset($this->configuration[$layer]['__channels'][$channel]) + || !is_array($this->configuration[$layer]['__channels'][$channel])) { + $this->configuration[$layer]['__channels'][$channel] = array(); + } + } + } + + return true; + } + + /** + * Get the type of a config value. + * + * @param string config key + * + * @return string type, one of "string", "integer", "file", + * "directory", "set" or "password". + * + * @access public + * + */ + function getType($key) + { + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['type']; + } + return false; + } + + /** + * Get the documentation for a config value. + * + * @param string config key + * @return string documentation string + * + * @access public + * + */ + function getDocs($key) + { + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['doc']; + } + + return false; + } + + /** + * Get the short documentation for a config value. + * + * @param string config key + * @return string short documentation string + * + * @access public + * + */ + function getPrompt($key) + { + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['prompt']; + } + + return false; + } + + /** + * Get the parameter group for a config key. + * + * @param string config key + * @return string parameter group + * + * @access public + * + */ + function getGroup($key) + { + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['group']; + } + + return false; + } + + /** + * Get the list of parameter groups. + * + * @return array list of parameter groups + * + * @access public + * + */ + function getGroups() + { + $tmp = array(); + foreach ($this->configuration_info as $key => $info) { + $tmp[$info['group']] = 1; + } + + return array_keys($tmp); + } + + /** + * Get the list of the parameters in a group. + * + * @param string $group parameter group + * @return array list of parameters in $group + * + * @access public + * + */ + function getGroupKeys($group) + { + $keys = array(); + foreach ($this->configuration_info as $key => $info) { + if ($info['group'] == $group) { + $keys[] = $key; + } + } + + return $keys; + } + + /** + * Get the list of allowed set values for a config value. Returns + * NULL for config values that are not sets. + * + * @param string config key + * @return array enumerated array of set values, or NULL if the + * config key is unknown or not a set + * + * @access public + * + */ + function getSetValues($key) + { + if (isset($this->configuration_info[$key]) && + isset($this->configuration_info[$key]['type']) && + $this->configuration_info[$key]['type'] == 'set') + { + $valid_set = $this->configuration_info[$key]['valid_set']; + reset($valid_set); + if (key($valid_set) === 0) { + return $valid_set; + } + + return array_keys($valid_set); + } + + return null; + } + + /** + * Get all the current config keys. + * + * @return array simple array of config keys + * + * @access public + */ + function getKeys() + { + $keys = array(); + foreach ($this->layers as $layer) { + $test = $this->configuration[$layer]; + if (isset($test['__channels'])) { + foreach ($test['__channels'] as $channel => $configs) { + $keys = array_merge($keys, $configs); + } + } + + unset($test['__channels']); + $keys = array_merge($keys, $test); + + } + return array_keys($keys); + } + + /** + * Remove the a config key from a specific config layer. + * + * @param string config key + * @param string (optional) config layer + * @param string (optional) channel (defaults to default channel) + * @return bool TRUE on success, FALSE on failure + * + * @access public + */ + function remove($key, $layer = 'user', $channel = null) + { + if ($channel === null) { + $channel = $this->getDefaultChannel(); + } + + if ($channel !== 'pear.php.net') { + if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { + unset($this->configuration[$layer]['__channels'][$channel][$key]); + return true; + } + } + + if (isset($this->configuration[$layer][$key])) { + unset($this->configuration[$layer][$key]); + return true; + } + + return false; + } + + /** + * Temporarily remove an entire config layer. USE WITH CARE! + * + * @param string config key + * @param string (optional) config layer + * @return bool TRUE on success, FALSE on failure + * + * @access public + */ + function removeLayer($layer) + { + if (isset($this->configuration[$layer])) { + $this->configuration[$layer] = array(); + return true; + } + + return false; + } + + /** + * Stores configuration data in a layer. + * + * @param string config layer to store + * @return bool TRUE on success, or PEAR error on failure + * + * @access public + */ + function store($layer = 'user', $data = null) + { + return $this->writeConfigFile(null, $layer, $data); + } + + /** + * Tells what config layer that gets to define a key. + * + * @param string config key + * @param boolean return the defining channel + * + * @return string|array the config layer, or an empty string if not found. + * + * if $returnchannel, the return is an array array('layer' => layername, + * 'channel' => channelname), or an empty string if not found + * + * @access public + */ + function definedBy($key, $returnchannel = false) + { + foreach ($this->layers as $layer) { + $channel = $this->getDefaultChannel(); + if ($channel !== 'pear.php.net') { + if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { + if ($returnchannel) { + return array('layer' => $layer, 'channel' => $channel); + } + return $layer; + } + } + + if (isset($this->configuration[$layer][$key])) { + if ($returnchannel) { + return array('layer' => $layer, 'channel' => 'pear.php.net'); + } + return $layer; + } + } + + return ''; + } + + /** + * Tells whether a given key exists as a config value. + * + * @param string config key + * @return bool whether exists in this object + * + * @access public + */ + function isDefined($key) + { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer][$key])) { + return true; + } + } + + return false; + } + + /** + * Tells whether a given config layer exists. + * + * @param string config layer + * @return bool whether exists in this object + * + * @access public + */ + function isDefinedLayer($layer) + { + return isset($this->configuration[$layer]); + } + + /** + * Returns the layers defined (except the 'default' one) + * + * @return array of the defined layers + */ + function getLayers() + { + $cf = $this->configuration; + unset($cf['default']); + return array_keys($cf); + } + + function apiVersion() + { + return '1.1'; + } + + /** + * @return PEAR_Registry + */ + function &getRegistry($use = null) + { + $layer = $use === null ? 'user' : $use; + if (isset($this->_registry[$layer])) { + return $this->_registry[$layer]; + } elseif ($use === null && isset($this->_registry['system'])) { + return $this->_registry['system']; + } elseif ($use === null && isset($this->_registry['default'])) { + return $this->_registry['default']; + } elseif ($use) { + $a = false; + return $a; + } + + // only go here if null was passed in + echo "CRITICAL ERROR: Registry could not be initialized from any value"; + exit(1); + } + + /** + * This is to allow customization like the use of installroot + * @param PEAR_Registry + * @return bool + */ + function setRegistry(&$reg, $layer = 'user') + { + if ($this->_noRegistry) { + return false; + } + + if (!in_array($layer, array('user', 'system'))) { + return false; + } + + $this->_registry[$layer] = &$reg; + if (is_object($reg)) { + $this->_registry[$layer]->setConfig($this, false); + } + + return true; + } + + function noRegistry() + { + $this->_noRegistry = true; + } + + /** + * @return PEAR_REST + */ + function &getREST($version, $options = array()) + { + $version = str_replace('.', '', $version); + if (!class_exists($class = 'PEAR_REST_' . $version)) { + require_once 'PEAR/REST/' . $version . '.php'; + } + + $remote = &new $class($this, $options); + return $remote; + } + + /** + * The ftp server is set in {@link readFTPConfigFile()}. It exists only if a + * remote configuration file has been specified + * @return PEAR_FTP|false + */ + function &getFTP() + { + if (isset($this->_ftp)) { + return $this->_ftp; + } + + $a = false; + return $a; + } + + function _prependPath($path, $prepend) + { + if (strlen($prepend) > 0) { + if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { + if (preg_match('/^[a-z]:/i', $prepend)) { + $prepend = substr($prepend, 2); + } elseif ($prepend{0} != '\\') { + $prepend = "\\$prepend"; + } + $path = substr($path, 0, 2) . $prepend . substr($path, 2); + } else { + $path = $prepend . $path; + } + } + return $path; + } + + /** + * @param string|false installation directory to prepend to all _dir variables, or false to + * disable + */ + function setInstallRoot($root) + { + if (substr($root, -1) == DIRECTORY_SEPARATOR) { + $root = substr($root, 0, -1); + } + $old = $this->_installRoot; + $this->_installRoot = $root; + if (($old != $root) && !$this->_noRegistry) { + foreach (array_keys($this->_registry) as $layer) { + if ($layer == 'ftp' || !isset($this->_registry[$layer])) { + continue; + } + $this->_registry[$layer] = + &new PEAR_Registry($this->get('php_dir', $layer, 'pear.php.net')); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; + } + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Dependency2.php b/typo3conf/ext/phpunit/PEAR/PEAR/Dependency2.php new file mode 100644 index 0000000..4405b3a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Dependency2.php @@ -0,0 +1,1358 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Dependency2.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Required for the PEAR_VALIDATE_* constants + */ +require_once 'PEAR/Validate.php'; + +/** + * Dependency check for PEAR packages + * + * This class handles both version 1.0 and 2.0 dependencies + * WARNING: *any* changes to this class must be duplicated in the + * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc, + * or unit tests will not actually validate the changes + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Dependency2 +{ + /** + * One of the PEAR_VALIDATE_* states + * @see PEAR_VALIDATE_NORMAL + * @var integer + */ + var $_state; + + /** + * Command-line options to install/upgrade/uninstall commands + * @param array + */ + var $_options; + + /** + * @var OS_Guess + */ + var $_os; + + /** + * @var PEAR_Registry + */ + var $_registry; + + /** + * @var PEAR_Config + */ + var $_config; + + /** + * @var PEAR_DependencyDB + */ + var $_dependencydb; + + /** + * Output of PEAR_Registry::parsedPackageName() + * @var array + */ + var $_currentPackage; + + /** + * @param PEAR_Config + * @param array installation options + * @param array format of PEAR_Registry::parsedPackageName() + * @param int installation state (one of PEAR_VALIDATE_*) + */ + function PEAR_Dependency2(&$config, $installoptions, $package, + $state = PEAR_VALIDATE_INSTALLING) + { + $this->_config = &$config; + if (!class_exists('PEAR_DependencyDB')) { + require_once 'PEAR/DependencyDB.php'; + } + + if (isset($installoptions['packagingroot'])) { + // make sure depdb is in the right location + $config->setInstallRoot($installoptions['packagingroot']); + } + + $this->_registry = &$config->getRegistry(); + $this->_dependencydb = &PEAR_DependencyDB::singleton($config); + if (isset($installoptions['packagingroot'])) { + $config->setInstallRoot(false); + } + + $this->_options = $installoptions; + $this->_state = $state; + if (!class_exists('OS_Guess')) { + require_once 'OS/Guess.php'; + } + + $this->_os = new OS_Guess; + $this->_currentPackage = $package; + } + + function _getExtraString($dep) + { + $extra = ' ('; + if (isset($dep['uri'])) { + return ''; + } + + if (isset($dep['recommended'])) { + $extra .= 'recommended version ' . $dep['recommended']; + } else { + if (isset($dep['min'])) { + $extra .= 'version >= ' . $dep['min']; + } + + if (isset($dep['max'])) { + if ($extra != ' (') { + $extra .= ', '; + } + $extra .= 'version <= ' . $dep['max']; + } + + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + + if ($extra != ' (') { + $extra .= ', '; + } + + $extra .= 'excluded versions: '; + foreach ($dep['exclude'] as $i => $exclude) { + if ($i) { + $extra .= ', '; + } + $extra .= $exclude; + } + } + } + + $extra .= ')'; + if ($extra == ' ()') { + $extra = ''; + } + + return $extra; + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function getPHP_OS() + { + return PHP_OS; + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function getsysname() + { + return $this->_os->getSysname(); + } + + /** + * Specify a dependency on an OS. Use arch for detailed os/processor information + * + * There are two generic OS dependencies that will be the most common, unix and windows. + * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix + */ + function validateOsDependency($dep) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING && $this->_state != PEAR_VALIDATE_DOWNLOADING) { + return true; + } + + if ($dep['name'] == '*') { + return true; + } + + $not = isset($dep['conflicts']) ? true : false; + switch (strtolower($dep['name'])) { + case 'windows' : + if ($not) { + if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError("Cannot install %s on Windows"); + } + + return $this->warning("warning: Cannot install %s on Windows"); + } + } else { + if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError("Can only install %s on Windows"); + } + + return $this->warning("warning: Can only install %s on Windows"); + } + } + break; + case 'unix' : + $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix'); + if ($not) { + if (in_array($this->getSysname(), $unices)) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError("Cannot install %s on any Unix system"); + } + + return $this->warning( "warning: Cannot install %s on any Unix system"); + } + } else { + if (!in_array($this->getSysname(), $unices)) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError("Can only install %s on a Unix system"); + } + + return $this->warning("warning: Can only install %s on a Unix system"); + } + } + break; + default : + if ($not) { + if (strtolower($dep['name']) == strtolower($this->getSysname())) { + if (!isset($this->_options['nodeps']) && + !isset($this->_options['force'])) { + return $this->raiseError('Cannot install %s on ' . $dep['name'] . + ' operating system'); + } + + return $this->warning('warning: Cannot install %s on ' . + $dep['name'] . ' operating system'); + } + } else { + if (strtolower($dep['name']) != strtolower($this->getSysname())) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('Cannot install %s on ' . + $this->getSysname() . + ' operating system, can only install on ' . $dep['name']); + } + + return $this->warning('warning: Cannot install %s on ' . + $this->getSysname() . + ' operating system, can only install on ' . $dep['name']); + } + } + } + return true; + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function matchSignature($pattern) + { + return $this->_os->matchSignature($pattern); + } + + /** + * Specify a complex dependency on an OS/processor/kernel version, + * Use OS for simple operating system dependency. + * + * This is the only dependency that accepts an eregable pattern. The pattern + * will be matched against the php_uname() output parsed by OS_Guess + */ + function validateArchDependency($dep) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING) { + return true; + } + + $not = isset($dep['conflicts']) ? true : false; + if (!$this->matchSignature($dep['pattern'])) { + if (!$not) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s Architecture dependency failed, does not ' . + 'match "' . $dep['pattern'] . '"'); + } + + return $this->warning('warning: %s Architecture dependency failed, does ' . + 'not match "' . $dep['pattern'] . '"'); + } + + return true; + } + + if ($not) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s Architecture dependency failed, required "' . + $dep['pattern'] . '"'); + } + + return $this->warning('warning: %s Architecture dependency failed, ' . + 'required "' . $dep['pattern'] . '"'); + } + + return true; + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function extension_loaded($name) + { + return extension_loaded($name); + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function phpversion($name = null) + { + if ($name !== null) { + return phpversion($name); + } + + return phpversion(); + } + + function validateExtensionDependency($dep, $required = true) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING && + $this->_state != PEAR_VALIDATE_DOWNLOADING) { + return true; + } + + $loaded = $this->extension_loaded($dep['name']); + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + } + + if (!isset($dep['min']) && !isset($dep['max']) && + !isset($dep['recommended']) && !isset($dep['exclude']) + ) { + if ($loaded) { + if (isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra); + } + + return $this->warning('warning: %s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra); + } + + return true; + } + + if (isset($dep['conflicts'])) { + return true; + } + + if ($required) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP extension "' . + $dep['name'] . '"' . $extra); + } + + return $this->warning('warning: %s requires PHP extension "' . + $dep['name'] . '"' . $extra); + } + + return $this->warning('%s can optionally use PHP extension "' . + $dep['name'] . '"' . $extra); + } + + if (!$loaded) { + if (isset($dep['conflicts'])) { + return true; + } + + if (!$required) { + return $this->warning('%s can optionally use PHP extension "' . + $dep['name'] . '"' . $extra); + } + + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP extension "' . $dep['name'] . + '"' . $extra); + } + + return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . + '"' . $extra); + } + + $version = (string) $this->phpversion($dep['name']); + if (empty($version)) { + $version = '0'; + } + + $fail = false; + if (isset($dep['min']) && !version_compare($version, $dep['min'], '>=')) { + $fail = true; + } + + if (isset($dep['max']) && !version_compare($version, $dep['max'], '<=')) { + $fail = true; + } + + if ($fail && !isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP extension "' . $dep['name'] . + '"' . $extra . ', installed version is ' . $version); + } + + return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . + '"' . $extra . ', installed version is ' . $version); + } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); + } + + return $this->warning('warning: %s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); + } + + if (isset($dep['exclude'])) { + foreach ($dep['exclude'] as $exclude) { + if (version_compare($version, $exclude, '==')) { + if (isset($dep['conflicts'])) { + continue; + } + + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s is not compatible with PHP extension "' . + $dep['name'] . '" version ' . + $exclude); + } + + return $this->warning('warning: %s is not compatible with PHP extension "' . + $dep['name'] . '" version ' . + $exclude); + } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); + } + + return $this->warning('warning: %s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); + } + } + } + + if (isset($dep['recommended'])) { + if (version_compare($version, $dep['recommended'], '==')) { + return true; + } + + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] . + ' version "' . $version . '"' . + ' is not the recommended version "' . $dep['recommended'] . + '", but may be compatible, use --force to install'); + } + + return $this->warning('warning: %s dependency: PHP extension ' . + $dep['name'] . ' version "' . $version . '"' . + ' is not the recommended version "' . $dep['recommended'].'"'); + } + + return true; + } + + function validatePhpDependency($dep) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING && + $this->_state != PEAR_VALIDATE_DOWNLOADING) { + return true; + } + + $version = $this->phpversion(); + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + } + + if (isset($dep['min'])) { + if (!version_compare($version, $dep['min'], '>=')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP' . + $extra . ', installed version is ' . $version); + } + + return $this->warning('warning: %s requires PHP' . + $extra . ', installed version is ' . $version); + } + } + + if (isset($dep['max'])) { + if (!version_compare($version, $dep['max'], '<=')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP' . + $extra . ', installed version is ' . $version); + } + + return $this->warning('warning: %s requires PHP' . + $extra . ', installed version is ' . $version); + } + } + + if (isset($dep['exclude'])) { + foreach ($dep['exclude'] as $exclude) { + if (version_compare($version, $exclude, '==')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s is not compatible with PHP version ' . + $exclude); + } + + return $this->warning( + 'warning: %s is not compatible with PHP version ' . + $exclude); + } + } + } + + return true; + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function getPEARVersion() + { + return '1.9.3'; + } + + function validatePearinstallerDependency($dep) + { + $pearversion = $this->getPEARVersion(); + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + } + + if (version_compare($pearversion, $dep['min'], '<')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); + } + + return $this->warning('warning: %s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); + } + + if (isset($dep['max'])) { + if (version_compare($pearversion, $dep['max'], '>')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); + } + + return $this->warning('warning: %s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); + } + } + + if (isset($dep['exclude'])) { + if (!isset($dep['exclude'][0])) { + $dep['exclude'] = array($dep['exclude']); + } + + foreach ($dep['exclude'] as $exclude) { + if (version_compare($exclude, $pearversion, '==')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s is not compatible with PEAR Installer ' . + 'version ' . $exclude); + } + + return $this->warning('warning: %s is not compatible with PEAR ' . + 'Installer version ' . $exclude); + } + } + } + + return true; + } + + function validateSubpackageDependency($dep, $required, $params) + { + return $this->validatePackageDependency($dep, $required, $params); + } + + /** + * @param array dependency information (2.0 format) + * @param boolean whether this is a required dependency + * @param array a list of downloaded packages to be installed, if any + * @param boolean if true, then deps on pear.php.net that fail will also check + * against pecl.php.net packages to accomodate extensions that have + * moved to pecl.php.net from pear.php.net + */ + function validatePackageDependency($dep, $required, $params, $depv1 = false) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING && + $this->_state != PEAR_VALIDATE_DOWNLOADING) { + return true; + } + + if (isset($dep['providesextension'])) { + if ($this->extension_loaded($dep['providesextension'])) { + $save = $dep; + $subdep = $dep; + $subdep['name'] = $subdep['providesextension']; + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $ret = $this->validateExtensionDependency($subdep, $required); + PEAR::popErrorHandling(); + if (!PEAR::isError($ret)) { + return true; + } + } + } + + if ($this->_state == PEAR_VALIDATE_INSTALLING) { + return $this->_validatePackageInstall($dep, $required, $depv1); + } + + if ($this->_state == PEAR_VALIDATE_DOWNLOADING) { + return $this->_validatePackageDownload($dep, $required, $params, $depv1); + } + } + + function _validatePackageDownload($dep, $required, $params, $depv1 = false) + { + $dep['package'] = $dep['name']; + if (isset($dep['uri'])) { + $dep['channel'] = '__uri'; + } + + $depname = $this->_registry->parsedPackageNameToString($dep, true); + $found = false; + foreach ($params as $param) { + if ($param->isEqual( + array('package' => $dep['name'], + 'channel' => $dep['channel']))) { + $found = true; + break; + } + + if ($depv1 && $dep['channel'] == 'pear.php.net') { + if ($param->isEqual( + array('package' => $dep['name'], + 'channel' => 'pecl.php.net'))) { + $found = true; + break; + } + } + } + + if (!$found && isset($dep['providesextension'])) { + foreach ($params as $param) { + if ($param->isExtension($dep['providesextension'])) { + $found = true; + break; + } + } + } + + if ($found) { + $version = $param->getVersion(); + $installed = false; + $downloaded = true; + } else { + if ($this->_registry->packageExists($dep['name'], $dep['channel'])) { + $installed = true; + $downloaded = false; + $version = $this->_registry->packageinfo($dep['name'], 'version', + $dep['channel']); + } else { + if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'], + 'pear.php.net')) { + $installed = true; + $downloaded = false; + $version = $this->_registry->packageinfo($dep['name'], 'version', + 'pear.php.net'); + } else { + $version = 'not installed or downloaded'; + $installed = false; + $downloaded = false; + } + } + } + + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude']) && !is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + + if (!isset($dep['min']) && !isset($dep['max']) && + !isset($dep['recommended']) && !isset($dep['exclude']) + ) { + if ($installed || $downloaded) { + $installed = $installed ? 'installed' : 'downloaded'; + if (isset($dep['conflicts'])) { + $rest = ''; + if ($version) { + $rest = ", $installed version is " . $version; + } + + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . $rest); + } + + return $this->warning('warning: %s conflicts with package "' . $depname . '"' . $extra . $rest); + } + + return true; + } + + if (isset($dep['conflicts'])) { + return true; + } + + if ($required) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires package "' . $depname . '"' . $extra); + } + + return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); + } + + return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); + } + + if (!$installed && !$downloaded) { + if (isset($dep['conflicts'])) { + return true; + } + + if ($required) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires package "' . $depname . '"' . $extra); + } + + return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); + } + + return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); + } + + $fail = false; + if (isset($dep['min']) && version_compare($version, $dep['min'], '<')) { + $fail = true; + } + + if (isset($dep['max']) && version_compare($version, $dep['max'], '>')) { + $fail = true; + } + + if ($fail && !isset($dep['conflicts'])) { + $installed = $installed ? 'installed' : 'downloaded'; + $dep['package'] = $dep['name']; + $dep = $this->_registry->parsedPackageNameToString($dep, true); + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } + + return $this->warning('warning: %s requires package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && + isset($dep['conflicts']) && !isset($dep['exclude'])) { + $installed = $installed ? 'installed' : 'downloaded'; + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . + ", $installed version is " . $version); + } + + return $this->warning('warning: %s conflicts with package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } + + if (isset($dep['exclude'])) { + $installed = $installed ? 'installed' : 'downloaded'; + foreach ($dep['exclude'] as $exclude) { + if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && + !isset($this->_options['force']) + ) { + return $this->raiseError('%s is not compatible with ' . + $installed . ' package "' . + $depname . '" version ' . + $exclude); + } + + return $this->warning('warning: %s is not compatible with ' . + $installed . ' package "' . + $depname . '" version ' . + $exclude); + } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { + $installed = $installed ? 'installed' : 'downloaded'; + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } + + return $this->warning('warning: %s conflicts with package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } + } + } + + if (isset($dep['recommended'])) { + $installed = $installed ? 'installed' : 'downloaded'; + if (version_compare($version, $dep['recommended'], '==')) { + return true; + } + + if (!$found && $installed) { + $param = $this->_registry->getPackage($dep['name'], $dep['channel']); + } + + if ($param) { + $found = false; + foreach ($params as $parent) { + if ($parent->isEqual($this->_currentPackage)) { + $found = true; + break; + } + } + + if ($found) { + if ($param->isCompatible($parent)) { + return true; + } + } else { // this is for validPackage() calls + $parent = $this->_registry->getPackage($this->_currentPackage['package'], + $this->_currentPackage['channel']); + if ($parent !== null && $param->isCompatible($parent)) { + return true; + } + } + } + + if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) && + !isset($this->_options['loose']) + ) { + return $this->raiseError('%s dependency package "' . $depname . + '" ' . $installed . ' version ' . $version . + ' is not the recommended version ' . $dep['recommended'] . + ', but may be compatible, use --force to install'); + } + + return $this->warning('warning: %s dependency package "' . $depname . + '" ' . $installed . ' version ' . $version . + ' is not the recommended version ' . $dep['recommended']); + } + + return true; + } + + function _validatePackageInstall($dep, $required, $depv1 = false) + { + return $this->_validatePackageDownload($dep, $required, array(), $depv1); + } + + /** + * Verify that uninstalling packages passed in to command line is OK. + * + * @param PEAR_Installer $dl + * @return PEAR_Error|true + */ + function validatePackageUninstall(&$dl) + { + if (PEAR::isError($this->_dependencydb)) { + return $this->_dependencydb; + } + + $params = array(); + // construct an array of "downloaded" packages to fool the package dependency checker + // into using these to validate uninstalls of circular dependencies + $downloaded = &$dl->getUninstallPackages(); + foreach ($downloaded as $i => $pf) { + if (!class_exists('PEAR_Downloader_Package')) { + require_once 'PEAR/Downloader/Package.php'; + } + $dp = &new PEAR_Downloader_Package($dl); + $dp->setPackageFile($downloaded[$i]); + $params[$i] = &$dp; + } + + // check cache + $memyselfandI = strtolower($this->_currentPackage['channel']) . '/' . + strtolower($this->_currentPackage['package']); + if (isset($dl->___uninstall_package_cache)) { + $badpackages = $dl->___uninstall_package_cache; + if (isset($badpackages[$memyselfandI]['warnings'])) { + foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { + $dl->log(0, $warning[0]); + } + } + + if (isset($badpackages[$memyselfandI]['errors'])) { + foreach ($badpackages[$memyselfandI]['errors'] as $error) { + if (is_array($error)) { + $dl->log(0, $error[0]); + } else { + $dl->log(0, $error->getMessage()); + } + } + + if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { + return $this->warning( + 'warning: %s should not be uninstalled, other installed packages depend ' . + 'on this package'); + } + + return $this->raiseError( + '%s cannot be uninstalled, other installed packages depend on this package'); + } + + return true; + } + + // first, list the immediate parents of each package to be uninstalled + $perpackagelist = array(); + $allparents = array(); + foreach ($params as $i => $param) { + $a = array( + 'channel' => strtolower($param->getChannel()), + 'package' => strtolower($param->getPackage()) + ); + + $deps = $this->_dependencydb->getDependentPackages($a); + if ($deps) { + foreach ($deps as $d) { + $pardeps = $this->_dependencydb->getDependencies($d); + foreach ($pardeps as $dep) { + if (strtolower($dep['dep']['channel']) == $a['channel'] && + strtolower($dep['dep']['name']) == $a['package']) { + if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) { + $perpackagelist[$a['channel'] . '/' . $a['package']] = array(); + } + $perpackagelist[$a['channel'] . '/' . $a['package']][] + = array($d['channel'] . '/' . $d['package'], $dep); + if (!isset($allparents[$d['channel'] . '/' . $d['package']])) { + $allparents[$d['channel'] . '/' . $d['package']] = array(); + } + if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) { + $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array(); + } + $allparents[$d['channel'] . '/' . $d['package']] + [$a['channel'] . '/' . $a['package']][] + = array($d, $dep); + } + } + } + } + } + + // next, remove any packages from the parents list that are not installed + $remove = array(); + foreach ($allparents as $parent => $d1) { + foreach ($d1 as $d) { + if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) { + continue; + } + $remove[$parent] = true; + } + } + + // next remove any packages from the parents list that are not passed in for + // uninstallation + foreach ($allparents as $parent => $d1) { + foreach ($d1 as $d) { + foreach ($params as $param) { + if (strtolower($param->getChannel()) == $d[0][0]['channel'] && + strtolower($param->getPackage()) == $d[0][0]['package']) { + // found it + continue 3; + } + } + $remove[$parent] = true; + } + } + + // remove all packages whose dependencies fail + // save which ones failed for error reporting + $badchildren = array(); + do { + $fail = false; + foreach ($remove as $package => $unused) { + if (!isset($allparents[$package])) { + continue; + } + + foreach ($allparents[$package] as $kid => $d1) { + foreach ($d1 as $depinfo) { + if ($depinfo[1]['type'] != 'optional') { + if (isset($badchildren[$kid])) { + continue; + } + $badchildren[$kid] = true; + $remove[$kid] = true; + $fail = true; + continue 2; + } + } + } + if ($fail) { + // start over, we removed some children + continue 2; + } + } + } while ($fail); + + // next, construct the list of packages that can't be uninstalled + $badpackages = array(); + $save = $this->_currentPackage; + foreach ($perpackagelist as $package => $packagedeps) { + foreach ($packagedeps as $parent) { + if (!isset($remove[$parent[0]])) { + continue; + } + + $packagename = $this->_registry->parsePackageName($parent[0]); + $packagename['channel'] = $this->_registry->channelAlias($packagename['channel']); + $pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']); + $packagename['package'] = $pa->getPackage(); + $this->_currentPackage = $packagename; + // parent is not present in uninstall list, make sure we can actually + // uninstall it (parent dep is optional) + $parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']); + $pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']); + $parentname['package'] = $pa->getPackage(); + $parent[1]['dep']['package'] = $parentname['package']; + $parent[1]['dep']['channel'] = $parentname['channel']; + if ($parent[1]['type'] == 'optional') { + $test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl); + if ($test !== true) { + $badpackages[$package]['warnings'][] = $test; + } + } else { + $test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl); + if ($test !== true) { + $badpackages[$package]['errors'][] = $test; + } + } + } + } + + $this->_currentPackage = $save; + $dl->___uninstall_package_cache = $badpackages; + if (isset($badpackages[$memyselfandI])) { + if (isset($badpackages[$memyselfandI]['warnings'])) { + foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { + $dl->log(0, $warning[0]); + } + } + + if (isset($badpackages[$memyselfandI]['errors'])) { + foreach ($badpackages[$memyselfandI]['errors'] as $error) { + if (is_array($error)) { + $dl->log(0, $error[0]); + } else { + $dl->log(0, $error->getMessage()); + } + } + + if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { + return $this->warning( + 'warning: %s should not be uninstalled, other installed packages depend ' . + 'on this package'); + } + + return $this->raiseError( + '%s cannot be uninstalled, other installed packages depend on this package'); + } + } + + return true; + } + + function _validatePackageUninstall($dep, $required, $dl) + { + $depname = $this->_registry->parsedPackageNameToString($dep, true); + $version = $this->_registry->packageinfo($dep['package'], 'version', $dep['channel']); + if (!$version) { + return true; + } + + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude']) && !is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + + if (isset($dep['conflicts'])) { + return true; // uninstall OK - these packages conflict (probably installed with --force) + } + + if (!isset($dep['min']) && !isset($dep['max'])) { + if (!$required) { + return $this->warning('"' . $depname . '" can be optionally used by ' . + 'installed package %s' . $extra); + } + + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('"' . $depname . '" is required by ' . + 'installed package %s' . $extra); + } + + return $this->warning('warning: "' . $depname . '" is required by ' . + 'installed package %s' . $extra); + } + + $fail = false; + if (isset($dep['min']) && version_compare($version, $dep['min'], '>=')) { + $fail = true; + } + + if (isset($dep['max']) && version_compare($version, $dep['max'], '<=')) { + $fail = true; + } + + // we re-use this variable, preserve the original value + $saverequired = $required; + if (!$required) { + return $this->warning($depname . $extra . ' can be optionally used by installed package' . + ' "%s"'); + } + + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError($depname . $extra . ' is required by installed package' . + ' "%s"'); + } + + return $this->raiseError('warning: ' . $depname . $extra . + ' is required by installed package "%s"'); + } + + /** + * validate a downloaded package against installed packages + * + * As of PEAR 1.4.3, this will only validate + * + * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * $pkg package identifier (either + * array('package' => blah, 'channel' => blah) or an array with + * index 'info' referencing an object) + * @param PEAR_Downloader $dl + * @param array $params full list of packages to install + * @return true|PEAR_Error + */ + function validatePackage($pkg, &$dl, $params = array()) + { + if (is_array($pkg) && isset($pkg['info'])) { + $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']); + } else { + $deps = $this->_dependencydb->getDependentPackageDependencies($pkg); + } + + $fail = false; + if ($deps) { + if (!class_exists('PEAR_Downloader_Package')) { + require_once 'PEAR/Downloader/Package.php'; + } + + $dp = &new PEAR_Downloader_Package($dl); + if (is_object($pkg)) { + $dp->setPackageFile($pkg); + } else { + $dp->setDownloadURL($pkg); + } + + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + foreach ($deps as $channel => $info) { + foreach ($info as $package => $ds) { + foreach ($params as $packd) { + if (strtolower($packd->getPackage()) == strtolower($package) && + $packd->getChannel() == $channel) { + $dl->log(3, 'skipping installed package check of "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $channel, 'package' => $package), + true) . + '", version "' . $packd->getVersion() . '" will be ' . + 'downloaded and installed'); + continue 2; // jump to next package + } + } + + foreach ($ds as $d) { + $checker = &new PEAR_Dependency2($this->_config, $this->_options, + array('channel' => $channel, 'package' => $package), $this->_state); + $dep = $d['dep']; + $required = $d['type'] == 'required'; + $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp)); + if (is_array($ret)) { + $dl->log(0, $ret[0]); + } elseif (PEAR::isError($ret)) { + $dl->log(0, $ret->getMessage()); + $fail = true; + } + } + } + } + PEAR::popErrorHandling(); + } + + if ($fail) { + return $this->raiseError( + '%s cannot be installed, conflicts with installed packages'); + } + + return true; + } + + /** + * validate a package.xml 1.0 dependency + */ + function validateDependency1($dep, $params = array()) + { + if (!isset($dep['optional'])) { + $dep['optional'] = 'no'; + } + + list($newdep, $type) = $this->normalizeDep($dep); + if (!$newdep) { + return $this->raiseError("Invalid Dependency"); + } + + if (method_exists($this, "validate{$type}Dependency")) { + return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no', + $params, true); + } + } + + /** + * Convert a 1.0 dep into a 2.0 dep + */ + function normalizeDep($dep) + { + $types = array( + 'pkg' => 'Package', + 'ext' => 'Extension', + 'os' => 'Os', + 'php' => 'Php' + ); + + if (!isset($types[$dep['type']])) { + return array(false, false); + } + + $type = $types[$dep['type']]; + + $newdep = array(); + switch ($type) { + case 'Package' : + $newdep['channel'] = 'pear.php.net'; + case 'Extension' : + case 'Os' : + $newdep['name'] = $dep['name']; + break; + } + + $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']); + switch ($dep['rel']) { + case 'has' : + return array($newdep, $type); + break; + case 'not' : + $newdep['conflicts'] = true; + break; + case '>=' : + case '>' : + $newdep['min'] = $dep['version']; + if ($dep['rel'] == '>') { + $newdep['exclude'] = $dep['version']; + } + break; + case '<=' : + case '<' : + $newdep['max'] = $dep['version']; + if ($dep['rel'] == '<') { + $newdep['exclude'] = $dep['version']; + } + break; + case 'ne' : + case '!=' : + $newdep['min'] = '0'; + $newdep['max'] = '100000'; + $newdep['exclude'] = $dep['version']; + break; + case '==' : + $newdep['min'] = $dep['version']; + $newdep['max'] = $dep['version']; + break; + } + if ($type == 'Php') { + if (!isset($newdep['min'])) { + $newdep['min'] = '4.4.0'; + } + + if (!isset($newdep['max'])) { + $newdep['max'] = '6.0.0'; + } + } + return array($newdep, $type); + } + + /** + * Converts text comparing operators to them sign equivalents + * + * Example: 'ge' to '>=' + * + * @access public + * @param string Operator + * @return string Sign equivalent + */ + function signOperator($operator) + { + switch($operator) { + case 'lt': return '<'; + case 'le': return '<='; + case 'gt': return '>'; + case 'ge': return '>='; + case 'eq': return '=='; + case 'ne': return '!='; + default: + return $operator; + } + } + + function raiseError($msg) + { + if (isset($this->_options['ignore-errors'])) { + return $this->warning($msg); + } + + return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString( + $this->_currentPackage, true))); + } + + function warning($msg) + { + return array(sprintf($msg, $this->_registry->parsedPackageNameToString( + $this->_currentPackage, true))); + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/DependencyDB.php b/typo3conf/ext/phpunit/PEAR/PEAR/DependencyDB.php new file mode 100644 index 0000000..b5d7ad5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/DependencyDB.php @@ -0,0 +1,769 @@ + + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: DependencyDB.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Needed for error handling + */ +require_once 'PEAR.php'; +require_once 'PEAR/Config.php'; + +$GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array(); +/** + * Track dependency relationships between installed packages + * @category pear + * @package PEAR + * @author Greg Beaver + * @author Tomas V.V.Cox + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_DependencyDB +{ + // {{{ properties + + /** + * This is initialized by {@link setConfig()} + * @var PEAR_Config + * @access private + */ + var $_config; + /** + * This is initialized by {@link setConfig()} + * @var PEAR_Registry + * @access private + */ + var $_registry; + /** + * Filename of the dependency DB (usually .depdb) + * @var string + * @access private + */ + var $_depdb = false; + /** + * File name of the lockfile (usually .depdblock) + * @var string + * @access private + */ + var $_lockfile = false; + /** + * Open file resource for locking the lockfile + * @var resource|false + * @access private + */ + var $_lockFp = false; + /** + * API version of this class, used to validate a file on-disk + * @var string + * @access private + */ + var $_version = '1.0'; + /** + * Cached dependency database file + * @var array|null + * @access private + */ + var $_cache; + + // }}} + // {{{ & singleton() + + /** + * Get a raw dependency database. Calls setConfig() and assertDepsDB() + * @param PEAR_Config + * @param string|false full path to the dependency database, or false to use default + * @return PEAR_DependencyDB|PEAR_Error + * @static + */ + function &singleton(&$config, $depdb = false) + { + $phpdir = $config->get('php_dir', null, 'pear.php.net'); + if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir])) { + $a = new PEAR_DependencyDB; + $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir] = &$a; + $a->setConfig($config, $depdb); + $e = $a->assertDepsDB(); + if (PEAR::isError($e)) { + return $e; + } + } + + return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir]; + } + + /** + * Set up the registry/location of dependency DB + * @param PEAR_Config|false + * @param string|false full path to the dependency database, or false to use default + */ + function setConfig(&$config, $depdb = false) + { + if (!$config) { + $this->_config = &PEAR_Config::singleton(); + } else { + $this->_config = &$config; + } + + $this->_registry = &$this->_config->getRegistry(); + if (!$depdb) { + $this->_depdb = $this->_config->get('php_dir', null, 'pear.php.net') . + DIRECTORY_SEPARATOR . '.depdb'; + } else { + $this->_depdb = $depdb; + } + + $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock'; + } + // }}} + + function hasWriteAccess() + { + if (!file_exists($this->_depdb)) { + $dir = $this->_depdb; + while ($dir && $dir != '.') { + $dir = dirname($dir); // cd .. + if ($dir != '.' && file_exists($dir)) { + if (is_writeable($dir)) { + return true; + } + + return false; + } + } + + return false; + } + + return is_writeable($this->_depdb); + } + + // {{{ assertDepsDB() + + /** + * Create the dependency database, if it doesn't exist. Error if the database is + * newer than the code reading it. + * @return void|PEAR_Error + */ + function assertDepsDB() + { + if (!is_file($this->_depdb)) { + $this->rebuildDB(); + return; + } + + $depdb = $this->_getDepDB(); + // Datatype format has been changed, rebuild the Deps DB + if ($depdb['_version'] < $this->_version) { + $this->rebuildDB(); + } + + if ($depdb['_version']{0} > $this->_version{0}) { + return PEAR::raiseError('Dependency database is version ' . + $depdb['_version'] . ', and we are version ' . + $this->_version . ', cannot continue'); + } + } + + /** + * Get a list of installed packages that depend on this package + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array + * @return array|false + */ + function getDependentPackages(&$pkg) + { + $data = $this->_getDepDB(); + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); + } + + if (isset($data['packages'][$channel][$package])) { + return $data['packages'][$channel][$package]; + } + + return false; + } + + /** + * Get a list of the actual dependencies of installed packages that depend on + * a package. + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array + * @return array|false + */ + function getDependentPackageDependencies(&$pkg) + { + $data = $this->_getDepDB(); + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); + } + + $depend = $this->getDependentPackages($pkg); + if (!$depend) { + return false; + } + + $dependencies = array(); + foreach ($depend as $info) { + $temp = $this->getDependencies($info); + foreach ($temp as $dep) { + if ( + isset($dep['dep'], $dep['dep']['channel'], $dep['dep']['name']) && + strtolower($dep['dep']['channel']) == $channel && + strtolower($dep['dep']['name']) == $package + ) { + if (!isset($dependencies[$info['channel']])) { + $dependencies[$info['channel']] = array(); + } + + if (!isset($dependencies[$info['channel']][$info['package']])) { + $dependencies[$info['channel']][$info['package']] = array(); + } + $dependencies[$info['channel']][$info['package']][] = $dep; + } + } + } + + return $dependencies; + } + + /** + * Get a list of dependencies of this installed package + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array + * @return array|false + */ + function getDependencies(&$pkg) + { + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); + } + + $data = $this->_getDepDB(); + if (isset($data['dependencies'][$channel][$package])) { + return $data['dependencies'][$channel][$package]; + } + + return false; + } + + /** + * Determine whether $parent depends on $child, near or deep + * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 + * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 + */ + function dependsOn($parent, $child) + { + $c = array(); + $this->_getDepDB(); + return $this->_dependsOn($parent, $child, $c); + } + + function _dependsOn($parent, $child, &$checked) + { + if (is_object($parent)) { + $channel = strtolower($parent->getChannel()); + $package = strtolower($parent->getPackage()); + } else { + $channel = strtolower($parent['channel']); + $package = strtolower($parent['package']); + } + + if (is_object($child)) { + $depchannel = strtolower($child->getChannel()); + $deppackage = strtolower($child->getPackage()); + } else { + $depchannel = strtolower($child['channel']); + $deppackage = strtolower($child['package']); + } + + if (isset($checked[$channel][$package][$depchannel][$deppackage])) { + return false; // avoid endless recursion + } + + $checked[$channel][$package][$depchannel][$deppackage] = true; + if (!isset($this->_cache['dependencies'][$channel][$package])) { + return false; + } + + foreach ($this->_cache['dependencies'][$channel][$package] as $info) { + if (isset($info['dep']['uri'])) { + if (is_object($child)) { + if ($info['dep']['uri'] == $child->getURI()) { + return true; + } + } elseif (isset($child['uri'])) { + if ($info['dep']['uri'] == $child['uri']) { + return true; + } + } + return false; + } + + if (strtolower($info['dep']['channel']) == $depchannel && + strtolower($info['dep']['name']) == $deppackage) { + return true; + } + } + + foreach ($this->_cache['dependencies'][$channel][$package] as $info) { + if (isset($info['dep']['uri'])) { + if ($this->_dependsOn(array( + 'uri' => $info['dep']['uri'], + 'package' => $info['dep']['name']), $child, $checked)) { + return true; + } + } else { + if ($this->_dependsOn(array( + 'channel' => $info['dep']['channel'], + 'package' => $info['dep']['name']), $child, $checked)) { + return true; + } + } + } + + return false; + } + + /** + * Register dependencies of a package that is being installed or upgraded + * @param PEAR_PackageFile_v2|PEAR_PackageFile_v2 + */ + function installPackage(&$package) + { + $data = $this->_getDepDB(); + unset($this->_cache); + $this->_setPackageDeps($data, $package); + $this->_writeDepDB($data); + } + + /** + * Remove dependencies of a package that is being uninstalled, or upgraded. + * + * Upgraded packages first uninstall, then install + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array If an array, then it must have + * indices 'channel' and 'package' + */ + function uninstallPackage(&$pkg) + { + $data = $this->_getDepDB(); + unset($this->_cache); + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); + } + + if (!isset($data['dependencies'][$channel][$package])) { + return true; + } + + foreach ($data['dependencies'][$channel][$package] as $dep) { + $found = false; + $depchannel = isset($dep['dep']['uri']) ? '__uri' : strtolower($dep['dep']['channel']); + $depname = strtolower($dep['dep']['name']); + if (isset($data['packages'][$depchannel][$depname])) { + foreach ($data['packages'][$depchannel][$depname] as $i => $info) { + if ($info['channel'] == $channel && $info['package'] == $package) { + $found = true; + break; + } + } + } + + if ($found) { + unset($data['packages'][$depchannel][$depname][$i]); + if (!count($data['packages'][$depchannel][$depname])) { + unset($data['packages'][$depchannel][$depname]); + if (!count($data['packages'][$depchannel])) { + unset($data['packages'][$depchannel]); + } + } else { + $data['packages'][$depchannel][$depname] = + array_values($data['packages'][$depchannel][$depname]); + } + } + } + + unset($data['dependencies'][$channel][$package]); + if (!count($data['dependencies'][$channel])) { + unset($data['dependencies'][$channel]); + } + + if (!count($data['dependencies'])) { + unset($data['dependencies']); + } + + if (!count($data['packages'])) { + unset($data['packages']); + } + + $this->_writeDepDB($data); + } + + /** + * Rebuild the dependency DB by reading registry entries. + * @return true|PEAR_Error + */ + function rebuildDB() + { + $depdb = array('_version' => $this->_version); + if (!$this->hasWriteAccess()) { + // allow startup for read-only with older Registry + return $depdb; + } + + $packages = $this->_registry->listAllPackages(); + if (PEAR::isError($packages)) { + return $packages; + } + + foreach ($packages as $channel => $ps) { + foreach ($ps as $package) { + $package = $this->_registry->getPackage($package, $channel); + if (PEAR::isError($package)) { + return $package; + } + $this->_setPackageDeps($depdb, $package); + } + } + + $error = $this->_writeDepDB($depdb); + if (PEAR::isError($error)) { + return $error; + } + + $this->_cache = $depdb; + return true; + } + + /** + * Register usage of the dependency DB to prevent race conditions + * @param int one of the LOCK_* constants + * @return true|PEAR_Error + * @access private + */ + function _lock($mode = LOCK_EX) + { + if (stristr(php_uname(), 'Windows 9')) { + return true; + } + + if ($mode != LOCK_UN && is_resource($this->_lockFp)) { + // XXX does not check type of lock (LOCK_SH/LOCK_EX) + return true; + } + + $open_mode = 'w'; + // XXX People reported problems with LOCK_SH and 'w' + if ($mode === LOCK_SH) { + if (!file_exists($this->_lockfile)) { + touch($this->_lockfile); + } elseif (!is_file($this->_lockfile)) { + return PEAR::raiseError('could not create Dependency lock file, ' . + 'it exists and is not a regular file'); + } + $open_mode = 'r'; + } + + if (!is_resource($this->_lockFp)) { + $this->_lockFp = @fopen($this->_lockfile, $open_mode); + } + + if (!is_resource($this->_lockFp)) { + return PEAR::raiseError("could not create Dependency lock file" . + (isset($php_errormsg) ? ": " . $php_errormsg : "")); + } + + if (!(int)flock($this->_lockFp, $mode)) { + switch ($mode) { + case LOCK_SH: $str = 'shared'; break; + case LOCK_EX: $str = 'exclusive'; break; + case LOCK_UN: $str = 'unlock'; break; + default: $str = 'unknown'; break; + } + + return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)"); + } + + return true; + } + + /** + * Release usage of dependency DB + * @return true|PEAR_Error + * @access private + */ + function _unlock() + { + $ret = $this->_lock(LOCK_UN); + if (is_resource($this->_lockFp)) { + fclose($this->_lockFp); + } + $this->_lockFp = null; + return $ret; + } + + /** + * Load the dependency database from disk, or return the cache + * @return array|PEAR_Error + */ + function _getDepDB() + { + if (!$this->hasWriteAccess()) { + return array('_version' => $this->_version); + } + + if (isset($this->_cache)) { + return $this->_cache; + } + + if (!$fp = fopen($this->_depdb, 'r')) { + $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'"); + return $err; + } + + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + clearstatcache(); + fclose($fp); + $data = unserialize(file_get_contents($this->_depdb)); + set_magic_quotes_runtime($rt); + $this->_cache = $data; + return $data; + } + + /** + * Write out the dependency database to disk + * @param array the database + * @return true|PEAR_Error + * @access private + */ + function _writeDepDB(&$deps) + { + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + + if (!$fp = fopen($this->_depdb, 'wb')) { + $this->_unlock(); + return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing"); + } + + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + fwrite($fp, serialize($deps)); + set_magic_quotes_runtime($rt); + fclose($fp); + $this->_unlock(); + $this->_cache = $deps; + return true; + } + + /** + * Register all dependencies from a package in the dependencies database, in essence + * "installing" the package's dependency information + * @param array the database + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @access private + */ + function _setPackageDeps(&$data, &$pkg) + { + $pkg->setConfig($this->_config); + if ($pkg->getPackagexmlVersion() == '1.0') { + $gen = &$pkg->getDefaultGenerator(); + $deps = $gen->dependenciesToV2(); + } else { + $deps = $pkg->getDeps(true); + } + + if (!$deps) { + return; + } + + if (!is_array($data)) { + $data = array(); + } + + if (!isset($data['dependencies'])) { + $data['dependencies'] = array(); + } + + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + + if (!isset($data['dependencies'][$channel])) { + $data['dependencies'][$channel] = array(); + } + + $data['dependencies'][$channel][$package] = array(); + if (isset($deps['required']['package'])) { + if (!isset($deps['required']['package'][0])) { + $deps['required']['package'] = array($deps['required']['package']); + } + + foreach ($deps['required']['package'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'required'); + } + } + + if (isset($deps['optional']['package'])) { + if (!isset($deps['optional']['package'][0])) { + $deps['optional']['package'] = array($deps['optional']['package']); + } + + foreach ($deps['optional']['package'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional'); + } + } + + if (isset($deps['required']['subpackage'])) { + if (!isset($deps['required']['subpackage'][0])) { + $deps['required']['subpackage'] = array($deps['required']['subpackage']); + } + + foreach ($deps['required']['subpackage'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'required'); + } + } + + if (isset($deps['optional']['subpackage'])) { + if (!isset($deps['optional']['subpackage'][0])) { + $deps['optional']['subpackage'] = array($deps['optional']['subpackage']); + } + + foreach ($deps['optional']['subpackage'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional'); + } + } + + if (isset($deps['group'])) { + if (!isset($deps['group'][0])) { + $deps['group'] = array($deps['group']); + } + + foreach ($deps['group'] as $group) { + if (isset($group['package'])) { + if (!isset($group['package'][0])) { + $group['package'] = array($group['package']); + } + + foreach ($group['package'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional', + $group['attribs']['name']); + } + } + + if (isset($group['subpackage'])) { + if (!isset($group['subpackage'][0])) { + $group['subpackage'] = array($group['subpackage']); + } + + foreach ($group['subpackage'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional', + $group['attribs']['name']); + } + } + } + } + + if ($data['dependencies'][$channel][$package] == array()) { + unset($data['dependencies'][$channel][$package]); + if (!count($data['dependencies'][$channel])) { + unset($data['dependencies'][$channel]); + } + } + } + + /** + * @param array the database + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param array the specific dependency + * @param required|optional whether this is a required or an optional dep + * @param string|false dependency group this dependency is from, or false for ordinary dep + */ + function _registerDep(&$data, &$pkg, $dep, $type, $group = false) + { + $info = array( + 'dep' => $dep, + 'type' => $type, + 'group' => $group + ); + + $dep = array_map('strtolower', $dep); + $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; + if (!isset($data['dependencies'])) { + $data['dependencies'] = array(); + } + + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + + if (!isset($data['dependencies'][$channel])) { + $data['dependencies'][$channel] = array(); + } + + if (!isset($data['dependencies'][$channel][$package])) { + $data['dependencies'][$channel][$package] = array(); + } + + $data['dependencies'][$channel][$package][] = $info; + if (isset($data['packages'][$depchannel][$dep['name']])) { + $found = false; + foreach ($data['packages'][$depchannel][$dep['name']] as $i => $p) { + if ($p['channel'] == $channel && $p['package'] == $package) { + $found = true; + break; + } + } + } else { + if (!isset($data['packages'])) { + $data['packages'] = array(); + } + + if (!isset($data['packages'][$depchannel])) { + $data['packages'][$depchannel] = array(); + } + + if (!isset($data['packages'][$depchannel][$dep['name']])) { + $data['packages'][$depchannel][$dep['name']] = array(); + } + + $found = false; + } + + if (!$found) { + $data['packages'][$depchannel][$dep['name']][] = array( + 'channel' => $channel, + 'package' => $package + ); + } + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Downloader.php b/typo3conf/ext/phpunit/PEAR/PEAR/Downloader.php new file mode 100644 index 0000000..bda5eb0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Downloader.php @@ -0,0 +1,1766 @@ + + * @author Stig Bakken + * @author Tomas V. V. Cox + * @author Martin Jansen + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Downloader.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.3.0 + */ + +/** + * Needed for constants, extending + */ +require_once 'PEAR/Common.php'; + +define('PEAR_INSTALLER_OK', 1); +define('PEAR_INSTALLER_FAILED', 0); +define('PEAR_INSTALLER_SKIPPED', -1); +define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2); + +/** + * Administration class used to download anything from the internet (PEAR Packages, + * static URLs, xml files) + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @author Stig Bakken + * @author Tomas V. V. Cox + * @author Martin Jansen + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.3.0 + */ +class PEAR_Downloader extends PEAR_Common +{ + /** + * @var PEAR_Registry + * @access private + */ + var $_registry; + + /** + * Preferred Installation State (snapshot, devel, alpha, beta, stable) + * @var string|null + * @access private + */ + var $_preferredState; + + /** + * Options from command-line passed to Install. + * + * Recognized options:
    + * - onlyreqdeps : install all required dependencies as well + * - alldeps : install all dependencies, including optional + * - installroot : base relative path to install files in + * - force : force a download even if warnings would prevent it + * - nocompress : download uncompressed tarballs + * @see PEAR_Command_Install + * @access private + * @var array + */ + var $_options; + + /** + * Downloaded Packages after a call to download(). + * + * Format of each entry: + * + * + * array('pkg' => 'package_name', 'file' => '/path/to/local/file', + * 'info' => array() // parsed package.xml + * ); + * + * @access private + * @var array + */ + var $_downloadedPackages = array(); + + /** + * Packages slated for download. + * + * This is used to prevent downloading a package more than once should it be a dependency + * for two packages to be installed. + * Format of each entry: + * + *
    +     * array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
    +     * );
    +     * 
    + * @access private + * @var array + */ + var $_toDownload = array(); + + /** + * Array of every package installed, with names lower-cased. + * + * Format: + * + * array('package1' => 0, 'package2' => 1, ); + * + * @var array + */ + var $_installed = array(); + + /** + * @var array + * @access private + */ + var $_errorStack = array(); + + /** + * @var boolean + * @access private + */ + var $_internalDownload = false; + + /** + * Temporary variable used in sorting packages by dependency in {@link sortPkgDeps()} + * @var array + * @access private + */ + var $_packageSortTree; + + /** + * Temporary directory, or configuration value where downloads will occur + * @var string + */ + var $_downloadDir; + + /** + * @param PEAR_Frontend_* + * @param array + * @param PEAR_Config + */ + function PEAR_Downloader(&$ui, $options, &$config) + { + parent::PEAR_Common(); + $this->_options = $options; + $this->config = &$config; + $this->_preferredState = $this->config->get('preferred_state'); + $this->ui = &$ui; + if (!$this->_preferredState) { + // don't inadvertantly use a non-set preferred_state + $this->_preferredState = null; + } + + if (isset($this->_options['installroot'])) { + $this->config->setInstallRoot($this->_options['installroot']); + } + $this->_registry = &$config->getRegistry(); + + if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) { + $this->_installed = $this->_registry->listAllPackages(); + foreach ($this->_installed as $key => $unused) { + if (!count($unused)) { + continue; + } + $strtolower = create_function('$a','return strtolower($a);'); + array_walk($this->_installed[$key], $strtolower); + } + } + } + + /** + * Attempt to discover a channel's remote capabilities from + * its server name + * @param string + * @return boolean + */ + function discover($channel) + { + $this->log(1, 'Attempting to discover channel "' . $channel . '"...'); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $callback = $this->ui ? array(&$this, '_downloadCallback') : null; + if (!class_exists('System')) { + require_once 'System.php'; + } + + $tmpdir = $this->config->get('temp_dir'); + $tmp = System::mktemp("-d -t $tmpdir"); + $a = $this->downloadHttp('http://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false); + PEAR::popErrorHandling(); + if (PEAR::isError($a)) { + // Attempt to fallback to https automatically. + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $this->log(1, 'Attempting fallback to https instead of http on channel "' . $channel . '"...'); + $a = $this->downloadHttp('https://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false); + PEAR::popErrorHandling(); + if (PEAR::isError($a)) { + return false; + } + } + + list($a, $lastmodified) = $a; + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $b = new PEAR_ChannelFile; + if ($b->fromXmlFile($a)) { + unlink($a); + if ($this->config->get('auto_discover')) { + $this->_registry->addChannel($b, $lastmodified); + $alias = $b->getName(); + if ($b->getName() == $this->_registry->channelName($b->getAlias())) { + $alias = $b->getAlias(); + } + + $this->log(1, 'Auto-discovered channel "' . $channel . + '", alias "' . $alias . '", adding to registry'); + } + + return true; + } + + unlink($a); + return false; + } + + /** + * For simpler unit-testing + * @param PEAR_Downloader + * @return PEAR_Downloader_Package + */ + function &newDownloaderPackage(&$t) + { + if (!class_exists('PEAR_Downloader_Package')) { + require_once 'PEAR/Downloader/Package.php'; + } + $a = &new PEAR_Downloader_Package($t); + return $a; + } + + /** + * For simpler unit-testing + * @param PEAR_Config + * @param array + * @param array + * @param int + */ + function &getDependency2Object(&$c, $i, $p, $s) + { + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; + } + $z = &new PEAR_Dependency2($c, $i, $p, $s); + return $z; + } + + function &download($params) + { + if (!count($params)) { + $a = array(); + return $a; + } + + if (!isset($this->_registry)) { + $this->_registry = &$this->config->getRegistry(); + } + + $channelschecked = array(); + // convert all parameters into PEAR_Downloader_Package objects + foreach ($params as $i => $param) { + $params[$i] = &$this->newDownloaderPackage($this); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = $params[$i]->initialize($param); + PEAR::staticPopErrorHandling(); + if (!$err) { + // skip parameters that were missed by preferred_state + continue; + } + + if (PEAR::isError($err)) { + if (!isset($this->_options['soft']) && $err->getMessage() !== '') { + $this->log(0, $err->getMessage()); + } + + $params[$i] = false; + if (is_object($param)) { + $param = $param->getChannel() . '/' . $param->getPackage(); + } + + if (!isset($this->_options['soft'])) { + $this->log(2, 'Package "' . $param . '" is not valid'); + } + + // Message logged above in a specific verbose mode, passing null to not show up on CLI + $this->pushError(null, PEAR_INSTALLER_SKIPPED); + } else { + do { + if ($params[$i] && $params[$i]->getType() == 'local') { + // bug #7090 skip channel.xml check for local packages + break; + } + + if ($params[$i] && !isset($channelschecked[$params[$i]->getChannel()]) && + !isset($this->_options['offline']) + ) { + $channelschecked[$params[$i]->getChannel()] = true; + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (!class_exists('System')) { + require_once 'System.php'; + } + + $curchannel = &$this->_registry->getChannel($params[$i]->getChannel()); + if (PEAR::isError($curchannel)) { + PEAR::staticPopErrorHandling(); + return $this->raiseError($curchannel); + } + + if (PEAR::isError($dir = $this->getDownloadDir())) { + PEAR::staticPopErrorHandling(); + break; + } + + $mirror = $this->config->get('preferred_mirror', null, $params[$i]->getChannel()); + $url = 'http://' . $mirror . '/channel.xml'; + $a = $this->downloadHttp($url, $this->ui, $dir, null, $curchannel->lastModified()); + + PEAR::staticPopErrorHandling(); + if (PEAR::isError($a) || !$a) { + // Attempt fallback to https automatically + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $a = $this->downloadHttp('https://' . $mirror . + '/channel.xml', $this->ui, $dir, null, $curchannel->lastModified()); + + PEAR::staticPopErrorHandling(); + if (PEAR::isError($a) || !$a) { + break; + } + } + $this->log(0, 'WARNING: channel "' . $params[$i]->getChannel() . '" has ' . + 'updated its protocols, use "' . PEAR_RUNTYPE . ' channel-update ' . $params[$i]->getChannel() . + '" to update'); + } + } while (false); + + if ($params[$i] && !isset($this->_options['downloadonly'])) { + if (isset($this->_options['packagingroot'])) { + $checkdir = $this->_prependPath( + $this->config->get('php_dir', null, $params[$i]->getChannel()), + $this->_options['packagingroot']); + } else { + $checkdir = $this->config->get('php_dir', + null, $params[$i]->getChannel()); + } + + while ($checkdir && $checkdir != '/' && !file_exists($checkdir)) { + $checkdir = dirname($checkdir); + } + + if ($checkdir == '.') { + $checkdir = '/'; + } + + if (!is_writeable($checkdir)) { + return PEAR::raiseError('Cannot install, php_dir for channel "' . + $params[$i]->getChannel() . '" is not writeable by the current user'); + } + } + } + } + + unset($channelschecked); + PEAR_Downloader_Package::removeDuplicates($params); + if (!count($params)) { + $a = array(); + return $a; + } + + if (!isset($this->_options['nodeps']) && !isset($this->_options['offline'])) { + $reverify = true; + while ($reverify) { + $reverify = false; + foreach ($params as $i => $param) { + //PHP Bug 40768 / PEAR Bug #10944 + //Nested foreaches fail in PHP 5.2.1 + key($params); + $ret = $params[$i]->detectDependencies($params); + if (PEAR::isError($ret)) { + $reverify = true; + $params[$i] = false; + PEAR_Downloader_Package::removeDuplicates($params); + if (!isset($this->_options['soft'])) { + $this->log(0, $ret->getMessage()); + } + continue 2; + } + } + } + } + + if (isset($this->_options['offline'])) { + $this->log(3, 'Skipping dependency download check, --offline specified'); + } + + if (!count($params)) { + $a = array(); + return $a; + } + + while (PEAR_Downloader_Package::mergeDependencies($params)); + PEAR_Downloader_Package::removeDuplicates($params, true); + $errorparams = array(); + if (PEAR_Downloader_Package::detectStupidDuplicates($params, $errorparams)) { + if (count($errorparams)) { + foreach ($errorparams as $param) { + $name = $this->_registry->parsedPackageNameToString($param->getParsedPackage()); + $this->pushError('Duplicate package ' . $name . ' found', PEAR_INSTALLER_FAILED); + } + $a = array(); + return $a; + } + } + + PEAR_Downloader_Package::removeInstalled($params); + if (!count($params)) { + $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); + $a = array(); + return $a; + } + + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->analyzeDependencies($params); + PEAR::popErrorHandling(); + if (!count($params)) { + $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); + $a = array(); + return $a; + } + + $ret = array(); + $newparams = array(); + if (isset($this->_options['pretend'])) { + return $params; + } + + $somefailed = false; + foreach ($params as $i => $package) { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $pf = &$params[$i]->download(); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($pf)) { + if (!isset($this->_options['soft'])) { + $this->log(1, $pf->getMessage()); + $this->log(0, 'Error: cannot download "' . + $this->_registry->parsedPackageNameToString($package->getParsedPackage(), + true) . + '"'); + } + $somefailed = true; + continue; + } + + $newparams[] = &$params[$i]; + $ret[] = array( + 'file' => $pf->getArchiveFile(), + 'info' => &$pf, + 'pkg' => $pf->getPackage() + ); + } + + if ($somefailed) { + // remove params that did not download successfully + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->analyzeDependencies($newparams, true); + PEAR::popErrorHandling(); + if (!count($newparams)) { + $this->pushError('Download failed', PEAR_INSTALLER_FAILED); + $a = array(); + return $a; + } + } + + $this->_downloadedPackages = $ret; + return $newparams; + } + + /** + * @param array all packages to be installed + */ + function analyzeDependencies(&$params, $force = false) + { + if (isset($this->_options['downloadonly'])) { + return; + } + + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $redo = true; + $reset = $hasfailed = $failed = false; + while ($redo) { + $redo = false; + foreach ($params as $i => $param) { + $deps = $param->getDeps(); + if (!$deps) { + $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), + $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); + $send = $param->getPackageFile(); + + $installcheck = $depchecker->validatePackage($send, $this, $params); + if (PEAR::isError($installcheck)) { + if (!isset($this->_options['soft'])) { + $this->log(0, $installcheck->getMessage()); + } + $hasfailed = true; + $params[$i] = false; + $reset = true; + $redo = true; + $failed = false; + PEAR_Downloader_Package::removeDuplicates($params); + continue 2; + } + continue; + } + + if (!$reset && $param->alreadyValidated() && !$force) { + continue; + } + + if (count($deps)) { + $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), + $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); + $send = $param->getPackageFile(); + if ($send === null) { + $send = $param->getDownloadURL(); + } + + $installcheck = $depchecker->validatePackage($send, $this, $params); + if (PEAR::isError($installcheck)) { + if (!isset($this->_options['soft'])) { + $this->log(0, $installcheck->getMessage()); + } + $hasfailed = true; + $params[$i] = false; + $reset = true; + $redo = true; + $failed = false; + PEAR_Downloader_Package::removeDuplicates($params); + continue 2; + } + + $failed = false; + if (isset($deps['required']) && is_array($deps['required'])) { + foreach ($deps['required'] as $type => $dep) { + // note: Dependency2 will never return a PEAR_Error if ignore-errors + // is specified, so soft is needed to turn off logging + if (!isset($dep[0])) { + if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep, + true, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } else { + foreach ($dep as $d) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($d, + true, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + } + + if (isset($deps['optional']) && is_array($deps['optional'])) { + foreach ($deps['optional'] as $type => $dep) { + if (!isset($dep[0])) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($dep, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } else { + foreach ($dep as $d) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($d, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + } + } + + $groupname = $param->getGroup(); + if (isset($deps['group']) && $groupname) { + if (!isset($deps['group'][0])) { + $deps['group'] = array($deps['group']); + } + + $found = false; + foreach ($deps['group'] as $group) { + if ($group['attribs']['name'] == $groupname) { + $found = true; + break; + } + } + + if ($found) { + unset($group['attribs']); + foreach ($group as $type => $dep) { + if (!isset($dep[0])) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($dep, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } else { + foreach ($dep as $d) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($d, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + } + } + } + } else { + foreach ($deps as $dep) { + if (PEAR::isError($e = $depchecker->validateDependency1($dep, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + $params[$i]->setValidated(); + } + + if ($failed) { + $hasfailed = true; + $params[$i] = false; + $reset = true; + $redo = true; + $failed = false; + PEAR_Downloader_Package::removeDuplicates($params); + continue 2; + } + } + } + + PEAR::staticPopErrorHandling(); + if ($hasfailed && (isset($this->_options['ignore-errors']) || + isset($this->_options['nodeps']))) { + // this is probably not needed, but just in case + if (!isset($this->_options['soft'])) { + $this->log(0, 'WARNING: dependencies failed'); + } + } + } + + /** + * Retrieve the directory that downloads will happen in + * @access private + * @return string + */ + function getDownloadDir() + { + if (isset($this->_downloadDir)) { + return $this->_downloadDir; + } + + $downloaddir = $this->config->get('download_dir'); + if (empty($downloaddir) || (is_dir($downloaddir) && !is_writable($downloaddir))) { + if (is_dir($downloaddir) && !is_writable($downloaddir)) { + $this->log(0, 'WARNING: configuration download directory "' . $downloaddir . + '" is not writeable. Change download_dir config variable to ' . + 'a writeable dir to avoid this warning'); + } + + if (!class_exists('System')) { + require_once 'System.php'; + } + + if (PEAR::isError($downloaddir = System::mktemp('-d'))) { + return $downloaddir; + } + $this->log(3, '+ tmp dir created at ' . $downloaddir); + } + + if (!is_writable($downloaddir)) { + if (PEAR::isError(System::mkdir(array('-p', $downloaddir))) || + !is_writable($downloaddir)) { + return PEAR::raiseError('download directory "' . $downloaddir . + '" is not writeable. Change download_dir config variable to ' . + 'a writeable dir'); + } + } + + return $this->_downloadDir = $downloaddir; + } + + function setDownloadDir($dir) + { + if (!@is_writable($dir)) { + if (PEAR::isError(System::mkdir(array('-p', $dir)))) { + return PEAR::raiseError('download directory "' . $dir . + '" is not writeable. Change download_dir config variable to ' . + 'a writeable dir'); + } + } + $this->_downloadDir = $dir; + } + + function configSet($key, $value, $layer = 'user', $channel = false) + { + $this->config->set($key, $value, $layer, $channel); + $this->_preferredState = $this->config->get('preferred_state', null, $channel); + if (!$this->_preferredState) { + // don't inadvertantly use a non-set preferred_state + $this->_preferredState = null; + } + } + + function setOptions($options) + { + $this->_options = $options; + } + + function getOptions() + { + return $this->_options; + } + + + /** + * @param array output of {@link parsePackageName()} + * @access private + */ + function _getPackageDownloadUrl($parr) + { + $curchannel = $this->config->get('default_channel'); + $this->configSet('default_channel', $parr['channel']); + // getDownloadURL returns an array. On error, it only contains information + // on the latest release as array(version, info). On success it contains + // array(version, info, download url string) + $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); + if (!$this->_registry->channelExists($parr['channel'])) { + do { + if ($this->config->get('auto_discover') && $this->discover($parr['channel'])) { + break; + } + + $this->configSet('default_channel', $curchannel); + return PEAR::raiseError('Unknown remote channel: ' . $parr['channel']); + } while (false); + } + + $chan = &$this->_registry->getChannel($parr['channel']); + if (PEAR::isError($chan)) { + return $chan; + } + + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $version = $this->_registry->packageInfo($parr['package'], 'version', $parr['channel']); + $stability = $this->_registry->packageInfo($parr['package'], 'stability', $parr['channel']); + // package is installed - use the installed release stability level + if (!isset($parr['state']) && $stability !== null) { + $state = $stability['release']; + } + PEAR::staticPopErrorHandling(); + $base2 = false; + + $preferred_mirror = $this->config->get('preferred_mirror'); + if (!$chan->supportsREST($preferred_mirror) || + ( + !($base2 = $chan->getBaseURL('REST1.3', $preferred_mirror)) + && + !($base = $chan->getBaseURL('REST1.0', $preferred_mirror)) + ) + ) { + return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.'); + } + + if ($base2) { + $rest = &$this->config->getREST('1.3', $this->_options); + $base = $base2; + } else { + $rest = &$this->config->getREST('1.0', $this->_options); + } + + $downloadVersion = false; + if (!isset($parr['version']) && !isset($parr['state']) && $version + && !PEAR::isError($version) + && !isset($this->_options['downloadonly']) + ) { + $downloadVersion = $version; + } + + $url = $rest->getDownloadURL($base, $parr, $state, $downloadVersion, $chan->getName()); + if (PEAR::isError($url)) { + $this->configSet('default_channel', $curchannel); + return $url; + } + + if ($parr['channel'] != $curchannel) { + $this->configSet('default_channel', $curchannel); + } + + if (!is_array($url)) { + return $url; + } + + $url['raw'] = false; // no checking is necessary for REST + if (!is_array($url['info'])) { + return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . + 'this should never happen'); + } + + if (!isset($this->_options['force']) && + !isset($this->_options['downloadonly']) && + $version && + !PEAR::isError($version) && + !isset($parr['group']) + ) { + if (version_compare($version, $url['version'], '=')) { + return PEAR::raiseError($this->_registry->parsedPackageNameToString( + $parr, true) . ' is already installed and is the same as the ' . + 'released version ' . $url['version'], -976); + } + + if (version_compare($version, $url['version'], '>')) { + return PEAR::raiseError($this->_registry->parsedPackageNameToString( + $parr, true) . ' is already installed and is newer than detected ' . + 'released version ' . $url['version'], -976); + } + } + + if (isset($url['info']['required']) || $url['compatible']) { + require_once 'PEAR/PackageFile/v2.php'; + $pf = new PEAR_PackageFile_v2; + $pf->setRawChannel($parr['channel']); + if ($url['compatible']) { + $pf->setRawCompatible($url['compatible']); + } + } else { + require_once 'PEAR/PackageFile/v1.php'; + $pf = new PEAR_PackageFile_v1; + } + + $pf->setRawPackage($url['package']); + $pf->setDeps($url['info']); + if ($url['compatible']) { + $pf->setCompatible($url['compatible']); + } + + $pf->setRawState($url['stability']); + $url['info'] = &$pf; + if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { + $ext = '.tar'; + } else { + $ext = '.tgz'; + } + + if (is_array($url) && isset($url['url'])) { + $url['url'] .= $ext; + } + + return $url; + } + + /** + * @param array dependency array + * @access private + */ + function _getDepPackageDownloadUrl($dep, $parr) + { + $xsdversion = isset($dep['rel']) ? '1.0' : '2.0'; + $curchannel = $this->config->get('default_channel'); + if (isset($dep['uri'])) { + $xsdversion = '2.0'; + $chan = &$this->_registry->getChannel('__uri'); + if (PEAR::isError($chan)) { + return $chan; + } + + $version = $this->_registry->packageInfo($dep['name'], 'version', '__uri'); + $this->configSet('default_channel', '__uri'); + } else { + if (isset($dep['channel'])) { + $remotechannel = $dep['channel']; + } else { + $remotechannel = 'pear.php.net'; + } + + if (!$this->_registry->channelExists($remotechannel)) { + do { + if ($this->config->get('auto_discover')) { + if ($this->discover($remotechannel)) { + break; + } + } + return PEAR::raiseError('Unknown remote channel: ' . $remotechannel); + } while (false); + } + + $chan = &$this->_registry->getChannel($remotechannel); + if (PEAR::isError($chan)) { + return $chan; + } + + $version = $this->_registry->packageInfo($dep['name'], 'version', $remotechannel); + $this->configSet('default_channel', $remotechannel); + } + + $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); + if (isset($parr['state']) && isset($parr['version'])) { + unset($parr['state']); + } + + if (isset($dep['uri'])) { + $info = &$this->newDownloaderPackage($this); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = $info->initialize($dep); + PEAR::staticPopErrorHandling(); + if (!$err) { + // skip parameters that were missed by preferred_state + return PEAR::raiseError('Cannot initialize dependency'); + } + + if (PEAR::isError($err)) { + if (!isset($this->_options['soft'])) { + $this->log(0, $err->getMessage()); + } + + if (is_object($info)) { + $param = $info->getChannel() . '/' . $info->getPackage(); + } + return PEAR::raiseError('Package "' . $param . '" is not valid'); + } + return $info; + } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) + && + ( + ($base2 = $chan->getBaseURL('REST1.3', $this->config->get('preferred_mirror'))) + || + ($base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) + ) + ) { + if ($base2) { + $base = $base2; + $rest = &$this->config->getREST('1.3', $this->_options); + } else { + $rest = &$this->config->getREST('1.0', $this->_options); + } + + $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr, + $state, $version, $chan->getName()); + if (PEAR::isError($url)) { + return $url; + } + + if ($parr['channel'] != $curchannel) { + $this->configSet('default_channel', $curchannel); + } + + if (!is_array($url)) { + return $url; + } + + $url['raw'] = false; // no checking is necessary for REST + if (!is_array($url['info'])) { + return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . + 'this should never happen'); + } + + if (isset($url['info']['required'])) { + if (!class_exists('PEAR_PackageFile_v2')) { + require_once 'PEAR/PackageFile/v2.php'; + } + $pf = new PEAR_PackageFile_v2; + $pf->setRawChannel($remotechannel); + } else { + if (!class_exists('PEAR_PackageFile_v1')) { + require_once 'PEAR/PackageFile/v1.php'; + } + $pf = new PEAR_PackageFile_v1; + + } + $pf->setRawPackage($url['package']); + $pf->setDeps($url['info']); + if ($url['compatible']) { + $pf->setCompatible($url['compatible']); + } + + $pf->setRawState($url['stability']); + $url['info'] = &$pf; + if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { + $ext = '.tar'; + } else { + $ext = '.tgz'; + } + + if (is_array($url) && isset($url['url'])) { + $url['url'] .= $ext; + } + + return $url; + } + + return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.'); + } + + /** + * @deprecated in favor of _getPackageDownloadUrl + */ + function getPackageDownloadUrl($package, $version = null, $channel = false) + { + if ($version) { + $package .= "-$version"; + } + if ($this === null || $this->_registry === null) { + $package = "http://pear.php.net/get/$package"; + } else { + $chan = $this->_registry->getChannel($channel); + if (PEAR::isError($chan)) { + return ''; + } + $package = "http://" . $chan->getServer() . "/get/$package"; + } + if (!extension_loaded("zlib")) { + $package .= '?uncompress=yes'; + } + return $package; + } + + /** + * Retrieve a list of downloaded packages after a call to {@link download()}. + * + * Also resets the list of downloaded packages. + * @return array + */ + function getDownloadedPackages() + { + $ret = $this->_downloadedPackages; + $this->_downloadedPackages = array(); + $this->_toDownload = array(); + return $ret; + } + + function _downloadCallback($msg, $params = null) + { + switch ($msg) { + case 'saveas': + $this->log(1, "downloading $params ..."); + break; + case 'done': + $this->log(1, '...done: ' . number_format($params, 0, '', ',') . ' bytes'); + break; + case 'bytesread': + static $bytes; + if (empty($bytes)) { + $bytes = 0; + } + if (!($bytes % 10240)) { + $this->log(1, '.', false); + } + $bytes += $params; + break; + case 'start': + if($params[1] == -1) { + $length = "Unknown size"; + } else { + $length = number_format($params[1], 0, '', ',')." bytes"; + } + $this->log(1, "Starting to download {$params[0]} ($length)"); + break; + } + if (method_exists($this->ui, '_downloadCallback')) + $this->ui->_downloadCallback($msg, $params); + } + + function _prependPath($path, $prepend) + { + if (strlen($prepend) > 0) { + if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { + if (preg_match('/^[a-z]:/i', $prepend)) { + $prepend = substr($prepend, 2); + } elseif ($prepend{0} != '\\') { + $prepend = "\\$prepend"; + } + $path = substr($path, 0, 2) . $prepend . substr($path, 2); + } else { + $path = $prepend . $path; + } + } + return $path; + } + + /** + * @param string + * @param integer + */ + function pushError($errmsg, $code = -1) + { + array_push($this->_errorStack, array($errmsg, $code)); + } + + function getErrorMsgs() + { + $msgs = array(); + $errs = $this->_errorStack; + foreach ($errs as $err) { + $msgs[] = $err[0]; + } + $this->_errorStack = array(); + return $msgs; + } + + /** + * for BC + * + * @deprecated + */ + function sortPkgDeps(&$packages, $uninstall = false) + { + $uninstall ? + $this->sortPackagesForUninstall($packages) : + $this->sortPackagesForInstall($packages); + } + + /** + * Sort a list of arrays of array(downloaded packagefilename) by dependency. + * + * This uses the topological sort method from graph theory, and the + * Structures_Graph package to properly sort dependencies for installation. + * @param array an array of downloaded PEAR_Downloader_Packages + * @return array array of array(packagefilename, package.xml contents) + */ + function sortPackagesForInstall(&$packages) + { + require_once 'Structures/Graph.php'; + require_once 'Structures/Graph/Node.php'; + require_once 'Structures/Graph/Manipulator/TopologicalSorter.php'; + $depgraph = new Structures_Graph(true); + $nodes = array(); + $reg = &$this->config->getRegistry(); + foreach ($packages as $i => $package) { + $pname = $reg->parsedPackageNameToString( + array( + 'channel' => $package->getChannel(), + 'package' => strtolower($package->getPackage()), + )); + $nodes[$pname] = new Structures_Graph_Node; + $nodes[$pname]->setData($packages[$i]); + $depgraph->addNode($nodes[$pname]); + } + + $deplinks = array(); + foreach ($nodes as $package => $node) { + $pf = &$node->getData(); + $pdeps = $pf->getDeps(true); + if (!$pdeps) { + continue; + } + + if ($pf->getPackagexmlVersion() == '1.0') { + foreach ($pdeps as $dep) { + if ($dep['type'] != 'pkg' || + (isset($dep['optional']) && $dep['optional'] == 'yes')) { + continue; + } + + $dname = $reg->parsedPackageNameToString( + array( + 'channel' => 'pear.php.net', + 'package' => strtolower($dep['name']), + )); + + if (isset($nodes[$dname])) { + if (!isset($deplinks[$dname])) { + $deplinks[$dname] = array(); + } + + $deplinks[$dname][$package] = 1; + // dependency is in installed packages + continue; + } + + $dname = $reg->parsedPackageNameToString( + array( + 'channel' => 'pecl.php.net', + 'package' => strtolower($dep['name']), + )); + + if (isset($nodes[$dname])) { + if (!isset($deplinks[$dname])) { + $deplinks[$dname] = array(); + } + + $deplinks[$dname][$package] = 1; + // dependency is in installed packages + continue; + } + } + } else { + // the only ordering we care about is: + // 1) subpackages must be installed before packages that depend on them + // 2) required deps must be installed before packages that depend on them + if (isset($pdeps['required']['subpackage'])) { + $t = $pdeps['required']['subpackage']; + if (!isset($t[0])) { + $t = array($t); + } + + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } + + if (isset($pdeps['group'])) { + if (!isset($pdeps['group'][0])) { + $pdeps['group'] = array($pdeps['group']); + } + + foreach ($pdeps['group'] as $group) { + if (isset($group['subpackage'])) { + $t = $group['subpackage']; + if (!isset($t[0])) { + $t = array($t); + } + + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } + } + } + + if (isset($pdeps['optional']['subpackage'])) { + $t = $pdeps['optional']['subpackage']; + if (!isset($t[0])) { + $t = array($t); + } + + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } + + if (isset($pdeps['required']['package'])) { + $t = $pdeps['required']['package']; + if (!isset($t[0])) { + $t = array($t); + } + + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } + + if (isset($pdeps['group'])) { + if (!isset($pdeps['group'][0])) { + $pdeps['group'] = array($pdeps['group']); + } + + foreach ($pdeps['group'] as $group) { + if (isset($group['package'])) { + $t = $group['package']; + if (!isset($t[0])) { + $t = array($t); + } + + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } + } + } + } + } + + $this->_detectDepCycle($deplinks); + foreach ($deplinks as $dependent => $parents) { + foreach ($parents as $parent => $unused) { + $nodes[$dependent]->connectTo($nodes[$parent]); + } + } + + $installOrder = Structures_Graph_Manipulator_TopologicalSorter::sort($depgraph); + $ret = array(); + for ($i = 0, $count = count($installOrder); $i < $count; $i++) { + foreach ($installOrder[$i] as $index => $sortedpackage) { + $data = &$installOrder[$i][$index]->getData(); + $ret[] = &$nodes[$reg->parsedPackageNameToString( + array( + 'channel' => $data->getChannel(), + 'package' => strtolower($data->getPackage()), + ))]->getData(); + } + } + + $packages = $ret; + return; + } + + /** + * Detect recursive links between dependencies and break the cycles + * + * @param array + * @access private + */ + function _detectDepCycle(&$deplinks) + { + do { + $keepgoing = false; + foreach ($deplinks as $dep => $parents) { + foreach ($parents as $parent => $unused) { + // reset the parent cycle detector + $this->_testCycle(null, null, null); + if ($this->_testCycle($dep, $deplinks, $parent)) { + $keepgoing = true; + unset($deplinks[$dep][$parent]); + if (count($deplinks[$dep]) == 0) { + unset($deplinks[$dep]); + } + + continue 3; + } + } + } + } while ($keepgoing); + } + + function _testCycle($test, $deplinks, $dep) + { + static $visited = array(); + if ($test === null) { + $visited = array(); + return; + } + + // this happens when a parent has a dep cycle on another dependency + // but the child is not part of the cycle + if (isset($visited[$dep])) { + return false; + } + + $visited[$dep] = 1; + if ($test == $dep) { + return true; + } + + if (isset($deplinks[$dep])) { + if (in_array($test, array_keys($deplinks[$dep]), true)) { + return true; + } + + foreach ($deplinks[$dep] as $parent => $unused) { + if ($this->_testCycle($test, $deplinks, $parent)) { + return true; + } + } + } + + return false; + } + + /** + * Set up the dependency for installation parsing + * + * @param array $t dependency information + * @param PEAR_Registry $reg + * @param array $deplinks list of dependency links already established + * @param array $nodes all existing package nodes + * @param string $package parent package name + * @access private + */ + function _setupGraph($t, $reg, &$deplinks, &$nodes, $package) + { + foreach ($t as $dep) { + $depchannel = !isset($dep['channel']) ? '__uri': $dep['channel']; + $dname = $reg->parsedPackageNameToString( + array( + 'channel' => $depchannel, + 'package' => strtolower($dep['name']), + )); + + if (isset($nodes[$dname])) { + if (!isset($deplinks[$dname])) { + $deplinks[$dname] = array(); + } + $deplinks[$dname][$package] = 1; + } + } + } + + function _dependsOn($a, $b) + { + return $this->_checkDepTree(strtolower($a->getChannel()), strtolower($a->getPackage()), $b); + } + + function _checkDepTree($channel, $package, $b, $checked = array()) + { + $checked[$channel][$package] = true; + if (!isset($this->_depTree[$channel][$package])) { + return false; + } + + if (isset($this->_depTree[$channel][$package][strtolower($b->getChannel())] + [strtolower($b->getPackage())])) { + return true; + } + + foreach ($this->_depTree[$channel][$package] as $ch => $packages) { + foreach ($packages as $pa => $true) { + if ($this->_checkDepTree($ch, $pa, $b, $checked)) { + return true; + } + } + } + + return false; + } + + function _sortInstall($a, $b) + { + if (!$a->getDeps() && !$b->getDeps()) { + return 0; // neither package has dependencies, order is insignificant + } + if ($a->getDeps() && !$b->getDeps()) { + return 1; // $a must be installed after $b because $a has dependencies + } + if (!$a->getDeps() && $b->getDeps()) { + return -1; // $b must be installed after $a because $b has dependencies + } + // both packages have dependencies + if ($this->_dependsOn($a, $b)) { + return 1; + } + if ($this->_dependsOn($b, $a)) { + return -1; + } + return 0; + } + + /** + * Download a file through HTTP. Considers suggested file name in + * Content-disposition: header and can run a callback function for + * different events. The callback will be called with two + * parameters: the callback type, and parameters. The implemented + * callback types are: + * + * 'setup' called at the very beginning, parameter is a UI object + * that should be used for all output + * 'message' the parameter is a string with an informational message + * 'saveas' may be used to save with a different file name, the + * parameter is the filename that is about to be used. + * If a 'saveas' callback returns a non-empty string, + * that file name will be used as the filename instead. + * Note that $save_dir will not be affected by this, only + * the basename of the file. + * 'start' download is starting, parameter is number of bytes + * that are expected, or -1 if unknown + * 'bytesread' parameter is the number of bytes read so far + * 'done' download is complete, parameter is the total number + * of bytes read + * 'connfailed' if the TCP/SSL connection fails, this callback is called + * with array(host,port,errno,errmsg) + * 'writefailed' if writing to disk fails, this callback is called + * with array(destfile,errmsg) + * + * If an HTTP proxy has been configured (http_proxy PEAR_Config + * setting), the proxy will be used. + * + * @param string $url the URL to download + * @param object $ui PEAR_Frontend_* instance + * @param object $config PEAR_Config instance + * @param string $save_dir directory to save file in + * @param mixed $callback function/method to call for status + * updates + * @param false|string|array $lastmodified header values to check against for caching + * use false to return the header values from this download + * @param false|array $accept Accept headers to send + * @param false|string $channel Channel to use for retrieving authentication + * @return string|array Returns the full path of the downloaded file or a PEAR + * error on failure. If the error is caused by + * socket-related errors, the error object will + * have the fsockopen error code available through + * getCode(). If caching is requested, then return the header + * values. + * + * @access public + */ + function downloadHttp($url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null, + $accept = false, $channel = false) + { + static $redirect = 0; + // always reset , so we are clean case of error + $wasredirect = $redirect; + $redirect = 0; + if ($callback) { + call_user_func($callback, 'setup', array(&$ui)); + } + + $info = parse_url($url); + if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) { + return PEAR::raiseError('Cannot download non-http URL "' . $url . '"'); + } + + if (!isset($info['host'])) { + return PEAR::raiseError('Cannot download from non-URL "' . $url . '"'); + } + + $host = isset($info['host']) ? $info['host'] : null; + $port = isset($info['port']) ? $info['port'] : null; + $path = isset($info['path']) ? $info['path'] : null; + + if (isset($this)) { + $config = &$this->config; + } else { + $config = &PEAR_Config::singleton(); + } + + $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; + if ($config->get('http_proxy') && + $proxy = parse_url($config->get('http_proxy'))) { + $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; + if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') { + $proxy_host = 'ssl://' . $proxy_host; + } + $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; + $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; + $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; + + if ($callback) { + call_user_func($callback, 'message', "Using HTTP proxy $host:$port"); + } + } + + if (empty($port)) { + $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80; + } + + $scheme = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http'; + + if ($proxy_host != '') { + $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr); + if (!$fp) { + if ($callback) { + call_user_func($callback, 'connfailed', array($proxy_host, $proxy_port, + $errno, $errstr)); + } + return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", $errno); + } + + if ($lastmodified === false || $lastmodified) { + $request = "GET $url HTTP/1.1\r\n"; + $request .= "Host: $host\r\n"; + } else { + $request = "GET $url HTTP/1.0\r\n"; + $request .= "Host: $host\r\n"; + } + } else { + $network_host = $host; + if (isset($info['scheme']) && $info['scheme'] == 'https') { + $network_host = 'ssl://' . $host; + } + + $fp = @fsockopen($network_host, $port, $errno, $errstr); + if (!$fp) { + if ($callback) { + call_user_func($callback, 'connfailed', array($host, $port, + $errno, $errstr)); + } + return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); + } + + if ($lastmodified === false || $lastmodified) { + $request = "GET $path HTTP/1.1\r\n"; + $request .= "Host: $host\r\n"; + } else { + $request = "GET $path HTTP/1.0\r\n"; + $request .= "Host: $host\r\n"; + } + } + + $ifmodifiedsince = ''; + if (is_array($lastmodified)) { + if (isset($lastmodified['Last-Modified'])) { + $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n"; + } + + if (isset($lastmodified['ETag'])) { + $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n"; + } + } else { + $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : ''); + } + + $request .= $ifmodifiedsince . + "User-Agent: PEAR/1.9.3/PHP/" . PHP_VERSION . "\r\n"; + + if (isset($this)) { // only pass in authentication for non-static calls + $username = $config->get('username', null, $channel); + $password = $config->get('password', null, $channel); + if ($username && $password) { + $tmp = base64_encode("$username:$password"); + $request .= "Authorization: Basic $tmp\r\n"; + } + } + + if ($proxy_host != '' && $proxy_user != '') { + $request .= 'Proxy-Authorization: Basic ' . + base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; + } + + if ($accept) { + $request .= 'Accept: ' . implode(', ', $accept) . "\r\n"; + } + + $request .= "Connection: close\r\n"; + $request .= "\r\n"; + fwrite($fp, $request); + $headers = array(); + $reply = 0; + while (trim($line = fgets($fp, 1024))) { + if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) { + $headers[strtolower($matches[1])] = trim($matches[2]); + } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { + $reply = (int)$matches[1]; + if ($reply == 304 && ($lastmodified || ($lastmodified === false))) { + return false; + } + + if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) { + return PEAR::raiseError("File $scheme://$host:$port$path not valid (received: $line)"); + } + } + } + + if ($reply != 200) { + if (!isset($headers['location'])) { + return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirected but no location)"); + } + + if ($wasredirect > 4) { + return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirection looped more than 5 times)"); + } + + $redirect = $wasredirect + 1; + return $this->downloadHttp($headers['location'], + $ui, $save_dir, $callback, $lastmodified, $accept); + } + + if (isset($headers['content-disposition']) && + preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|\\z)/', $headers['content-disposition'], $matches)) { + $save_as = basename($matches[1]); + } else { + $save_as = basename($url); + } + + if ($callback) { + $tmp = call_user_func($callback, 'saveas', $save_as); + if ($tmp) { + $save_as = $tmp; + } + } + + $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as; + if (is_link($dest_file)) { + return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $dest_file . ' as it is symlinked to ' . readlink($dest_file) . ' - Possible symlink attack'); + } + + if (!$wp = @fopen($dest_file, 'wb')) { + fclose($fp); + if ($callback) { + call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); + } + return PEAR::raiseError("could not open $dest_file for writing"); + } + + $length = isset($headers['content-length']) ? $headers['content-length'] : -1; + + $bytes = 0; + if ($callback) { + call_user_func($callback, 'start', array(basename($dest_file), $length)); + } + + while ($data = fread($fp, 1024)) { + $bytes += strlen($data); + if ($callback) { + call_user_func($callback, 'bytesread', $bytes); + } + if (!@fwrite($wp, $data)) { + fclose($fp); + if ($callback) { + call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); + } + return PEAR::raiseError("$dest_file: write failed ($php_errormsg)"); + } + } + + fclose($fp); + fclose($wp); + if ($callback) { + call_user_func($callback, 'done', $bytes); + } + + if ($lastmodified === false || $lastmodified) { + if (isset($headers['etag'])) { + $lastmodified = array('ETag' => $headers['etag']); + } + + if (isset($headers['last-modified'])) { + if (is_array($lastmodified)) { + $lastmodified['Last-Modified'] = $headers['last-modified']; + } else { + $lastmodified = $headers['last-modified']; + } + } + return array($dest_file, $lastmodified, $headers); + } + return $dest_file; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Downloader/Package.php b/typo3conf/ext/phpunit/PEAR/PEAR/Downloader/Package.php new file mode 100644 index 0000000..60c9834 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Downloader/Package.php @@ -0,0 +1,1988 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Package.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Error code when parameter initialization fails because no releases + * exist within preferred_state, but releases do exist + */ +define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003); +/** + * Error code when parameter initialization fails because no releases + * exist that will work with the existing PHP version + */ +define('PEAR_DOWNLOADER_PACKAGE_PHPVERSION', -1004); + +/** + * Coordinates download parameters and manages their dependencies + * prior to downloading them. + * + * Input can come from three sources: + * + * - local files (archives or package.xml) + * - remote files (downloadable urls) + * - abstract package names + * + * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires + * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the + * format returned of dependencies is slightly different from that used in package.xml. + * + * This class hides the differences between these elements, and makes automatic + * dependency resolution a piece of cake. It also manages conflicts when + * two classes depend on incompatible dependencies, or differing versions of the same + * package dependency. In addition, download will not be attempted if the php version is + * not supported, PEAR installer version is not supported, or non-PECL extensions are not + * installed. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Downloader_Package +{ + /** + * @var PEAR_Downloader + */ + var $_downloader; + /** + * @var PEAR_Config + */ + var $_config; + /** + * @var PEAR_Registry + */ + var $_registry; + /** + * Used to implement packagingroot properly + * @var PEAR_Registry + */ + var $_installRegistry; + /** + * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2 + */ + var $_packagefile; + /** + * @var array + */ + var $_parsedname; + /** + * @var array + */ + var $_downloadURL; + /** + * @var array + */ + var $_downloadDeps = array(); + /** + * @var boolean + */ + var $_valid = false; + /** + * @var boolean + */ + var $_analyzed = false; + /** + * if this or a parent package was invoked with Package-state, this is set to the + * state variable. + * + * This allows temporary reassignment of preferred_state for a parent package and all of + * its dependencies. + * @var string|false + */ + var $_explicitState = false; + /** + * If this package is invoked with Package#group, this variable will be true + */ + var $_explicitGroup = false; + /** + * Package type local|url + * @var string + */ + var $_type; + /** + * Contents of package.xml, if downloaded from a remote channel + * @var string|false + * @access private + */ + var $_rawpackagefile; + /** + * @var boolean + * @access private + */ + var $_validated = false; + + /** + * @param PEAR_Downloader + */ + function PEAR_Downloader_Package(&$downloader) + { + $this->_downloader = &$downloader; + $this->_config = &$this->_downloader->config; + $this->_registry = &$this->_config->getRegistry(); + $options = $downloader->getOptions(); + if (isset($options['packagingroot'])) { + $this->_config->setInstallRoot($options['packagingroot']); + $this->_installRegistry = &$this->_config->getRegistry(); + $this->_config->setInstallRoot(false); + } else { + $this->_installRegistry = &$this->_registry; + } + $this->_valid = $this->_analyzed = false; + } + + /** + * Parse the input and determine whether this is a local file, a remote uri, or an + * abstract package name. + * + * This is the heart of the PEAR_Downloader_Package(), and is used in + * {@link PEAR_Downloader::download()} + * @param string + * @return bool|PEAR_Error + */ + function initialize($param) + { + $origErr = $this->_fromFile($param); + if ($this->_valid) { + return true; + } + + $options = $this->_downloader->getOptions(); + if (isset($options['offline'])) { + if (PEAR::isError($origErr) && !isset($options['soft'])) { + foreach ($origErr->getUserInfo() as $userInfo) { + if (isset($userInfo['message'])) { + $this->_downloader->log(0, $userInfo['message']); + } + } + + $this->_downloader->log(0, $origErr->getMessage()); + } + + return PEAR::raiseError('Cannot download non-local package "' . $param . '"'); + } + + $err = $this->_fromUrl($param); + if (PEAR::isError($err) || !$this->_valid) { + if ($this->_type == 'url') { + if (PEAR::isError($err) && !isset($options['soft'])) { + $this->_downloader->log(0, $err->getMessage()); + } + + return PEAR::raiseError("Invalid or missing remote package file"); + } + + $err = $this->_fromString($param); + if (PEAR::isError($err) || !$this->_valid) { + if (PEAR::isError($err) && $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) { + return false; // instruct the downloader to silently skip + } + + if (isset($this->_type) && $this->_type == 'local' && PEAR::isError($origErr)) { + if (is_array($origErr->getUserInfo())) { + foreach ($origErr->getUserInfo() as $err) { + if (is_array($err)) { + $err = $err['message']; + } + + if (!isset($options['soft'])) { + $this->_downloader->log(0, $err); + } + } + } + + if (!isset($options['soft'])) { + $this->_downloader->log(0, $origErr->getMessage()); + } + + if (is_array($param)) { + $param = $this->_registry->parsedPackageNameToString($param, true); + } + + if (!isset($options['soft'])) { + $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file"); + } + + // Passing no message back - already logged above + return PEAR::raiseError(); + } + + if (PEAR::isError($err) && !isset($options['soft'])) { + $this->_downloader->log(0, $err->getMessage()); + } + + if (is_array($param)) { + $param = $this->_registry->parsedPackageNameToString($param, true); + } + + if (!isset($options['soft'])) { + $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file"); + } + + // Passing no message back - already logged above + return PEAR::raiseError(); + } + } + + return true; + } + + /** + * Retrieve any non-local packages + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error + */ + function &download() + { + if (isset($this->_packagefile)) { + return $this->_packagefile; + } + + if (isset($this->_downloadURL['url'])) { + $this->_isvalid = false; + $info = $this->getParsedPackage(); + foreach ($info as $i => $p) { + $info[$i] = strtolower($p); + } + + $err = $this->_fromUrl($this->_downloadURL['url'], + $this->_registry->parsedPackageNameToString($this->_parsedname, true)); + $newinfo = $this->getParsedPackage(); + foreach ($newinfo as $i => $p) { + $newinfo[$i] = strtolower($p); + } + + if ($info != $newinfo) { + do { + if ($info['channel'] == 'pecl.php.net' && $newinfo['channel'] == 'pear.php.net') { + $info['channel'] = 'pear.php.net'; + if ($info == $newinfo) { + // skip the channel check if a pecl package says it's a PEAR package + break; + } + } + if ($info['channel'] == 'pear.php.net' && $newinfo['channel'] == 'pecl.php.net') { + $info['channel'] = 'pecl.php.net'; + if ($info == $newinfo) { + // skip the channel check if a pecl package says it's a PEAR package + break; + } + } + + return PEAR::raiseError('CRITICAL ERROR: We are ' . + $this->_registry->parsedPackageNameToString($info) . ', but the file ' . + 'downloaded claims to be ' . + $this->_registry->parsedPackageNameToString($this->getParsedPackage())); + } while (false); + } + + if (PEAR::isError($err) || !$this->_valid) { + return $err; + } + } + + $this->_type = 'local'; + return $this->_packagefile; + } + + function &getPackageFile() + { + return $this->_packagefile; + } + + function &getDownloader() + { + return $this->_downloader; + } + + function getType() + { + return $this->_type; + } + + /** + * Like {@link initialize()}, but operates on a dependency + */ + function fromDepURL($dep) + { + $this->_downloadURL = $dep; + if (isset($dep['uri'])) { + $options = $this->_downloader->getOptions(); + if (!extension_loaded("zlib") || isset($options['nocompress'])) { + $ext = '.tar'; + } else { + $ext = '.tgz'; + } + + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->_fromUrl($dep['uri'] . $ext); + PEAR::popErrorHandling(); + if (PEAR::isError($err)) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $err->getMessage()); + } + + return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' . + 'cannot download'); + } + } else { + $this->_parsedname = + array( + 'package' => $dep['info']->getPackage(), + 'channel' => $dep['info']->getChannel(), + 'version' => $dep['version'] + ); + if (!isset($dep['nodefault'])) { + $this->_parsedname['group'] = 'default'; // download the default dependency group + $this->_explicitGroup = false; + } + + $this->_rawpackagefile = $dep['raw']; + } + } + + function detectDependencies($params) + { + $options = $this->_downloader->getOptions(); + if (isset($options['downloadonly'])) { + return; + } + + if (isset($options['offline'])) { + $this->_downloader->log(3, 'Skipping dependency download check, --offline specified'); + return; + } + + $pname = $this->getParsedPackage(); + if (!$pname) { + return; + } + + $deps = $this->getDeps(); + if (!$deps) { + return; + } + + if (isset($deps['required'])) { // package.xml 2.0 + return $this->_detect2($deps, $pname, $options, $params); + } + + return $this->_detect1($deps, $pname, $options, $params); + } + + function setValidated() + { + $this->_validated = true; + } + + function alreadyValidated() + { + return $this->_validated; + } + + /** + * Remove packages to be downloaded that are already installed + * @param array of PEAR_Downloader_Package objects + * @static + */ + function removeInstalled(&$params) + { + if (!isset($params[0])) { + return; + } + + $options = $params[0]->_downloader->getOptions(); + if (!isset($options['downloadonly'])) { + foreach ($params as $i => $param) { + $package = $param->getPackage(); + $channel = $param->getChannel(); + // remove self if already installed with this version + // this does not need any pecl magic - we only remove exact matches + if ($param->_installRegistry->packageExists($package, $channel)) { + $packageVersion = $param->_installRegistry->packageInfo($package, 'version', $channel); + if (version_compare($packageVersion, $param->getVersion(), '==')) { + if (!isset($options['force'])) { + $info = $param->getParsedPackage(); + unset($info['version']); + unset($info['state']); + if (!isset($options['soft'])) { + $param->_downloader->log(1, 'Skipping package "' . + $param->getShortName() . + '", already installed as version ' . $packageVersion); + } + $params[$i] = false; + } + } elseif (!isset($options['force']) && !isset($options['upgrade']) && + !isset($options['soft'])) { + $info = $param->getParsedPackage(); + $param->_downloader->log(1, 'Skipping package "' . + $param->getShortName() . + '", already installed as version ' . $packageVersion); + $params[$i] = false; + } + } + } + } + + PEAR_Downloader_Package::removeDuplicates($params); + } + + function _detect2($deps, $pname, $options, $params) + { + $this->_downloadDeps = array(); + $groupnotfound = false; + foreach (array('package', 'subpackage') as $packagetype) { + // get required dependency group + if (isset($deps['required'][$packagetype])) { + if (isset($deps['required'][$packagetype][0])) { + foreach ($deps['required'][$packagetype] as $dep) { + if (isset($dep['conflicts'])) { + // skip any package that this package conflicts with + continue; + } + $ret = $this->_detect2Dep($dep, $pname, 'required', $params); + if (is_array($ret)) { + $this->_downloadDeps[] = $ret; + } elseif (PEAR::isError($ret) && !isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); + } + } + } else { + $dep = $deps['required'][$packagetype]; + if (!isset($dep['conflicts'])) { + // skip any package that this package conflicts with + $ret = $this->_detect2Dep($dep, $pname, 'required', $params); + if (is_array($ret)) { + $this->_downloadDeps[] = $ret; + } elseif (PEAR::isError($ret) && !isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); + } + } + } + } + + // get optional dependency group, if any + if (isset($deps['optional'][$packagetype])) { + $skipnames = array(); + if (!isset($deps['optional'][$packagetype][0])) { + $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]); + } + + foreach ($deps['optional'][$packagetype] as $dep) { + $skip = false; + if (!isset($options['alldeps'])) { + $dep['package'] = $dep['name']; + if (!isset($options['soft'])) { + $this->_downloader->log(3, 'Notice: package "' . + $this->_registry->parsedPackageNameToString($this->getParsedPackage(), + true) . '" optional dependency "' . + $this->_registry->parsedPackageNameToString(array('package' => + $dep['name'], 'channel' => 'pear.php.net'), true) . + '" will not be automatically downloaded'); + } + $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true); + $skip = true; + unset($dep['package']); + } + + $ret = $this->_detect2Dep($dep, $pname, 'optional', $params); + if (PEAR::isError($ret) && !isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); + } + + if (!$ret) { + $dep['package'] = $dep['name']; + $skip = count($skipnames) ? + $skipnames[count($skipnames) - 1] : ''; + if ($skip == + $this->_registry->parsedPackageNameToString($dep, true)) { + array_pop($skipnames); + } + } + + if (!$skip && is_array($ret)) { + $this->_downloadDeps[] = $ret; + } + } + + if (count($skipnames)) { + if (!isset($options['soft'])) { + $this->_downloader->log(1, 'Did not download optional dependencies: ' . + implode(', ', $skipnames) . + ', use --alldeps to download automatically'); + } + } + } + + // get requested dependency group, if any + $groupname = $this->getGroup(); + $explicit = $this->_explicitGroup; + if (!$groupname) { + if (!$this->canDefault()) { + continue; + } + + $groupname = 'default'; // try the default dependency group + } + + if ($groupnotfound) { + continue; + } + + if (isset($deps['group'])) { + if (isset($deps['group']['attribs'])) { + if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) { + $group = $deps['group']; + } elseif ($explicit) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, 'Warning: package "' . + $this->_registry->parsedPackageNameToString($pname, true) . + '" has no dependency ' . 'group named "' . $groupname . '"'); + } + + $groupnotfound = true; + continue; + } + } else { + $found = false; + foreach ($deps['group'] as $group) { + if (strtolower($group['attribs']['name']) == strtolower($groupname)) { + $found = true; + break; + } + } + + if (!$found) { + if ($explicit) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, 'Warning: package "' . + $this->_registry->parsedPackageNameToString($pname, true) . + '" has no dependency ' . 'group named "' . $groupname . '"'); + } + } + + $groupnotfound = true; + continue; + } + } + } + + if (isset($group) && isset($group[$packagetype])) { + if (isset($group[$packagetype][0])) { + foreach ($group[$packagetype] as $dep) { + $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' . + $group['attribs']['name'] . '"', $params); + if (is_array($ret)) { + $this->_downloadDeps[] = $ret; + } elseif (PEAR::isError($ret) && !isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); + } + } + } else { + $ret = $this->_detect2Dep($group[$packagetype], $pname, + 'dependency group "' . + $group['attribs']['name'] . '"', $params); + if (is_array($ret)) { + $this->_downloadDeps[] = $ret; + } elseif (PEAR::isError($ret) && !isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); + } + } + } + } + } + + function _detect2Dep($dep, $pname, $group, $params) + { + if (isset($dep['conflicts'])) { + return true; + } + + $options = $this->_downloader->getOptions(); + if (isset($dep['uri'])) { + return array('uri' => $dep['uri'], 'dep' => $dep);; + } + + $testdep = $dep; + $testdep['package'] = $dep['name']; + if (PEAR_Downloader_Package::willDownload($testdep, $params)) { + $dep['package'] = $dep['name']; + if (!isset($options['soft'])) { + $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group . + ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", will be installed'); + } + return false; + } + + $options = $this->_downloader->getOptions(); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if ($this->_explicitState) { + $pname['state'] = $this->_explicitState; + } + + $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname); + if (PEAR::isError($url)) { + PEAR::popErrorHandling(); + return $url; + } + + $dep['package'] = $dep['name']; + $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' && + !isset($options['alldeps']), true); + PEAR::popErrorHandling(); + if (PEAR::isError($ret)) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); + } + + return false; + } + + // check to see if a dep is already installed and is the same or newer + if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) { + $oper = 'has'; + } else { + $oper = 'gt'; + } + + // do not try to move this before getDepPackageDownloadURL + // we can't determine whether upgrade is necessary until we know what + // version would be downloaded + if (!isset($options['force']) && $this->isInstalled($ret, $oper)) { + $version = $this->_installRegistry->packageInfo($dep['name'], 'version', $dep['channel']); + $dep['package'] = $dep['name']; + if (!isset($options['soft'])) { + $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group . + ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '" version ' . $url['version'] . ', already installed as version ' . + $version); + } + + return false; + } + + if (isset($dep['nodefault'])) { + $ret['nodefault'] = true; + } + + return $ret; + } + + function _detect1($deps, $pname, $options, $params) + { + $this->_downloadDeps = array(); + $skipnames = array(); + foreach ($deps as $dep) { + $nodownload = false; + if (isset ($dep['type']) && $dep['type'] === 'pkg') { + $dep['channel'] = 'pear.php.net'; + $dep['package'] = $dep['name']; + switch ($dep['rel']) { + case 'not' : + continue 2; + case 'ge' : + case 'eq' : + case 'gt' : + case 'has' : + $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? + 'required' : + 'optional'; + if (PEAR_Downloader_Package::willDownload($dep, $params)) { + $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group + . ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", will be installed'); + continue 2; + } + $fakedp = new PEAR_PackageFile_v1; + $fakedp->setPackage($dep['name']); + // skip internet check if we are not upgrading (bug #5810) + if (!isset($options['upgrade']) && $this->isInstalled( + $fakedp, $dep['rel'])) { + $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group + . ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", is already installed'); + continue 2; + } + } + + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if ($this->_explicitState) { + $pname['state'] = $this->_explicitState; + } + + $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname); + $chan = 'pear.php.net'; + if (PEAR::isError($url)) { + // check to see if this is a pecl package that has jumped + // from pear.php.net to pecl.php.net channel + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; + } + + $newdep = PEAR_Dependency2::normalizeDep($dep); + $newdep = $newdep[0]; + $newdep['channel'] = 'pecl.php.net'; + $chan = 'pecl.php.net'; + $url = $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname); + $obj = &$this->_installRegistry->getPackage($dep['name']); + if (PEAR::isError($url)) { + PEAR::popErrorHandling(); + if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) { + $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? + 'required' : + 'optional'; + $dep['package'] = $dep['name']; + if (!isset($options['soft'])) { + $this->_downloader->log(3, $this->getShortName() . + ': Skipping ' . $group . ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", already installed as version ' . $obj->getVersion()); + } + $skip = count($skipnames) ? + $skipnames[count($skipnames) - 1] : ''; + if ($skip == + $this->_registry->parsedPackageNameToString($dep, true)) { + array_pop($skipnames); + } + continue; + } else { + if (isset($dep['optional']) && $dep['optional'] == 'yes') { + $this->_downloader->log(2, $this->getShortName() . + ': Skipping optional dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", no releases exist'); + continue; + } else { + return $url; + } + } + } + } + + PEAR::popErrorHandling(); + if (!isset($options['alldeps'])) { + if (isset($dep['optional']) && $dep['optional'] == 'yes') { + if (!isset($options['soft'])) { + $this->_downloader->log(3, 'Notice: package "' . + $this->getShortName() . + '" optional dependency "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $chan, 'package' => + $dep['name']), true) . + '" will not be automatically downloaded'); + } + $skipnames[] = $this->_registry->parsedPackageNameToString( + array('channel' => $chan, 'package' => + $dep['name']), true); + $nodownload = true; + } + } + + if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) { + if (!isset($dep['optional']) || $dep['optional'] == 'no') { + if (!isset($options['soft'])) { + $this->_downloader->log(3, 'Notice: package "' . + $this->getShortName() . + '" required dependency "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $chan, 'package' => + $dep['name']), true) . + '" will not be automatically downloaded'); + } + $skipnames[] = $this->_registry->parsedPackageNameToString( + array('channel' => $chan, 'package' => + $dep['name']), true); + $nodownload = true; + } + } + + // check to see if a dep is already installed + // do not try to move this before getDepPackageDownloadURL + // we can't determine whether upgrade is necessary until we know what + // version would be downloaded + if (!isset($options['force']) && $this->isInstalled( + $url, $dep['rel'])) { + $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? + 'required' : + 'optional'; + $dep['package'] = $dep['name']; + if (isset($newdep)) { + $version = $this->_installRegistry->packageInfo($newdep['name'], 'version', $newdep['channel']); + } else { + $version = $this->_installRegistry->packageInfo($dep['name'], 'version'); + } + + $dep['version'] = $url['version']; + if (!isset($options['soft'])) { + $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group . + ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", already installed as version ' . $version); + } + + $skip = count($skipnames) ? + $skipnames[count($skipnames) - 1] : ''; + if ($skip == + $this->_registry->parsedPackageNameToString($dep, true)) { + array_pop($skipnames); + } + + continue; + } + + if ($nodownload) { + continue; + } + + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if (isset($newdep)) { + $dep = $newdep; + } + + $dep['package'] = $dep['name']; + $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, + isset($dep['optional']) && $dep['optional'] == 'yes' && + !isset($options['alldeps']), true); + PEAR::popErrorHandling(); + if (PEAR::isError($ret)) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); + } + continue; + } + + $this->_downloadDeps[] = $ret; + } + } + + if (count($skipnames)) { + if (!isset($options['soft'])) { + $this->_downloader->log(1, 'Did not download dependencies: ' . + implode(', ', $skipnames) . + ', use --alldeps or --onlyreqdeps to download automatically'); + } + } + } + + function setDownloadURL($pkg) + { + $this->_downloadURL = $pkg; + } + + /** + * Set the package.xml object for this downloaded package + * + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg + */ + function setPackageFile(&$pkg) + { + $this->_packagefile = &$pkg; + } + + function getShortName() + { + return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(), + 'package' => $this->getPackage()), true); + } + + function getParsedPackage() + { + if (isset($this->_packagefile) || isset($this->_parsedname)) { + return array('channel' => $this->getChannel(), + 'package' => $this->getPackage(), + 'version' => $this->getVersion()); + } + + return false; + } + + function getDownloadURL() + { + return $this->_downloadURL; + } + + function canDefault() + { + if (isset($this->_downloadURL) && isset($this->_downloadURL['nodefault'])) { + return false; + } + + return true; + } + + function getPackage() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getPackage(); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->getPackage(); + } + + return false; + } + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + */ + function isSubpackage(&$pf) + { + if (isset($this->_packagefile)) { + return $this->_packagefile->isSubpackage($pf); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->isSubpackage($pf); + } + + return false; + } + + function getPackageType() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getPackageType(); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->getPackageType(); + } + + return false; + } + + function isBundle() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getPackageType() == 'bundle'; + } + + return false; + } + + function getPackageXmlVersion() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getPackagexmlVersion(); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->getPackagexmlVersion(); + } + + return '1.0'; + } + + function getChannel() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getChannel(); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->getChannel(); + } + + return false; + } + + function getURI() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getURI(); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->getURI(); + } + + return false; + } + + function getVersion() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getVersion(); + } elseif (isset($this->_downloadURL['version'])) { + return $this->_downloadURL['version']; + } + + return false; + } + + function isCompatible($pf) + { + if (isset($this->_packagefile)) { + return $this->_packagefile->isCompatible($pf); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->isCompatible($pf); + } + + return true; + } + + function setGroup($group) + { + $this->_parsedname['group'] = $group; + } + + function getGroup() + { + if (isset($this->_parsedname['group'])) { + return $this->_parsedname['group']; + } + + return ''; + } + + function isExtension($name) + { + if (isset($this->_packagefile)) { + return $this->_packagefile->isExtension($name); + } elseif (isset($this->_downloadURL['info'])) { + if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') { + return $this->_downloadURL['info']->getProvidesExtension() == $name; + } + + return false; + } + + return false; + } + + function getDeps() + { + if (isset($this->_packagefile)) { + $ver = $this->_packagefile->getPackagexmlVersion(); + if (version_compare($ver, '2.0', '>=')) { + return $this->_packagefile->getDeps(true); + } + + return $this->_packagefile->getDeps(); + } elseif (isset($this->_downloadURL['info'])) { + $ver = $this->_downloadURL['info']->getPackagexmlVersion(); + if (version_compare($ver, '2.0', '>=')) { + return $this->_downloadURL['info']->getDeps(true); + } + + return $this->_downloadURL['info']->getDeps(); + } + + return array(); + } + + /** + * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency + * returned from getDepDownloadURL() + */ + function isEqual($param) + { + if (is_object($param)) { + $channel = $param->getChannel(); + $package = $param->getPackage(); + if ($param->getURI()) { + $param = array( + 'channel' => $param->getChannel(), + 'package' => $param->getPackage(), + 'version' => $param->getVersion(), + 'uri' => $param->getURI(), + ); + } else { + $param = array( + 'channel' => $param->getChannel(), + 'package' => $param->getPackage(), + 'version' => $param->getVersion(), + ); + } + } else { + if (isset($param['uri'])) { + if ($this->getChannel() != '__uri') { + return false; + } + return $param['uri'] == $this->getURI(); + } + + $package = isset($param['package']) ? $param['package'] : $param['info']->getPackage(); + $channel = isset($param['channel']) ? $param['channel'] : $param['info']->getChannel(); + if (isset($param['rel'])) { + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; + } + + $newdep = PEAR_Dependency2::normalizeDep($param); + $newdep = $newdep[0]; + } elseif (isset($param['min'])) { + $newdep = $param; + } + } + + if (isset($newdep)) { + if (!isset($newdep['min'])) { + $newdep['min'] = '0'; + } + + if (!isset($newdep['max'])) { + $newdep['max'] = '100000000000000000000'; + } + + // use magic to support pecl packages suddenly jumping to the pecl channel + // we need to support both dependency possibilities + if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') { + if ($package == $this->getPackage()) { + $channel = 'pecl.php.net'; + } + } + if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') { + if ($package == $this->getPackage()) { + $channel = 'pear.php.net'; + } + } + + return (strtolower($package) == strtolower($this->getPackage()) && + $channel == $this->getChannel() && + version_compare($newdep['min'], $this->getVersion(), '<=') && + version_compare($newdep['max'], $this->getVersion(), '>=')); + } + + // use magic to support pecl packages suddenly jumping to the pecl channel + if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') { + if (strtolower($package) == strtolower($this->getPackage())) { + $channel = 'pear.php.net'; + } + } + + if (isset($param['version'])) { + return (strtolower($package) == strtolower($this->getPackage()) && + $channel == $this->getChannel() && + $param['version'] == $this->getVersion()); + } + + return strtolower($package) == strtolower($this->getPackage()) && + $channel == $this->getChannel(); + } + + function isInstalled($dep, $oper = '==') + { + if (!$dep) { + return false; + } + + if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') { + return false; + } + + if (is_object($dep)) { + $package = $dep->getPackage(); + $channel = $dep->getChannel(); + if ($dep->getURI()) { + $dep = array( + 'uri' => $dep->getURI(), + 'version' => $dep->getVersion(), + ); + } else { + $dep = array( + 'version' => $dep->getVersion(), + ); + } + } else { + if (isset($dep['uri'])) { + $channel = '__uri'; + $package = $dep['dep']['name']; + } else { + $channel = $dep['info']->getChannel(); + $package = $dep['info']->getPackage(); + } + } + + $options = $this->_downloader->getOptions(); + $test = $this->_installRegistry->packageExists($package, $channel); + if (!$test && $channel == 'pecl.php.net') { + // do magic to allow upgrading from old pecl packages to new ones + $test = $this->_installRegistry->packageExists($package, 'pear.php.net'); + $channel = 'pear.php.net'; + } + + if ($test) { + if (isset($dep['uri'])) { + if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) { + return true; + } + } + + if (isset($options['upgrade'])) { + $packageVersion = $this->_installRegistry->packageInfo($package, 'version', $channel); + if (version_compare($packageVersion, $dep['version'], '>=')) { + return true; + } + + return false; + } + + return true; + } + + return false; + } + + /** + * Detect duplicate package names with differing versions + * + * If a user requests to install Date 1.4.6 and Date 1.4.7, + * for instance, this is a logic error. This method + * detects this situation. + * + * @param array $params array of PEAR_Downloader_Package objects + * @param array $errorparams empty array + * @return array array of stupid duplicated packages in PEAR_Downloader_Package obejcts + */ + function detectStupidDuplicates($params, &$errorparams) + { + $existing = array(); + foreach ($params as $i => $param) { + $package = $param->getPackage(); + $channel = $param->getChannel(); + $group = $param->getGroup(); + if (!isset($existing[$channel . '/' . $package])) { + $existing[$channel . '/' . $package] = array(); + } + + if (!isset($existing[$channel . '/' . $package][$group])) { + $existing[$channel . '/' . $package][$group] = array(); + } + + $existing[$channel . '/' . $package][$group][] = $i; + } + + $indices = array(); + foreach ($existing as $package => $groups) { + foreach ($groups as $group => $dupes) { + if (count($dupes) > 1) { + $indices = $indices + $dupes; + } + } + } + + $indices = array_unique($indices); + foreach ($indices as $index) { + $errorparams[] = $params[$index]; + } + + return count($errorparams); + } + + /** + * @param array + * @param bool ignore install groups - for final removal of dupe packages + * @static + */ + function removeDuplicates(&$params, $ignoreGroups = false) + { + $pnames = array(); + foreach ($params as $i => $param) { + if (!$param) { + continue; + } + + if ($param->getPackage()) { + $group = $ignoreGroups ? '' : $param->getGroup(); + $pnames[$i] = $param->getChannel() . '/' . + $param->getPackage() . '-' . $param->getVersion() . '#' . $group; + } + } + + $pnames = array_unique($pnames); + $unset = array_diff(array_keys($params), array_keys($pnames)); + $testp = array_flip($pnames); + foreach ($params as $i => $param) { + if (!$param) { + $unset[] = $i; + continue; + } + + if (!is_a($param, 'PEAR_Downloader_Package')) { + $unset[] = $i; + continue; + } + + $group = $ignoreGroups ? '' : $param->getGroup(); + if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' . + $param->getVersion() . '#' . $group])) { + $unset[] = $i; + } + } + + foreach ($unset as $i) { + unset($params[$i]); + } + + $ret = array(); + foreach ($params as $i => $param) { + $ret[] = &$params[$i]; + } + + $params = array(); + foreach ($ret as $i => $param) { + $params[] = &$ret[$i]; + } + } + + function explicitState() + { + return $this->_explicitState; + } + + function setExplicitState($s) + { + $this->_explicitState = $s; + } + + /** + * @static + */ + function mergeDependencies(&$params) + { + $bundles = $newparams = array(); + foreach ($params as $i => $param) { + if (!$param->isBundle()) { + continue; + } + + $bundles[] = $i; + $pf = &$param->getPackageFile(); + $newdeps = array(); + $contents = $pf->getBundledPackages(); + if (!is_array($contents)) { + $contents = array($contents); + } + + foreach ($contents as $file) { + $filecontents = $pf->getFileContents($file); + $dl = &$param->getDownloader(); + $options = $dl->getOptions(); + if (PEAR::isError($dir = $dl->getDownloadDir())) { + return $dir; + } + + $fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb'); + if (!$fp) { + continue; + } + + // FIXME do symlink check + + fwrite($fp, $filecontents, strlen($filecontents)); + fclose($fp); + if ($s = $params[$i]->explicitState()) { + $obj->setExplicitState($s); + } + + $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader()); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if (PEAR::isError($dir = $dl->getDownloadDir())) { + PEAR::popErrorHandling(); + return $dir; + } + + $e = $obj->_fromFile($a = $dir . DIRECTORY_SEPARATOR . $file); + PEAR::popErrorHandling(); + if (PEAR::isError($e)) { + if (!isset($options['soft'])) { + $dl->log(0, $e->getMessage()); + } + continue; + } + + $j = &$obj; + if (!PEAR_Downloader_Package::willDownload($j, + array_merge($params, $newparams)) && !$param->isInstalled($j)) { + $newparams[] = &$j; + } + } + } + + foreach ($bundles as $i) { + unset($params[$i]); // remove bundles - only their contents matter for installation + } + + PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices + if (count($newparams)) { // add in bundled packages for install + foreach ($newparams as $i => $unused) { + $params[] = &$newparams[$i]; + } + $newparams = array(); + } + + foreach ($params as $i => $param) { + $newdeps = array(); + foreach ($param->_downloadDeps as $dep) { + $merge = array_merge($params, $newparams); + if (!PEAR_Downloader_Package::willDownload($dep, $merge) + && !$param->isInstalled($dep) + ) { + $newdeps[] = $dep; + } else { + //var_dump($dep); + // detect versioning conflicts here + } + } + + // convert the dependencies into PEAR_Downloader_Package objects for the next time around + $params[$i]->_downloadDeps = array(); + foreach ($newdeps as $dep) { + $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader()); + if ($s = $params[$i]->explicitState()) { + $obj->setExplicitState($s); + } + + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $e = $obj->fromDepURL($dep); + PEAR::popErrorHandling(); + if (PEAR::isError($e)) { + if (!isset($options['soft'])) { + $obj->_downloader->log(0, $e->getMessage()); + } + continue; + } + + $e = $obj->detectDependencies($params); + if (PEAR::isError($e)) { + if (!isset($options['soft'])) { + $obj->_downloader->log(0, $e->getMessage()); + } + } + + $j = &$obj; + $newparams[] = &$j; + } + } + + if (count($newparams)) { + foreach ($newparams as $i => $unused) { + $params[] = &$newparams[$i]; + } + return true; + } + + return false; + } + + + /** + * @static + */ + function willDownload($param, $params) + { + if (!is_array($params)) { + return false; + } + + foreach ($params as $obj) { + if ($obj->isEqual($param)) { + return true; + } + } + + return false; + } + + /** + * For simpler unit-testing + * @param PEAR_Config + * @param int + * @param string + */ + function &getPackagefileObject(&$c, $d) + { + $a = &new PEAR_PackageFile($c, $d); + return $a; + } + + /** + * This will retrieve from a local file if possible, and parse out + * a group name as well. The original parameter will be modified to reflect this. + * @param string|array can be a parsed package name as well + * @access private + */ + function _fromFile(&$param) + { + $saveparam = $param; + if (is_string($param)) { + if (!@file_exists($param)) { + $test = explode('#', $param); + $group = array_pop($test); + if (@file_exists(implode('#', $test))) { + $this->setGroup($group); + $param = implode('#', $test); + $this->_explicitGroup = true; + } + } + + if (@is_file($param)) { + $this->_type = 'local'; + $options = $this->_downloader->getOptions(); + $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->_debug); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING); + PEAR::popErrorHandling(); + if (PEAR::isError($pf)) { + $this->_valid = false; + $param = $saveparam; + return $pf; + } + $this->_packagefile = &$pf; + if (!$this->getGroup()) { + $this->setGroup('default'); // install the default dependency group + } + return $this->_valid = true; + } + } + $param = $saveparam; + return $this->_valid = false; + } + + function _fromUrl($param, $saveparam = '') + { + if (!is_array($param) && (preg_match('#^(http|https|ftp)://#', $param))) { + $options = $this->_downloader->getOptions(); + $this->_type = 'url'; + $callback = $this->_downloader->ui ? + array(&$this->_downloader, '_downloadCallback') : null; + $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN); + if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) { + $this->_downloader->popErrorHandling(); + return $dir; + } + + $this->_downloader->log(3, 'Downloading "' . $param . '"'); + $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui, + $dir, $callback, null, false, $this->getChannel()); + $this->_downloader->popErrorHandling(); + if (PEAR::isError($file)) { + if (!empty($saveparam)) { + $saveparam = ", cannot download \"$saveparam\""; + } + $err = PEAR::raiseError('Could not download from "' . $param . + '"' . $saveparam . ' (' . $file->getMessage() . ')'); + return $err; + } + + if ($this->_rawpackagefile) { + require_once 'Archive/Tar.php'; + $tar = &new Archive_Tar($file); + $packagexml = $tar->extractInString('package2.xml'); + if (!$packagexml) { + $packagexml = $tar->extractInString('package.xml'); + } + + if (str_replace(array("\n", "\r"), array('',''), $packagexml) != + str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) { + if ($this->getChannel() != 'pear.php.net') { + return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' . + 'not match value returned from xml-rpc'); + } + + // be more lax for the existing PEAR packages that have not-ok + // characters in their package.xml + $this->_downloader->log(0, 'CRITICAL WARNING: The "' . + $this->getPackage() . '" package has invalid characters in its ' . + 'package.xml. The next version of PEAR may not be able to install ' . + 'this package for security reasons. Please open a bug report at ' . + 'http://pear.php.net/package/' . $this->getPackage() . '/bugs'); + } + } + + // whew, download worked! + $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug); + + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING); + PEAR::popErrorHandling(); + if (PEAR::isError($pf)) { + if (is_array($pf->getUserInfo())) { + foreach ($pf->getUserInfo() as $err) { + if (is_array($err)) { + $err = $err['message']; + } + + if (!isset($options['soft'])) { + $this->_downloader->log(0, "Validation Error: $err"); + } + } + } + + if (!isset($options['soft'])) { + $this->_downloader->log(0, $pf->getMessage()); + } + + ///FIXME need to pass back some error code that we can use to match with to cancel all further operations + /// At least stop all deps of this package from being installed + $out = $saveparam ? $saveparam : $param; + $err = PEAR::raiseError('Download of "' . $out . '" succeeded, but it is not a valid package archive'); + $this->_valid = false; + return $err; + } + + $this->_packagefile = &$pf; + $this->setGroup('default'); // install the default dependency group + return $this->_valid = true; + } + + return $this->_valid = false; + } + + /** + * + * @param string|array pass in an array of format + * array( + * 'package' => 'pname', + * ['channel' => 'channame',] + * ['version' => 'version',] + * ['state' => 'state',]) + * or a string of format [channame/]pname[-version|-state] + */ + function _fromString($param) + { + $options = $this->_downloader->getOptions(); + $channel = $this->_config->get('default_channel'); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pname = $this->_registry->parsePackageName($param, $channel); + PEAR::popErrorHandling(); + if (PEAR::isError($pname)) { + if ($pname->getCode() == 'invalid') { + $this->_valid = false; + return false; + } + + if ($pname->getCode() == 'channel') { + $parsed = $pname->getUserInfo(); + if ($this->_downloader->discover($parsed['channel'])) { + if ($this->_config->get('auto_discover')) { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pname = $this->_registry->parsePackageName($param, $channel); + PEAR::popErrorHandling(); + } else { + if (!isset($options['soft'])) { + $this->_downloader->log(0, 'Channel "' . $parsed['channel'] . + '" is not initialized, use ' . + '"pear channel-discover ' . $parsed['channel'] . '" to initialize' . + 'or pear config-set auto_discover 1'); + } + } + } + + if (PEAR::isError($pname)) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $pname->getMessage()); + } + + if (is_array($param)) { + $param = $this->_registry->parsedPackageNameToString($param); + } + + $err = PEAR::raiseError('invalid package name/package file "' . $param . '"'); + $this->_valid = false; + return $err; + } + } else { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $pname->getMessage()); + } + + $err = PEAR::raiseError('invalid package name/package file "' . $param . '"'); + $this->_valid = false; + return $err; + } + } + + if (!isset($this->_type)) { + $this->_type = 'rest'; + } + + $this->_parsedname = $pname; + $this->_explicitState = isset($pname['state']) ? $pname['state'] : false; + $this->_explicitGroup = isset($pname['group']) ? true : false; + + $info = $this->_downloader->_getPackageDownloadUrl($pname); + if (PEAR::isError($info)) { + if ($info->getCode() != -976 && $pname['channel'] == 'pear.php.net') { + // try pecl + $pname['channel'] = 'pecl.php.net'; + if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) { + if (!PEAR::isError($test)) { + $info = PEAR::raiseError($info->getMessage() . ' - package ' . + $this->_registry->parsedPackageNameToString($pname, true) . + ' can be installed with "pecl install ' . $pname['package'] . + '"'); + } else { + $pname['channel'] = 'pear.php.net'; + } + } else { + $pname['channel'] = 'pear.php.net'; + } + } + + return $info; + } + + $this->_rawpackagefile = $info['raw']; + $ret = $this->_analyzeDownloadURL($info, $param, $pname); + if (PEAR::isError($ret)) { + return $ret; + } + + if ($ret) { + $this->_downloadURL = $ret; + return $this->_valid = (bool) $ret; + } + } + + /** + * @param array output of package.getDownloadURL + * @param string|array|object information for detecting packages to be downloaded, and + * for errors + * @param array name information of the package + * @param array|null packages to be downloaded + * @param bool is this an optional dependency? + * @param bool is this any kind of dependency? + * @access private + */ + function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false, + $isdependency = false) + { + if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) { + return false; + } + + if ($info === false) { + $saveparam = !is_string($param) ? ", cannot download \"$param\"" : ''; + + // no releases exist + return PEAR::raiseError('No releases for package "' . + $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam); + } + + if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) { + $err = false; + if ($pname['channel'] == 'pecl.php.net') { + if ($info['info']->getChannel() != 'pear.php.net') { + $err = true; + } + } elseif ($info['info']->getChannel() == 'pecl.php.net') { + if ($pname['channel'] != 'pear.php.net') { + $err = true; + } + } else { + $err = true; + } + + if ($err) { + return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] . + '" retrieved another channel\'s name for download! ("' . + $info['info']->getChannel() . '")'); + } + } + + $preferred_state = $this->_config->get('preferred_state'); + if (!isset($info['url'])) { + $package_version = $this->_registry->packageInfo($info['info']->getPackage(), + 'version', $info['info']->getChannel()); + if ($this->isInstalled($info)) { + if ($isdependency && version_compare($info['version'], $package_version, '<=')) { + // ignore bogus errors of "failed to download dependency" + // if it is already installed and the one that would be + // downloaded is older or the same version (Bug #7219) + return false; + } + } + + if ($info['version'] === $package_version) { + if (!isset($options['soft'])) { + $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . + '/' . $pname['package'] . '-' . $package_version. ', additionally the suggested version' . + ' (' . $package_version . ') is the same as the locally installed one.'); + } + + return false; + } + + if (version_compare($info['version'], $package_version, '<=')) { + if (!isset($options['soft'])) { + $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . + '/' . $pname['package'] . '-' . $package_version . ', additionally the suggested version' . + ' (' . $info['version'] . ') is a lower version than the locally installed one (' . $package_version . ').'); + } + + return false; + } + + $instead = ', will instead download version ' . $info['version'] . + ', stability "' . $info['info']->getState() . '"'; + // releases exist, but we failed to get any + if (isset($this->_downloader->_options['force'])) { + if (isset($pname['version'])) { + $vs = ', version "' . $pname['version'] . '"'; + } elseif (isset($pname['state'])) { + $vs = ', stability "' . $pname['state'] . '"'; + } elseif ($param == 'dependency') { + if (!class_exists('PEAR_Common')) { + require_once 'PEAR/Common.php'; + } + + if (!in_array($info['info']->getState(), + PEAR_Common::betterStates($preferred_state, true))) { + if ($optional) { + // don't spit out confusing error message + return $this->_downloader->_getPackageDownloadUrl( + array('package' => $pname['package'], + 'channel' => $pname['channel'], + 'version' => $info['version'])); + } + $vs = ' within preferred state "' . $preferred_state . + '"'; + } else { + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; + } + + if ($optional) { + // don't spit out confusing error message + return $this->_downloader->_getPackageDownloadUrl( + array('package' => $pname['package'], + 'channel' => $pname['channel'], + 'version' => $info['version'])); + } + $vs = PEAR_Dependency2::_getExtraString($pname); + $instead = ''; + } + } else { + $vs = ' within preferred state "' . $preferred_state . '"'; + } + + if (!isset($options['soft'])) { + $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . + '/' . $pname['package'] . $vs . $instead); + } + + // download the latest release + return $this->_downloader->_getPackageDownloadUrl( + array('package' => $pname['package'], + 'channel' => $pname['channel'], + 'version' => $info['version'])); + } else { + if (isset($info['php']) && $info['php']) { + $err = PEAR::raiseError('Failed to download ' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], + 'package' => $pname['package']), + true) . + ', latest release is version ' . $info['php']['v'] . + ', but it requires PHP version "' . + $info['php']['m'] . '", use "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], 'package' => $pname['package'], + 'version' => $info['php']['v'])) . '" to install', + PEAR_DOWNLOADER_PACKAGE_PHPVERSION); + return $err; + } + + // construct helpful error message + if (isset($pname['version'])) { + $vs = ', version "' . $pname['version'] . '"'; + } elseif (isset($pname['state'])) { + $vs = ', stability "' . $pname['state'] . '"'; + } elseif ($param == 'dependency') { + if (!class_exists('PEAR_Common')) { + require_once 'PEAR/Common.php'; + } + + if (!in_array($info['info']->getState(), + PEAR_Common::betterStates($preferred_state, true))) { + if ($optional) { + // don't spit out confusing error message, and don't die on + // optional dep failure! + return $this->_downloader->_getPackageDownloadUrl( + array('package' => $pname['package'], + 'channel' => $pname['channel'], + 'version' => $info['version'])); + } + $vs = ' within preferred state "' . $preferred_state . '"'; + } else { + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; + } + + if ($optional) { + // don't spit out confusing error message, and don't die on + // optional dep failure! + return $this->_downloader->_getPackageDownloadUrl( + array('package' => $pname['package'], + 'channel' => $pname['channel'], + 'version' => $info['version'])); + } + $vs = PEAR_Dependency2::_getExtraString($pname); + } + } else { + $vs = ' within preferred state "' . $this->_downloader->config->get('preferred_state') . '"'; + } + + $options = $this->_downloader->getOptions(); + // this is only set by the "download-all" command + if (isset($options['ignorepreferred_state'])) { + $err = PEAR::raiseError( + 'Failed to download ' . $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], 'package' => $pname['package']), + true) + . $vs . + ', latest release is version ' . $info['version'] . + ', stability "' . $info['info']->getState() . '", use "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], 'package' => $pname['package'], + 'version' => $info['version'])) . '" to install', + PEAR_DOWNLOADER_PACKAGE_STATE); + return $err; + } + + // Checks if the user has a package installed already and checks the release against + // the state against the installed package, this allows upgrades for packages + // with lower stability than the preferred_state + $stability = $this->_registry->packageInfo($pname['package'], 'stability', $pname['channel']); + if (!$this->isInstalled($info) + || !in_array($info['info']->getState(), PEAR_Common::betterStates($stability['release'], true)) + ) { + $err = PEAR::raiseError( + 'Failed to download ' . $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], 'package' => $pname['package']), + true) + . $vs . + ', latest release is version ' . $info['version'] . + ', stability "' . $info['info']->getState() . '", use "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], 'package' => $pname['package'], + 'version' => $info['version'])) . '" to install'); + return $err; + } + } + } + + if (isset($info['deprecated']) && $info['deprecated']) { + $this->_downloader->log(0, + 'WARNING: "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $info['info']->getChannel(), + 'package' => $info['info']->getPackage()), true) . + '" is deprecated in favor of "' . + $this->_registry->parsedPackageNameToString($info['deprecated'], true) . + '"'); + } + + return $info; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/ErrorStack.php b/typo3conf/ext/phpunit/PEAR/PEAR/ErrorStack.php new file mode 100644 index 0000000..c7f848a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/ErrorStack.php @@ -0,0 +1,985 @@ + + * @copyright 2004-2008 Greg Beaver + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: ErrorStack.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR_ErrorStack + */ + +/** + * Singleton storage + * + * Format: + *
    + * array(
    + *  'package1' => PEAR_ErrorStack object,
    + *  'package2' => PEAR_ErrorStack object,
    + *  ...
    + * )
    + * 
    + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] + */ +$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array(); + +/** + * Global error callback (default) + * + * This is only used if set to non-false. * is the default callback for + * all packages, whereas specific packages may set a default callback + * for all instances, regardless of whether they are a singleton or not. + * + * To exclude non-singletons, only set the local callback for the singleton + * @see PEAR_ErrorStack::setDefaultCallback() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] + */ +$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array( + '*' => false, +); + +/** + * Global Log object (default) + * + * This is only used if set to non-false. Use to set a default log object for + * all stacks, regardless of instantiation order or location + * @see PEAR_ErrorStack::setDefaultLogger() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] + */ +$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false; + +/** + * Global Overriding Callback + * + * This callback will override any error callbacks that specific loggers have set. + * Use with EXTREME caution + * @see PEAR_ErrorStack::staticPushCallback() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] + */ +$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); + +/**#@+ + * One of four possible return values from the error Callback + * @see PEAR_ErrorStack::_errorCallback() + */ +/** + * If this is returned, then the error will be both pushed onto the stack + * and logged. + */ +define('PEAR_ERRORSTACK_PUSHANDLOG', 1); +/** + * If this is returned, then the error will only be pushed onto the stack, + * and not logged. + */ +define('PEAR_ERRORSTACK_PUSH', 2); +/** + * If this is returned, then the error will only be logged, but not pushed + * onto the error stack. + */ +define('PEAR_ERRORSTACK_LOG', 3); +/** + * If this is returned, then the error is completely ignored. + */ +define('PEAR_ERRORSTACK_IGNORE', 4); +/** + * If this is returned, then the error is logged and die() is called. + */ +define('PEAR_ERRORSTACK_DIE', 5); +/**#@-*/ + +/** + * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in + * the singleton method. + */ +define('PEAR_ERRORSTACK_ERR_NONCLASS', 1); + +/** + * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()} + * that has no __toString() method + */ +define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2); +/** + * Error Stack Implementation + * + * Usage: + * + * // global error stack + * $global_stack = &PEAR_ErrorStack::singleton('MyPackage'); + * // local error stack + * $local_stack = new PEAR_ErrorStack('MyPackage'); + * + * @author Greg Beaver + * @version 1.9.3 + * @package PEAR_ErrorStack + * @category Debugging + * @copyright 2004-2008 Greg Beaver + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: ErrorStack.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR_ErrorStack + */ +class PEAR_ErrorStack { + /** + * Errors are stored in the order that they are pushed on the stack. + * @since 0.4alpha Errors are no longer organized by error level. + * This renders pop() nearly unusable, and levels could be more easily + * handled in a callback anyway + * @var array + * @access private + */ + var $_errors = array(); + + /** + * Storage of errors by level. + * + * Allows easy retrieval and deletion of only errors from a particular level + * @since PEAR 1.4.0dev + * @var array + * @access private + */ + var $_errorsByLevel = array(); + + /** + * Package name this error stack represents + * @var string + * @access protected + */ + var $_package; + + /** + * Determines whether a PEAR_Error is thrown upon every error addition + * @var boolean + * @access private + */ + var $_compat = false; + + /** + * If set to a valid callback, this will be used to generate the error + * message from the error code, otherwise the message passed in will be + * used + * @var false|string|array + * @access private + */ + var $_msgCallback = false; + + /** + * If set to a valid callback, this will be used to generate the error + * context for an error. For PHP-related errors, this will be a file + * and line number as retrieved from debug_backtrace(), but can be + * customized for other purposes. The error might actually be in a separate + * configuration file, or in a database query. + * @var false|string|array + * @access protected + */ + var $_contextCallback = false; + + /** + * If set to a valid callback, this will be called every time an error + * is pushed onto the stack. The return value will be used to determine + * whether to allow an error to be pushed or logged. + * + * The return value must be one an PEAR_ERRORSTACK_* constant + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @var false|string|array + * @access protected + */ + var $_errorCallback = array(); + + /** + * PEAR::Log object for logging errors + * @var false|Log + * @access protected + */ + var $_logger = false; + + /** + * Error messages - designed to be overridden + * @var array + * @abstract + */ + var $_errorMsgs = array(); + + /** + * Set up a new error stack + * + * @param string $package name of the package this error stack represents + * @param callback $msgCallback callback used for error message generation + * @param callback $contextCallback callback used for context generation, + * defaults to {@link getFileLine()} + * @param boolean $throwPEAR_Error + */ + function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false, + $throwPEAR_Error = false) + { + $this->_package = $package; + $this->setMessageCallback($msgCallback); + $this->setContextCallback($contextCallback); + $this->_compat = $throwPEAR_Error; + } + + /** + * Return a single error stack for this package. + * + * Note that all parameters are ignored if the stack for package $package + * has already been instantiated + * @param string $package name of the package this error stack represents + * @param callback $msgCallback callback used for error message generation + * @param callback $contextCallback callback used for context generation, + * defaults to {@link getFileLine()} + * @param boolean $throwPEAR_Error + * @param string $stackClass class to instantiate + * @static + * @return PEAR_ErrorStack + */ + function &singleton($package, $msgCallback = false, $contextCallback = false, + $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack') + { + if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; + } + if (!class_exists($stackClass)) { + if (function_exists('debug_backtrace')) { + $trace = debug_backtrace(); + } + PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS, + 'exception', array('stackclass' => $stackClass), + 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)', + false, $trace); + } + $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] = + new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error); + + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; + } + + /** + * Internal error handler for PEAR_ErrorStack class + * + * Dies if the error is an exception (and would have died anyway) + * @access private + */ + function _handleError($err) + { + if ($err['level'] == 'exception') { + $message = $err['message']; + if (isset($_SERVER['REQUEST_URI'])) { + echo '
    '; + } else { + echo "\n"; + } + var_dump($err['context']); + die($message); + } + } + + /** + * Set up a PEAR::Log object for all error stacks that don't have one + * @param Log $log + * @static + */ + function setDefaultLogger(&$log) + { + if (is_object($log) && method_exists($log, 'log') ) { + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; + } elseif (is_callable($log)) { + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; + } + } + + /** + * Set up a PEAR::Log object for this error stack + * @param Log $log + */ + function setLogger(&$log) + { + if (is_object($log) && method_exists($log, 'log') ) { + $this->_logger = &$log; + } elseif (is_callable($log)) { + $this->_logger = &$log; + } + } + + /** + * Set an error code => error message mapping callback + * + * This method sets the callback that can be used to generate error + * messages for any instance + * @param array|string Callback function/method + */ + function setMessageCallback($msgCallback) + { + if (!$msgCallback) { + $this->_msgCallback = array(&$this, 'getErrorMessage'); + } else { + if (is_callable($msgCallback)) { + $this->_msgCallback = $msgCallback; + } + } + } + + /** + * Get an error code => error message mapping callback + * + * This method returns the current callback that can be used to generate error + * messages + * @return array|string|false Callback function/method or false if none + */ + function getMessageCallback() + { + return $this->_msgCallback; + } + + /** + * Sets a default callback to be used by all error stacks + * + * This method sets the callback that can be used to generate error + * messages for a singleton + * @param array|string Callback function/method + * @param string Package name, or false for all packages + * @static + */ + function setDefaultCallback($callback = false, $package = false) + { + if (!is_callable($callback)) { + $callback = false; + } + $package = $package ? $package : '*'; + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback; + } + + /** + * Set a callback that generates context information (location of error) for an error stack + * + * This method sets the callback that can be used to generate context + * information for an error. Passing in NULL will disable context generation + * and remove the expensive call to debug_backtrace() + * @param array|string|null Callback function/method + */ + function setContextCallback($contextCallback) + { + if ($contextCallback === null) { + return $this->_contextCallback = false; + } + if (!$contextCallback) { + $this->_contextCallback = array(&$this, 'getFileLine'); + } else { + if (is_callable($contextCallback)) { + $this->_contextCallback = $contextCallback; + } + } + } + + /** + * Set an error Callback + * If set to a valid callback, this will be called every time an error + * is pushed onto the stack. The return value will be used to determine + * whether to allow an error to be pushed or logged. + * + * The return value must be one of the ERRORSTACK_* constants. + * + * This functionality can be used to emulate PEAR's pushErrorHandling, and + * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of + * the error stack or logging + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @see popCallback() + * @param string|array $cb + */ + function pushCallback($cb) + { + array_push($this->_errorCallback, $cb); + } + + /** + * Remove a callback from the error callback stack + * @see pushCallback() + * @return array|string|false + */ + function popCallback() + { + if (!count($this->_errorCallback)) { + return false; + } + return array_pop($this->_errorCallback); + } + + /** + * Set a temporary overriding error callback for every package error stack + * + * Use this to temporarily disable all existing callbacks (can be used + * to emulate the @ operator, for instance) + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @see staticPopCallback(), pushCallback() + * @param string|array $cb + * @static + */ + function staticPushCallback($cb) + { + array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb); + } + + /** + * Remove a temporary overriding error callback + * @see staticPushCallback() + * @return array|string|false + * @static + */ + function staticPopCallback() + { + $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']); + if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) { + $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); + } + return $ret; + } + + /** + * Add an error to the stack + * + * If the message generator exists, it is called with 2 parameters. + * - the current Error Stack object + * - an array that is in the same format as an error. Available indices + * are 'code', 'package', 'time', 'params', 'level', and 'context' + * + * Next, if the error should contain context information, this is + * handled by the context grabbing method. + * Finally, the error is pushed onto the proper error stack + * @param int $code Package-specific error code + * @param string $level Error level. This is NOT spell-checked + * @param array $params associative array of error parameters + * @param string $msg Error message, or a portion of it if the message + * is to be generated + * @param array $repackage If this error re-packages an error pushed by + * another package, place the array returned from + * {@link pop()} in this parameter + * @param array $backtrace Protected parameter: use this to pass in the + * {@link debug_backtrace()} that should be used + * to find error context + * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also + * thrown. If a PEAR_Error is returned, the userinfo + * property is set to the following array: + * + * + * array( + * 'code' => $code, + * 'params' => $params, + * 'package' => $this->_package, + * 'level' => $level, + * 'time' => time(), + * 'context' => $context, + * 'message' => $msg, + * //['repackage' => $err] repackaged error array/Exception class + * ); + * + * + * Normally, the previous array is returned. + */ + function push($code, $level = 'error', $params = array(), $msg = false, + $repackage = false, $backtrace = false) + { + $context = false; + // grab error context + if ($this->_contextCallback) { + if (!$backtrace) { + $backtrace = debug_backtrace(); + } + $context = call_user_func($this->_contextCallback, $code, $params, $backtrace); + } + + // save error + $time = explode(' ', microtime()); + $time = $time[1] + $time[0]; + $err = array( + 'code' => $code, + 'params' => $params, + 'package' => $this->_package, + 'level' => $level, + 'time' => $time, + 'context' => $context, + 'message' => $msg, + ); + + if ($repackage) { + $err['repackage'] = $repackage; + } + + // set up the error message, if necessary + if ($this->_msgCallback) { + $msg = call_user_func_array($this->_msgCallback, + array(&$this, $err)); + $err['message'] = $msg; + } + $push = $log = true; + $die = false; + // try the overriding callback first + $callback = $this->staticPopCallback(); + if ($callback) { + $this->staticPushCallback($callback); + } + if (!is_callable($callback)) { + // try the local callback next + $callback = $this->popCallback(); + if (is_callable($callback)) { + $this->pushCallback($callback); + } else { + // try the default callback + $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ? + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] : + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*']; + } + } + if (is_callable($callback)) { + switch(call_user_func($callback, $err)){ + case PEAR_ERRORSTACK_IGNORE: + return $err; + break; + case PEAR_ERRORSTACK_PUSH: + $log = false; + break; + case PEAR_ERRORSTACK_LOG: + $push = false; + break; + case PEAR_ERRORSTACK_DIE: + $die = true; + break; + // anything else returned has the same effect as pushandlog + } + } + if ($push) { + array_unshift($this->_errors, $err); + if (!isset($this->_errorsByLevel[$err['level']])) { + $this->_errorsByLevel[$err['level']] = array(); + } + $this->_errorsByLevel[$err['level']][] = &$this->_errors[0]; + } + if ($log) { + if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) { + $this->_log($err); + } + } + if ($die) { + die(); + } + if ($this->_compat && $push) { + return $this->raiseError($msg, $code, null, null, $err); + } + return $err; + } + + /** + * Static version of {@link push()} + * + * @param string $package Package name this error belongs to + * @param int $code Package-specific error code + * @param string $level Error level. This is NOT spell-checked + * @param array $params associative array of error parameters + * @param string $msg Error message, or a portion of it if the message + * is to be generated + * @param array $repackage If this error re-packages an error pushed by + * another package, place the array returned from + * {@link pop()} in this parameter + * @param array $backtrace Protected parameter: use this to pass in the + * {@link debug_backtrace()} that should be used + * to find error context + * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also + * thrown. see docs for {@link push()} + * @static + */ + function staticPush($package, $code, $level = 'error', $params = array(), + $msg = false, $repackage = false, $backtrace = false) + { + $s = &PEAR_ErrorStack::singleton($package); + if ($s->_contextCallback) { + if (!$backtrace) { + if (function_exists('debug_backtrace')) { + $backtrace = debug_backtrace(); + } + } + } + return $s->push($code, $level, $params, $msg, $repackage, $backtrace); + } + + /** + * Log an error using PEAR::Log + * @param array $err Error array + * @param array $levels Error level => Log constant map + * @access protected + */ + function _log($err) + { + if ($this->_logger) { + $logger = &$this->_logger; + } else { + $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']; + } + if (is_a($logger, 'Log')) { + $levels = array( + 'exception' => PEAR_LOG_CRIT, + 'alert' => PEAR_LOG_ALERT, + 'critical' => PEAR_LOG_CRIT, + 'error' => PEAR_LOG_ERR, + 'warning' => PEAR_LOG_WARNING, + 'notice' => PEAR_LOG_NOTICE, + 'info' => PEAR_LOG_INFO, + 'debug' => PEAR_LOG_DEBUG); + if (isset($levels[$err['level']])) { + $level = $levels[$err['level']]; + } else { + $level = PEAR_LOG_INFO; + } + $logger->log($err['message'], $level, $err); + } else { // support non-standard logs + call_user_func($logger, $err); + } + } + + + /** + * Pop an error off of the error stack + * + * @return false|array + * @since 0.4alpha it is no longer possible to specify a specific error + * level to return - the last error pushed will be returned, instead + */ + function pop() + { + $err = @array_shift($this->_errors); + if (!is_null($err)) { + @array_pop($this->_errorsByLevel[$err['level']]); + if (!count($this->_errorsByLevel[$err['level']])) { + unset($this->_errorsByLevel[$err['level']]); + } + } + return $err; + } + + /** + * Pop an error off of the error stack, static method + * + * @param string package name + * @return boolean + * @since PEAR1.5.0a1 + */ + function staticPop($package) + { + if ($package) { + if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return false; + } + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop(); + } + } + + /** + * Determine whether there are any errors on the stack + * @param string|array Level name. Use to determine if any errors + * of level (string), or levels (array) have been pushed + * @return boolean + */ + function hasErrors($level = false) + { + if ($level) { + return isset($this->_errorsByLevel[$level]); + } + return count($this->_errors); + } + + /** + * Retrieve all errors since last purge + * + * @param boolean set in order to empty the error stack + * @param string level name, to return only errors of a particular severity + * @return array + */ + function getErrors($purge = false, $level = false) + { + if (!$purge) { + if ($level) { + if (!isset($this->_errorsByLevel[$level])) { + return array(); + } else { + return $this->_errorsByLevel[$level]; + } + } else { + return $this->_errors; + } + } + if ($level) { + $ret = $this->_errorsByLevel[$level]; + foreach ($this->_errorsByLevel[$level] as $i => $unused) { + // entries are references to the $_errors array + $this->_errorsByLevel[$level][$i] = false; + } + // array_filter removes all entries === false + $this->_errors = array_filter($this->_errors); + unset($this->_errorsByLevel[$level]); + return $ret; + } + $ret = $this->_errors; + $this->_errors = array(); + $this->_errorsByLevel = array(); + return $ret; + } + + /** + * Determine whether there are any errors on a single error stack, or on any error stack + * + * The optional parameter can be used to test the existence of any errors without the need of + * singleton instantiation + * @param string|false Package name to check for errors + * @param string Level name to check for a particular severity + * @return boolean + * @static + */ + function staticHasErrors($package = false, $level = false) + { + if ($package) { + if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return false; + } + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level); + } + foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { + if ($obj->hasErrors($level)) { + return true; + } + } + return false; + } + + /** + * Get a list of all errors since last purge, organized by package + * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be + * @param boolean $purge Set to purge the error stack of existing errors + * @param string $level Set to a level name in order to retrieve only errors of a particular level + * @param boolean $merge Set to return a flat array, not organized by package + * @param array $sortfunc Function used to sort a merged array - default + * sorts by time, and should be good for most cases + * @static + * @return array + */ + function staticGetErrors($purge = false, $level = false, $merge = false, + $sortfunc = array('PEAR_ErrorStack', '_sortErrors')) + { + $ret = array(); + if (!is_callable($sortfunc)) { + $sortfunc = array('PEAR_ErrorStack', '_sortErrors'); + } + foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { + $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level); + if ($test) { + if ($merge) { + $ret = array_merge($ret, $test); + } else { + $ret[$package] = $test; + } + } + } + if ($merge) { + usort($ret, $sortfunc); + } + return $ret; + } + + /** + * Error sorting function, sorts by time + * @access private + */ + function _sortErrors($a, $b) + { + if ($a['time'] == $b['time']) { + return 0; + } + if ($a['time'] < $b['time']) { + return 1; + } + return -1; + } + + /** + * Standard file/line number/function/class context callback + * + * This function uses a backtrace generated from {@link debug_backtrace()} + * and so will not work at all in PHP < 4.3.0. The frame should + * reference the frame that contains the source of the error. + * @return array|false either array('file' => file, 'line' => line, + * 'function' => function name, 'class' => class name) or + * if this doesn't work, then false + * @param unused + * @param integer backtrace frame. + * @param array Results of debug_backtrace() + * @static + */ + function getFileLine($code, $params, $backtrace = null) + { + if ($backtrace === null) { + return false; + } + $frame = 0; + $functionframe = 1; + if (!isset($backtrace[1])) { + $functionframe = 0; + } else { + while (isset($backtrace[$functionframe]['function']) && + $backtrace[$functionframe]['function'] == 'eval' && + isset($backtrace[$functionframe + 1])) { + $functionframe++; + } + } + if (isset($backtrace[$frame])) { + if (!isset($backtrace[$frame]['file'])) { + $frame++; + } + $funcbacktrace = $backtrace[$functionframe]; + $filebacktrace = $backtrace[$frame]; + $ret = array('file' => $filebacktrace['file'], + 'line' => $filebacktrace['line']); + // rearrange for eval'd code or create function errors + if (strpos($filebacktrace['file'], '(') && + preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'], + $matches)) { + $ret['file'] = $matches[1]; + $ret['line'] = $matches[2] + 0; + } + if (isset($funcbacktrace['function']) && isset($backtrace[1])) { + if ($funcbacktrace['function'] != 'eval') { + if ($funcbacktrace['function'] == '__lambda_func') { + $ret['function'] = 'create_function() code'; + } else { + $ret['function'] = $funcbacktrace['function']; + } + } + } + if (isset($funcbacktrace['class']) && isset($backtrace[1])) { + $ret['class'] = $funcbacktrace['class']; + } + return $ret; + } + return false; + } + + /** + * Standard error message generation callback + * + * This method may also be called by a custom error message generator + * to fill in template values from the params array, simply + * set the third parameter to the error message template string to use + * + * The special variable %__msg% is reserved: use it only to specify + * where a message passed in by the user should be placed in the template, + * like so: + * + * Error message: %msg% - internal error + * + * If the message passed like so: + * + * + * $stack->push(ERROR_CODE, 'error', array(), 'server error 500'); + * + * + * The returned error message will be "Error message: server error 500 - + * internal error" + * @param PEAR_ErrorStack + * @param array + * @param string|false Pre-generated error message template + * @static + * @return string + */ + function getErrorMessage(&$stack, $err, $template = false) + { + if ($template) { + $mainmsg = $template; + } else { + $mainmsg = $stack->getErrorMessageTemplate($err['code']); + } + $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg); + if (is_array($err['params']) && count($err['params'])) { + foreach ($err['params'] as $name => $val) { + if (is_array($val)) { + // @ is needed in case $val is a multi-dimensional array + $val = @implode(', ', $val); + } + if (is_object($val)) { + if (method_exists($val, '__toString')) { + $val = $val->__toString(); + } else { + PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING, + 'warning', array('obj' => get_class($val)), + 'object %obj% passed into getErrorMessage, but has no __toString() method'); + $val = 'Object'; + } + } + $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg); + } + } + return $mainmsg; + } + + /** + * Standard Error Message Template generator from code + * @return string + */ + function getErrorMessageTemplate($code) + { + if (!isset($this->_errorMsgs[$code])) { + return '%__msg%'; + } + return $this->_errorMsgs[$code]; + } + + /** + * Set the Error Message Template array + * + * The array format must be: + *
    +     * array(error code => 'message template',...)
    +     * 
    + * + * Error message parameters passed into {@link push()} will be used as input + * for the error message. If the template is 'message %foo% was %bar%', and the + * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will + * be 'message one was six' + * @return string + */ + function setErrorMessageTemplate($template) + { + $this->_errorMsgs = $template; + } + + + /** + * emulate PEAR::raiseError() + * + * @return PEAR_Error + */ + function raiseError() + { + require_once 'PEAR.php'; + $args = func_get_args(); + return call_user_func_array(array('PEAR', 'raiseError'), $args); + } +} +$stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack'); +$stack->pushCallback(array('PEAR_ErrorStack', '_handleError')); +?> diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Exception.php b/typo3conf/ext/phpunit/PEAR/PEAR/Exception.php new file mode 100644 index 0000000..83512b9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Exception.php @@ -0,0 +1,389 @@ + + * @author Hans Lellelid + * @author Bertrand Mansion + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Exception.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.3.3 + */ + + +/** + * Base PEAR_Exception Class + * + * 1) Features: + * + * - Nestable exceptions (throw new PEAR_Exception($msg, $prev_exception)) + * - Definable triggers, shot when exceptions occur + * - Pretty and informative error messages + * - Added more context info available (like class, method or cause) + * - cause can be a PEAR_Exception or an array of mixed + * PEAR_Exceptions/PEAR_ErrorStack warnings + * - callbacks for specific exception classes and their children + * + * 2) Ideas: + * + * - Maybe a way to define a 'template' for the output + * + * 3) Inherited properties from PHP Exception Class: + * + * protected $message + * protected $code + * protected $line + * protected $file + * private $trace + * + * 4) Inherited methods from PHP Exception Class: + * + * __clone + * __construct + * getMessage + * getCode + * getFile + * getLine + * getTraceSafe + * getTraceSafeAsString + * __toString + * + * 5) Usage example + * + * + * require_once 'PEAR/Exception.php'; + * + * class Test { + * function foo() { + * throw new PEAR_Exception('Error Message', ERROR_CODE); + * } + * } + * + * function myLogger($pear_exception) { + * echo $pear_exception->getMessage(); + * } + * // each time a exception is thrown the 'myLogger' will be called + * // (its use is completely optional) + * PEAR_Exception::addObserver('myLogger'); + * $test = new Test; + * try { + * $test->foo(); + * } catch (PEAR_Exception $e) { + * print $e; + * } + * + * + * @category pear + * @package PEAR + * @author Tomas V.V.Cox + * @author Hans Lellelid + * @author Bertrand Mansion + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.3.3 + * + */ +class PEAR_Exception extends Exception +{ + const OBSERVER_PRINT = -2; + const OBSERVER_TRIGGER = -4; + const OBSERVER_DIE = -8; + protected $cause; + private static $_observers = array(); + private static $_uniqueid = 0; + private $_trace; + + /** + * Supported signatures: + * - PEAR_Exception(string $message); + * - PEAR_Exception(string $message, int $code); + * - PEAR_Exception(string $message, Exception $cause); + * - PEAR_Exception(string $message, Exception $cause, int $code); + * - PEAR_Exception(string $message, PEAR_Error $cause); + * - PEAR_Exception(string $message, PEAR_Error $cause, int $code); + * - PEAR_Exception(string $message, array $causes); + * - PEAR_Exception(string $message, array $causes, int $code); + * @param string exception message + * @param int|Exception|PEAR_Error|array|null exception cause + * @param int|null exception code or null + */ + public function __construct($message, $p2 = null, $p3 = null) + { + if (is_int($p2)) { + $code = $p2; + $this->cause = null; + } elseif (is_object($p2) || is_array($p2)) { + // using is_object allows both Exception and PEAR_Error + if (is_object($p2) && !($p2 instanceof Exception)) { + if (!class_exists('PEAR_Error') || !($p2 instanceof PEAR_Error)) { + throw new PEAR_Exception('exception cause must be Exception, ' . + 'array, or PEAR_Error'); + } + } + $code = $p3; + if (is_array($p2) && isset($p2['message'])) { + // fix potential problem of passing in a single warning + $p2 = array($p2); + } + $this->cause = $p2; + } else { + $code = null; + $this->cause = null; + } + parent::__construct($message, $code); + $this->signal(); + } + + /** + * @param mixed $callback - A valid php callback, see php func is_callable() + * - A PEAR_Exception::OBSERVER_* constant + * - An array(const PEAR_Exception::OBSERVER_*, + * mixed $options) + * @param string $label The name of the observer. Use this if you want + * to remove it later with removeObserver() + */ + public static function addObserver($callback, $label = 'default') + { + self::$_observers[$label] = $callback; + } + + public static function removeObserver($label = 'default') + { + unset(self::$_observers[$label]); + } + + /** + * @return int unique identifier for an observer + */ + public static function getUniqueId() + { + return self::$_uniqueid++; + } + + private function signal() + { + foreach (self::$_observers as $func) { + if (is_callable($func)) { + call_user_func($func, $this); + continue; + } + settype($func, 'array'); + switch ($func[0]) { + case self::OBSERVER_PRINT : + $f = (isset($func[1])) ? $func[1] : '%s'; + printf($f, $this->getMessage()); + break; + case self::OBSERVER_TRIGGER : + $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE; + trigger_error($this->getMessage(), $f); + break; + case self::OBSERVER_DIE : + $f = (isset($func[1])) ? $func[1] : '%s'; + die(printf($f, $this->getMessage())); + break; + default: + trigger_error('invalid observer type', E_USER_WARNING); + } + } + } + + /** + * Return specific error information that can be used for more detailed + * error messages or translation. + * + * This method may be overridden in child exception classes in order + * to add functionality not present in PEAR_Exception and is a placeholder + * to define API + * + * The returned array must be an associative array of parameter => value like so: + *
    +     * array('name' => $name, 'context' => array(...))
    +     * 
    + * @return array + */ + public function getErrorData() + { + return array(); + } + + /** + * Returns the exception that caused this exception to be thrown + * @access public + * @return Exception|array The context of the exception + */ + public function getCause() + { + return $this->cause; + } + + /** + * Function must be public to call on caused exceptions + * @param array + */ + public function getCauseMessage(&$causes) + { + $trace = $this->getTraceSafe(); + $cause = array('class' => get_class($this), + 'message' => $this->message, + 'file' => 'unknown', + 'line' => 'unknown'); + if (isset($trace[0])) { + if (isset($trace[0]['file'])) { + $cause['file'] = $trace[0]['file']; + $cause['line'] = $trace[0]['line']; + } + } + $causes[] = $cause; + if ($this->cause instanceof PEAR_Exception) { + $this->cause->getCauseMessage($causes); + } elseif ($this->cause instanceof Exception) { + $causes[] = array('class' => get_class($this->cause), + 'message' => $this->cause->getMessage(), + 'file' => $this->cause->getFile(), + 'line' => $this->cause->getLine()); + } elseif (class_exists('PEAR_Error') && $this->cause instanceof PEAR_Error) { + $causes[] = array('class' => get_class($this->cause), + 'message' => $this->cause->getMessage(), + 'file' => 'unknown', + 'line' => 'unknown'); + } elseif (is_array($this->cause)) { + foreach ($this->cause as $cause) { + if ($cause instanceof PEAR_Exception) { + $cause->getCauseMessage($causes); + } elseif ($cause instanceof Exception) { + $causes[] = array('class' => get_class($cause), + 'message' => $cause->getMessage(), + 'file' => $cause->getFile(), + 'line' => $cause->getLine()); + } elseif (class_exists('PEAR_Error') && $cause instanceof PEAR_Error) { + $causes[] = array('class' => get_class($cause), + 'message' => $cause->getMessage(), + 'file' => 'unknown', + 'line' => 'unknown'); + } elseif (is_array($cause) && isset($cause['message'])) { + // PEAR_ErrorStack warning + $causes[] = array( + 'class' => $cause['package'], + 'message' => $cause['message'], + 'file' => isset($cause['context']['file']) ? + $cause['context']['file'] : + 'unknown', + 'line' => isset($cause['context']['line']) ? + $cause['context']['line'] : + 'unknown', + ); + } + } + } + } + + public function getTraceSafe() + { + if (!isset($this->_trace)) { + $this->_trace = $this->getTrace(); + if (empty($this->_trace)) { + $backtrace = debug_backtrace(); + $this->_trace = array($backtrace[count($backtrace)-1]); + } + } + return $this->_trace; + } + + public function getErrorClass() + { + $trace = $this->getTraceSafe(); + return $trace[0]['class']; + } + + public function getErrorMethod() + { + $trace = $this->getTraceSafe(); + return $trace[0]['function']; + } + + public function __toString() + { + if (isset($_SERVER['REQUEST_URI'])) { + return $this->toHtml(); + } + return $this->toText(); + } + + public function toHtml() + { + $trace = $this->getTraceSafe(); + $causes = array(); + $this->getCauseMessage($causes); + $html = '' . "\n"; + foreach ($causes as $i => $cause) { + $html .= '\n"; + } + $html .= '' . "\n" + . '' + . '' + . '' . "\n"; + + foreach ($trace as $k => $v) { + $html .= '' + . '' + . '' . "\n"; + } + $html .= '' + . '' + . '' . "\n" + . '
    ' + . str_repeat('-', $i) . ' ' . $cause['class'] . ': ' + . htmlspecialchars($cause['message']) . ' in ' . $cause['file'] . ' ' + . 'on line ' . $cause['line'] . '' + . "
    Exception trace
    #FunctionLocation
    ' . $k . ''; + if (!empty($v['class'])) { + $html .= $v['class'] . $v['type']; + } + $html .= $v['function']; + $args = array(); + if (!empty($v['args'])) { + foreach ($v['args'] as $arg) { + if (is_null($arg)) $args[] = 'null'; + elseif (is_array($arg)) $args[] = 'Array'; + elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')'; + elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false'; + elseif (is_int($arg) || is_double($arg)) $args[] = $arg; + else { + $arg = (string)$arg; + $str = htmlspecialchars(substr($arg, 0, 16)); + if (strlen($arg) > 16) $str .= '…'; + $args[] = "'" . $str . "'"; + } + } + } + $html .= '(' . implode(', ',$args) . ')' + . '' . (isset($v['file']) ? $v['file'] : 'unknown') + . ':' . (isset($v['line']) ? $v['line'] : 'unknown') + . '
    ' . ($k+1) . '{main} 
    '; + return $html; + } + + public function toText() + { + $causes = array(); + $this->getCauseMessage($causes); + $causeMsg = ''; + foreach ($causes as $i => $cause) { + $causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': ' + . $cause['message'] . ' in ' . $cause['file'] + . ' on line ' . $cause['line'] . "\n"; + } + return $causeMsg . $this->getTraceAsString(); + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/FixPHP5PEARWarnings.php b/typo3conf/ext/phpunit/PEAR/PEAR/FixPHP5PEARWarnings.php new file mode 100644 index 0000000..be5dc3c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/FixPHP5PEARWarnings.php @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Frontend.php b/typo3conf/ext/phpunit/PEAR/PEAR/Frontend.php new file mode 100644 index 0000000..7b4b7c5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Frontend.php @@ -0,0 +1,228 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Frontend.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Include error handling + */ +//require_once 'PEAR.php'; + +/** + * Which user interface class is being used. + * @var string class name + */ +$GLOBALS['_PEAR_FRONTEND_CLASS'] = 'PEAR_Frontend_CLI'; + +/** + * Instance of $_PEAR_Command_uiclass. + * @var object + */ +$GLOBALS['_PEAR_FRONTEND_SINGLETON'] = null; + +/** + * Singleton-based frontend for PEAR user input/output + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Frontend extends PEAR +{ + /** + * Retrieve the frontend object + * @return PEAR_Frontend_CLI|PEAR_Frontend_Web|PEAR_Frontend_Gtk + * @static + */ + function &singleton($type = null) + { + if ($type === null) { + if (!isset($GLOBALS['_PEAR_FRONTEND_SINGLETON'])) { + $a = false; + return $a; + } + return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; + } + + $a = PEAR_Frontend::setFrontendClass($type); + return $a; + } + + /** + * Set the frontend class that will be used by calls to {@link singleton()} + * + * Frontends are expected to conform to the PEAR naming standard of + * _ => DIRECTORY_SEPARATOR (PEAR_Frontend_CLI is in PEAR/Frontend/CLI.php) + * @param string $uiclass full class name + * @return PEAR_Frontend + * @static + */ + function &setFrontendClass($uiclass) + { + if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && + is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], $uiclass)) { + return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; + } + + if (!class_exists($uiclass)) { + $file = str_replace('_', '/', $uiclass) . '.php'; + if (PEAR_Frontend::isIncludeable($file)) { + include_once $file; + } + } + + if (class_exists($uiclass)) { + $obj = &new $uiclass; + // quick test to see if this class implements a few of the most + // important frontend methods + if (is_a($obj, 'PEAR_Frontend')) { + $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$obj; + $GLOBALS['_PEAR_FRONTEND_CLASS'] = $uiclass; + return $obj; + } + + $err = PEAR::raiseError("not a frontend class: $uiclass"); + return $err; + } + + $err = PEAR::raiseError("no such class: $uiclass"); + return $err; + } + + /** + * Set the frontend class that will be used by calls to {@link singleton()} + * + * Frontends are expected to be a descendant of PEAR_Frontend + * @param PEAR_Frontend + * @return PEAR_Frontend + * @static + */ + function &setFrontendObject($uiobject) + { + if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && + is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], get_class($uiobject))) { + return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; + } + + if (!is_a($uiobject, 'PEAR_Frontend')) { + $err = PEAR::raiseError('not a valid frontend class: (' . + get_class($uiobject) . ')'); + return $err; + } + + $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$uiobject; + $GLOBALS['_PEAR_FRONTEND_CLASS'] = get_class($uiobject); + return $uiobject; + } + + /** + * @param string $path relative or absolute include path + * @return boolean + * @static + */ + function isIncludeable($path) + { + if (file_exists($path) && is_readable($path)) { + return true; + } + + $fp = @fopen($path, 'r', true); + if ($fp) { + fclose($fp); + return true; + } + + return false; + } + + /** + * @param PEAR_Config + */ + function setConfig(&$config) + { + } + + /** + * This can be overridden to allow session-based temporary file management + * + * By default, all files are deleted at the end of a session. The web installer + * needs to be able to sustain a list over many sessions in order to support + * user interaction with install scripts + */ + function addTempFile($file) + { + $GLOBALS['_PEAR_Common_tempfiles'][] = $file; + } + + /** + * Log an action + * + * @param string $msg the message to log + * @param boolean $append_crlf + * @return boolean true + * @abstract + */ + function log($msg, $append_crlf = true) + { + } + + /** + * Run a post-installation script + * + * @param array $scripts array of post-install scripts + * @abstract + */ + function runPostinstallScripts(&$scripts) + { + } + + /** + * Display human-friendly output formatted depending on the + * $command parameter. + * + * This should be able to handle basic output data with no command + * @param mixed $data data structure containing the information to display + * @param string $command command from which this method was called + * @abstract + */ + function outputData($data, $command = '_default') + { + } + + /** + * Display a modal form dialog and return the given input + * + * A frontend that requires multiple requests to retrieve and process + * data must take these needs into account, and implement the request + * handling code. + * @param string $command command from which this method was called + * @param array $prompts associative array. keys are the input field names + * and values are the description + * @param array $types array of input field types (text, password, + * etc.) keys have to be the same like in $prompts + * @param array $defaults array of default values. again keys have + * to be the same like in $prompts. Do not depend + * on a default value being set. + * @return array input sent by the user + * @abstract + */ + function userDialog($command, $prompts, $types = array(), $defaults = array()) + { + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Frontend/CLI.php b/typo3conf/ext/phpunit/PEAR/PEAR/Frontend/CLI.php new file mode 100644 index 0000000..14102a6 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Frontend/CLI.php @@ -0,0 +1,751 @@ + + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: CLI.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ +/** + * base class + */ +require_once 'PEAR/Frontend.php'; + +/** + * Command-line Frontend for the PEAR Installer + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Frontend_CLI extends PEAR_Frontend +{ + /** + * What type of user interface this frontend is for. + * @var string + * @access public + */ + var $type = 'CLI'; + var $lp = ''; // line prefix + + var $params = array(); + var $term = array( + 'bold' => '', + 'normal' => '', + ); + + function PEAR_Frontend_CLI() + { + parent::PEAR(); + $term = getenv('TERM'); //(cox) $_ENV is empty for me in 4.1.1 + if (function_exists('posix_isatty') && !posix_isatty(1)) { + // output is being redirected to a file or through a pipe + } elseif ($term) { + if (preg_match('/^(xterm|vt220|linux)/', $term)) { + $this->term['bold'] = sprintf("%c%c%c%c", 27, 91, 49, 109); + $this->term['normal'] = sprintf("%c%c%c", 27, 91, 109); + } elseif (preg_match('/^vt100/', $term)) { + $this->term['bold'] = sprintf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); + $this->term['normal'] = sprintf("%c%c%c%c%c", 27, 91, 109, 0, 0); + } + } elseif (OS_WINDOWS) { + // XXX add ANSI codes here + } + } + + /** + * @param object PEAR_Error object + */ + function displayError($e) + { + return $this->_displayLine($e->getMessage()); + } + + /** + * @param object PEAR_Error object + */ + function displayFatalError($eobj) + { + $this->displayError($eobj); + if (class_exists('PEAR_Config')) { + $config = &PEAR_Config::singleton(); + if ($config->get('verbose') > 5) { + if (function_exists('debug_print_backtrace')) { + debug_print_backtrace(); + exit(1); + } + + $raised = false; + foreach (debug_backtrace() as $i => $frame) { + if (!$raised) { + if (isset($frame['class']) + && strtolower($frame['class']) == 'pear' + && strtolower($frame['function']) == 'raiseerror' + ) { + $raised = true; + } else { + continue; + } + } + + $frame['class'] = !isset($frame['class']) ? '' : $frame['class']; + $frame['type'] = !isset($frame['type']) ? '' : $frame['type']; + $frame['function'] = !isset($frame['function']) ? '' : $frame['function']; + $frame['line'] = !isset($frame['line']) ? '' : $frame['line']; + $this->_displayLine("#$i: $frame[class]$frame[type]$frame[function] $frame[line]"); + } + } + } + + exit(1); + } + + /** + * Instruct the runInstallScript method to skip a paramgroup that matches the + * id value passed in. + * + * This method is useful for dynamically configuring which sections of a post-install script + * will be run based on the user's setup, which is very useful for making flexible + * post-install scripts without losing the cross-Frontend ability to retrieve user input + * @param string + */ + function skipParamgroup($id) + { + $this->_skipSections[$id] = true; + } + + function runPostinstallScripts(&$scripts) + { + foreach ($scripts as $i => $script) { + $this->runInstallScript($scripts[$i]->_params, $scripts[$i]->_obj); + } + } + + /** + * @param array $xml contents of postinstallscript tag + * @param object $script post-installation script + * @param string install|upgrade + */ + function runInstallScript($xml, &$script) + { + $this->_skipSections = array(); + if (!is_array($xml) || !isset($xml['paramgroup'])) { + $script->run(array(), '_default'); + return; + } + + $completedPhases = array(); + if (!isset($xml['paramgroup'][0])) { + $xml['paramgroup'] = array($xml['paramgroup']); + } + + foreach ($xml['paramgroup'] as $group) { + if (isset($this->_skipSections[$group['id']])) { + // the post-install script chose to skip this section dynamically + continue; + } + + if (isset($group['name'])) { + $paramname = explode('::', $group['name']); + if ($lastgroup['id'] != $paramname[0]) { + continue; + } + + $group['name'] = $paramname[1]; + if (!isset($answers)) { + return; + } + + if (isset($answers[$group['name']])) { + switch ($group['conditiontype']) { + case '=' : + if ($answers[$group['name']] != $group['value']) { + continue 2; + } + break; + case '!=' : + if ($answers[$group['name']] == $group['value']) { + continue 2; + } + break; + case 'preg_match' : + if (!@preg_match('/' . $group['value'] . '/', + $answers[$group['name']])) { + continue 2; + } + break; + default : + return; + } + } + } + + $lastgroup = $group; + if (isset($group['instructions'])) { + $this->_display($group['instructions']); + } + + if (!isset($group['param'][0])) { + $group['param'] = array($group['param']); + } + + if (isset($group['param'])) { + if (method_exists($script, 'postProcessPrompts')) { + $prompts = $script->postProcessPrompts($group['param'], $group['id']); + if (!is_array($prompts) || count($prompts) != count($group['param'])) { + $this->outputData('postinstall', 'Error: post-install script did not ' . + 'return proper post-processed prompts'); + $prompts = $group['param']; + } else { + foreach ($prompts as $i => $var) { + if (!is_array($var) || !isset($var['prompt']) || + !isset($var['name']) || + ($var['name'] != $group['param'][$i]['name']) || + ($var['type'] != $group['param'][$i]['type']) + ) { + $this->outputData('postinstall', 'Error: post-install script ' . + 'modified the variables or prompts, severe security risk. ' . + 'Will instead use the defaults from the package.xml'); + $prompts = $group['param']; + } + } + } + + $answers = $this->confirmDialog($prompts); + } else { + $answers = $this->confirmDialog($group['param']); + } + } + + if ((isset($answers) && $answers) || !isset($group['param'])) { + if (!isset($answers)) { + $answers = array(); + } + + array_unshift($completedPhases, $group['id']); + if (!$script->run($answers, $group['id'])) { + $script->run($completedPhases, '_undoOnError'); + return; + } + } else { + $script->run($completedPhases, '_undoOnError'); + return; + } + } + } + + /** + * Ask for user input, confirm the answers and continue until the user is satisfied + * @param array an array of arrays, format array('name' => 'paramname', 'prompt' => + * 'text to display', 'type' => 'string'[, default => 'default value']) + * @return array + */ + function confirmDialog($params) + { + $answers = $prompts = $types = array(); + foreach ($params as $param) { + $prompts[$param['name']] = $param['prompt']; + $types[$param['name']] = $param['type']; + $answers[$param['name']] = isset($param['default']) ? $param['default'] : ''; + } + + $tried = false; + do { + if ($tried) { + $i = 1; + foreach ($answers as $var => $value) { + if (!strlen($value)) { + echo $this->bold("* Enter an answer for #" . $i . ": ({$prompts[$var]})\n"); + } + $i++; + } + } + + $answers = $this->userDialog('', $prompts, $types, $answers); + $tried = true; + } while (is_array($answers) && count(array_filter($answers)) != count($prompts)); + + return $answers; + } + + function userDialog($command, $prompts, $types = array(), $defaults = array(), $screensize = 20) + { + if (!is_array($prompts)) { + return array(); + } + + $testprompts = array_keys($prompts); + $result = $defaults; + + reset($prompts); + if (count($prompts) === 1) { + foreach ($prompts as $key => $prompt) { + $type = $types[$key]; + $default = @$defaults[$key]; + print "$prompt "; + if ($default) { + print "[$default] "; + } + print ": "; + + $line = fgets(STDIN, 2048); + $result[$key] = ($default && trim($line) == '') ? $default : trim($line); + } + + return $result; + } + + $first_run = true; + while (true) { + $descLength = max(array_map('strlen', $prompts)); + $descFormat = "%-{$descLength}s"; + $last = count($prompts); + + $i = 0; + foreach ($prompts as $n => $var) { + $res = isset($result[$n]) ? $result[$n] : null; + printf("%2d. $descFormat : %s\n", ++$i, $prompts[$n], $res); + } + print "\n1-$last, 'all', 'abort', or Enter to continue: "; + + $tmp = trim(fgets(STDIN, 1024)); + if (empty($tmp)) { + break; + } + + if ($tmp == 'abort') { + return false; + } + + if (isset($testprompts[(int)$tmp - 1])) { + $var = $testprompts[(int)$tmp - 1]; + $desc = $prompts[$var]; + $current = @$result[$var]; + print "$desc [$current] : "; + $tmp = trim(fgets(STDIN, 1024)); + if ($tmp !== '') { + $result[$var] = $tmp; + } + } elseif ($tmp == 'all') { + foreach ($prompts as $var => $desc) { + $current = $result[$var]; + print "$desc [$current] : "; + $tmp = trim(fgets(STDIN, 1024)); + if (trim($tmp) !== '') { + $result[$var] = trim($tmp); + } + } + } + + $first_run = false; + } + + return $result; + } + + function userConfirm($prompt, $default = 'yes') + { + trigger_error("PEAR_Frontend_CLI::userConfirm not yet converted", E_USER_ERROR); + static $positives = array('y', 'yes', 'on', '1'); + static $negatives = array('n', 'no', 'off', '0'); + print "$this->lp$prompt [$default] : "; + $fp = fopen("php://stdin", "r"); + $line = fgets($fp, 2048); + fclose($fp); + $answer = strtolower(trim($line)); + if (empty($answer)) { + $answer = $default; + } + if (in_array($answer, $positives)) { + return true; + } + if (in_array($answer, $negatives)) { + return false; + } + if (in_array($default, $positives)) { + return true; + } + return false; + } + + function outputData($data, $command = '_default') + { + switch ($command) { + case 'channel-info': + foreach ($data as $type => $section) { + if ($type == 'main') { + $section['data'] = array_values($section['data']); + } + + $this->outputData($section); + } + break; + case 'install': + case 'upgrade': + case 'upgrade-all': + if (is_array($data) && isset($data['release_warnings'])) { + $this->_displayLine(''); + $this->_startTable(array( + 'border' => false, + 'caption' => 'Release Warnings' + )); + $this->_tableRow(array($data['release_warnings']), null, array(1 => array('wrap' => 55))); + $this->_endTable(); + $this->_displayLine(''); + } + + $this->_displayLine(is_array($data) ? $data['data'] : $data); + break; + case 'search': + $this->_startTable($data); + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); + } + + $packages = array(); + foreach($data['data'] as $category) { + foreach($category as $name => $pkg) { + $packages[$pkg[0]] = $pkg; + } + } + + $p = array_keys($packages); + natcasesort($p); + foreach ($p as $name) { + $this->_tableRow($packages[$name], null, array(1 => array('wrap' => 55))); + } + + $this->_endTable(); + break; + case 'list-all': + if (!isset($data['data'])) { + $this->_displayLine('No packages in channel'); + break; + } + + $this->_startTable($data); + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); + } + + $packages = array(); + foreach($data['data'] as $category) { + foreach($category as $name => $pkg) { + $packages[$pkg[0]] = $pkg; + } + } + + $p = array_keys($packages); + natcasesort($p); + foreach ($p as $name) { + $pkg = $packages[$name]; + unset($pkg[4], $pkg[5]); + $this->_tableRow($pkg, null, array(1 => array('wrap' => 55))); + } + + $this->_endTable(); + break; + case 'config-show': + $data['border'] = false; + $opts = array( + 0 => array('wrap' => 30), + 1 => array('wrap' => 20), + 2 => array('wrap' => 35) + ); + + $this->_startTable($data); + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], array('bold' => true), $opts); + } + + foreach ($data['data'] as $group) { + foreach ($group as $value) { + if ($value[2] == '') { + $value[2] = ""; + } + + $this->_tableRow($value, null, $opts); + } + } + + $this->_endTable(); + break; + case 'remote-info': + $d = $data; + $data = array( + 'caption' => 'Package details:', + 'border' => false, + 'data' => array( + array("Latest", $data['stable']), + array("Installed", $data['installed']), + array("Package", $data['name']), + array("License", $data['license']), + array("Category", $data['category']), + array("Summary", $data['summary']), + array("Description", $data['description']), + ), + ); + + if (isset($d['deprecated']) && $d['deprecated']) { + $conf = &PEAR_Config::singleton(); + $reg = $conf->getRegistry(); + $name = $reg->parsedPackageNameToString($d['deprecated'], true); + $data['data'][] = array('Deprecated! use', $name); + } + default: { + if (is_array($data)) { + $this->_startTable($data); + $count = count($data['data'][0]); + if ($count == 2) { + $opts = array(0 => array('wrap' => 25), + 1 => array('wrap' => 48) + ); + } elseif ($count == 3) { + $opts = array(0 => array('wrap' => 30), + 1 => array('wrap' => 20), + 2 => array('wrap' => 35) + ); + } else { + $opts = null; + } + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], + array('bold' => true), + $opts); + } + + if (is_array($data['data'])) { + foreach($data['data'] as $row) { + $this->_tableRow($row, null, $opts); + } + } else { + $this->_tableRow(array($data['data']), null, $opts); + } + $this->_endTable(); + } else { + $this->_displayLine($data); + } + } + } + } + + function log($text, $append_crlf = true) + { + if ($append_crlf) { + return $this->_displayLine($text); + } + + return $this->_display($text); + } + + function bold($text) + { + if (empty($this->term['bold'])) { + return strtoupper($text); + } + + return $this->term['bold'] . $text . $this->term['normal']; + } + + function _displayHeading($title) + { + print $this->lp.$this->bold($title)."\n"; + print $this->lp.str_repeat("=", strlen($title))."\n"; + } + + function _startTable($params = array()) + { + $params['table_data'] = array(); + $params['widest'] = array(); // indexed by column + $params['highest'] = array(); // indexed by row + $params['ncols'] = 0; + $this->params = $params; + } + + function _tableRow($columns, $rowparams = array(), $colparams = array()) + { + $highest = 1; + for ($i = 0; $i < count($columns); $i++) { + $col = &$columns[$i]; + if (isset($colparams[$i]) && !empty($colparams[$i]['wrap'])) { + $col = wordwrap($col, $colparams[$i]['wrap']); + } + + if (strpos($col, "\n") !== false) { + $multiline = explode("\n", $col); + $w = 0; + foreach ($multiline as $n => $line) { + $len = strlen($line); + if ($len > $w) { + $w = $len; + } + } + $lines = count($multiline); + } else { + $w = strlen($col); + } + + if (isset($this->params['widest'][$i])) { + if ($w > $this->params['widest'][$i]) { + $this->params['widest'][$i] = $w; + } + } else { + $this->params['widest'][$i] = $w; + } + + $tmp = count_chars($columns[$i], 1); + // handle unix, mac and windows formats + $lines = (isset($tmp[10]) ? $tmp[10] : (isset($tmp[13]) ? $tmp[13] : 0)) + 1; + if ($lines > $highest) { + $highest = $lines; + } + } + + if (count($columns) > $this->params['ncols']) { + $this->params['ncols'] = count($columns); + } + + $new_row = array( + 'data' => $columns, + 'height' => $highest, + 'rowparams' => $rowparams, + 'colparams' => $colparams, + ); + $this->params['table_data'][] = $new_row; + } + + function _endTable() + { + extract($this->params); + if (!empty($caption)) { + $this->_displayHeading($caption); + } + + if (count($table_data) === 0) { + return; + } + + if (!isset($width)) { + $width = $widest; + } else { + for ($i = 0; $i < $ncols; $i++) { + if (!isset($width[$i])) { + $width[$i] = $widest[$i]; + } + } + } + + $border = false; + if (empty($border)) { + $cellstart = ''; + $cellend = ' '; + $rowend = ''; + $padrowend = false; + $borderline = ''; + } else { + $cellstart = '| '; + $cellend = ' '; + $rowend = '|'; + $padrowend = true; + $borderline = '+'; + foreach ($width as $w) { + $borderline .= str_repeat('-', $w + strlen($cellstart) + strlen($cellend) - 1); + $borderline .= '+'; + } + } + + if ($borderline) { + $this->_displayLine($borderline); + } + + for ($i = 0; $i < count($table_data); $i++) { + extract($table_data[$i]); + if (!is_array($rowparams)) { + $rowparams = array(); + } + + if (!is_array($colparams)) { + $colparams = array(); + } + + $rowlines = array(); + if ($height > 1) { + for ($c = 0; $c < count($data); $c++) { + $rowlines[$c] = preg_split('/(\r?\n|\r)/', $data[$c]); + if (count($rowlines[$c]) < $height) { + $rowlines[$c] = array_pad($rowlines[$c], $height, ''); + } + } + } else { + for ($c = 0; $c < count($data); $c++) { + $rowlines[$c] = array($data[$c]); + } + } + + for ($r = 0; $r < $height; $r++) { + $rowtext = ''; + for ($c = 0; $c < count($data); $c++) { + if (isset($colparams[$c])) { + $attribs = array_merge($rowparams, $colparams); + } else { + $attribs = $rowparams; + } + + $w = isset($width[$c]) ? $width[$c] : 0; + //$cell = $data[$c]; + $cell = $rowlines[$c][$r]; + $l = strlen($cell); + if ($l > $w) { + $cell = substr($cell, 0, $w); + } + + if (isset($attribs['bold'])) { + $cell = $this->bold($cell); + } + + if ($l < $w) { + // not using str_pad here because we may + // add bold escape characters to $cell + $cell .= str_repeat(' ', $w - $l); + } + + $rowtext .= $cellstart . $cell . $cellend; + } + + if (!$border) { + $rowtext = rtrim($rowtext); + } + + $rowtext .= $rowend; + $this->_displayLine($rowtext); + } + } + + if ($borderline) { + $this->_displayLine($borderline); + } + } + + function _displayLine($text) + { + print "$this->lp$text\n"; + } + + function _display($text) + { + print $text; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer.php b/typo3conf/ext/phpunit/PEAR/PEAR/Installer.php new file mode 100644 index 0000000..9108530 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer.php @@ -0,0 +1,1830 @@ + + * @author Tomas V.V. Cox + * @author Martin Jansen + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Installer.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * Used for installation groups in package.xml 2.0 and platform exceptions + */ +require_once 'OS/Guess.php'; +require_once 'PEAR/Downloader.php'; + +define('PEAR_INSTALLER_NOBINARY', -240); +/** + * Administration class used to install PEAR packages and maintain the + * installed package database. + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V.V. Cox + * @author Martin Jansen + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Installer extends PEAR_Downloader +{ + // {{{ properties + + /** name of the package directory, for example Foo-1.0 + * @var string + */ + var $pkgdir; + + /** directory where PHP code files go + * @var string + */ + var $phpdir; + + /** directory where PHP extension files go + * @var string + */ + var $extdir; + + /** directory where documentation goes + * @var string + */ + var $docdir; + + /** installation root directory (ala PHP's INSTALL_ROOT or + * automake's DESTDIR + * @var string + */ + var $installroot = ''; + + /** debug level + * @var int + */ + var $debug = 1; + + /** temporary directory + * @var string + */ + var $tmpdir; + + /** + * PEAR_Registry object used by the installer + * @var PEAR_Registry + */ + var $registry; + + /** + * array of PEAR_Downloader_Packages + * @var array + */ + var $_downloadedPackages; + + /** List of file transactions queued for an install/upgrade/uninstall. + * + * Format: + * array( + * 0 => array("rename => array("from-file", "to-file")), + * 1 => array("delete" => array("file-to-delete")), + * ... + * ) + * + * @var array + */ + var $file_operations = array(); + + // }}} + + // {{{ constructor + + /** + * PEAR_Installer constructor. + * + * @param object $ui user interface object (instance of PEAR_Frontend_*) + * + * @access public + */ + function PEAR_Installer(&$ui) + { + parent::PEAR_Common(); + $this->setFrontendObject($ui); + $this->debug = $this->config->get('verbose'); + } + + function setOptions($options) + { + $this->_options = $options; + } + + function setConfig(&$config) + { + $this->config = &$config; + $this->_registry = &$config->getRegistry(); + } + + // }}} + + function _removeBackups($files) + { + foreach ($files as $path) { + $this->addFileOperation('removebackup', array($path)); + } + } + + // {{{ _deletePackageFiles() + + /** + * Delete a package's installed files, does not remove empty directories. + * + * @param string package name + * @param string channel name + * @param bool if true, then files are backed up first + * @return bool TRUE on success, or a PEAR error on failure + * @access protected + */ + function _deletePackageFiles($package, $channel = false, $backup = false) + { + if (!$channel) { + $channel = 'pear.php.net'; + } + + if (!strlen($package)) { + return $this->raiseError("No package to uninstall given"); + } + + if (strtolower($package) == 'pear' && $channel == 'pear.php.net') { + // to avoid race conditions, include all possible needed files + require_once 'PEAR/Task/Common.php'; + require_once 'PEAR/Task/Replace.php'; + require_once 'PEAR/Task/Unixeol.php'; + require_once 'PEAR/Task/Windowseol.php'; + require_once 'PEAR/PackageFile/v1.php'; + require_once 'PEAR/PackageFile/v2.php'; + require_once 'PEAR/PackageFile/Generator/v1.php'; + require_once 'PEAR/PackageFile/Generator/v2.php'; + } + + $filelist = $this->_registry->packageInfo($package, 'filelist', $channel); + if ($filelist == null) { + return $this->raiseError("$channel/$package not installed"); + } + + $ret = array(); + foreach ($filelist as $file => $props) { + if (empty($props['installed_as'])) { + continue; + } + + $path = $props['installed_as']; + if ($backup) { + $this->addFileOperation('backup', array($path)); + $ret[] = $path; + } + + $this->addFileOperation('delete', array($path)); + } + + if ($backup) { + return $ret; + } + + return true; + } + + // }}} + // {{{ _installFile() + + /** + * @param string filename + * @param array attributes from tag in package.xml + * @param string path to install the file in + * @param array options from command-line + * @access private + */ + function _installFile($file, $atts, $tmp_path, $options) + { + // {{{ return if this file is meant for another platform + static $os; + if (!isset($this->_registry)) { + $this->_registry = &$this->config->getRegistry(); + } + + if (isset($atts['platform'])) { + if (empty($os)) { + $os = new OS_Guess(); + } + + if (strlen($atts['platform']) && $atts['platform']{0} == '!') { + $negate = true; + $platform = substr($atts['platform'], 1); + } else { + $negate = false; + $platform = $atts['platform']; + } + + if ((bool) $os->matchSignature($platform) === $negate) { + $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")"); + return PEAR_INSTALLER_SKIPPED; + } + } + // }}} + + $channel = $this->pkginfo->getChannel(); + // {{{ assemble the destination paths + switch ($atts['role']) { + case 'src': + case 'extsrc': + $this->source_files++; + return; + case 'doc': + case 'data': + case 'test': + $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel) . + DIRECTORY_SEPARATOR . $this->pkginfo->getPackage(); + unset($atts['baseinstalldir']); + break; + case 'ext': + case 'php': + $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel); + break; + case 'script': + $dest_dir = $this->config->get('bin_dir', null, $channel); + break; + default: + return $this->raiseError("Invalid role `$atts[role]' for file $file"); + } + + $save_destdir = $dest_dir; + if (!empty($atts['baseinstalldir'])) { + $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; + } + + if (dirname($file) != '.' && empty($atts['install-as'])) { + $dest_dir .= DIRECTORY_SEPARATOR . dirname($file); + } + + if (empty($atts['install-as'])) { + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file); + } else { + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as']; + } + $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file; + + // Clean up the DIRECTORY_SEPARATOR mess + $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; + list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), + array(DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR), + array($dest_file, $orig_file)); + $final_dest_file = $installed_as = $dest_file; + if (isset($this->_options['packagingroot'])) { + $installedas_dest_dir = dirname($final_dest_file); + $installedas_dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); + $final_dest_file = $this->_prependPath($final_dest_file, $this->_options['packagingroot']); + } else { + $installedas_dest_dir = dirname($final_dest_file); + $installedas_dest_file = $installedas_dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); + } + + $dest_dir = dirname($final_dest_file); + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); + if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) { + return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED); + } + // }}} + + if (empty($this->_options['register-only']) && + (!file_exists($dest_dir) || !is_dir($dest_dir))) { + if (!$this->mkDirHier($dest_dir)) { + return $this->raiseError("failed to mkdir $dest_dir", + PEAR_INSTALLER_FAILED); + } + $this->log(3, "+ mkdir $dest_dir"); + } + + // pretty much nothing happens if we are only registering the install + if (empty($this->_options['register-only'])) { + if (empty($atts['replacements'])) { + if (!file_exists($orig_file)) { + return $this->raiseError("file $orig_file does not exist", + PEAR_INSTALLER_FAILED); + } + + if (!@copy($orig_file, $dest_file)) { + return $this->raiseError("failed to write $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } + + $this->log(3, "+ cp $orig_file $dest_file"); + if (isset($atts['md5sum'])) { + $md5sum = md5_file($dest_file); + } + } else { + // {{{ file with replacements + if (!file_exists($orig_file)) { + return $this->raiseError("file does not exist", + PEAR_INSTALLER_FAILED); + } + + $contents = file_get_contents($orig_file); + if ($contents === false) { + $contents = ''; + } + + if (isset($atts['md5sum'])) { + $md5sum = md5($contents); + } + + $subst_from = $subst_to = array(); + foreach ($atts['replacements'] as $a) { + $to = ''; + if ($a['type'] == 'php-const') { + if (preg_match('/^[a-z0-9_]+\\z/i', $a['to'])) { + eval("\$to = $a[to];"); + } else { + if (!isset($options['soft'])) { + $this->log(0, "invalid php-const replacement: $a[to]"); + } + continue; + } + } elseif ($a['type'] == 'pear-config') { + if ($a['to'] == 'master_server') { + $chan = $this->_registry->getChannel($channel); + if (!PEAR::isError($chan)) { + $to = $chan->getServer(); + } else { + $to = $this->config->get($a['to'], null, $channel); + } + } else { + $to = $this->config->get($a['to'], null, $channel); + } + if (is_null($to)) { + if (!isset($options['soft'])) { + $this->log(0, "invalid pear-config replacement: $a[to]"); + } + continue; + } + } elseif ($a['type'] == 'package-info') { + if ($t = $this->pkginfo->packageInfo($a['to'])) { + $to = $t; + } else { + if (!isset($options['soft'])) { + $this->log(0, "invalid package-info replacement: $a[to]"); + } + continue; + } + } + if (!is_null($to)) { + $subst_from[] = $a['from']; + $subst_to[] = $to; + } + } + + $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file"); + if (sizeof($subst_from)) { + $contents = str_replace($subst_from, $subst_to, $contents); + } + + $wp = @fopen($dest_file, "wb"); + if (!is_resource($wp)) { + return $this->raiseError("failed to create $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } + + if (@fwrite($wp, $contents) === false) { + return $this->raiseError("failed writing to $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } + + fclose($wp); + // }}} + } + + // {{{ check the md5 + if (isset($md5sum)) { + if (strtolower($md5sum) === strtolower($atts['md5sum'])) { + $this->log(2, "md5sum ok: $final_dest_file"); + } else { + if (empty($options['force'])) { + // delete the file + if (file_exists($dest_file)) { + unlink($dest_file); + } + + if (!isset($options['ignore-errors'])) { + return $this->raiseError("bad md5sum for file $final_dest_file", + PEAR_INSTALLER_FAILED); + } + + if (!isset($options['soft'])) { + $this->log(0, "warning : bad md5sum for file $final_dest_file"); + } + } else { + if (!isset($options['soft'])) { + $this->log(0, "warning : bad md5sum for file $final_dest_file"); + } + } + } + } + // }}} + // {{{ set file permissions + if (!OS_WINDOWS) { + if ($atts['role'] == 'script') { + $mode = 0777 & ~(int)octdec($this->config->get('umask')); + $this->log(3, "+ chmod +x $dest_file"); + } else { + $mode = 0666 & ~(int)octdec($this->config->get('umask')); + } + + if ($atts['role'] != 'src') { + $this->addFileOperation("chmod", array($mode, $dest_file)); + if (!@chmod($dest_file, $mode)) { + if (!isset($options['soft'])) { + $this->log(0, "failed to change mode of $dest_file: $php_errormsg"); + } + } + } + } + // }}} + + if ($atts['role'] == 'src') { + rename($dest_file, $final_dest_file); + $this->log(2, "renamed source file $dest_file to $final_dest_file"); + } else { + $this->addFileOperation("rename", array($dest_file, $final_dest_file, + $atts['role'] == 'ext')); + } + } + + // Store the full path where the file was installed for easy unistall + if ($atts['role'] != 'script') { + $loc = $this->config->get($atts['role'] . '_dir'); + } else { + $loc = $this->config->get('bin_dir'); + } + + if ($atts['role'] != 'src') { + $this->addFileOperation("installed_as", array($file, $installed_as, + $loc, + dirname(substr($installedas_dest_file, strlen($loc))))); + } + + //$this->log(2, "installed: $dest_file"); + return PEAR_INSTALLER_OK; + } + + // }}} + // {{{ _installFile2() + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string filename + * @param array attributes from tag in package.xml + * @param string path to install the file in + * @param array options from command-line + * @access private + */ + function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options) + { + $atts = $real_atts; + if (!isset($this->_registry)) { + $this->_registry = &$this->config->getRegistry(); + } + + $channel = $pkg->getChannel(); + // {{{ assemble the destination paths + if (!in_array($atts['attribs']['role'], + PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) { + return $this->raiseError('Invalid role `' . $atts['attribs']['role'] . + "' for file $file"); + } + + $role = &PEAR_Installer_Role::factory($pkg, $atts['attribs']['role'], $this->config); + $err = $role->setup($this, $pkg, $atts['attribs'], $file); + if (PEAR::isError($err)) { + return $err; + } + + if (!$role->isInstallable()) { + return; + } + + $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path); + if (PEAR::isError($info)) { + return $info; + } + + list($save_destdir, $dest_dir, $dest_file, $orig_file) = $info; + if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) { + return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED); + } + + $final_dest_file = $installed_as = $dest_file; + if (isset($this->_options['packagingroot'])) { + $final_dest_file = $this->_prependPath($final_dest_file, + $this->_options['packagingroot']); + } + + $dest_dir = dirname($final_dest_file); + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); + // }}} + + if (empty($this->_options['register-only'])) { + if (!file_exists($dest_dir) || !is_dir($dest_dir)) { + if (!$this->mkDirHier($dest_dir)) { + return $this->raiseError("failed to mkdir $dest_dir", + PEAR_INSTALLER_FAILED); + } + $this->log(3, "+ mkdir $dest_dir"); + } + } + + $attribs = $atts['attribs']; + unset($atts['attribs']); + // pretty much nothing happens if we are only registering the install + if (empty($this->_options['register-only'])) { + if (!count($atts)) { // no tasks + if (!file_exists($orig_file)) { + return $this->raiseError("file $orig_file does not exist", + PEAR_INSTALLER_FAILED); + } + + if (!@copy($orig_file, $dest_file)) { + return $this->raiseError("failed to write $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } + + $this->log(3, "+ cp $orig_file $dest_file"); + if (isset($attribs['md5sum'])) { + $md5sum = md5_file($dest_file); + } + } else { // file with tasks + if (!file_exists($orig_file)) { + return $this->raiseError("file $orig_file does not exist", + PEAR_INSTALLER_FAILED); + } + + $contents = file_get_contents($orig_file); + if ($contents === false) { + $contents = ''; + } + + if (isset($attribs['md5sum'])) { + $md5sum = md5($contents); + } + + foreach ($atts as $tag => $raw) { + $tag = str_replace(array($pkg->getTasksNs() . ':', '-'), array('', '_'), $tag); + $task = "PEAR_Task_$tag"; + $task = &new $task($this->config, $this, PEAR_TASK_INSTALL); + if (!$task->isScript()) { // scripts are only handled after installation + $task->init($raw, $attribs, $pkg->getLastInstalledVersion()); + $res = $task->startSession($pkg, $contents, $final_dest_file); + if ($res === false) { + continue; // skip this file + } + + if (PEAR::isError($res)) { + return $res; + } + + $contents = $res; // save changes + } + + $wp = @fopen($dest_file, "wb"); + if (!is_resource($wp)) { + return $this->raiseError("failed to create $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } + + if (fwrite($wp, $contents) === false) { + return $this->raiseError("failed writing to $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } + + fclose($wp); + } + } + + // {{{ check the md5 + if (isset($md5sum)) { + // Make sure the original md5 sum matches with expected + if (strtolower($md5sum) === strtolower($attribs['md5sum'])) { + $this->log(2, "md5sum ok: $final_dest_file"); + + if (isset($contents)) { + // set md5 sum based on $content in case any tasks were run. + $real_atts['attribs']['md5sum'] = md5($contents); + } + } else { + if (empty($options['force'])) { + // delete the file + if (file_exists($dest_file)) { + unlink($dest_file); + } + + if (!isset($options['ignore-errors'])) { + return $this->raiseError("bad md5sum for file $final_dest_file", + PEAR_INSTALLER_FAILED); + } + + if (!isset($options['soft'])) { + $this->log(0, "warning : bad md5sum for file $final_dest_file"); + } + } else { + if (!isset($options['soft'])) { + $this->log(0, "warning : bad md5sum for file $final_dest_file"); + } + } + } + } else { + $real_atts['attribs']['md5sum'] = md5_file($dest_file); + } + + // }}} + // {{{ set file permissions + if (!OS_WINDOWS) { + if ($role->isExecutable()) { + $mode = 0777 & ~(int)octdec($this->config->get('umask')); + $this->log(3, "+ chmod +x $dest_file"); + } else { + $mode = 0666 & ~(int)octdec($this->config->get('umask')); + } + + if ($attribs['role'] != 'src') { + $this->addFileOperation("chmod", array($mode, $dest_file)); + if (!@chmod($dest_file, $mode)) { + if (!isset($options['soft'])) { + $this->log(0, "failed to change mode of $dest_file: $php_errormsg"); + } + } + } + } + // }}} + + if ($attribs['role'] == 'src') { + rename($dest_file, $final_dest_file); + $this->log(2, "renamed source file $dest_file to $final_dest_file"); + } else { + $this->addFileOperation("rename", array($dest_file, $final_dest_file, $role->isExtension())); + } + } + + // Store the full path where the file was installed for easy uninstall + if ($attribs['role'] != 'src') { + $loc = $this->config->get($role->getLocationConfig(), null, $channel); + $this->addFileOperation('installed_as', array($file, $installed_as, + $loc, + dirname(substr($installed_as, strlen($loc))))); + } + + //$this->log(2, "installed: $dest_file"); + return PEAR_INSTALLER_OK; + } + + // }}} + // {{{ addFileOperation() + + /** + * Add a file operation to the current file transaction. + * + * @see startFileTransaction() + * @param string $type This can be one of: + * - rename: rename a file ($data has 3 values) + * - backup: backup an existing file ($data has 1 value) + * - removebackup: clean up backups created during install ($data has 1 value) + * - chmod: change permissions on a file ($data has 2 values) + * - delete: delete a file ($data has 1 value) + * - rmdir: delete a directory if empty ($data has 1 value) + * - installed_as: mark a file as installed ($data has 4 values). + * @param array $data For all file operations, this array must contain the + * full path to the file or directory that is being operated on. For + * the rename command, the first parameter must be the file to rename, + * the second its new name, the third whether this is a PHP extension. + * + * The installed_as operation contains 4 elements in this order: + * 1. Filename as listed in the filelist element from package.xml + * 2. Full path to the installed file + * 3. Full path from the php_dir configuration variable used in this + * installation + * 4. Relative path from the php_dir that this file is installed in + */ + function addFileOperation($type, $data) + { + if (!is_array($data)) { + return $this->raiseError('Internal Error: $data in addFileOperation' + . ' must be an array, was ' . gettype($data)); + } + + if ($type == 'chmod') { + $octmode = decoct($data[0]); + $this->log(3, "adding to transaction: $type $octmode $data[1]"); + } else { + $this->log(3, "adding to transaction: $type " . implode(" ", $data)); + } + $this->file_operations[] = array($type, $data); + } + + // }}} + // {{{ startFileTransaction() + + function startFileTransaction($rollback_in_case = false) + { + if (count($this->file_operations) && $rollback_in_case) { + $this->rollbackFileTransaction(); + } + $this->file_operations = array(); + } + + // }}} + // {{{ commitFileTransaction() + + function commitFileTransaction() + { + // {{{ first, check permissions and such manually + $errors = array(); + foreach ($this->file_operations as $key => $tr) { + list($type, $data) = $tr; + switch ($type) { + case 'rename': + if (!file_exists($data[0])) { + $errors[] = "cannot rename file $data[0], doesn't exist"; + } + + // check that dest dir. is writable + if (!is_writable(dirname($data[1]))) { + $errors[] = "permission denied ($type): $data[1]"; + } + break; + case 'chmod': + // check that file is writable + if (!is_writable($data[1])) { + $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]); + } + break; + case 'delete': + if (!file_exists($data[0])) { + $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted"); + } + // check that directory is writable + if (file_exists($data[0])) { + if (!is_writable(dirname($data[0]))) { + $errors[] = "permission denied ($type): $data[0]"; + } else { + // make sure the file to be deleted can be opened for writing + $fp = false; + if (!is_dir($data[0]) && + (!is_writable($data[0]) || !($fp = @fopen($data[0], 'a')))) { + $errors[] = "permission denied ($type): $data[0]"; + } elseif ($fp) { + fclose($fp); + } + } + + /* Verify we are not deleting a file owned by another package + * This can happen when a file moves from package A to B in + * an upgrade ala http://pear.php.net/17986 + */ + $info = array( + 'package' => strtolower($this->pkginfo->getName()), + 'channel' => strtolower($this->pkginfo->getChannel()), + ); + $result = $this->_registry->checkFileMap($data[0], $info, '1.1'); + if (is_array($result)) { + $res = array_diff($result, $info); + if (!empty($res)) { + $new = $this->_registry->getPackage($result[1], $result[0]); + $this->file_operations[$key] = false; + $this->log(3, "file $data[0] was scheduled for removal from {$this->pkginfo->getName()} but is owned by {$new->getChannel()}/{$new->getName()}, removal has been cancelled."); + } + } + } + break; + } + + } + // }}} + + $n = count($this->file_operations); + $this->log(2, "about to commit $n file operations for " . $this->pkginfo->getName()); + + $m = count($errors); + if ($m > 0) { + foreach ($errors as $error) { + if (!isset($this->_options['soft'])) { + $this->log(1, $error); + } + } + + if (!isset($this->_options['ignore-errors'])) { + return false; + } + } + + $this->_dirtree = array(); + // {{{ really commit the transaction + foreach ($this->file_operations as $i => $tr) { + if (!$tr) { + // support removal of non-existing backups + continue; + } + + list($type, $data) = $tr; + switch ($type) { + case 'backup': + if (!file_exists($data[0])) { + $this->file_operations[$i] = false; + break; + } + + if (!@copy($data[0], $data[0] . '.bak')) { + $this->log(1, 'Could not copy ' . $data[0] . ' to ' . $data[0] . + '.bak ' . $php_errormsg); + return false; + } + $this->log(3, "+ backup $data[0] to $data[0].bak"); + break; + case 'removebackup': + if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) { + unlink($data[0] . '.bak'); + $this->log(3, "+ rm backup of $data[0] ($data[0].bak)"); + } + break; + case 'rename': + $test = file_exists($data[1]) ? @unlink($data[1]) : null; + if (!$test && file_exists($data[1])) { + if ($data[2]) { + $extra = ', this extension must be installed manually. Rename to "' . + basename($data[1]) . '"'; + } else { + $extra = ''; + } + + if (!isset($this->_options['soft'])) { + $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' . + $data[0] . $extra); + } + + if (!isset($this->_options['ignore-errors'])) { + return false; + } + } + + // permissions issues with rename - copy() is far superior + $perms = @fileperms($data[0]); + if (!@copy($data[0], $data[1])) { + $this->log(1, 'Could not rename ' . $data[0] . ' to ' . $data[1] . + ' ' . $php_errormsg); + return false; + } + + // copy over permissions, otherwise they are lost + @chmod($data[1], $perms); + @unlink($data[0]); + $this->log(3, "+ mv $data[0] $data[1]"); + break; + case 'chmod': + if (!@chmod($data[1], $data[0])) { + $this->log(1, 'Could not chmod ' . $data[1] . ' to ' . + decoct($data[0]) . ' ' . $php_errormsg); + return false; + } + + $octmode = decoct($data[0]); + $this->log(3, "+ chmod $octmode $data[1]"); + break; + case 'delete': + if (file_exists($data[0])) { + if (!@unlink($data[0])) { + $this->log(1, 'Could not delete ' . $data[0] . ' ' . + $php_errormsg); + return false; + } + $this->log(3, "+ rm $data[0]"); + } + break; + case 'rmdir': + if (file_exists($data[0])) { + do { + $testme = opendir($data[0]); + while (false !== ($entry = readdir($testme))) { + if ($entry == '.' || $entry == '..') { + continue; + } + closedir($testme); + break 2; // this directory is not empty and can't be + // deleted + } + + closedir($testme); + if (!@rmdir($data[0])) { + $this->log(1, 'Could not rmdir ' . $data[0] . ' ' . + $php_errormsg); + return false; + } + $this->log(3, "+ rmdir $data[0]"); + } while (false); + } + break; + case 'installed_as': + $this->pkginfo->setInstalledAs($data[0], $data[1]); + if (!isset($this->_dirtree[dirname($data[1])])) { + $this->_dirtree[dirname($data[1])] = true; + $this->pkginfo->setDirtree(dirname($data[1])); + + while(!empty($data[3]) && dirname($data[3]) != $data[3] && + $data[3] != '/' && $data[3] != '\\') { + $this->pkginfo->setDirtree($pp = + $this->_prependPath($data[3], $data[2])); + $this->_dirtree[$pp] = true; + $data[3] = dirname($data[3]); + } + } + break; + } + } + // }}} + $this->log(2, "successfully committed $n file operations"); + $this->file_operations = array(); + return true; + } + + // }}} + // {{{ rollbackFileTransaction() + + function rollbackFileTransaction() + { + $n = count($this->file_operations); + $this->log(2, "rolling back $n file operations"); + foreach ($this->file_operations as $tr) { + list($type, $data) = $tr; + switch ($type) { + case 'backup': + if (file_exists($data[0] . '.bak')) { + if (file_exists($data[0] && is_writable($data[0]))) { + unlink($data[0]); + } + @copy($data[0] . '.bak', $data[0]); + $this->log(3, "+ restore $data[0] from $data[0].bak"); + } + break; + case 'removebackup': + if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) { + unlink($data[0] . '.bak'); + $this->log(3, "+ rm backup of $data[0] ($data[0].bak)"); + } + break; + case 'rename': + @unlink($data[0]); + $this->log(3, "+ rm $data[0]"); + break; + case 'mkdir': + @rmdir($data[0]); + $this->log(3, "+ rmdir $data[0]"); + break; + case 'chmod': + break; + case 'delete': + break; + case 'installed_as': + $this->pkginfo->setInstalledAs($data[0], false); + break; + } + } + $this->pkginfo->resetDirtree(); + $this->file_operations = array(); + } + + // }}} + // {{{ mkDirHier($dir) + + function mkDirHier($dir) + { + $this->addFileOperation('mkdir', array($dir)); + return parent::mkDirHier($dir); + } + + // }}} + // {{{ download() + + /** + * Download any files and their dependencies, if necessary + * + * @param array a mixed list of package names, local files, or package.xml + * @param PEAR_Config + * @param array options from the command line + * @param array this is the array that will be populated with packages to + * install. Format of each entry: + * + * + * array('pkg' => 'package_name', 'file' => '/path/to/local/file', + * 'info' => array() // parsed package.xml + * ); + * + * @param array this will be populated with any error messages + * @param false private recursion variable + * @param false private recursion variable + * @param false private recursion variable + * @deprecated in favor of PEAR_Downloader + */ + function download($packages, $options, &$config, &$installpackages, + &$errors, $installed = false, $willinstall = false, $state = false) + { + // trickiness: initialize here + parent::PEAR_Downloader($this->ui, $options, $config); + $ret = parent::download($packages); + $errors = $this->getErrorMsgs(); + $installpackages = $this->getDownloadedPackages(); + trigger_error("PEAR Warning: PEAR_Installer::download() is deprecated " . + "in favor of PEAR_Downloader class", E_USER_WARNING); + return $ret; + } + + // }}} + // {{{ _parsePackageXml() + + function _parsePackageXml(&$descfile) + { + // Parse xml file ----------------------------------------------- + $pkg = new PEAR_PackageFile($this->config, $this->debug); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $p = &$pkg->fromAnyFile($descfile, PEAR_VALIDATE_INSTALLING); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($p)) { + if (is_array($p->getUserInfo())) { + foreach ($p->getUserInfo() as $err) { + $loglevel = $err['level'] == 'error' ? 0 : 1; + if (!isset($this->_options['soft'])) { + $this->log($loglevel, ucfirst($err['level']) . ': ' . $err['message']); + } + } + } + return $this->raiseError('Installation failed: invalid package file'); + } + + $descfile = $p->getPackageFile(); + return $p; + } + + // }}} + /** + * Set the list of PEAR_Downloader_Package objects to allow more sane + * dependency validation + * @param array + */ + function setDownloadedPackages(&$pkgs) + { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->analyzeDependencies($pkgs); + PEAR::popErrorHandling(); + if (PEAR::isError($err)) { + return $err; + } + $this->_downloadedPackages = &$pkgs; + } + + /** + * Set the list of PEAR_Downloader_Package objects to allow more sane + * dependency validation + * @param array + */ + function setUninstallPackages(&$pkgs) + { + $this->_downloadedPackages = &$pkgs; + } + + function getInstallPackages() + { + return $this->_downloadedPackages; + } + + // {{{ install() + + /** + * Installs the files within the package file specified. + * + * @param string|PEAR_Downloader_Package $pkgfile path to the package file, + * or a pre-initialized packagefile object + * @param array $options + * recognized options: + * - installroot : optional prefix directory for installation + * - force : force installation + * - register-only : update registry but don't install files + * - upgrade : upgrade existing install + * - soft : fail silently + * - nodeps : ignore dependency conflicts/missing dependencies + * - alldeps : install all dependencies + * - onlyreqdeps : install only required dependencies + * + * @return array|PEAR_Error package info if successful + */ + function install($pkgfile, $options = array()) + { + $this->_options = $options; + $this->_registry = &$this->config->getRegistry(); + if (is_object($pkgfile)) { + $dlpkg = &$pkgfile; + $pkg = $pkgfile->getPackageFile(); + $pkgfile = $pkg->getArchiveFile(); + $descfile = $pkg->getPackageFile(); + } else { + $descfile = $pkgfile; + $pkg = $this->_parsePackageXml($descfile); + if (PEAR::isError($pkg)) { + return $pkg; + } + } + + $tmpdir = dirname($descfile); + if (realpath($descfile) != realpath($pkgfile)) { + // Use the temp_dir since $descfile can contain the download dir path + $tmpdir = $this->config->get('temp_dir', null, 'pear.php.net'); + $tmpdir = System::mktemp("-d -t $tmpdir"); + + $tar = new Archive_Tar($pkgfile); + if (!$tar->extract($tmpdir)) { + return $this->raiseError("unable to unpack $pkgfile"); + } + } + + $pkgname = $pkg->getName(); + $channel = $pkg->getChannel(); + if (isset($this->_options['packagingroot'])) { + $regdir = $this->_prependPath( + $this->config->get('php_dir', null, 'pear.php.net'), + $this->_options['packagingroot']); + + $packrootphp_dir = $this->_prependPath( + $this->config->get('php_dir', null, $channel), + $this->_options['packagingroot']); + } + + if (isset($options['installroot'])) { + $this->config->setInstallRoot($options['installroot']); + $this->_registry = &$this->config->getRegistry(); + $installregistry = &$this->_registry; + $this->installroot = ''; // all done automagically now + $php_dir = $this->config->get('php_dir', null, $channel); + } else { + $this->config->setInstallRoot(false); + $this->_registry = &$this->config->getRegistry(); + if (isset($this->_options['packagingroot'])) { + $installregistry = &new PEAR_Registry($regdir); + if (!$installregistry->channelExists($channel, true)) { + // we need to fake a channel-discover of this channel + $chanobj = $this->_registry->getChannel($channel, true); + $installregistry->addChannel($chanobj); + } + $php_dir = $packrootphp_dir; + } else { + $installregistry = &$this->_registry; + $php_dir = $this->config->get('php_dir', null, $channel); + } + $this->installroot = ''; + } + + // {{{ checks to do when not in "force" mode + if (empty($options['force']) && + (file_exists($this->config->get('php_dir')) && + is_dir($this->config->get('php_dir')))) { + $testp = $channel == 'pear.php.net' ? $pkgname : array($channel, $pkgname); + $instfilelist = $pkg->getInstallationFileList(true); + if (PEAR::isError($instfilelist)) { + return $instfilelist; + } + + // ensure we have the most accurate registry + $installregistry->flushFileMap(); + $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1'); + if (PEAR::isError($test)) { + return $test; + } + + if (sizeof($test)) { + $pkgs = $this->getInstallPackages(); + $found = false; + foreach ($pkgs as $param) { + if ($pkg->isSubpackageOf($param)) { + $found = true; + break; + } + } + + if ($found) { + // subpackages can conflict with earlier versions of parent packages + $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel()); + $tmp = $test; + foreach ($tmp as $file => $info) { + if (is_array($info)) { + if (strtolower($info[1]) == strtolower($param->getPackage()) && + strtolower($info[0]) == strtolower($param->getChannel()) + ) { + if (isset($parentreg['filelist'][$file])) { + unset($parentreg['filelist'][$file]); + } else{ + $pos = strpos($file, '/'); + $basedir = substr($file, 0, $pos); + $file2 = substr($file, $pos + 1); + if (isset($parentreg['filelist'][$file2]['baseinstalldir']) + && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir + ) { + unset($parentreg['filelist'][$file2]); + } + } + + unset($test[$file]); + } + } else { + if (strtolower($param->getChannel()) != 'pear.php.net') { + continue; + } + + if (strtolower($info) == strtolower($param->getPackage())) { + if (isset($parentreg['filelist'][$file])) { + unset($parentreg['filelist'][$file]); + } else{ + $pos = strpos($file, '/'); + $basedir = substr($file, 0, $pos); + $file2 = substr($file, $pos + 1); + if (isset($parentreg['filelist'][$file2]['baseinstalldir']) + && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir + ) { + unset($parentreg['filelist'][$file2]); + } + } + + unset($test[$file]); + } + } + } + + $pfk = &new PEAR_PackageFile($this->config); + $parentpkg = &$pfk->fromArray($parentreg); + $installregistry->updatePackage2($parentpkg); + } + + if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) { + $tmp = $test; + foreach ($tmp as $file => $info) { + if (is_string($info)) { + // pear.php.net packages are always stored as strings + if (strtolower($info) == strtolower($param->getPackage())) { + // upgrading existing package + unset($test[$file]); + } + } + } + } + + if (count($test)) { + $msg = "$channel/$pkgname: conflicting files found:\n"; + $longest = max(array_map("strlen", array_keys($test))); + $fmt = "%${longest}s (%s)\n"; + foreach ($test as $file => $info) { + if (!is_array($info)) { + $info = array('pear.php.net', $info); + } + $info = $info[0] . '/' . $info[1]; + $msg .= sprintf($fmt, $file, $info); + } + + if (!isset($options['ignore-errors'])) { + return $this->raiseError($msg); + } + + if (!isset($options['soft'])) { + $this->log(0, "WARNING: $msg"); + } + } + } + } + // }}} + + $this->startFileTransaction(); + + if (empty($options['upgrade']) && empty($options['soft'])) { + // checks to do only when installing new packages + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + } + } else { + $test = $installregistry->packageExists($pkgname, $channel); + } + + if (empty($options['force']) && $test) { + return $this->raiseError("$channel/$pkgname is already installed"); + } + } else { + $usechannel = $channel; + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + $usechannel = 'pear.php.net'; + } + } else { + $test = $installregistry->packageExists($pkgname, $channel); + } + + if ($test) { + $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel); + $v2 = $pkg->getVersion(); + $cmp = version_compare("$v1", "$v2", 'gt'); + if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) { + return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)"); + } + + if (empty($options['register-only'])) { + // when upgrading, remove old release's files first: + if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel, + true))) { + if (!isset($options['ignore-errors'])) { + return $this->raiseError($err); + } + + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: ' . $err->getMessage()); + } + } else { + $backedup = $err; + } + } + } + } + + // {{{ Copy files to dest dir --------------------------------------- + + // info from the package it self we want to access from _installFile + $this->pkginfo = &$pkg; + // used to determine whether we should build any C code + $this->source_files = 0; + + $savechannel = $this->config->get('default_channel'); + if (empty($options['register-only']) && !is_dir($php_dir)) { + if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) { + return $this->raiseError("no installation destination directory '$php_dir'\n"); + } + } + + if (substr($pkgfile, -4) != '.xml') { + $tmpdir .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion(); + } + + $this->configSet('default_channel', $channel); + // {{{ install files + + $ver = $pkg->getPackagexmlVersion(); + if (version_compare($ver, '2.0', '>=')) { + $filelist = $pkg->getInstallationFilelist(); + } else { + $filelist = $pkg->getFileList(); + } + + if (PEAR::isError($filelist)) { + return $filelist; + } + + $p = &$installregistry->getPackage($pkgname, $channel); + $dirtree = (empty($options['register-only']) && $p) ? $p->getDirTree() : false; + + $pkg->resetFilelist(); + $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(), + 'version', $pkg->getChannel())); + foreach ($filelist as $file => $atts) { + $this->expectError(PEAR_INSTALLER_FAILED); + if ($pkg->getPackagexmlVersion() == '1.0') { + $res = $this->_installFile($file, $atts, $tmpdir, $options); + } else { + $res = $this->_installFile2($pkg, $file, $atts, $tmpdir, $options); + } + $this->popExpect(); + + if (PEAR::isError($res)) { + if (empty($options['ignore-errors'])) { + $this->rollbackFileTransaction(); + if ($res->getMessage() == "file does not exist") { + $this->raiseError("file $file in package.xml does not exist"); + } + + return $this->raiseError($res); + } + + if (!isset($options['soft'])) { + $this->log(0, "Warning: " . $res->getMessage()); + } + } + + $real = isset($atts['attribs']) ? $atts['attribs'] : $atts; + if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') { + // Register files that were installed + $pkg->installedFile($file, $atts); + } + } + // }}} + + // {{{ compile and install source files + if ($this->source_files > 0 && empty($options['nobuild'])) { + if (PEAR::isError($err = + $this->_compileSourceFiles($savechannel, $pkg))) { + return $err; + } + } + // }}} + + if (isset($backedup)) { + $this->_removeBackups($backedup); + } + + if (!$this->commitFileTransaction()) { + $this->rollbackFileTransaction(); + $this->configSet('default_channel', $savechannel); + return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED); + } + // }}} + + $ret = false; + $installphase = 'install'; + $oldversion = false; + // {{{ Register that the package is installed ----------------------- + if (empty($options['upgrade'])) { + // if 'force' is used, replace the info in registry + $usechannel = $channel; + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + $usechannel = 'pear.php.net'; + } + } else { + $test = $installregistry->packageExists($pkgname, $channel); + } + + if (!empty($options['force']) && $test) { + $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel); + $installregistry->deletePackage($pkgname, $usechannel); + } + $ret = $installregistry->addPackage2($pkg); + } else { + if ($dirtree) { + $this->startFileTransaction(); + // attempt to delete empty directories + uksort($dirtree, array($this, '_sortDirs')); + foreach($dirtree as $dir => $notused) { + $this->addFileOperation('rmdir', array($dir)); + } + $this->commitFileTransaction(); + } + + $usechannel = $channel; + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + $usechannel = 'pear.php.net'; + } + } else { + $test = $installregistry->packageExists($pkgname, $channel); + } + + // new: upgrade installs a package if it isn't installed + if (!$test) { + $ret = $installregistry->addPackage2($pkg); + } else { + if ($usechannel != $channel) { + $installregistry->deletePackage($pkgname, $usechannel); + $ret = $installregistry->addPackage2($pkg); + } else { + $ret = $installregistry->updatePackage2($pkg); + } + $installphase = 'upgrade'; + } + } + + if (!$ret) { + $this->configSet('default_channel', $savechannel); + return $this->raiseError("Adding package $channel/$pkgname to registry failed"); + } + // }}} + + $this->configSet('default_channel', $savechannel); + if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist + if (PEAR_Task_Common::hasPostinstallTasks()) { + PEAR_Task_Common::runPostinstallTasks($installphase); + } + } + + return $pkg->toArray(true); + } + + // }}} + + // {{{ _compileSourceFiles() + /** + * @param string + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + */ + function _compileSourceFiles($savechannel, &$filelist) + { + require_once 'PEAR/Builder.php'; + $this->log(1, "$this->source_files source files, building"); + $bob = &new PEAR_Builder($this->ui); + $bob->debug = $this->debug; + $built = $bob->build($filelist, array(&$this, '_buildCallback')); + if (PEAR::isError($built)) { + $this->rollbackFileTransaction(); + $this->configSet('default_channel', $savechannel); + return $built; + } + + $this->log(1, "\nBuild process completed successfully"); + foreach ($built as $ext) { + $bn = basename($ext['file']); + list($_ext_name, $_ext_suff) = explode('.', $bn); + if ($_ext_suff == '.so' || $_ext_suff == '.dll') { + if (extension_loaded($_ext_name)) { + $this->raiseError("Extension '$_ext_name' already loaded. " . + 'Please unload it in your php.ini file ' . + 'prior to install or upgrade'); + } + $role = 'ext'; + } else { + $role = 'src'; + } + + $dest = $ext['dest']; + $packagingroot = ''; + if (isset($this->_options['packagingroot'])) { + $packagingroot = $this->_options['packagingroot']; + } + + $copyto = $this->_prependPath($dest, $packagingroot); + $extra = $copyto != $dest ? " as '$copyto'" : ''; + $this->log(1, "Installing '$dest'$extra"); + + $copydir = dirname($copyto); + // pretty much nothing happens if we are only registering the install + if (empty($this->_options['register-only'])) { + if (!file_exists($copydir) || !is_dir($copydir)) { + if (!$this->mkDirHier($copydir)) { + return $this->raiseError("failed to mkdir $copydir", + PEAR_INSTALLER_FAILED); + } + + $this->log(3, "+ mkdir $copydir"); + } + + if (!@copy($ext['file'], $copyto)) { + return $this->raiseError("failed to write $copyto ($php_errormsg)", PEAR_INSTALLER_FAILED); + } + + $this->log(3, "+ cp $ext[file] $copyto"); + $this->addFileOperation('rename', array($ext['file'], $copyto)); + if (!OS_WINDOWS) { + $mode = 0666 & ~(int)octdec($this->config->get('umask')); + $this->addFileOperation('chmod', array($mode, $copyto)); + if (!@chmod($copyto, $mode)) { + $this->log(0, "failed to change mode of $copyto ($php_errormsg)"); + } + } + } + + + $data = array( + 'role' => $role, + 'name' => $bn, + 'installed_as' => $dest, + 'php_api' => $ext['php_api'], + 'zend_mod_api' => $ext['zend_mod_api'], + 'zend_ext_api' => $ext['zend_ext_api'], + ); + + if ($filelist->getPackageXmlVersion() == '1.0') { + $filelist->installedFile($bn, $data); + } else { + $filelist->installedFile($bn, array('attribs' => $data)); + } + } + } + + // }}} + function &getUninstallPackages() + { + return $this->_downloadedPackages; + } + // {{{ uninstall() + + /** + * Uninstall a package + * + * This method removes all files installed by the application, and then + * removes any empty directories. + * @param string package name + * @param array Command-line options. Possibilities include: + * + * - installroot: base installation dir, if not the default + * - register-only : update registry but don't remove files + * - nodeps: do not process dependencies of other packages to ensure + * uninstallation does not break things + */ + function uninstall($package, $options = array()) + { + $installRoot = isset($options['installroot']) ? $options['installroot'] : ''; + $this->config->setInstallRoot($installRoot); + + $this->installroot = ''; + $this->_registry = &$this->config->getRegistry(); + if (is_object($package)) { + $channel = $package->getChannel(); + $pkg = $package; + $package = $pkg->getPackage(); + } else { + $pkg = false; + $info = $this->_registry->parsePackageName($package, + $this->config->get('default_channel')); + $channel = $info['channel']; + $package = $info['package']; + } + + $savechannel = $this->config->get('default_channel'); + $this->configSet('default_channel', $channel); + if (!is_object($pkg)) { + $pkg = $this->_registry->getPackage($package, $channel); + } + + if (!$pkg) { + $this->configSet('default_channel', $savechannel); + return $this->raiseError($this->_registry->parsedPackageNameToString( + array( + 'channel' => $channel, + 'package' => $package + ), true) . ' not installed'); + } + + if ($pkg->getInstalledBinary()) { + // this is just an alias for a binary package + return $this->_registry->deletePackage($package, $channel); + } + + $filelist = $pkg->getFilelist(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; + } + + $depchecker = &new PEAR_Dependency2($this->config, $options, + array('channel' => $channel, 'package' => $package), + PEAR_VALIDATE_UNINSTALLING); + $e = $depchecker->validatePackageUninstall($this); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($e)) { + if (!isset($options['ignore-errors'])) { + return $this->raiseError($e); + } + + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: ' . $e->getMessage()); + } + } elseif (is_array($e)) { + if (!isset($options['soft'])) { + $this->log(0, $e[0]); + } + } + + $this->pkginfo = &$pkg; + // pretty much nothing happens if we are only registering the uninstall + if (empty($options['register-only'])) { + // {{{ Delete the files + $this->startFileTransaction(); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) { + PEAR::popErrorHandling(); + $this->rollbackFileTransaction(); + $this->configSet('default_channel', $savechannel); + if (!isset($options['ignore-errors'])) { + return $this->raiseError($err); + } + + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: ' . $err->getMessage()); + } + } else { + PEAR::popErrorHandling(); + } + + if (!$this->commitFileTransaction()) { + $this->rollbackFileTransaction(); + if (!isset($options['ignore-errors'])) { + return $this->raiseError("uninstall failed"); + } + + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: uninstall failed'); + } + } else { + $this->startFileTransaction(); + $dirtree = $pkg->getDirTree(); + if ($dirtree === false) { + $this->configSet('default_channel', $savechannel); + return $this->_registry->deletePackage($package, $channel); + } + + // attempt to delete empty directories + uksort($dirtree, array($this, '_sortDirs')); + foreach($dirtree as $dir => $notused) { + $this->addFileOperation('rmdir', array($dir)); + } + + if (!$this->commitFileTransaction()) { + $this->rollbackFileTransaction(); + if (!isset($options['ignore-errors'])) { + return $this->raiseError("uninstall failed"); + } + + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: uninstall failed'); + } + } + } + // }}} + } + + $this->configSet('default_channel', $savechannel); + // Register that the package is no longer installed + return $this->_registry->deletePackage($package, $channel); + } + + /** + * Sort a list of arrays of array(downloaded packagefilename) by dependency. + * + * It also removes duplicate dependencies + * @param array an array of PEAR_PackageFile_v[1/2] objects + * @return array|PEAR_Error array of array(packagefilename, package.xml contents) + */ + function sortPackagesForUninstall(&$packages) + { + $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config); + if (PEAR::isError($this->_dependencyDB)) { + return $this->_dependencyDB; + } + usort($packages, array(&$this, '_sortUninstall')); + } + + function _sortUninstall($a, $b) + { + if (!$a->getDeps() && !$b->getDeps()) { + return 0; // neither package has dependencies, order is insignificant + } + if ($a->getDeps() && !$b->getDeps()) { + return -1; // $a must be installed after $b because $a has dependencies + } + if (!$a->getDeps() && $b->getDeps()) { + return 1; // $b must be installed after $a because $b has dependencies + } + // both packages have dependencies + if ($this->_dependencyDB->dependsOn($a, $b)) { + return -1; + } + if ($this->_dependencyDB->dependsOn($b, $a)) { + return 1; + } + return 0; + } + + // }}} + // {{{ _sortDirs() + function _sortDirs($a, $b) + { + if (strnatcmp($a, $b) == -1) return 1; + if (strnatcmp($a, $b) == 1) return -1; + return 0; + } + + // }}} + + // {{{ _buildCallback() + + function _buildCallback($what, $data) + { + if (($what == 'cmdoutput' && $this->debug > 1) || + ($what == 'output' && $this->debug > 0)) { + $this->ui->outputData(rtrim($data), 'build'); + } + } + + // }}} +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role.php b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role.php new file mode 100644 index 0000000..aabf330 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role.php @@ -0,0 +1,276 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Role.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * base class for installer roles + */ +require_once 'PEAR/Installer/Role/Common.php'; +require_once 'PEAR/XMLParser.php'; +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role +{ + /** + * Set up any additional configuration variables that file roles require + * + * Never call this directly, it is called by the PEAR_Config constructor + * @param PEAR_Config + * @access private + * @static + */ + function initializeConfig(&$config) + { + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $class => $info) { + if (!$info['config_vars']) { + continue; + } + + $config->_addConfigVars($class, $info['config_vars']); + } + } + + /** + * @param PEAR_PackageFile_v2 + * @param string role name + * @param PEAR_Config + * @return PEAR_Installer_Role_Common + * @static + */ + function &factory($pkg, $role, &$config) + { + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + + if (!in_array($role, PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) { + $a = false; + return $a; + } + + $a = 'PEAR_Installer_Role_' . ucfirst($role); + if (!class_exists($a)) { + require_once str_replace('_', '/', $a) . '.php'; + } + + $b = new $a($config); + return $b; + } + + /** + * Get a list of file roles that are valid for the particular release type. + * + * For instance, src files serve no purpose in regular php releases. + * @param string + * @param bool clear cache + * @return array + * @static + */ + function getValidRoles($release, $clear = false) + { + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + + static $ret = array(); + if ($clear) { + $ret = array(); + } + + if (isset($ret[$release])) { + return $ret[$release]; + } + + $ret[$release] = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if (in_array($release, $okreleases['releasetypes'])) { + $ret[$release][] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); + } + } + + return $ret[$release]; + } + + /** + * Get a list of roles that require their files to be installed + * + * Most roles must be installed, but src and package roles, for instance + * are pseudo-roles. src files are compiled into a new extension. Package + * roles are actually fully bundled releases of a package + * @param bool clear cache + * @return array + * @static + */ + function getInstallableRoles($clear = false) + { + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + + static $ret; + if ($clear) { + unset($ret); + } + + if (isset($ret)) { + return $ret; + } + + $ret = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if ($okreleases['installable']) { + $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); + } + } + + return $ret; + } + + /** + * Return an array of roles that are affected by the baseinstalldir attribute + * + * Most roles ignore this attribute, and instead install directly into: + * PackageName/filepath + * so a tests file tests/file.phpt is installed into PackageName/tests/filepath.php + * @param bool clear cache + * @return array + * @static + */ + function getBaseinstallRoles($clear = false) + { + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + + static $ret; + if ($clear) { + unset($ret); + } + + if (isset($ret)) { + return $ret; + } + + $ret = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if ($okreleases['honorsbaseinstall']) { + $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); + } + } + + return $ret; + } + + /** + * Return an array of file roles that should be analyzed for PHP content at package time, + * like the "php" role. + * @param bool clear cache + * @return array + * @static + */ + function getPhpRoles($clear = false) + { + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + + static $ret; + if ($clear) { + unset($ret); + } + + if (isset($ret)) { + return $ret; + } + + $ret = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if ($okreleases['phpfile']) { + $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); + } + } + + return $ret; + } + + /** + * Scan through the Command directory looking for classes + * and see what commands they implement. + * @param string which directory to look for classes, defaults to + * the Installer/Roles subdirectory of + * the directory from where this file (__FILE__) is + * included. + * + * @return bool TRUE on success, a PEAR error on failure + * @access public + * @static + */ + function registerRoles($dir = null) + { + $GLOBALS['_PEAR_INSTALLER_ROLES'] = array(); + $parser = new PEAR_XMLParser; + if ($dir === null) { + $dir = dirname(__FILE__) . '/Role'; + } + + if (!file_exists($dir) || !is_dir($dir)) { + return PEAR::raiseError("registerRoles: opendir($dir) failed: does not exist/is not directory"); + } + + $dp = @opendir($dir); + if (empty($dp)) { + return PEAR::raiseError("registerRoles: opendir($dir) failed: $php_errmsg"); + } + + while ($entry = readdir($dp)) { + if ($entry{0} == '.' || substr($entry, -4) != '.xml') { + continue; + } + + $class = "PEAR_Installer_Role_".substr($entry, 0, -4); + // List of roles + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'][$class])) { + $file = "$dir/$entry"; + $parser->parse(file_get_contents($file)); + $data = $parser->getData(); + if (!is_array($data['releasetypes'])) { + $data['releasetypes'] = array($data['releasetypes']); + } + + $GLOBALS['_PEAR_INSTALLER_ROLES'][$class] = $data; + } + } + + closedir($dp); + ksort($GLOBALS['_PEAR_INSTALLER_ROLES']); + PEAR_Installer_Role::getBaseinstallRoles(true); + PEAR_Installer_Role::getInstallableRoles(true); + PEAR_Installer_Role::getPhpRoles(true); + PEAR_Installer_Role::getValidRoles('****', true); + return true; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Cfg.php b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Cfg.php new file mode 100644 index 0000000..962327a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Cfg.php @@ -0,0 +1,106 @@ + + * @copyright 2007-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Cfg.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.7.0 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 2007-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.7.0 + */ +class PEAR_Installer_Role_Cfg extends PEAR_Installer_Role_Common +{ + /** + * @var PEAR_Installer + */ + var $installer; + + /** + * the md5 of the original file + * + * @var unknown_type + */ + var $md5 = null; + + /** + * Do any unusual setup here + * @param PEAR_Installer + * @param PEAR_PackageFile_v2 + * @param array file attributes + * @param string file name + */ + function setup(&$installer, $pkg, $atts, $file) + { + $this->installer = &$installer; + $reg = &$this->installer->config->getRegistry(); + $package = $reg->getPackage($pkg->getPackage(), $pkg->getChannel()); + if ($package) { + $filelist = $package->getFilelist(); + if (isset($filelist[$file]) && isset($filelist[$file]['md5sum'])) { + $this->md5 = $filelist[$file]['md5sum']; + } + } + } + + function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null) + { + $test = parent::processInstallation($pkg, $atts, $file, $tmp_path, $layer); + if (@file_exists($test[2]) && @file_exists($test[3])) { + $md5 = md5_file($test[2]); + // configuration has already been installed, check for mods + if ($md5 !== $this->md5 && $md5 !== md5_file($test[3])) { + // configuration has been modified, so save our version as + // configfile-version + $old = $test[2]; + $test[2] .= '.new-' . $pkg->getVersion(); + // backup original and re-install it + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $tmpcfg = $this->config->get('temp_dir'); + $newloc = System::mkdir(array('-p', $tmpcfg)); + if (!$newloc) { + // try temp_dir + $newloc = System::mktemp(array('-d')); + if (!$newloc || PEAR::isError($newloc)) { + PEAR::popErrorHandling(); + return PEAR::raiseError('Could not save existing configuration file '. + $old . ', unable to install. Please set temp_dir ' . + 'configuration variable to a writeable location and try again'); + } + } else { + $newloc = $tmpcfg; + } + + $temp_file = $newloc . DIRECTORY_SEPARATOR . uniqid('savefile'); + if (!@copy($old, $temp_file)) { + PEAR::popErrorHandling(); + return PEAR::raiseError('Could not save existing configuration file '. + $old . ', unable to install. Please set temp_dir ' . + 'configuration variable to a writeable location and try again'); + } + + PEAR::popErrorHandling(); + $this->installer->log(0, "WARNING: configuration file $old is being installed as $test[2], you should manually merge in changes to the existing configuration file"); + $this->installer->addFileOperation('rename', array($temp_file, $old, false)); + $this->installer->addFileOperation('delete', array($temp_file)); + } + } + + return $test; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Cfg.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Cfg.xml new file mode 100644 index 0000000..7a415dc --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Cfg.xml @@ -0,0 +1,15 @@ + + php + extsrc + extbin + zendextsrc + zendextbin + 1 + cfg_dir + + 1 + + + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Common.php b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Common.php new file mode 100644 index 0000000..fedb72a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Common.php @@ -0,0 +1,174 @@ + + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Common.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Base class for all installation roles. + * + * This class allows extensibility of file roles. Packages with complex + * customization can now provide custom file roles along with the possibility of + * adding configuration values to match. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Common +{ + /** + * @var PEAR_Config + * @access protected + */ + var $config; + + /** + * @param PEAR_Config + */ + function PEAR_Installer_Role_Common(&$config) + { + $this->config = $config; + } + + /** + * Retrieve configuration information about a file role from its XML info + * + * @param string $role Role Classname, as in "PEAR_Installer_Role_Data" + * @return array + */ + function getInfo($role) + { + if (empty($GLOBALS['_PEAR_INSTALLER_ROLES'][$role])) { + return PEAR::raiseError('Unknown Role class: "' . $role . '"'); + } + return $GLOBALS['_PEAR_INSTALLER_ROLES'][$role]; + } + + /** + * This is called for each file to set up the directories and files + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param array attributes from the tag + * @param string file name + * @return array an array consisting of: + * + * 1 the original, pre-baseinstalldir installation directory + * 2 the final installation directory + * 3 the full path to the final location of the file + * 4 the location of the pre-installation file + */ + function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null) + { + $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . + ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); + if (PEAR::isError($roleInfo)) { + return $roleInfo; + } + if (!$roleInfo['locationconfig']) { + return false; + } + if ($roleInfo['honorsbaseinstall']) { + $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], $layer, + $pkg->getChannel()); + if (!empty($atts['baseinstalldir'])) { + $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; + } + } elseif ($roleInfo['unusualbaseinstall']) { + $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], + $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage(); + if (!empty($atts['baseinstalldir'])) { + $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; + } + } else { + $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], + $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage(); + } + if (dirname($file) != '.' && empty($atts['install-as'])) { + $dest_dir .= DIRECTORY_SEPARATOR . dirname($file); + } + if (empty($atts['install-as'])) { + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file); + } else { + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as']; + } + $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file; + + // Clean up the DIRECTORY_SEPARATOR mess + $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; + + list($dest_dir, $dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), + array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR), + array($dest_dir, $dest_file, $orig_file)); + return array($save_destdir, $dest_dir, $dest_file, $orig_file); + } + + /** + * Get the name of the configuration variable that specifies the location of this file + * @return string|false + */ + function getLocationConfig() + { + $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . + ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); + if (PEAR::isError($roleInfo)) { + return $roleInfo; + } + return $roleInfo['locationconfig']; + } + + /** + * Do any unusual setup here + * @param PEAR_Installer + * @param PEAR_PackageFile_v2 + * @param array file attributes + * @param string file name + */ + function setup(&$installer, $pkg, $atts, $file) + { + } + + function isExecutable() + { + $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . + ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); + if (PEAR::isError($roleInfo)) { + return $roleInfo; + } + return $roleInfo['executable']; + } + + function isInstallable() + { + $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . + ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); + if (PEAR::isError($roleInfo)) { + return $roleInfo; + } + return $roleInfo['installable']; + } + + function isExtension() + { + $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . + ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); + if (PEAR::isError($roleInfo)) { + return $roleInfo; + } + return $roleInfo['phpextension']; + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Data.php b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Data.php new file mode 100644 index 0000000..7da1584 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Data.php @@ -0,0 +1,28 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Data.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Data extends PEAR_Installer_Role_Common {} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Data.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Data.xml new file mode 100644 index 0000000..eae6372 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Data.xml @@ -0,0 +1,15 @@ + + php + extsrc + extbin + zendextsrc + zendextbin + 1 + data_dir + + + + + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Doc.php b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Doc.php new file mode 100644 index 0000000..b3bd5db --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Doc.php @@ -0,0 +1,28 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Doc.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Doc extends PEAR_Installer_Role_Common {} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Doc.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Doc.xml new file mode 100644 index 0000000..173afba --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Doc.xml @@ -0,0 +1,15 @@ + + php + extsrc + extbin + zendextsrc + zendextbin + 1 + doc_dir + + + + + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Ext.php b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Ext.php new file mode 100644 index 0000000..c1f9658 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Ext.php @@ -0,0 +1,28 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Ext.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Ext extends PEAR_Installer_Role_Common {} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Ext.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Ext.xml new file mode 100644 index 0000000..e2940fe --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Ext.xml @@ -0,0 +1,12 @@ + + extbin + zendextbin + 1 + ext_dir + 1 + + + + 1 + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Php.php b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Php.php new file mode 100644 index 0000000..53bab23 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Php.php @@ -0,0 +1,28 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Php.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Php extends PEAR_Installer_Role_Common {} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Php.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Php.xml new file mode 100644 index 0000000..6b9a0e6 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Php.xml @@ -0,0 +1,15 @@ + + php + extsrc + extbin + zendextsrc + zendextbin + 1 + php_dir + 1 + + 1 + + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Script.php b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Script.php new file mode 100644 index 0000000..c70e14f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Script.php @@ -0,0 +1,28 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Script.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Script extends PEAR_Installer_Role_Common {} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Script.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Script.xml new file mode 100644 index 0000000..e732cf2 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Script.xml @@ -0,0 +1,15 @@ + + php + extsrc + extbin + zendextsrc + zendextbin + 1 + bin_dir + 1 + + + 1 + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Src.php b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Src.php new file mode 100644 index 0000000..10bf381 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Src.php @@ -0,0 +1,34 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Src.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Src extends PEAR_Installer_Role_Common +{ + function setup(&$installer, $pkg, $atts, $file) + { + $installer->source_files++; + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Src.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Src.xml new file mode 100644 index 0000000..1034834 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Src.xml @@ -0,0 +1,12 @@ + + extsrc + zendextsrc + 1 + temp_dir + + + + + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Test.php b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Test.php new file mode 100644 index 0000000..ec2ed63 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Test.php @@ -0,0 +1,28 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Test.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Test extends PEAR_Installer_Role_Common {} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Test.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Test.xml new file mode 100644 index 0000000..51d5b89 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Test.xml @@ -0,0 +1,15 @@ + + php + extsrc + extbin + zendextsrc + zendextbin + 1 + test_dir + + + + + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Www.php b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Www.php new file mode 100644 index 0000000..5db87f4 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Www.php @@ -0,0 +1,28 @@ + + * @copyright 2007-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Www.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.7.0 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 2007-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.7.0 + */ +class PEAR_Installer_Role_Www extends PEAR_Installer_Role_Common {} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Www.xml b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Www.xml new file mode 100644 index 0000000..7598be3 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Installer/Role/Www.xml @@ -0,0 +1,15 @@ + + php + extsrc + extbin + zendextsrc + zendextbin + 1 + www_dir + 1 + + + + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile.php b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile.php new file mode 100644 index 0000000..a352f31 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile.php @@ -0,0 +1,492 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: PackageFile.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * needed for PEAR_VALIDATE_* constants + */ +require_once 'PEAR/Validate.php'; +/** + * Error code if the package.xml tag does not contain a valid version + */ +define('PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION', 1); +/** + * Error code if the package.xml tag version is not supported (version 1.0 and 1.1 are the only supported versions, + * currently + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_PACKAGEVERSION', 2); +/** + * Abstraction for the package.xml package description file + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile +{ + /** + * @var PEAR_Config + */ + var $_config; + var $_debug; + + var $_logger = false; + /** + * @var boolean + */ + var $_rawReturn = false; + + /** + * helper for extracting Archive_Tar errors + * @var array + * @access private + */ + var $_extractErrors = array(); + + /** + * + * @param PEAR_Config $config + * @param ? $debug + * @param string @tmpdir Optional temporary directory for uncompressing + * files + */ + function PEAR_PackageFile(&$config, $debug = false) + { + $this->_config = $config; + $this->_debug = $debug; + } + + /** + * Turn off validation - return a parsed package.xml without checking it + * + * This is used by the package-validate command + */ + function rawReturn() + { + $this->_rawReturn = true; + } + + function setLogger(&$l) + { + $this->_logger = &$l; + } + + /** + * Create a PEAR_PackageFile_Parser_v* of a given version. + * @param int $version + * @return PEAR_PackageFile_Parser_v1|PEAR_PackageFile_Parser_v1 + */ + function &parserFactory($version) + { + if (!in_array($version{0}, array('1', '2'))) { + $a = false; + return $a; + } + + include_once 'PEAR/PackageFile/Parser/v' . $version{0} . '.php'; + $version = $version{0}; + $class = "PEAR_PackageFile_Parser_v$version"; + $a = new $class; + return $a; + } + + /** + * For simpler unit-testing + * @return string + */ + function getClassPrefix() + { + return 'PEAR_PackageFile_v'; + } + + /** + * Create a PEAR_PackageFile_v* of a given version. + * @param int $version + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v1 + */ + function &factory($version) + { + if (!in_array($version{0}, array('1', '2'))) { + $a = false; + return $a; + } + + include_once 'PEAR/PackageFile/v' . $version{0} . '.php'; + $version = $version{0}; + $class = $this->getClassPrefix() . $version; + $a = new $class; + return $a; + } + + /** + * Create a PEAR_PackageFile_v* from its toArray() method + * + * WARNING: no validation is performed, the array is assumed to be valid, + * always parse from xml if you want validation. + * @param array $arr + * @return PEAR_PackageFileManager_v1|PEAR_PackageFileManager_v2 + * @uses factory() to construct the returned object. + */ + function &fromArray($arr) + { + if (isset($arr['xsdversion'])) { + $obj = &$this->factory($arr['xsdversion']); + if ($this->_logger) { + $obj->setLogger($this->_logger); + } + + $obj->setConfig($this->_config); + $obj->fromArray($arr); + return $obj; + } + + if (isset($arr['package']['attribs']['version'])) { + $obj = &$this->factory($arr['package']['attribs']['version']); + } else { + $obj = &$this->factory('1.0'); + } + + if ($this->_logger) { + $obj->setLogger($this->_logger); + } + + $obj->setConfig($this->_config); + $obj->fromArray($arr); + return $obj; + } + + /** + * Create a PEAR_PackageFile_v* from an XML string. + * @access public + * @param string $data contents of package.xml file + * @param int $state package state (one of PEAR_VALIDATE_* constants) + * @param string $file full path to the package.xml file (and the files + * it references) + * @param string $archive optional name of the archive that the XML was + * extracted from, if any + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @uses parserFactory() to construct a parser to load the package. + */ + function &fromXmlString($data, $state, $file, $archive = false) + { + if (preg_match('/]+version=[\'"]([0-9]+\.[0-9]+)[\'"]/', $data, $packageversion)) { + if (!in_array($packageversion[1], array('1.0', '2.0', '2.1'))) { + return PEAR::raiseError('package.xml version "' . $packageversion[1] . + '" is not supported, only 1.0, 2.0, and 2.1 are supported.'); + } + + $object = &$this->parserFactory($packageversion[1]); + if ($this->_logger) { + $object->setLogger($this->_logger); + } + + $object->setConfig($this->_config); + $pf = $object->parse($data, $file, $archive); + if (PEAR::isError($pf)) { + return $pf; + } + + if ($this->_rawReturn) { + return $pf; + } + + if (!$pf->validate($state)) {; + if ($this->_config->get('verbose') > 0 + && $this->_logger && $pf->getValidationWarnings(false) + ) { + foreach ($pf->getValidationWarnings(false) as $warning) { + $this->_logger->log(0, 'ERROR: ' . $warning['message']); + } + } + + $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', + 2, null, null, $pf->getValidationWarnings()); + return $a; + } + + if ($this->_logger && $pf->getValidationWarnings(false)) { + foreach ($pf->getValidationWarnings() as $warning) { + $this->_logger->log(0, 'WARNING: ' . $warning['message']); + } + } + + if (method_exists($pf, 'flattenFilelist')) { + $pf->flattenFilelist(); // for v2 + } + + return $pf; + } elseif (preg_match('/]+version=[\'"]([^"\']+)[\'"]/', $data, $packageversion)) { + $a = PEAR::raiseError('package.xml file "' . $file . + '" has unsupported package.xml version "' . $packageversion[1] . '"'); + return $a; + } else { + if (!class_exists('PEAR_ErrorStack')) { + require_once 'PEAR/ErrorStack.php'; + } + + PEAR_ErrorStack::staticPush('PEAR_PackageFile', + PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION, + 'warning', array('xml' => $data), 'package.xml "' . $file . + '" has no package.xml version'); + $object = &$this->parserFactory('1.0'); + $object->setConfig($this->_config); + $pf = $object->parse($data, $file, $archive); + if (PEAR::isError($pf)) { + return $pf; + } + + if ($this->_rawReturn) { + return $pf; + } + + if (!$pf->validate($state)) { + $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', + 2, null, null, $pf->getValidationWarnings()); + return $a; + } + + if ($this->_logger && $pf->getValidationWarnings(false)) { + foreach ($pf->getValidationWarnings() as $warning) { + $this->_logger->log(0, 'WARNING: ' . $warning['message']); + } + } + + if (method_exists($pf, 'flattenFilelist')) { + $pf->flattenFilelist(); // for v2 + } + + return $pf; + } + } + + /** + * Register a temporary file or directory. When the destructor is + * executed, all registered temporary files and directories are + * removed. + * + * @param string $file name of file or directory + * @return void + */ + function addTempFile($file) + { + $GLOBALS['_PEAR_Common_tempfiles'][] = $file; + } + + /** + * Create a PEAR_PackageFile_v* from a compresed Tar or Tgz file. + * @access public + * @param string contents of package.xml file + * @param int package state (one of PEAR_VALIDATE_* constants) + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @using Archive_Tar to extract the files + * @using fromPackageFile() to load the package after the package.xml + * file is extracted. + */ + function &fromTgzFile($file, $state) + { + if (!class_exists('Archive_Tar')) { + require_once 'Archive/Tar.php'; + } + + $tar = new Archive_Tar($file); + if ($this->_debug <= 1) { + $tar->pushErrorHandling(PEAR_ERROR_RETURN); + } + + $content = $tar->listContent(); + if ($this->_debug <= 1) { + $tar->popErrorHandling(); + } + + if (!is_array($content)) { + if (is_string($file) && strlen($file < 255) && + (!file_exists($file) || !@is_file($file))) { + $ret = PEAR::raiseError("could not open file \"$file\""); + return $ret; + } + + $file = realpath($file); + $ret = PEAR::raiseError("Could not get contents of package \"$file\"". + '. Invalid tgz file.'); + return $ret; + } + + if (!count($content) && !@is_file($file)) { + $ret = PEAR::raiseError("could not open file \"$file\""); + return $ret; + } + + $xml = null; + $origfile = $file; + foreach ($content as $file) { + $name = $file['filename']; + if ($name == 'package2.xml') { // allow a .tgz to distribute both versions + $xml = $name; + break; + } + + if ($name == 'package.xml') { + $xml = $name; + break; + } elseif (preg_match('/package.xml$/', $name, $match)) { + $xml = $name; + break; + } + } + + $tmpdir = System::mktemp('-t ' . $this->_config->get('temp_dir') . ' -d pear'); + if ($tmpdir === false) { + $ret = PEAR::raiseError("there was a problem with getting the configured temp directory"); + return $ret; + } + + PEAR_PackageFile::addTempFile($tmpdir); + + $this->_extractErrors(); + PEAR::staticPushErrorHandling(PEAR_ERROR_CALLBACK, array($this, '_extractErrors')); + + if (!$xml || !$tar->extractList(array($xml), $tmpdir)) { + $extra = implode("\n", $this->_extractErrors()); + if ($extra) { + $extra = ' ' . $extra; + } + + PEAR::staticPopErrorHandling(); + $ret = PEAR::raiseError('could not extract the package.xml file from "' . + $origfile . '"' . $extra); + return $ret; + } + + PEAR::staticPopErrorHandling(); + $ret = &PEAR_PackageFile::fromPackageFile("$tmpdir/$xml", $state, $origfile); + return $ret; + } + + /** + * helper callback for extracting Archive_Tar errors + * + * @param PEAR_Error|null $err + * @return array + * @access private + */ + function _extractErrors($err = null) + { + static $errors = array(); + if ($err === null) { + $e = $errors; + $errors = array(); + return $e; + } + $errors[] = $err->getMessage(); + } + + /** + * Create a PEAR_PackageFile_v* from a package.xml file. + * + * @access public + * @param string $descfile name of package xml file + * @param int $state package state (one of PEAR_VALIDATE_* constants) + * @param string|false $archive name of the archive this package.xml came + * from, if any + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @uses PEAR_PackageFile::fromXmlString to create the oject after the + * XML is loaded from the package.xml file. + */ + function &fromPackageFile($descfile, $state, $archive = false) + { + $fp = false; + if (is_string($descfile) && strlen($descfile) < 255 && + ( + !file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) + || (!$fp = @fopen($descfile, 'r')) + ) + ) { + $a = PEAR::raiseError("Unable to open $descfile"); + return $a; + } + + // read the whole thing so we only get one cdata callback + // for each block of cdata + fclose($fp); + $data = file_get_contents($descfile); + $ret = &PEAR_PackageFile::fromXmlString($data, $state, $descfile, $archive); + return $ret; + } + + /** + * Create a PEAR_PackageFile_v* from a .tgz archive or package.xml file. + * + * This method is able to extract information about a package from a .tgz + * archive or from a XML package definition file. + * + * @access public + * @param string $info file name + * @param int $state package state (one of PEAR_VALIDATE_* constants) + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @uses fromPackageFile() if the file appears to be XML + * @uses fromTgzFile() to load all non-XML files + */ + function &fromAnyFile($info, $state) + { + if (is_dir($info)) { + $dir_name = realpath($info); + if (file_exists($dir_name . '/package.xml')) { + $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package.xml', $state); + } elseif (file_exists($dir_name . '/package2.xml')) { + $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package2.xml', $state); + } else { + $info = PEAR::raiseError("No package definition found in '$info' directory"); + } + + return $info; + } + + $fp = false; + if (is_string($info) && strlen($info) < 255 && + (file_exists($info) || ($fp = @fopen($info, 'r'))) + ) { + + if ($fp) { + fclose($fp); + } + + $tmp = substr($info, -4); + if ($tmp == '.xml') { + $info = &PEAR_PackageFile::fromPackageFile($info, $state); + } elseif ($tmp == '.tar' || $tmp == '.tgz') { + $info = &PEAR_PackageFile::fromTgzFile($info, $state); + } else { + $fp = fopen($info, 'r'); + $test = fread($fp, 5); + fclose($fp); + if ($test == ' + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: v1.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * needed for PEAR_VALIDATE_* constants + */ +require_once 'PEAR/Validate.php'; +require_once 'System.php'; +require_once 'PEAR/PackageFile/v2.php'; +/** + * This class converts a PEAR_PackageFile_v1 object into any output format. + * + * Supported output formats include array, XML string, and a PEAR_PackageFile_v2 + * object, for converting package.xml 1.0 into package.xml 2.0 with no sweat. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile_Generator_v1 +{ + /** + * @var PEAR_PackageFile_v1 + */ + var $_packagefile; + function PEAR_PackageFile_Generator_v1(&$packagefile) + { + $this->_packagefile = &$packagefile; + } + + function getPackagerVersion() + { + return '1.9.3'; + } + + /** + * @param PEAR_Packager + * @param bool if true, a .tgz is written, otherwise a .tar is written + * @param string|null directory in which to save the .tgz + * @return string|PEAR_Error location of package or error object + */ + function toTgz(&$packager, $compress = true, $where = null) + { + require_once 'Archive/Tar.php'; + if ($where === null) { + if (!($where = System::mktemp(array('-d')))) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: mktemp failed'); + } + } elseif (!@System::mkDir(array('-p', $where))) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: "' . $where . '" could' . + ' not be created'); + } + if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') && + !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: unable to save package.xml as' . + ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"'); + } + if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: invalid package file'); + } + $pkginfo = $this->_packagefile->getArray(); + $ext = $compress ? '.tgz' : '.tar'; + $pkgver = $pkginfo['package'] . '-' . $pkginfo['version']; + $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext; + if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) && + !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: cannot create tgz file "' . + getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"'); + } + if ($pkgfile = $this->_packagefile->getPackageFile()) { + $pkgdir = dirname(realpath($pkgfile)); + $pkgfile = basename($pkgfile); + } else { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: package file object must ' . + 'be created from a real file'); + } + // {{{ Create the package file list + $filelist = array(); + $i = 0; + + foreach ($this->_packagefile->getFilelist() as $fname => $atts) { + $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; + if (!file_exists($file)) { + return PEAR::raiseError("File does not exist: $fname"); + } else { + $filelist[$i++] = $file; + if (!isset($atts['md5sum'])) { + $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($file)); + } + $packager->log(2, "Adding file $fname"); + } + } + // }}} + $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true); + if ($packagexml) { + $tar =& new Archive_Tar($dest_package, $compress); + $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors + // ----- Creates with the package.xml file + $ok = $tar->createModify(array($packagexml), '', $where); + if (PEAR::isError($ok)) { + return $ok; + } elseif (!$ok) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed'); + } + // ----- Add the content of the package + if (!$tar->addModify($filelist, $pkgver, $pkgdir)) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed'); + } + return $dest_package; + } + } + + /** + * @param string|null directory to place the package.xml in, or null for a temporary dir + * @param int one of the PEAR_VALIDATE_* constants + * @param string name of the generated file + * @param bool if true, then no analysis will be performed on role="php" files + * @return string|PEAR_Error path to the created file on success + */ + function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml', + $nofilechecking = false) + { + if (!$this->_packagefile->validate($state, $nofilechecking)) { + return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: invalid package.xml', + null, null, null, $this->_packagefile->getValidationWarnings()); + } + if ($where === null) { + if (!($where = System::mktemp(array('-d')))) { + return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: mktemp failed'); + } + } elseif (!@System::mkDir(array('-p', $where))) { + return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: "' . $where . '" could' . + ' not be created'); + } + $newpkgfile = $where . DIRECTORY_SEPARATOR . $name; + $np = @fopen($newpkgfile, 'wb'); + if (!$np) { + return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: unable to save ' . + "$name as $newpkgfile"); + } + fwrite($np, $this->toXml($state, true)); + fclose($np); + return $newpkgfile; + } + + /** + * fix both XML encoding to be UTF8, and replace standard XML entities < > " & ' + * + * @param string $string + * @return string + * @access private + */ + function _fixXmlEncoding($string) + { + if (version_compare(phpversion(), '5.0.0', 'lt')) { + $string = utf8_encode($string); + } + return strtr($string, array( + '&' => '&', + '>' => '>', + '<' => '<', + '"' => '"', + '\'' => ''' )); + } + + /** + * Return an XML document based on the package info (as returned + * by the PEAR_Common::infoFrom* methods). + * + * @return string XML data + */ + function toXml($state = PEAR_VALIDATE_NORMAL, $nofilevalidation = false) + { + $this->_packagefile->setDate(date('Y-m-d')); + if (!$this->_packagefile->validate($state, $nofilevalidation)) { + return false; + } + $pkginfo = $this->_packagefile->getArray(); + static $maint_map = array( + "handle" => "user", + "name" => "name", + "email" => "email", + "role" => "role", + ); + $ret = "\n"; + $ret .= "\n"; + $ret .= "\n" . +" $pkginfo[package]"; + if (isset($pkginfo['extends'])) { + $ret .= "\n$pkginfo[extends]"; + } + $ret .= + "\n ".$this->_fixXmlEncoding($pkginfo['summary'])."\n" . +" ".trim($this->_fixXmlEncoding($pkginfo['description']))."\n \n" . +" \n"; + foreach ($pkginfo['maintainers'] as $maint) { + $ret .= " \n"; + foreach ($maint_map as $idx => $elm) { + $ret .= " <$elm>"; + $ret .= $this->_fixXmlEncoding($maint[$idx]); + $ret .= "\n"; + } + $ret .= " \n"; + } + $ret .= " \n"; + $ret .= $this->_makeReleaseXml($pkginfo, false, $state); + if (isset($pkginfo['changelog']) && count($pkginfo['changelog']) > 0) { + $ret .= " \n"; + foreach ($pkginfo['changelog'] as $oldrelease) { + $ret .= $this->_makeReleaseXml($oldrelease, true); + } + $ret .= " \n"; + } + $ret .= "\n"; + return $ret; + } + + // }}} + // {{{ _makeReleaseXml() + + /** + * Generate part of an XML description with release information. + * + * @param array $pkginfo array with release information + * @param bool $changelog whether the result will be in a changelog element + * + * @return string XML data + * + * @access private + */ + function _makeReleaseXml($pkginfo, $changelog = false, $state = PEAR_VALIDATE_NORMAL) + { + // XXX QUOTE ENTITIES IN PCDATA, OR EMBED IN CDATA BLOCKS!! + $indent = $changelog ? " " : ""; + $ret = "$indent \n"; + if (!empty($pkginfo['version'])) { + $ret .= "$indent $pkginfo[version]\n"; + } + if (!empty($pkginfo['release_date'])) { + $ret .= "$indent $pkginfo[release_date]\n"; + } + if (!empty($pkginfo['release_license'])) { + $ret .= "$indent $pkginfo[release_license]\n"; + } + if (!empty($pkginfo['release_state'])) { + $ret .= "$indent $pkginfo[release_state]\n"; + } + if (!empty($pkginfo['release_notes'])) { + $ret .= "$indent ".trim($this->_fixXmlEncoding($pkginfo['release_notes'])) + ."\n$indent \n"; + } + if (!empty($pkginfo['release_warnings'])) { + $ret .= "$indent ".$this->_fixXmlEncoding($pkginfo['release_warnings'])."\n"; + } + if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) { + $ret .= "$indent \n"; + foreach ($pkginfo['release_deps'] as $dep) { + $ret .= "$indent _fixXmlEncoding($c['name']) . "\""; + if (isset($c['default'])) { + $ret .= " default=\"" . $this->_fixXmlEncoding($c['default']) . "\""; + } + $ret .= " prompt=\"" . $this->_fixXmlEncoding($c['prompt']) . "\""; + $ret .= "/>\n"; + } + $ret .= "$indent \n"; + } + if (isset($pkginfo['provides'])) { + foreach ($pkginfo['provides'] as $key => $what) { + $ret .= "$indent recursiveXmlFilelist($pkginfo['filelist']); + } else { + foreach ($pkginfo['filelist'] as $file => $fa) { + if (!isset($fa['role'])) { + $fa['role'] = ''; + } + $ret .= "$indent _fixXmlEncoding($fa['baseinstalldir']) . '"'; + } + if (isset($fa['md5sum'])) { + $ret .= " md5sum=\"$fa[md5sum]\""; + } + if (isset($fa['platform'])) { + $ret .= " platform=\"$fa[platform]\""; + } + if (!empty($fa['install-as'])) { + $ret .= ' install-as="' . + $this->_fixXmlEncoding($fa['install-as']) . '"'; + } + $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"'; + if (empty($fa['replacements'])) { + $ret .= "/>\n"; + } else { + $ret .= ">\n"; + foreach ($fa['replacements'] as $r) { + $ret .= "$indent $v) { + $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"'; + } + $ret .= "/>\n"; + } + $ret .= "$indent \n"; + } + } + } + $ret .= "$indent \n"; + } + $ret .= "$indent \n"; + return $ret; + } + + /** + * @param array + * @access protected + */ + function recursiveXmlFilelist($list) + { + $this->_dirs = array(); + foreach ($list as $file => $attributes) { + $this->_addDir($this->_dirs, explode('/', dirname($file)), $file, $attributes); + } + return $this->_formatDir($this->_dirs); + } + + /** + * @param array + * @param array + * @param string|null + * @param array|null + * @access private + */ + function _addDir(&$dirs, $dir, $file = null, $attributes = null) + { + if ($dir == array() || $dir == array('.')) { + $dirs['files'][basename($file)] = $attributes; + return; + } + $curdir = array_shift($dir); + if (!isset($dirs['dirs'][$curdir])) { + $dirs['dirs'][$curdir] = array(); + } + $this->_addDir($dirs['dirs'][$curdir], $dir, $file, $attributes); + } + + /** + * @param array + * @param string + * @param string + * @access private + */ + function _formatDir($dirs, $indent = '', $curdir = '') + { + $ret = ''; + if (!count($dirs)) { + return ''; + } + if (isset($dirs['dirs'])) { + uksort($dirs['dirs'], 'strnatcasecmp'); + foreach ($dirs['dirs'] as $dir => $contents) { + $usedir = "$curdir/$dir"; + $ret .= "$indent \n"; + $ret .= $this->_formatDir($contents, "$indent ", $usedir); + $ret .= "$indent \n"; + } + } + if (isset($dirs['files'])) { + uksort($dirs['files'], 'strnatcasecmp'); + foreach ($dirs['files'] as $file => $attribs) { + $ret .= $this->_formatFile($file, $attribs, $indent); + } + } + return $ret; + } + + /** + * @param string + * @param array + * @param string + * @access private + */ + function _formatFile($file, $attributes, $indent) + { + $ret = "$indent _fixXmlEncoding($attributes['baseinstalldir']) . '"'; + } + if (isset($attributes['md5sum'])) { + $ret .= " md5sum=\"$attributes[md5sum]\""; + } + if (isset($attributes['platform'])) { + $ret .= " platform=\"$attributes[platform]\""; + } + if (!empty($attributes['install-as'])) { + $ret .= ' install-as="' . + $this->_fixXmlEncoding($attributes['install-as']) . '"'; + } + $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"'; + if (empty($attributes['replacements'])) { + $ret .= "/>\n"; + } else { + $ret .= ">\n"; + foreach ($attributes['replacements'] as $r) { + $ret .= "$indent $v) { + $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"'; + } + $ret .= "/>\n"; + } + $ret .= "$indent \n"; + } + return $ret; + } + + // {{{ _unIndent() + + /** + * Unindent given string (?) + * + * @param string $str The string that has to be unindented. + * @return string + * @access private + */ + function _unIndent($str) + { + // remove leading newlines + $str = preg_replace('/^[\r\n]+/', '', $str); + // find whitespace at the beginning of the first line + $indent_len = strspn($str, " \t"); + $indent = substr($str, 0, $indent_len); + $data = ''; + // remove the same amount of whitespace from following lines + foreach (explode("\n", $str) as $line) { + if (substr($line, 0, $indent_len) == $indent) { + $data .= substr($line, $indent_len) . "\n"; + } + } + return $data; + } + + /** + * @return array + */ + function dependenciesToV2() + { + $arr = array(); + $this->_convertDependencies2_0($arr); + return $arr['dependencies']; + } + + /** + * Convert a package.xml version 1.0 into version 2.0 + * + * Note that this does a basic conversion, to allow more advanced + * features like bundles and multiple releases + * @param string the classname to instantiate and return. This must be + * PEAR_PackageFile_v2 or a descendant + * @param boolean if true, only valid, deterministic package.xml 1.0 as defined by the + * strictest parameters will be converted + * @return PEAR_PackageFile_v2|PEAR_Error + */ + function &toV2($class = 'PEAR_PackageFile_v2', $strict = false) + { + if ($strict) { + if (!$this->_packagefile->validate()) { + $a = PEAR::raiseError('invalid package.xml version 1.0 cannot be converted' . + ' to version 2.0', null, null, null, + $this->_packagefile->getValidationWarnings(true)); + return $a; + } + } + + $arr = array( + 'attribs' => array( + 'version' => '2.0', + 'xmlns' => 'http://pear.php.net/dtd/package-2.0', + 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0', + 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:schemaLocation' => "http://pear.php.net/dtd/tasks-1.0\n" . +"http://pear.php.net/dtd/tasks-1.0.xsd\n" . +"http://pear.php.net/dtd/package-2.0\n" . +'http://pear.php.net/dtd/package-2.0.xsd', + ), + 'name' => $this->_packagefile->getPackage(), + 'channel' => 'pear.php.net', + ); + $arr['summary'] = $this->_packagefile->getSummary(); + $arr['description'] = $this->_packagefile->getDescription(); + $maintainers = $this->_packagefile->getMaintainers(); + foreach ($maintainers as $maintainer) { + if ($maintainer['role'] != 'lead') { + continue; + } + $new = array( + 'name' => $maintainer['name'], + 'user' => $maintainer['handle'], + 'email' => $maintainer['email'], + 'active' => 'yes', + ); + $arr['lead'][] = $new; + } + + if (!isset($arr['lead'])) { // some people... you know? + $arr['lead'] = array( + 'name' => 'unknown', + 'user' => 'unknown', + 'email' => 'noleadmaintainer@example.com', + 'active' => 'no', + ); + } + + if (count($arr['lead']) == 1) { + $arr['lead'] = $arr['lead'][0]; + } + + foreach ($maintainers as $maintainer) { + if ($maintainer['role'] == 'lead') { + continue; + } + $new = array( + 'name' => $maintainer['name'], + 'user' => $maintainer['handle'], + 'email' => $maintainer['email'], + 'active' => 'yes', + ); + $arr[$maintainer['role']][] = $new; + } + + if (isset($arr['developer']) && count($arr['developer']) == 1) { + $arr['developer'] = $arr['developer'][0]; + } + + if (isset($arr['contributor']) && count($arr['contributor']) == 1) { + $arr['contributor'] = $arr['contributor'][0]; + } + + if (isset($arr['helper']) && count($arr['helper']) == 1) { + $arr['helper'] = $arr['helper'][0]; + } + + $arr['date'] = $this->_packagefile->getDate(); + $arr['version'] = + array( + 'release' => $this->_packagefile->getVersion(), + 'api' => $this->_packagefile->getVersion(), + ); + $arr['stability'] = + array( + 'release' => $this->_packagefile->getState(), + 'api' => $this->_packagefile->getState(), + ); + $licensemap = + array( + 'php' => 'http://www.php.net/license', + 'php license' => 'http://www.php.net/license', + 'lgpl' => 'http://www.gnu.org/copyleft/lesser.html', + 'bsd' => 'http://www.opensource.org/licenses/bsd-license.php', + 'bsd style' => 'http://www.opensource.org/licenses/bsd-license.php', + 'bsd-style' => 'http://www.opensource.org/licenses/bsd-license.php', + 'mit' => 'http://www.opensource.org/licenses/mit-license.php', + 'gpl' => 'http://www.gnu.org/copyleft/gpl.html', + 'apache' => 'http://www.opensource.org/licenses/apache2.0.php' + ); + + if (isset($licensemap[strtolower($this->_packagefile->getLicense())])) { + $arr['license'] = array( + 'attribs' => array('uri' => + $licensemap[strtolower($this->_packagefile->getLicense())]), + '_content' => $this->_packagefile->getLicense() + ); + } else { + // don't use bogus uri + $arr['license'] = $this->_packagefile->getLicense(); + } + + $arr['notes'] = $this->_packagefile->getNotes(); + $temp = array(); + $arr['contents'] = $this->_convertFilelist2_0($temp); + $this->_convertDependencies2_0($arr); + $release = ($this->_packagefile->getConfigureOptions() || $this->_isExtension) ? + 'extsrcrelease' : 'phprelease'; + if ($release == 'extsrcrelease') { + $arr['channel'] = 'pecl.php.net'; + $arr['providesextension'] = $arr['name']; // assumption + } + + $arr[$release] = array(); + if ($this->_packagefile->getConfigureOptions()) { + $arr[$release]['configureoption'] = $this->_packagefile->getConfigureOptions(); + foreach ($arr[$release]['configureoption'] as $i => $opt) { + $arr[$release]['configureoption'][$i] = array('attribs' => $opt); + } + if (count($arr[$release]['configureoption']) == 1) { + $arr[$release]['configureoption'] = $arr[$release]['configureoption'][0]; + } + } + + $this->_convertRelease2_0($arr[$release], $temp); + if ($release == 'extsrcrelease' && count($arr[$release]) > 1) { + // multiple extsrcrelease tags added in PEAR 1.4.1 + $arr['dependencies']['required']['pearinstaller']['min'] = '1.4.1'; + } + + if ($cl = $this->_packagefile->getChangelog()) { + foreach ($cl as $release) { + $rel = array(); + $rel['version'] = + array( + 'release' => $release['version'], + 'api' => $release['version'], + ); + if (!isset($release['release_state'])) { + $release['release_state'] = 'stable'; + } + + $rel['stability'] = + array( + 'release' => $release['release_state'], + 'api' => $release['release_state'], + ); + if (isset($release['release_date'])) { + $rel['date'] = $release['release_date']; + } else { + $rel['date'] = date('Y-m-d'); + } + + if (isset($release['release_license'])) { + if (isset($licensemap[strtolower($release['release_license'])])) { + $uri = $licensemap[strtolower($release['release_license'])]; + } else { + $uri = 'http://www.example.com'; + } + $rel['license'] = array( + 'attribs' => array('uri' => $uri), + '_content' => $release['release_license'] + ); + } else { + $rel['license'] = $arr['license']; + } + + if (!isset($release['release_notes'])) { + $release['release_notes'] = 'no release notes'; + } + + $rel['notes'] = $release['release_notes']; + $arr['changelog']['release'][] = $rel; + } + } + + $ret = new $class; + $ret->setConfig($this->_packagefile->_config); + if (isset($this->_packagefile->_logger) && is_object($this->_packagefile->_logger)) { + $ret->setLogger($this->_packagefile->_logger); + } + + $ret->fromArray($arr); + return $ret; + } + + /** + * @param array + * @param bool + * @access private + */ + function _convertDependencies2_0(&$release, $internal = false) + { + $peardep = array('pearinstaller' => + array('min' => '1.4.0b1')); // this is a lot safer + $required = $optional = array(); + $release['dependencies'] = array('required' => array()); + if ($this->_packagefile->hasDeps()) { + foreach ($this->_packagefile->getDeps() as $dep) { + if (!isset($dep['optional']) || $dep['optional'] == 'no') { + $required[] = $dep; + } else { + $optional[] = $dep; + } + } + foreach (array('required', 'optional') as $arr) { + $deps = array(); + foreach ($$arr as $dep) { + // organize deps by dependency type and name + if (!isset($deps[$dep['type']])) { + $deps[$dep['type']] = array(); + } + if (isset($dep['name'])) { + $deps[$dep['type']][$dep['name']][] = $dep; + } else { + $deps[$dep['type']][] = $dep; + } + } + do { + if (isset($deps['php'])) { + $php = array(); + if (count($deps['php']) > 1) { + $php = $this->_processPhpDeps($deps['php']); + } else { + if (!isset($deps['php'][0])) { + list($key, $blah) = each ($deps['php']); // stupid buggy versions + $deps['php'] = array($blah[0]); + } + $php = $this->_processDep($deps['php'][0]); + if (!$php) { + break; // poor mans throw + } + } + $release['dependencies'][$arr]['php'] = $php; + } + } while (false); + do { + if (isset($deps['pkg'])) { + $pkg = array(); + $pkg = $this->_processMultipleDepsName($deps['pkg']); + if (!$pkg) { + break; // poor mans throw + } + $release['dependencies'][$arr]['package'] = $pkg; + } + } while (false); + do { + if (isset($deps['ext'])) { + $pkg = array(); + $pkg = $this->_processMultipleDepsName($deps['ext']); + $release['dependencies'][$arr]['extension'] = $pkg; + } + } while (false); + // skip sapi - it's not supported so nobody will have used it + // skip os - it's not supported in 1.0 + } + } + if (isset($release['dependencies']['required'])) { + $release['dependencies']['required'] = + array_merge($peardep, $release['dependencies']['required']); + } else { + $release['dependencies']['required'] = $peardep; + } + if (!isset($release['dependencies']['required']['php'])) { + $release['dependencies']['required']['php'] = + array('min' => '4.0.0'); + } + $order = array(); + $bewm = $release['dependencies']['required']; + $order['php'] = $bewm['php']; + $order['pearinstaller'] = $bewm['pearinstaller']; + isset($bewm['package']) ? $order['package'] = $bewm['package'] :0; + isset($bewm['extension']) ? $order['extension'] = $bewm['extension'] :0; + $release['dependencies']['required'] = $order; + } + + /** + * @param array + * @access private + */ + function _convertFilelist2_0(&$package) + { + $ret = array('dir' => + array( + 'attribs' => array('name' => '/'), + 'file' => array() + ) + ); + $package['platform'] = + $package['install-as'] = array(); + $this->_isExtension = false; + foreach ($this->_packagefile->getFilelist() as $name => $file) { + $file['name'] = $name; + if (isset($file['role']) && $file['role'] == 'src') { + $this->_isExtension = true; + } + if (isset($file['replacements'])) { + $repl = $file['replacements']; + unset($file['replacements']); + } else { + unset($repl); + } + if (isset($file['install-as'])) { + $package['install-as'][$name] = $file['install-as']; + unset($file['install-as']); + } + if (isset($file['platform'])) { + $package['platform'][$name] = $file['platform']; + unset($file['platform']); + } + $file = array('attribs' => $file); + if (isset($repl)) { + foreach ($repl as $replace ) { + $file['tasks:replace'][] = array('attribs' => $replace); + } + if (count($repl) == 1) { + $file['tasks:replace'] = $file['tasks:replace'][0]; + } + } + $ret['dir']['file'][] = $file; + } + return $ret; + } + + /** + * Post-process special files with install-as/platform attributes and + * make the release tag. + * + * This complex method follows this work-flow to create the release tags: + * + *
    +     * - if any install-as/platform exist, create a generic release and fill it with
    +     *   o  tags for 
    +     *   o  tags for 
    +     *   o  tags for 
    +     *   o  tags for 
    +     * - create a release for each platform encountered and fill with
    +     *   o  tags for 
    +     *   o  tags for 
    +     *   o  tags for 
    +     *   o  tags for 
    +     *   o  tags for 
    +     *   o  tags for 
    +     *   o  tags for 
    +     * 
    + * + * It does this by accessing the $package parameter, which contains an array with + * indices: + * + * - platform: mapping of file => OS the file should be installed on + * - install-as: mapping of file => installed name + * - osmap: mapping of OS => list of files that should be installed + * on that OS + * - notosmap: mapping of OS => list of files that should not be + * installed on that OS + * + * @param array + * @param array + * @access private + */ + function _convertRelease2_0(&$release, $package) + { + //- if any install-as/platform exist, create a generic release and fill it with + if (count($package['platform']) || count($package['install-as'])) { + $generic = array(); + $genericIgnore = array(); + foreach ($package['install-as'] as $file => $as) { + //o tags for + if (!isset($package['platform'][$file])) { + $generic[] = $file; + continue; + } + //o tags for + if (isset($package['platform'][$file]) && + $package['platform'][$file]{0} == '!') { + $generic[] = $file; + continue; + } + //o tags for + if (isset($package['platform'][$file]) && + $package['platform'][$file]{0} != '!') { + $genericIgnore[] = $file; + continue; + } + } + foreach ($package['platform'] as $file => $platform) { + if (isset($package['install-as'][$file])) { + continue; + } + if ($platform{0} != '!') { + //o tags for + $genericIgnore[] = $file; + } + } + if (count($package['platform'])) { + $oses = $notplatform = $platform = array(); + foreach ($package['platform'] as $file => $os) { + // get a list of oses + if ($os{0} == '!') { + if (isset($oses[substr($os, 1)])) { + continue; + } + $oses[substr($os, 1)] = count($oses); + } else { + if (isset($oses[$os])) { + continue; + } + $oses[$os] = count($oses); + } + } + //- create a release for each platform encountered and fill with + foreach ($oses as $os => $releaseNum) { + $release[$releaseNum]['installconditions']['os']['name'] = $os; + $release[$releaseNum]['filelist'] = array('install' => array(), + 'ignore' => array()); + foreach ($package['install-as'] as $file => $as) { + //o tags for + if (!isset($package['platform'][$file])) { + $release[$releaseNum]['filelist']['install'][] = + array( + 'attribs' => array( + 'name' => $file, + 'as' => $as, + ), + ); + continue; + } + //o tags for + // + if (isset($package['platform'][$file]) && + $package['platform'][$file] == $os) { + $release[$releaseNum]['filelist']['install'][] = + array( + 'attribs' => array( + 'name' => $file, + 'as' => $as, + ), + ); + continue; + } + //o tags for + // + if (isset($package['platform'][$file]) && + $package['platform'][$file] != "!$os" && + $package['platform'][$file]{0} == '!') { + $release[$releaseNum]['filelist']['install'][] = + array( + 'attribs' => array( + 'name' => $file, + 'as' => $as, + ), + ); + continue; + } + //o tags for + // + if (isset($package['platform'][$file]) && + $package['platform'][$file] == "!$os") { + $release[$releaseNum]['filelist']['ignore'][] = + array( + 'attribs' => array( + 'name' => $file, + ), + ); + continue; + } + //o tags for + // + if (isset($package['platform'][$file]) && + $package['platform'][$file]{0} != '!' && + $package['platform'][$file] != $os) { + $release[$releaseNum]['filelist']['ignore'][] = + array( + 'attribs' => array( + 'name' => $file, + ), + ); + continue; + } + } + foreach ($package['platform'] as $file => $platform) { + if (isset($package['install-as'][$file])) { + continue; + } + //o tags for + if ($platform == "!$os") { + $release[$releaseNum]['filelist']['ignore'][] = + array( + 'attribs' => array( + 'name' => $file, + ), + ); + continue; + } + //o tags for + if ($platform{0} != '!' && $platform != $os) { + $release[$releaseNum]['filelist']['ignore'][] = + array( + 'attribs' => array( + 'name' => $file, + ), + ); + } + } + if (!count($release[$releaseNum]['filelist']['install'])) { + unset($release[$releaseNum]['filelist']['install']); + } + if (!count($release[$releaseNum]['filelist']['ignore'])) { + unset($release[$releaseNum]['filelist']['ignore']); + } + } + if (count($generic) || count($genericIgnore)) { + $release[count($oses)] = array(); + if (count($generic)) { + foreach ($generic as $file) { + if (isset($package['install-as'][$file])) { + $installas = $package['install-as'][$file]; + } else { + $installas = $file; + } + $release[count($oses)]['filelist']['install'][] = + array( + 'attribs' => array( + 'name' => $file, + 'as' => $installas, + ) + ); + } + } + if (count($genericIgnore)) { + foreach ($genericIgnore as $file) { + $release[count($oses)]['filelist']['ignore'][] = + array( + 'attribs' => array( + 'name' => $file, + ) + ); + } + } + } + // cleanup + foreach ($release as $i => $rel) { + if (isset($rel['filelist']['install']) && + count($rel['filelist']['install']) == 1) { + $release[$i]['filelist']['install'] = + $release[$i]['filelist']['install'][0]; + } + if (isset($rel['filelist']['ignore']) && + count($rel['filelist']['ignore']) == 1) { + $release[$i]['filelist']['ignore'] = + $release[$i]['filelist']['ignore'][0]; + } + } + if (count($release) == 1) { + $release = $release[0]; + } + } else { + // no platform atts, but some install-as atts + foreach ($package['install-as'] as $file => $value) { + $release['filelist']['install'][] = + array( + 'attribs' => array( + 'name' => $file, + 'as' => $value + ) + ); + } + if (count($release['filelist']['install']) == 1) { + $release['filelist']['install'] = $release['filelist']['install'][0]; + } + } + } + } + + /** + * @param array + * @return array + * @access private + */ + function _processDep($dep) + { + if ($dep['type'] == 'php') { + if ($dep['rel'] == 'has') { + // come on - everyone has php! + return false; + } + } + $php = array(); + if ($dep['type'] != 'php') { + $php['name'] = $dep['name']; + if ($dep['type'] == 'pkg') { + $php['channel'] = 'pear.php.net'; + } + } + switch ($dep['rel']) { + case 'gt' : + $php['min'] = $dep['version']; + $php['exclude'] = $dep['version']; + break; + case 'ge' : + if (!isset($dep['version'])) { + if ($dep['type'] == 'php') { + if (isset($dep['name'])) { + $dep['version'] = $dep['name']; + } + } + } + $php['min'] = $dep['version']; + break; + case 'lt' : + $php['max'] = $dep['version']; + $php['exclude'] = $dep['version']; + break; + case 'le' : + $php['max'] = $dep['version']; + break; + case 'eq' : + $php['min'] = $dep['version']; + $php['max'] = $dep['version']; + break; + case 'ne' : + $php['exclude'] = $dep['version']; + break; + case 'not' : + $php['conflicts'] = 'yes'; + break; + } + return $php; + } + + /** + * @param array + * @return array + */ + function _processPhpDeps($deps) + { + $test = array(); + foreach ($deps as $dep) { + $test[] = $this->_processDep($dep); + } + $min = array(); + $max = array(); + foreach ($test as $dep) { + if (!$dep) { + continue; + } + if (isset($dep['min'])) { + $min[$dep['min']] = count($min); + } + if (isset($dep['max'])) { + $max[$dep['max']] = count($max); + } + } + if (count($min) > 0) { + uksort($min, 'version_compare'); + } + if (count($max) > 0) { + uksort($max, 'version_compare'); + } + if (count($min)) { + // get the highest minimum + $min = array_pop($a = array_flip($min)); + } else { + $min = false; + } + if (count($max)) { + // get the lowest maximum + $max = array_shift($a = array_flip($max)); + } else { + $max = false; + } + if ($min) { + $php['min'] = $min; + } + if ($max) { + $php['max'] = $max; + } + $exclude = array(); + foreach ($test as $dep) { + if (!isset($dep['exclude'])) { + continue; + } + $exclude[] = $dep['exclude']; + } + if (count($exclude)) { + $php['exclude'] = $exclude; + } + return $php; + } + + /** + * process multiple dependencies that have a name, like package deps + * @param array + * @return array + * @access private + */ + function _processMultipleDepsName($deps) + { + $ret = $tests = array(); + foreach ($deps as $name => $dep) { + foreach ($dep as $d) { + $tests[$name][] = $this->_processDep($d); + } + } + + foreach ($tests as $name => $test) { + $max = $min = $php = array(); + $php['name'] = $name; + foreach ($test as $dep) { + if (!$dep) { + continue; + } + if (isset($dep['channel'])) { + $php['channel'] = 'pear.php.net'; + } + if (isset($dep['conflicts']) && $dep['conflicts'] == 'yes') { + $php['conflicts'] = 'yes'; + } + if (isset($dep['min'])) { + $min[$dep['min']] = count($min); + } + if (isset($dep['max'])) { + $max[$dep['max']] = count($max); + } + } + if (count($min) > 0) { + uksort($min, 'version_compare'); + } + if (count($max) > 0) { + uksort($max, 'version_compare'); + } + if (count($min)) { + // get the highest minimum + $min = array_pop($a = array_flip($min)); + } else { + $min = false; + } + if (count($max)) { + // get the lowest maximum + $max = array_shift($a = array_flip($max)); + } else { + $max = false; + } + if ($min) { + $php['min'] = $min; + } + if ($max) { + $php['max'] = $max; + } + $exclude = array(); + foreach ($test as $dep) { + if (!isset($dep['exclude'])) { + continue; + } + $exclude[] = $dep['exclude']; + } + if (count($exclude)) { + $php['exclude'] = $exclude; + } + $ret[] = $php; + } + return $ret; + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/Generator/v2.php b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/Generator/v2.php new file mode 100644 index 0000000..c334b54 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/Generator/v2.php @@ -0,0 +1,893 @@ + + * @author Stephan Schmidt (original XML_Serializer code) + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: v2.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * file/dir manipulation routines + */ +require_once 'System.php'; +require_once 'XML/Util.php'; + +/** + * This class converts a PEAR_PackageFile_v2 object into any output format. + * + * Supported output formats include array, XML string (using S. Schmidt's + * XML_Serializer, slightly customized) + * @category pear + * @package PEAR + * @author Greg Beaver + * @author Stephan Schmidt (original XML_Serializer code) + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile_Generator_v2 +{ + /** + * default options for the serialization + * @access private + * @var array $_defaultOptions + */ + var $_defaultOptions = array( + 'indent' => ' ', // string used for indentation + 'linebreak' => "\n", // string used for newlines + 'typeHints' => false, // automatically add type hin attributes + 'addDecl' => true, // add an XML declaration + 'defaultTagName' => 'XML_Serializer_Tag', // tag used for indexed arrays or invalid names + 'classAsTagName' => false, // use classname for objects in indexed arrays + 'keyAttribute' => '_originalKey', // attribute where original key is stored + 'typeAttribute' => '_type', // attribute for type (only if typeHints => true) + 'classAttribute' => '_class', // attribute for class of objects (only if typeHints => true) + 'scalarAsAttributes' => false, // scalar values (strings, ints,..) will be serialized as attribute + 'prependAttributes' => '', // prepend string for attributes + 'indentAttributes' => false, // indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column + 'mode' => 'simplexml', // use 'simplexml' to use parent name as tagname if transforming an indexed array + 'addDoctype' => false, // add a doctype declaration + 'doctype' => null, // supply a string or an array with id and uri ({@see XML_Util::getDoctypeDeclaration()} + 'rootName' => 'package', // name of the root tag + 'rootAttributes' => array( + 'version' => '2.0', + 'xmlns' => 'http://pear.php.net/dtd/package-2.0', + 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0', + 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0 +http://pear.php.net/dtd/tasks-1.0.xsd +http://pear.php.net/dtd/package-2.0 +http://pear.php.net/dtd/package-2.0.xsd', + ), // attributes of the root tag + 'attributesArray' => 'attribs', // all values in this key will be treated as attributes + 'contentName' => '_content', // this value will be used directly as content, instead of creating a new tag, may only be used in conjuction with attributesArray + 'beautifyFilelist' => false, + 'encoding' => 'UTF-8', + ); + + /** + * options for the serialization + * @access private + * @var array $options + */ + var $options = array(); + + /** + * current tag depth + * @var integer $_tagDepth + */ + var $_tagDepth = 0; + + /** + * serilialized representation of the data + * @var string $_serializedData + */ + var $_serializedData = null; + /** + * @var PEAR_PackageFile_v2 + */ + var $_packagefile; + /** + * @param PEAR_PackageFile_v2 + */ + function PEAR_PackageFile_Generator_v2(&$packagefile) + { + $this->_packagefile = &$packagefile; + if (isset($this->_packagefile->encoding)) { + $this->_defaultOptions['encoding'] = $this->_packagefile->encoding; + } + } + + /** + * @return string + */ + function getPackagerVersion() + { + return '1.9.3'; + } + + /** + * @param PEAR_Packager + * @param bool generate a .tgz or a .tar + * @param string|null temporary directory to package in + */ + function toTgz(&$packager, $compress = true, $where = null) + { + $a = null; + return $this->toTgz2($packager, $a, $compress, $where); + } + + /** + * Package up both a package.xml and package2.xml for the same release + * @param PEAR_Packager + * @param PEAR_PackageFile_v1 + * @param bool generate a .tgz or a .tar + * @param string|null temporary directory to package in + */ + function toTgz2(&$packager, &$pf1, $compress = true, $where = null) + { + require_once 'Archive/Tar.php'; + if (!$this->_packagefile->isEquivalent($pf1)) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . + basename($pf1->getPackageFile()) . + '" is not equivalent to "' . basename($this->_packagefile->getPackageFile()) + . '"'); + } + + if ($where === null) { + if (!($where = System::mktemp(array('-d')))) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: mktemp failed'); + } + } elseif (!@System::mkDir(array('-p', $where))) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . $where . '" could' . + ' not be created'); + } + + $file = $where . DIRECTORY_SEPARATOR . 'package.xml'; + if (file_exists($file) && !is_file($file)) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: unable to save package.xml as' . + ' "' . $file .'"'); + } + + if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: invalid package.xml'); + } + + $ext = $compress ? '.tgz' : '.tar'; + $pkgver = $this->_packagefile->getPackage() . '-' . $this->_packagefile->getVersion(); + $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext; + if (file_exists($dest_package) && !is_file($dest_package)) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: cannot create tgz file "' . + $dest_package . '"'); + } + + $pkgfile = $this->_packagefile->getPackageFile(); + if (!$pkgfile) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: package file object must ' . + 'be created from a real file'); + } + + $pkgdir = dirname(realpath($pkgfile)); + $pkgfile = basename($pkgfile); + + // {{{ Create the package file list + $filelist = array(); + $i = 0; + $this->_packagefile->flattenFilelist(); + $contents = $this->_packagefile->getContents(); + if (isset($contents['bundledpackage'])) { // bundles of packages + $contents = $contents['bundledpackage']; + if (!isset($contents[0])) { + $contents = array($contents); + } + + $packageDir = $where; + foreach ($contents as $i => $package) { + $fname = $package; + $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; + if (!file_exists($file)) { + return $packager->raiseError("File does not exist: $fname"); + } + + $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname; + System::mkdir(array('-p', dirname($tfile))); + copy($file, $tfile); + $filelist[$i++] = $tfile; + $packager->log(2, "Adding package $fname"); + } + } else { // normal packages + $contents = $contents['dir']['file']; + if (!isset($contents[0])) { + $contents = array($contents); + } + + $packageDir = $where; + foreach ($contents as $i => $file) { + $fname = $file['attribs']['name']; + $atts = $file['attribs']; + $orig = $file; + $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; + if (!file_exists($file)) { + return $packager->raiseError("File does not exist: $fname"); + } + + $origperms = fileperms($file); + $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname; + unset($orig['attribs']); + if (count($orig)) { // file with tasks + // run any package-time tasks + $contents = file_get_contents($file); + foreach ($orig as $tag => $raw) { + $tag = str_replace( + array($this->_packagefile->getTasksNs() . ':', '-'), + array('', '_'), $tag); + $task = "PEAR_Task_$tag"; + $task = &new $task($this->_packagefile->_config, + $this->_packagefile->_logger, + PEAR_TASK_PACKAGE); + $task->init($raw, $atts, null); + $res = $task->startSession($this->_packagefile, $contents, $tfile); + if (!$res) { + continue; // skip this task + } + + if (PEAR::isError($res)) { + return $res; + } + + $contents = $res; // save changes + System::mkdir(array('-p', dirname($tfile))); + $wp = fopen($tfile, "wb"); + fwrite($wp, $contents); + fclose($wp); + } + } + + if (!file_exists($tfile)) { + System::mkdir(array('-p', dirname($tfile))); + copy($file, $tfile); + } + + chmod($tfile, $origperms); + $filelist[$i++] = $tfile; + $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($tfile), $i - 1); + $packager->log(2, "Adding file $fname"); + } + } + // }}} + + $name = $pf1 !== null ? 'package2.xml' : 'package.xml'; + $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, $name); + if ($packagexml) { + $tar =& new Archive_Tar($dest_package, $compress); + $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors + // ----- Creates with the package.xml file + $ok = $tar->createModify(array($packagexml), '', $where); + if (PEAR::isError($ok)) { + return $packager->raiseError($ok); + } elseif (!$ok) { + return $packager->raiseError('PEAR_Packagefile_v2::toTgz(): adding ' . $name . + ' failed'); + } + + // ----- Add the content of the package + if (!$tar->addModify($filelist, $pkgver, $where)) { + return $packager->raiseError( + 'PEAR_Packagefile_v2::toTgz(): tarball creation failed'); + } + + // add the package.xml version 1.0 + if ($pf1 !== null) { + $pfgen = &$pf1->getDefaultGenerator(); + $packagexml1 = $pfgen->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true); + if (!$tar->addModify(array($packagexml1), '', $where)) { + return $packager->raiseError( + 'PEAR_Packagefile_v2::toTgz(): adding package.xml failed'); + } + } + + return $dest_package; + } + } + + function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml') + { + if (!$this->_packagefile->validate($state)) { + return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: invalid package.xml', + null, null, null, $this->_packagefile->getValidationWarnings()); + } + + if ($where === null) { + if (!($where = System::mktemp(array('-d')))) { + return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: mktemp failed'); + } + } elseif (!@System::mkDir(array('-p', $where))) { + return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: "' . $where . '" could' . + ' not be created'); + } + + $newpkgfile = $where . DIRECTORY_SEPARATOR . $name; + $np = @fopen($newpkgfile, 'wb'); + if (!$np) { + return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: unable to save ' . + "$name as $newpkgfile"); + } + fwrite($np, $this->toXml($state)); + fclose($np); + return $newpkgfile; + } + + function &toV2() + { + return $this->_packagefile; + } + + /** + * Return an XML document based on the package info (as returned + * by the PEAR_Common::infoFrom* methods). + * + * @return string XML data + */ + function toXml($state = PEAR_VALIDATE_NORMAL, $options = array()) + { + $this->_packagefile->setDate(date('Y-m-d')); + $this->_packagefile->setTime(date('H:i:s')); + if (!$this->_packagefile->validate($state)) { + return false; + } + + if (is_array($options)) { + $this->options = array_merge($this->_defaultOptions, $options); + } else { + $this->options = $this->_defaultOptions; + } + + $arr = $this->_packagefile->getArray(); + if (isset($arr['filelist'])) { + unset($arr['filelist']); + } + + if (isset($arr['_lastversion'])) { + unset($arr['_lastversion']); + } + + // Fix the notes a little bit + if (isset($arr['notes'])) { + // This trims out the indenting, needs fixing + $arr['notes'] = "\n" . trim($arr['notes']) . "\n"; + } + + if (isset($arr['changelog']) && !empty($arr['changelog'])) { + // Fix for inconsistency how the array is filled depending on the changelog release amount + if (!isset($arr['changelog']['release'][0])) { + $release = $arr['changelog']['release']; + unset($arr['changelog']['release']); + + $arr['changelog']['release'] = array(); + $arr['changelog']['release'][0] = $release; + } + + foreach (array_keys($arr['changelog']['release']) as $key) { + $c =& $arr['changelog']['release'][$key]; + if (isset($c['notes'])) { + // This trims out the indenting, needs fixing + $c['notes'] = "\n" . trim($c['notes']) . "\n"; + } + } + } + + if ($state ^ PEAR_VALIDATE_PACKAGING && !isset($arr['bundle'])) { + $use = $this->_recursiveXmlFilelist($arr['contents']['dir']['file']); + unset($arr['contents']['dir']['file']); + if (isset($use['dir'])) { + $arr['contents']['dir']['dir'] = $use['dir']; + } + if (isset($use['file'])) { + $arr['contents']['dir']['file'] = $use['file']; + } + $this->options['beautifyFilelist'] = true; + } + + $arr['attribs']['packagerversion'] = '1.9.3'; + if ($this->serialize($arr, $options)) { + return $this->_serializedData . "\n"; + } + + return false; + } + + + function _recursiveXmlFilelist($list) + { + $dirs = array(); + if (isset($list['attribs'])) { + $file = $list['attribs']['name']; + unset($list['attribs']['name']); + $attributes = $list['attribs']; + $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes); + } else { + foreach ($list as $a) { + $file = $a['attribs']['name']; + $attributes = $a['attribs']; + unset($a['attribs']); + $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes, $a); + } + } + $this->_formatDir($dirs); + $this->_deFormat($dirs); + return $dirs; + } + + function _addDir(&$dirs, $dir, $file = null, $attributes = null, $tasks = null) + { + if (!$tasks) { + $tasks = array(); + } + if ($dir == array() || $dir == array('.')) { + $dirs['file'][basename($file)] = $tasks; + $attributes['name'] = basename($file); + $dirs['file'][basename($file)]['attribs'] = $attributes; + return; + } + $curdir = array_shift($dir); + if (!isset($dirs['dir'][$curdir])) { + $dirs['dir'][$curdir] = array(); + } + $this->_addDir($dirs['dir'][$curdir], $dir, $file, $attributes, $tasks); + } + + function _formatDir(&$dirs) + { + if (!count($dirs)) { + return array(); + } + $newdirs = array(); + if (isset($dirs['dir'])) { + $newdirs['dir'] = $dirs['dir']; + } + if (isset($dirs['file'])) { + $newdirs['file'] = $dirs['file']; + } + $dirs = $newdirs; + if (isset($dirs['dir'])) { + uksort($dirs['dir'], 'strnatcasecmp'); + foreach ($dirs['dir'] as $dir => $contents) { + $this->_formatDir($dirs['dir'][$dir]); + } + } + if (isset($dirs['file'])) { + uksort($dirs['file'], 'strnatcasecmp'); + }; + } + + function _deFormat(&$dirs) + { + if (!count($dirs)) { + return array(); + } + $newdirs = array(); + if (isset($dirs['dir'])) { + foreach ($dirs['dir'] as $dir => $contents) { + $newdir = array(); + $newdir['attribs']['name'] = $dir; + $this->_deFormat($contents); + foreach ($contents as $tag => $val) { + $newdir[$tag] = $val; + } + $newdirs['dir'][] = $newdir; + } + if (count($newdirs['dir']) == 1) { + $newdirs['dir'] = $newdirs['dir'][0]; + } + } + if (isset($dirs['file'])) { + foreach ($dirs['file'] as $name => $file) { + $newdirs['file'][] = $file; + } + if (count($newdirs['file']) == 1) { + $newdirs['file'] = $newdirs['file'][0]; + } + } + $dirs = $newdirs; + } + + /** + * reset all options to default options + * + * @access public + * @see setOption(), XML_Unserializer() + */ + function resetOptions() + { + $this->options = $this->_defaultOptions; + } + + /** + * set an option + * + * You can use this method if you do not want to set all options in the constructor + * + * @access public + * @see resetOption(), XML_Serializer() + */ + function setOption($name, $value) + { + $this->options[$name] = $value; + } + + /** + * sets several options at once + * + * You can use this method if you do not want to set all options in the constructor + * + * @access public + * @see resetOption(), XML_Unserializer(), setOption() + */ + function setOptions($options) + { + $this->options = array_merge($this->options, $options); + } + + /** + * serialize data + * + * @access public + * @param mixed $data data to serialize + * @return boolean true on success, pear error on failure + */ + function serialize($data, $options = null) + { + // if options have been specified, use them instead + // of the previously defined ones + if (is_array($options)) { + $optionsBak = $this->options; + if (isset($options['overrideOptions']) && $options['overrideOptions'] == true) { + $this->options = array_merge($this->_defaultOptions, $options); + } else { + $this->options = array_merge($this->options, $options); + } + } else { + $optionsBak = null; + } + + // start depth is zero + $this->_tagDepth = 0; + $this->_serializedData = ''; + // serialize an array + if (is_array($data)) { + $tagName = isset($this->options['rootName']) ? $this->options['rootName'] : 'array'; + $this->_serializedData .= $this->_serializeArray($data, $tagName, $this->options['rootAttributes']); + } + + // add doctype declaration + if ($this->options['addDoctype'] === true) { + $this->_serializedData = XML_Util::getDoctypeDeclaration($tagName, $this->options['doctype']) + . $this->options['linebreak'] + . $this->_serializedData; + } + + // build xml declaration + if ($this->options['addDecl']) { + $atts = array(); + $encoding = isset($this->options['encoding']) ? $this->options['encoding'] : null; + $this->_serializedData = XML_Util::getXMLDeclaration('1.0', $encoding) + . $this->options['linebreak'] + . $this->_serializedData; + } + + + if ($optionsBak !== null) { + $this->options = $optionsBak; + } + + return true; + } + + /** + * get the result of the serialization + * + * @access public + * @return string serialized XML + */ + function getSerializedData() + { + if ($this->_serializedData === null) { + return $this->raiseError('No serialized data available. Use XML_Serializer::serialize() first.', XML_SERIALIZER_ERROR_NO_SERIALIZATION); + } + return $this->_serializedData; + } + + /** + * serialize any value + * + * This method checks for the type of the value and calls the appropriate method + * + * @access private + * @param mixed $value + * @param string $tagName + * @param array $attributes + * @return string + */ + function _serializeValue($value, $tagName = null, $attributes = array()) + { + if (is_array($value)) { + $xml = $this->_serializeArray($value, $tagName, $attributes); + } elseif (is_object($value)) { + $xml = $this->_serializeObject($value, $tagName); + } else { + $tag = array( + 'qname' => $tagName, + 'attributes' => $attributes, + 'content' => $value + ); + $xml = $this->_createXMLTag($tag); + } + return $xml; + } + + /** + * serialize an array + * + * @access private + * @param array $array array to serialize + * @param string $tagName name of the root tag + * @param array $attributes attributes for the root tag + * @return string $string serialized data + * @uses XML_Util::isValidName() to check, whether key has to be substituted + */ + function _serializeArray(&$array, $tagName = null, $attributes = array()) + { + $_content = null; + + /** + * check for special attributes + */ + if ($this->options['attributesArray'] !== null) { + if (isset($array[$this->options['attributesArray']])) { + $attributes = $array[$this->options['attributesArray']]; + unset($array[$this->options['attributesArray']]); + } + /** + * check for special content + */ + if ($this->options['contentName'] !== null) { + if (isset($array[$this->options['contentName']])) { + $_content = $array[$this->options['contentName']]; + unset($array[$this->options['contentName']]); + } + } + } + + /* + * if mode is set to simpleXML, check whether + * the array is associative or indexed + */ + if (is_array($array) && $this->options['mode'] == 'simplexml') { + $indexed = true; + if (!count($array)) { + $indexed = false; + } + foreach ($array as $key => $val) { + if (!is_int($key)) { + $indexed = false; + break; + } + } + + if ($indexed && $this->options['mode'] == 'simplexml') { + $string = ''; + foreach ($array as $key => $val) { + if ($this->options['beautifyFilelist'] && $tagName == 'dir') { + if (!isset($this->_curdir)) { + $this->_curdir = ''; + } + $savedir = $this->_curdir; + if (isset($val['attribs'])) { + if ($val['attribs']['name'] == '/') { + $this->_curdir = '/'; + } else { + if ($this->_curdir == '/') { + $this->_curdir = ''; + } + $this->_curdir .= '/' . $val['attribs']['name']; + } + } + } + $string .= $this->_serializeValue( $val, $tagName, $attributes); + if ($this->options['beautifyFilelist'] && $tagName == 'dir') { + $string .= ' '; + if (empty($savedir)) { + unset($this->_curdir); + } else { + $this->_curdir = $savedir; + } + } + + $string .= $this->options['linebreak']; + // do indentation + if ($this->options['indent'] !== null && $this->_tagDepth > 0) { + $string .= str_repeat($this->options['indent'], $this->_tagDepth); + } + } + return rtrim($string); + } + } + + if ($this->options['scalarAsAttributes'] === true) { + foreach ($array as $key => $value) { + if (is_scalar($value) && (XML_Util::isValidName($key) === true)) { + unset($array[$key]); + $attributes[$this->options['prependAttributes'].$key] = $value; + } + } + } + + // check for empty array => create empty tag + if (empty($array)) { + $tag = array( + 'qname' => $tagName, + 'content' => $_content, + 'attributes' => $attributes + ); + + } else { + $this->_tagDepth++; + $tmp = $this->options['linebreak']; + foreach ($array as $key => $value) { + // do indentation + if ($this->options['indent'] !== null && $this->_tagDepth > 0) { + $tmp .= str_repeat($this->options['indent'], $this->_tagDepth); + } + + // copy key + $origKey = $key; + // key cannot be used as tagname => use default tag + $valid = XML_Util::isValidName($key); + if (PEAR::isError($valid)) { + if ($this->options['classAsTagName'] && is_object($value)) { + $key = get_class($value); + } else { + $key = $this->options['defaultTagName']; + } + } + $atts = array(); + if ($this->options['typeHints'] === true) { + $atts[$this->options['typeAttribute']] = gettype($value); + if ($key !== $origKey) { + $atts[$this->options['keyAttribute']] = (string)$origKey; + } + + } + if ($this->options['beautifyFilelist'] && $key == 'dir') { + if (!isset($this->_curdir)) { + $this->_curdir = ''; + } + $savedir = $this->_curdir; + if (isset($value['attribs'])) { + if ($value['attribs']['name'] == '/') { + $this->_curdir = '/'; + } else { + $this->_curdir .= '/' . $value['attribs']['name']; + } + } + } + + if (is_string($value) && $value && ($value{strlen($value) - 1} == "\n")) { + $value .= str_repeat($this->options['indent'], $this->_tagDepth); + } + $tmp .= $this->_createXMLTag(array( + 'qname' => $key, + 'attributes' => $atts, + 'content' => $value ) + ); + if ($this->options['beautifyFilelist'] && $key == 'dir') { + if (isset($value['attribs'])) { + $tmp .= ' '; + if (empty($savedir)) { + unset($this->_curdir); + } else { + $this->_curdir = $savedir; + } + } + } + $tmp .= $this->options['linebreak']; + } + + $this->_tagDepth--; + if ($this->options['indent']!==null && $this->_tagDepth>0) { + $tmp .= str_repeat($this->options['indent'], $this->_tagDepth); + } + + if (trim($tmp) === '') { + $tmp = null; + } + + $tag = array( + 'qname' => $tagName, + 'content' => $tmp, + 'attributes' => $attributes + ); + } + if ($this->options['typeHints'] === true) { + if (!isset($tag['attributes'][$this->options['typeAttribute']])) { + $tag['attributes'][$this->options['typeAttribute']] = 'array'; + } + } + + $string = $this->_createXMLTag($tag, false); + return $string; + } + + /** + * create a tag from an array + * this method awaits an array in the following format + * array( + * 'qname' => $tagName, + * 'attributes' => array(), + * 'content' => $content, // optional + * 'namespace' => $namespace // optional + * 'namespaceUri' => $namespaceUri // optional + * ) + * + * @access private + * @param array $tag tag definition + * @param boolean $replaceEntities whether to replace XML entities in content or not + * @return string $string XML tag + */ + function _createXMLTag($tag, $replaceEntities = true) + { + if ($this->options['indentAttributes'] !== false) { + $multiline = true; + $indent = str_repeat($this->options['indent'], $this->_tagDepth); + + if ($this->options['indentAttributes'] == '_auto') { + $indent .= str_repeat(' ', (strlen($tag['qname'])+2)); + + } else { + $indent .= $this->options['indentAttributes']; + } + } else { + $indent = $multiline = false; + } + + if (is_array($tag['content'])) { + if (empty($tag['content'])) { + $tag['content'] = ''; + } + } elseif(is_scalar($tag['content']) && (string)$tag['content'] == '') { + $tag['content'] = ''; + } + + if (is_scalar($tag['content']) || is_null($tag['content'])) { + if ($this->options['encoding'] == 'UTF-8' && + version_compare(phpversion(), '5.0.0', 'lt') + ) { + $tag['content'] = utf8_encode($tag['content']); + } + + if ($replaceEntities === true) { + $replaceEntities = XML_UTIL_ENTITIES_XML; + } + + $tag = XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $this->options['linebreak']); + } elseif (is_array($tag['content'])) { + $tag = $this->_serializeArray($tag['content'], $tag['qname'], $tag['attributes']); + } elseif (is_object($tag['content'])) { + $tag = $this->_serializeObject($tag['content'], $tag['qname'], $tag['attributes']); + } elseif (is_resource($tag['content'])) { + settype($tag['content'], 'string'); + $tag = XML_Util::createTagFromArray($tag, $replaceEntities); + } + return $tag; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/Parser/v1.php b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/Parser/v1.php new file mode 100644 index 0000000..db1a952 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/Parser/v1.php @@ -0,0 +1,459 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: v1.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * package.xml abstraction class + */ +require_once 'PEAR/PackageFile/v1.php'; +/** + * Parser for package.xml version 1.0 + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: @PEAR-VER@ + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile_Parser_v1 +{ + var $_registry; + var $_config; + var $_logger; + /** + * BC hack to allow PEAR_Common::infoFromString() to sort of + * work with the version 2.0 format - there's no filelist though + * @param PEAR_PackageFile_v2 + */ + function fromV2($packagefile) + { + $info = $packagefile->getArray(true); + $ret = new PEAR_PackageFile_v1; + $ret->fromArray($info['old']); + } + + function setConfig(&$c) + { + $this->_config = &$c; + $this->_registry = &$c->getRegistry(); + } + + function setLogger(&$l) + { + $this->_logger = &$l; + } + + /** + * @param string contents of package.xml file, version 1.0 + * @return bool success of parsing + */ + function &parse($data, $file, $archive = false) + { + if (!extension_loaded('xml')) { + return PEAR::raiseError('Cannot create xml parser for parsing package.xml, no xml extension'); + } + $xp = xml_parser_create(); + if (!$xp) { + $a = &PEAR::raiseError('Cannot create xml parser for parsing package.xml'); + return $a; + } + xml_set_object($xp, $this); + xml_set_element_handler($xp, '_element_start_1_0', '_element_end_1_0'); + xml_set_character_data_handler($xp, '_pkginfo_cdata_1_0'); + xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false); + + $this->element_stack = array(); + $this->_packageInfo = array('provides' => array()); + $this->current_element = false; + unset($this->dir_install); + $this->_packageInfo['filelist'] = array(); + $this->filelist =& $this->_packageInfo['filelist']; + $this->dir_names = array(); + $this->in_changelog = false; + $this->d_i = 0; + $this->cdata = ''; + $this->_isValid = true; + + if (!xml_parse($xp, $data, 1)) { + $code = xml_get_error_code($xp); + $line = xml_get_current_line_number($xp); + xml_parser_free($xp); + $a = &PEAR::raiseError(sprintf("XML error: %s at line %d", + $str = xml_error_string($code), $line), 2); + return $a; + } + + xml_parser_free($xp); + + $pf = new PEAR_PackageFile_v1; + $pf->setConfig($this->_config); + if (isset($this->_logger)) { + $pf->setLogger($this->_logger); + } + $pf->setPackagefile($file, $archive); + $pf->fromArray($this->_packageInfo); + return $pf; + } + // {{{ _unIndent() + + /** + * Unindent given string + * + * @param string $str The string that has to be unindented. + * @return string + * @access private + */ + function _unIndent($str) + { + // remove leading newlines + $str = preg_replace('/^[\r\n]+/', '', $str); + // find whitespace at the beginning of the first line + $indent_len = strspn($str, " \t"); + $indent = substr($str, 0, $indent_len); + $data = ''; + // remove the same amount of whitespace from following lines + foreach (explode("\n", $str) as $line) { + if (substr($line, 0, $indent_len) == $indent) { + $data .= substr($line, $indent_len) . "\n"; + } elseif (trim(substr($line, 0, $indent_len))) { + $data .= ltrim($line); + } + } + return $data; + } + + // Support for package DTD v1.0: + // {{{ _element_start_1_0() + + /** + * XML parser callback for ending elements. Used for version 1.0 + * packages. + * + * @param resource $xp XML parser resource + * @param string $name name of ending element + * + * @return void + * + * @access private + */ + function _element_start_1_0($xp, $name, $attribs) + { + array_push($this->element_stack, $name); + $this->current_element = $name; + $spos = sizeof($this->element_stack) - 2; + $this->prev_element = ($spos >= 0) ? $this->element_stack[$spos] : ''; + $this->current_attributes = $attribs; + $this->cdata = ''; + switch ($name) { + case 'dir': + if ($this->in_changelog) { + break; + } + if (array_key_exists('name', $attribs) && $attribs['name'] != '/') { + $attribs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), + $attribs['name']); + if (strrpos($attribs['name'], '/') === strlen($attribs['name']) - 1) { + $attribs['name'] = substr($attribs['name'], 0, + strlen($attribs['name']) - 1); + } + if (strpos($attribs['name'], '/') === 0) { + $attribs['name'] = substr($attribs['name'], 1); + } + $this->dir_names[] = $attribs['name']; + } + if (isset($attribs['baseinstalldir'])) { + $this->dir_install = $attribs['baseinstalldir']; + } + if (isset($attribs['role'])) { + $this->dir_role = $attribs['role']; + } + break; + case 'file': + if ($this->in_changelog) { + break; + } + if (isset($attribs['name'])) { + $path = ''; + if (count($this->dir_names)) { + foreach ($this->dir_names as $dir) { + $path .= $dir . '/'; + } + } + $path .= preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), + $attribs['name']); + unset($attribs['name']); + $this->current_path = $path; + $this->filelist[$path] = $attribs; + // Set the baseinstalldir only if the file don't have this attrib + if (!isset($this->filelist[$path]['baseinstalldir']) && + isset($this->dir_install)) + { + $this->filelist[$path]['baseinstalldir'] = $this->dir_install; + } + // Set the Role + if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) { + $this->filelist[$path]['role'] = $this->dir_role; + } + } + break; + case 'replace': + if (!$this->in_changelog) { + $this->filelist[$this->current_path]['replacements'][] = $attribs; + } + break; + case 'maintainers': + $this->_packageInfo['maintainers'] = array(); + $this->m_i = 0; // maintainers array index + break; + case 'maintainer': + // compatibility check + if (!isset($this->_packageInfo['maintainers'])) { + $this->_packageInfo['maintainers'] = array(); + $this->m_i = 0; + } + $this->_packageInfo['maintainers'][$this->m_i] = array(); + $this->current_maintainer =& $this->_packageInfo['maintainers'][$this->m_i]; + break; + case 'changelog': + $this->_packageInfo['changelog'] = array(); + $this->c_i = 0; // changelog array index + $this->in_changelog = true; + break; + case 'release': + if ($this->in_changelog) { + $this->_packageInfo['changelog'][$this->c_i] = array(); + $this->current_release = &$this->_packageInfo['changelog'][$this->c_i]; + } else { + $this->current_release = &$this->_packageInfo; + } + break; + case 'deps': + if (!$this->in_changelog) { + $this->_packageInfo['release_deps'] = array(); + } + break; + case 'dep': + // dependencies array index + if (!$this->in_changelog) { + $this->d_i++; + isset($attribs['type']) ? ($attribs['type'] = strtolower($attribs['type'])) : false; + $this->_packageInfo['release_deps'][$this->d_i] = $attribs; + } + break; + case 'configureoptions': + if (!$this->in_changelog) { + $this->_packageInfo['configure_options'] = array(); + } + break; + case 'configureoption': + if (!$this->in_changelog) { + $this->_packageInfo['configure_options'][] = $attribs; + } + break; + case 'provides': + if (empty($attribs['type']) || empty($attribs['name'])) { + break; + } + $attribs['explicit'] = true; + $this->_packageInfo['provides']["$attribs[type];$attribs[name]"] = $attribs; + break; + case 'package' : + if (isset($attribs['version'])) { + $this->_packageInfo['xsdversion'] = trim($attribs['version']); + } else { + $this->_packageInfo['xsdversion'] = '1.0'; + } + if (isset($attribs['packagerversion'])) { + $this->_packageInfo['packagerversion'] = $attribs['packagerversion']; + } + break; + } + } + + // }}} + // {{{ _element_end_1_0() + + /** + * XML parser callback for ending elements. Used for version 1.0 + * packages. + * + * @param resource $xp XML parser resource + * @param string $name name of ending element + * + * @return void + * + * @access private + */ + function _element_end_1_0($xp, $name) + { + $data = trim($this->cdata); + switch ($name) { + case 'name': + switch ($this->prev_element) { + case 'package': + $this->_packageInfo['package'] = $data; + break; + case 'maintainer': + $this->current_maintainer['name'] = $data; + break; + } + break; + case 'extends' : + $this->_packageInfo['extends'] = $data; + break; + case 'summary': + $this->_packageInfo['summary'] = $data; + break; + case 'description': + $data = $this->_unIndent($this->cdata); + $this->_packageInfo['description'] = $data; + break; + case 'user': + $this->current_maintainer['handle'] = $data; + break; + case 'email': + $this->current_maintainer['email'] = $data; + break; + case 'role': + $this->current_maintainer['role'] = $data; + break; + case 'version': + if ($this->in_changelog) { + $this->current_release['version'] = $data; + } else { + $this->_packageInfo['version'] = $data; + } + break; + case 'date': + if ($this->in_changelog) { + $this->current_release['release_date'] = $data; + } else { + $this->_packageInfo['release_date'] = $data; + } + break; + case 'notes': + // try to "de-indent" release notes in case someone + // has been over-indenting their xml ;-) + // Trim only on the right side + $data = rtrim($this->_unIndent($this->cdata)); + if ($this->in_changelog) { + $this->current_release['release_notes'] = $data; + } else { + $this->_packageInfo['release_notes'] = $data; + } + break; + case 'warnings': + if ($this->in_changelog) { + $this->current_release['release_warnings'] = $data; + } else { + $this->_packageInfo['release_warnings'] = $data; + } + break; + case 'state': + if ($this->in_changelog) { + $this->current_release['release_state'] = $data; + } else { + $this->_packageInfo['release_state'] = $data; + } + break; + case 'license': + if ($this->in_changelog) { + $this->current_release['release_license'] = $data; + } else { + $this->_packageInfo['release_license'] = $data; + } + break; + case 'dep': + if ($data && !$this->in_changelog) { + $this->_packageInfo['release_deps'][$this->d_i]['name'] = $data; + } + break; + case 'dir': + if ($this->in_changelog) { + break; + } + array_pop($this->dir_names); + break; + case 'file': + if ($this->in_changelog) { + break; + } + if ($data) { + $path = ''; + if (count($this->dir_names)) { + foreach ($this->dir_names as $dir) { + $path .= $dir . '/'; + } + } + $path .= $data; + $this->filelist[$path] = $this->current_attributes; + // Set the baseinstalldir only if the file don't have this attrib + if (!isset($this->filelist[$path]['baseinstalldir']) && + isset($this->dir_install)) + { + $this->filelist[$path]['baseinstalldir'] = $this->dir_install; + } + // Set the Role + if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) { + $this->filelist[$path]['role'] = $this->dir_role; + } + } + break; + case 'maintainer': + if (empty($this->_packageInfo['maintainers'][$this->m_i]['role'])) { + $this->_packageInfo['maintainers'][$this->m_i]['role'] = 'lead'; + } + $this->m_i++; + break; + case 'release': + if ($this->in_changelog) { + $this->c_i++; + } + break; + case 'changelog': + $this->in_changelog = false; + break; + } + array_pop($this->element_stack); + $spos = sizeof($this->element_stack) - 1; + $this->current_element = ($spos > 0) ? $this->element_stack[$spos] : ''; + $this->cdata = ''; + } + + // }}} + // {{{ _pkginfo_cdata_1_0() + + /** + * XML parser callback for character data. Used for version 1.0 + * packages. + * + * @param resource $xp XML parser resource + * @param string $name character data + * + * @return void + * + * @access private + */ + function _pkginfo_cdata_1_0($xp, $data) + { + if (isset($this->cdata)) { + $this->cdata .= $data; + } + } + + // }}} +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/Parser/v2.php b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/Parser/v2.php new file mode 100644 index 0000000..e2f5c8d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/Parser/v2.php @@ -0,0 +1,113 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: v2.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * base xml parser class + */ +require_once 'PEAR/XMLParser.php'; +require_once 'PEAR/PackageFile/v2.php'; +/** + * Parser for package.xml version 2.0 + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: @PEAR-VER@ + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile_Parser_v2 extends PEAR_XMLParser +{ + var $_config; + var $_logger; + var $_registry; + + function setConfig(&$c) + { + $this->_config = &$c; + $this->_registry = &$c->getRegistry(); + } + + function setLogger(&$l) + { + $this->_logger = &$l; + } + /** + * Unindent given string + * + * @param string $str The string that has to be unindented. + * @return string + * @access private + */ + function _unIndent($str) + { + // remove leading newlines + $str = preg_replace('/^[\r\n]+/', '', $str); + // find whitespace at the beginning of the first line + $indent_len = strspn($str, " \t"); + $indent = substr($str, 0, $indent_len); + $data = ''; + // remove the same amount of whitespace from following lines + foreach (explode("\n", $str) as $line) { + if (substr($line, 0, $indent_len) == $indent) { + $data .= substr($line, $indent_len) . "\n"; + } else { + $data .= $line . "\n"; + } + } + return $data; + } + + /** + * post-process data + * + * @param string $data + * @param string $element element name + */ + function postProcess($data, $element) + { + if ($element == 'notes') { + return trim($this->_unIndent($data)); + } + return trim($data); + } + + /** + * @param string + * @param string file name of the package.xml + * @param string|false name of the archive this package.xml came from, if any + * @param string class name to instantiate and return. This must be PEAR_PackageFile_v2 or + * a subclass + * @return PEAR_PackageFile_v2 + */ + function &parse($data, $file, $archive = false, $class = 'PEAR_PackageFile_v2') + { + if (PEAR::isError($err = parent::parse($data, $file))) { + return $err; + } + + $ret = new $class; + $ret->encoding = $this->encoding; + $ret->setConfig($this->_config); + if (isset($this->_logger)) { + $ret->setLogger($this->_logger); + } + + $ret->fromArray($this->_unserializedData); + $ret->setPackagefile($file, $archive); + return $ret; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v1.php b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v1.php new file mode 100644 index 0000000..8dc83c9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v1.php @@ -0,0 +1,1612 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: v1.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * For error handling + */ +require_once 'PEAR/ErrorStack.php'; + +/** + * Error code if parsing is attempted with no xml extension + */ +define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3); + +/** + * Error code if creating the xml parser resource fails + */ +define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4); + +/** + * Error code used for all sax xml parsing errors + */ +define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5); + +/** + * Error code used when there is no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6); + +/** + * Error code when a package name is not valid + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7); + +/** + * Error code used when no summary is parsed + */ +define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8); + +/** + * Error code for summaries that are more than 1 line + */ +define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9); + +/** + * Error code used when no description is present + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10); + +/** + * Error code used when no license is present + */ +define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11); + +/** + * Error code used when a version number is not present + */ +define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12); + +/** + * Error code used when a version number is invalid + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_VERSION', 13); + +/** + * Error code when release state is missing + */ +define('PEAR_PACKAGEFILE_ERROR_NO_STATE', 14); + +/** + * Error code when release state is invalid + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_STATE', 15); + +/** + * Error code when release state is missing + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DATE', 16); + +/** + * Error code when release state is invalid + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_DATE', 17); + +/** + * Error code when no release notes are found + */ +define('PEAR_PACKAGEFILE_ERROR_NO_NOTES', 18); + +/** + * Error code when no maintainers are found + */ +define('PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS', 19); + +/** + * Error code when a maintainer has no handle + */ +define('PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE', 20); + +/** + * Error code when a maintainer has no handle + */ +define('PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE', 21); + +/** + * Error code when a maintainer has no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME', 22); + +/** + * Error code when a maintainer has no email + */ +define('PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL', 23); + +/** + * Error code when a maintainer has no handle + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_MAINTROLE', 24); + +/** + * Error code when a dependency is not a PHP dependency, but has no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DEPNAME', 25); + +/** + * Error code when a dependency has no type (pkg, php, etc.) + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE', 26); + +/** + * Error code when a dependency has no relation (lt, ge, has, etc.) + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DEPREL', 27); + +/** + * Error code when a dependency is not a 'has' relation, but has no version + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION', 28); + +/** + * Error code when a dependency has an invalid relation + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPREL', 29); + +/** + * Error code when a dependency has an invalid type + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPTYPE', 30); + +/** + * Error code when a dependency has an invalid optional option + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL', 31); + +/** + * Error code when a dependency is a pkg dependency, and has an invalid package name + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPNAME', 32); + +/** + * Error code when a dependency has a channel="foo" attribute, and foo is not a registered channel + */ +define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_DEPCHANNEL', 33); + +/** + * Error code when rel="has" and version attribute is present. + */ +define('PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED', 34); + +/** + * Error code when type="php" and dependency name is present + */ +define('PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED', 35); + +/** + * Error code when a configure option has no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_CONFNAME', 36); + +/** + * Error code when a configure option has no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT', 37); + +/** + * Error code when a file in the filelist has an invalid role + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE', 38); + +/** + * Error code when a file in the filelist has no role + */ +define('PEAR_PACKAGEFILE_ERROR_NO_FILEROLE', 39); + +/** + * Error code when analyzing a php source file that has parse errors + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE', 40); + +/** + * Error code when analyzing a php source file reveals a source element + * without a package name prefix + */ +define('PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX', 41); + +/** + * Error code when an unknown channel is specified + */ +define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_CHANNEL', 42); + +/** + * Error code when no files are found in the filelist + */ +define('PEAR_PACKAGEFILE_ERROR_NO_FILES', 43); + +/** + * Error code when a file is not valid php according to _analyzeSourceCode() + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_FILE', 44); + +/** + * Error code when the channel validator returns an error or warning + */ +define('PEAR_PACKAGEFILE_ERROR_CHANNELVAL', 45); + +/** + * Error code when a php5 package is packaged in php4 (analysis doesn't work) + */ +define('PEAR_PACKAGEFILE_ERROR_PHP5', 46); + +/** + * Error code when a file is listed in package.xml but does not exist + */ +define('PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND', 47); + +/** + * Error code when a + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile_v1 +{ + /** + * @access private + * @var PEAR_ErrorStack + * @access private + */ + var $_stack; + + /** + * A registry object, used to access the package name validation regex for non-standard channels + * @var PEAR_Registry + * @access private + */ + var $_registry; + + /** + * An object that contains a log method that matches PEAR_Common::log's signature + * @var object + * @access private + */ + var $_logger; + + /** + * Parsed package information + * @var array + * @access private + */ + var $_packageInfo; + + /** + * path to package.xml + * @var string + * @access private + */ + var $_packageFile; + + /** + * path to package .tgz or false if this is a local/extracted package.xml + * @var string + * @access private + */ + var $_archiveFile; + + /** + * @var int + * @access private + */ + var $_isValid = 0; + + /** + * Determines whether this packagefile was initialized only with partial package info + * + * If this package file was constructed via parsing REST, it will only contain + * + * - package name + * - channel name + * - dependencies + * @var boolean + * @access private + */ + var $_incomplete = true; + + /** + * @param bool determines whether to return a PEAR_Error object, or use the PEAR_ErrorStack + * @param string Name of Error Stack class to use. + */ + function PEAR_PackageFile_v1() + { + $this->_stack = &new PEAR_ErrorStack('PEAR_PackageFile_v1'); + $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); + $this->_isValid = 0; + } + + function installBinary($installer) + { + return false; + } + + function isExtension($name) + { + return false; + } + + function setConfig(&$config) + { + $this->_config = &$config; + $this->_registry = &$config->getRegistry(); + } + + function setRequestedGroup() + { + // placeholder + } + + /** + * For saving in the registry. + * + * Set the last version that was installed + * @param string + */ + function setLastInstalledVersion($version) + { + $this->_packageInfo['_lastversion'] = $version; + } + + /** + * @return string|false + */ + function getLastInstalledVersion() + { + if (isset($this->_packageInfo['_lastversion'])) { + return $this->_packageInfo['_lastversion']; + } + return false; + } + + function getInstalledBinary() + { + return false; + } + + function listPostinstallScripts() + { + return false; + } + + function initPostinstallScripts() + { + return false; + } + + function setLogger(&$logger) + { + if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) { + return PEAR::raiseError('Logger must be compatible with PEAR_Common::log'); + } + $this->_logger = &$logger; + } + + function setPackagefile($file, $archive = false) + { + $this->_packageFile = $file; + $this->_archiveFile = $archive ? $archive : $file; + } + + function getPackageFile() + { + return isset($this->_packageFile) ? $this->_packageFile : false; + } + + function getPackageType() + { + return 'php'; + } + + function getArchiveFile() + { + return $this->_archiveFile; + } + + function packageInfo($field) + { + if (!is_string($field) || empty($field) || + !isset($this->_packageInfo[$field])) { + return false; + } + return $this->_packageInfo[$field]; + } + + function setDirtree($path) + { + if (!isset($this->_packageInfo['dirtree'])) { + $this->_packageInfo['dirtree'] = array(); + } + $this->_packageInfo['dirtree'][$path] = true; + } + + function getDirtree() + { + if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) { + return $this->_packageInfo['dirtree']; + } + return false; + } + + function resetDirtree() + { + unset($this->_packageInfo['dirtree']); + } + + function fromArray($pinfo) + { + $this->_incomplete = false; + $this->_packageInfo = $pinfo; + } + + function isIncomplete() + { + return $this->_incomplete; + } + + function getChannel() + { + return 'pear.php.net'; + } + + function getUri() + { + return false; + } + + function getTime() + { + return false; + } + + function getExtends() + { + if (isset($this->_packageInfo['extends'])) { + return $this->_packageInfo['extends']; + } + return false; + } + + /** + * @return array + */ + function toArray() + { + if (!$this->validate(PEAR_VALIDATE_NORMAL)) { + return false; + } + return $this->getArray(); + } + + function getArray() + { + return $this->_packageInfo; + } + + function getName() + { + return $this->getPackage(); + } + + function getPackage() + { + if (isset($this->_packageInfo['package'])) { + return $this->_packageInfo['package']; + } + return false; + } + + /** + * WARNING - don't use this unless you know what you are doing + */ + function setRawPackage($package) + { + $this->_packageInfo['package'] = $package; + } + + function setPackage($package) + { + $this->_packageInfo['package'] = $package; + $this->_isValid = false; + } + + function getVersion() + { + if (isset($this->_packageInfo['version'])) { + return $this->_packageInfo['version']; + } + return false; + } + + function setVersion($version) + { + $this->_packageInfo['version'] = $version; + $this->_isValid = false; + } + + function clearMaintainers() + { + unset($this->_packageInfo['maintainers']); + } + + function getMaintainers() + { + if (isset($this->_packageInfo['maintainers'])) { + return $this->_packageInfo['maintainers']; + } + return false; + } + + /** + * Adds a new maintainer - no checking of duplicates is performed, use + * updatemaintainer for that purpose. + */ + function addMaintainer($role, $handle, $name, $email) + { + $this->_packageInfo['maintainers'][] = + array('handle' => $handle, 'role' => $role, 'email' => $email, 'name' => $name); + $this->_isValid = false; + } + + function updateMaintainer($role, $handle, $name, $email) + { + $found = false; + if (!isset($this->_packageInfo['maintainers']) || + !is_array($this->_packageInfo['maintainers'])) { + return $this->addMaintainer($role, $handle, $name, $email); + } + foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { + if ($maintainer['handle'] == $handle) { + $found = $i; + break; + } + } + if ($found !== false) { + unset($this->_packageInfo['maintainers'][$found]); + $this->_packageInfo['maintainers'] = + array_values($this->_packageInfo['maintainers']); + } + $this->addMaintainer($role, $handle, $name, $email); + } + + function deleteMaintainer($handle) + { + $found = false; + foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { + if ($maintainer['handle'] == $handle) { + $found = $i; + break; + } + } + if ($found !== false) { + unset($this->_packageInfo['maintainers'][$found]); + $this->_packageInfo['maintainers'] = + array_values($this->_packageInfo['maintainers']); + return true; + } + return false; + } + + function getState() + { + if (isset($this->_packageInfo['release_state'])) { + return $this->_packageInfo['release_state']; + } + return false; + } + + function setRawState($state) + { + $this->_packageInfo['release_state'] = $state; + } + + function setState($state) + { + $this->_packageInfo['release_state'] = $state; + $this->_isValid = false; + } + + function getDate() + { + if (isset($this->_packageInfo['release_date'])) { + return $this->_packageInfo['release_date']; + } + return false; + } + + function setDate($date) + { + $this->_packageInfo['release_date'] = $date; + $this->_isValid = false; + } + + function getLicense() + { + if (isset($this->_packageInfo['release_license'])) { + return $this->_packageInfo['release_license']; + } + return false; + } + + function setLicense($date) + { + $this->_packageInfo['release_license'] = $date; + $this->_isValid = false; + } + + function getSummary() + { + if (isset($this->_packageInfo['summary'])) { + return $this->_packageInfo['summary']; + } + return false; + } + + function setSummary($summary) + { + $this->_packageInfo['summary'] = $summary; + $this->_isValid = false; + } + + function getDescription() + { + if (isset($this->_packageInfo['description'])) { + return $this->_packageInfo['description']; + } + return false; + } + + function setDescription($desc) + { + $this->_packageInfo['description'] = $desc; + $this->_isValid = false; + } + + function getNotes() + { + if (isset($this->_packageInfo['release_notes'])) { + return $this->_packageInfo['release_notes']; + } + return false; + } + + function setNotes($notes) + { + $this->_packageInfo['release_notes'] = $notes; + $this->_isValid = false; + } + + function getDeps() + { + if (isset($this->_packageInfo['release_deps'])) { + return $this->_packageInfo['release_deps']; + } + return false; + } + + /** + * Reset dependencies prior to adding new ones + */ + function clearDeps() + { + unset($this->_packageInfo['release_deps']); + } + + function addPhpDep($version, $rel) + { + $this->_isValid = false; + $this->_packageInfo['release_deps'][] = + array('type' => 'php', + 'rel' => $rel, + 'version' => $version); + } + + function addPackageDep($name, $version, $rel, $optional = 'no') + { + $this->_isValid = false; + $dep = + array('type' => 'pkg', + 'name' => $name, + 'rel' => $rel, + 'optional' => $optional); + if ($rel != 'has' && $rel != 'not') { + $dep['version'] = $version; + } + $this->_packageInfo['release_deps'][] = $dep; + } + + function addExtensionDep($name, $version, $rel, $optional = 'no') + { + $this->_isValid = false; + $this->_packageInfo['release_deps'][] = + array('type' => 'ext', + 'name' => $name, + 'rel' => $rel, + 'version' => $version, + 'optional' => $optional); + } + + /** + * WARNING - do not use this function directly unless you know what you're doing + */ + function setDeps($deps) + { + $this->_packageInfo['release_deps'] = $deps; + } + + function hasDeps() + { + return isset($this->_packageInfo['release_deps']) && + count($this->_packageInfo['release_deps']); + } + + function getDependencyGroup($group) + { + return false; + } + + function isCompatible($pf) + { + return false; + } + + function isSubpackageOf($p) + { + return $p->isSubpackage($this); + } + + function isSubpackage($p) + { + return false; + } + + function dependsOn($package, $channel) + { + if (strtolower($channel) != 'pear.php.net') { + return false; + } + if (!($deps = $this->getDeps())) { + return false; + } + foreach ($deps as $dep) { + if ($dep['type'] != 'pkg') { + continue; + } + if (strtolower($dep['name']) == strtolower($package)) { + return true; + } + } + return false; + } + + function getConfigureOptions() + { + if (isset($this->_packageInfo['configure_options'])) { + return $this->_packageInfo['configure_options']; + } + return false; + } + + function hasConfigureOptions() + { + return isset($this->_packageInfo['configure_options']) && + count($this->_packageInfo['configure_options']); + } + + function addConfigureOption($name, $prompt, $default = false) + { + $o = array('name' => $name, 'prompt' => $prompt); + if ($default !== false) { + $o['default'] = $default; + } + if (!isset($this->_packageInfo['configure_options'])) { + $this->_packageInfo['configure_options'] = array(); + } + $this->_packageInfo['configure_options'][] = $o; + } + + function clearConfigureOptions() + { + unset($this->_packageInfo['configure_options']); + } + + function getProvides() + { + if (isset($this->_packageInfo['provides'])) { + return $this->_packageInfo['provides']; + } + return false; + } + + function getProvidesExtension() + { + return false; + } + + function addFile($dir, $file, $attrs) + { + $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir); + if ($dir == '/' || $dir == '') { + $dir = ''; + } else { + $dir .= '/'; + } + $file = $dir . $file; + $file = preg_replace('![\\/]+!', '/', $file); + $this->_packageInfo['filelist'][$file] = $attrs; + } + + function getInstallationFilelist() + { + return $this->getFilelist(); + } + + function getFilelist() + { + if (isset($this->_packageInfo['filelist'])) { + return $this->_packageInfo['filelist']; + } + return false; + } + + function setFileAttribute($file, $attr, $value) + { + $this->_packageInfo['filelist'][$file][$attr] = $value; + } + + function resetFilelist() + { + $this->_packageInfo['filelist'] = array(); + } + + function setInstalledAs($file, $path) + { + if ($path) { + return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; + } + unset($this->_packageInfo['filelist'][$file]['installed_as']); + } + + function installedFile($file, $atts) + { + if (isset($this->_packageInfo['filelist'][$file])) { + $this->_packageInfo['filelist'][$file] = + array_merge($this->_packageInfo['filelist'][$file], $atts); + } else { + $this->_packageInfo['filelist'][$file] = $atts; + } + } + + function getChangelog() + { + if (isset($this->_packageInfo['changelog'])) { + return $this->_packageInfo['changelog']; + } + return false; + } + + function getPackagexmlVersion() + { + return '1.0'; + } + + /** + * Wrapper to {@link PEAR_ErrorStack::getErrors()} + * @param boolean determines whether to purge the error stack after retrieving + * @return array + */ + function getValidationWarnings($purge = true) + { + return $this->_stack->getErrors($purge); + } + + // }}} + /** + * Validation error. Also marks the object contents as invalid + * @param error code + * @param array error information + * @access private + */ + function _validateError($code, $params = array()) + { + $this->_stack->push($code, 'error', $params, false, false, debug_backtrace()); + $this->_isValid = false; + } + + /** + * Validation warning. Does not mark the object contents invalid. + * @param error code + * @param array error information + * @access private + */ + function _validateWarning($code, $params = array()) + { + $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace()); + } + + /** + * @param integer error code + * @access protected + */ + function _getErrorMessage() + { + return array( + PEAR_PACKAGEFILE_ERROR_NO_NAME => + 'Missing Package Name', + PEAR_PACKAGEFILE_ERROR_NO_SUMMARY => + 'No summary found', + PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY => + 'Summary should be on one line', + PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION => + 'Missing description', + PEAR_PACKAGEFILE_ERROR_NO_LICENSE => + 'Missing license', + PEAR_PACKAGEFILE_ERROR_NO_VERSION => + 'No release version found', + PEAR_PACKAGEFILE_ERROR_NO_STATE => + 'No release state found', + PEAR_PACKAGEFILE_ERROR_NO_DATE => + 'No release date found', + PEAR_PACKAGEFILE_ERROR_NO_NOTES => + 'No release notes found', + PEAR_PACKAGEFILE_ERROR_NO_LEAD => + 'Package must have at least one lead maintainer', + PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS => + 'No maintainers found, at least one must be defined', + PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE => + 'Maintainer %index% has no handle (user ID at channel server)', + PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE => + 'Maintainer %index% has no role', + PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME => + 'Maintainer %index% has no name', + PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL => + 'Maintainer %index% has no email', + PEAR_PACKAGEFILE_ERROR_NO_DEPNAME => + 'Dependency %index% is not a php dependency, and has no name', + PEAR_PACKAGEFILE_ERROR_NO_DEPREL => + 'Dependency %index% has no relation (rel)', + PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE => + 'Dependency %index% has no type', + PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED => + 'PHP Dependency %index% has a name attribute of "%name%" which will be' . + ' ignored!', + PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION => + 'Dependency %index% is not a rel="has" or rel="not" dependency, ' . + 'and has no version', + PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION => + 'Dependency %index% is a type="php" dependency, ' . + 'and has no version', + PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED => + 'Dependency %index% is a rel="%rel%" dependency, versioning is ignored', + PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL => + 'Dependency %index% has invalid optional value "%opt%", should be yes or no', + PEAR_PACKAGEFILE_PHP_NO_NOT => + 'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' . + ' to exclude specific versions', + PEAR_PACKAGEFILE_ERROR_NO_CONFNAME => + 'Configure Option %index% has no name', + PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT => + 'Configure Option %index% has no prompt', + PEAR_PACKAGEFILE_ERROR_NO_FILES => + 'No files in section of package.xml', + PEAR_PACKAGEFILE_ERROR_NO_FILEROLE => + 'File "%file%" has no role, expecting one of "%roles%"', + PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE => + 'File "%file%" has invalid role "%role%", expecting one of "%roles%"', + PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME => + 'File "%file%" cannot start with ".", cannot package or install', + PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE => + 'Parser error: invalid PHP found in file "%file%"', + PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX => + 'in %file%: %type% "%name%" not prefixed with package name "%package%"', + PEAR_PACKAGEFILE_ERROR_INVALID_FILE => + 'Parser error: invalid PHP file "%file%"', + PEAR_PACKAGEFILE_ERROR_CHANNELVAL => + 'Channel validator error: field "%field%" - %reason%', + PEAR_PACKAGEFILE_ERROR_PHP5 => + 'Error, PHP5 token encountered in %file%, analysis should be in PHP5', + PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND => + 'File "%file%" in package.xml does not exist', + PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS => + 'Package.xml contains non-ISO-8859-1 characters, and may not validate', + ); + } + + /** + * Validate XML package definition file. + * + * @access public + * @return boolean + */ + function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false) + { + if (($this->_isValid & $state) == $state) { + return true; + } + $this->_isValid = true; + $info = $this->_packageInfo; + if (empty($info['package'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME); + $this->_packageName = $pn = 'unknown'; + } else { + $this->_packageName = $pn = $info['package']; + } + + if (empty($info['summary'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY); + } elseif (strpos(trim($info['summary']), "\n") !== false) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY, + array('summary' => $info['summary'])); + } + if (empty($info['description'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION); + } + if (empty($info['release_license'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE); + } + if (empty($info['version'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION); + } + if (empty($info['release_state'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE); + } + if (empty($info['release_date'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE); + } + if (empty($info['release_notes'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES); + } + if (empty($info['maintainers'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS); + } else { + $haslead = false; + $i = 1; + foreach ($info['maintainers'] as $m) { + if (empty($m['handle'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE, + array('index' => $i)); + } + if (empty($m['role'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE, + array('index' => $i, 'roles' => PEAR_Common::getUserRoles())); + } elseif ($m['role'] == 'lead') { + $haslead = true; + } + if (empty($m['name'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME, + array('index' => $i)); + } + if (empty($m['email'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL, + array('index' => $i)); + } + $i++; + } + if (!$haslead) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD); + } + } + if (!empty($info['release_deps'])) { + $i = 1; + foreach ($info['release_deps'] as $d) { + if (!isset($d['type']) || empty($d['type'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE, + array('index' => $i, 'types' => PEAR_Common::getDependencyTypes())); + continue; + } + if (!isset($d['rel']) || empty($d['rel'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL, + array('index' => $i, 'rels' => PEAR_Common::getDependencyRelations())); + continue; + } + if (!empty($d['optional'])) { + if (!in_array($d['optional'], array('yes', 'no'))) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL, + array('index' => $i, 'opt' => $d['optional'])); + } + } + if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION, + array('index' => $i)); + } elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && !empty($d['version'])) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED, + array('index' => $i, 'rel' => $d['rel'])); + } + if ($d['type'] == 'php' && !empty($d['name'])) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED, + array('index' => $i, 'name' => $d['name'])); + } elseif ($d['type'] != 'php' && empty($d['name'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME, + array('index' => $i)); + } + if ($d['type'] == 'php' && empty($d['version'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION, + array('index' => $i)); + } + if (($d['rel'] == 'not') && ($d['type'] == 'php')) { + $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT, + array('index' => $i)); + } + $i++; + } + } + if (!empty($info['configure_options'])) { + $i = 1; + foreach ($info['configure_options'] as $c) { + if (empty($c['name'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME, + array('index' => $i)); + } + if (empty($c['prompt'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT, + array('index' => $i)); + } + $i++; + } + } + if (empty($info['filelist'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES); + $errors[] = 'no files'; + } else { + foreach ($info['filelist'] as $file => $fa) { + if (empty($fa['role'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE, + array('file' => $file, 'roles' => PEAR_Common::getFileRoles())); + continue; + } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE, + array('file' => $file, 'role' => $fa['role'], 'roles' => PEAR_Common::getFileRoles())); + } + if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $file))) { + // file contains .. parent directory or . cur directory references + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, + array('file' => $file)); + } + if (isset($fa['install-as']) && + preg_match('~/\.\.?(/|\\z)|^\.\.?/~', + str_replace('\\', '/', $fa['install-as']))) { + // install-as contains .. parent directory or . cur directory references + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, + array('file' => $file . ' [installed as ' . $fa['install-as'] . ']')); + } + if (isset($fa['baseinstalldir']) && + preg_match('~/\.\.?(/|\\z)|^\.\.?/~', + str_replace('\\', '/', $fa['baseinstalldir']))) { + // install-as contains .. parent directory or . cur directory references + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, + array('file' => $file . ' [baseinstalldir ' . $fa['baseinstalldir'] . ']')); + } + } + } + if (isset($this->_registry) && $this->_isValid) { + $chan = $this->_registry->getChannel('pear.php.net'); + if (PEAR::isError($chan)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $chan->getMessage()); + return $this->_isValid = 0; + } + $validator = $chan->getValidationObject(); + $validator->setPackageFile($this); + $validator->validate($state); + $failures = $validator->getFailures(); + foreach ($failures['errors'] as $error) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error); + } + foreach ($failures['warnings'] as $warning) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning); + } + } + if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$nofilechecking) { + if ($this->_analyzePhpFiles()) { + $this->_isValid = true; + } + } + if ($this->_isValid) { + return $this->_isValid = $state; + } + return $this->_isValid = 0; + } + + function _analyzePhpFiles() + { + if (!$this->_isValid) { + return false; + } + if (!isset($this->_packageFile)) { + return false; + } + $dir_prefix = dirname($this->_packageFile); + $common = new PEAR_Common; + $log = isset($this->_logger) ? array(&$this->_logger, 'log') : + array($common, 'log'); + $info = $this->getFilelist(); + foreach ($info as $file => $fa) { + if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND, + array('file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file)); + continue; + } + if ($fa['role'] == 'php' && $dir_prefix) { + call_user_func_array($log, array(1, "Analyzing $file")); + $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); + if ($srcinfo) { + $this->_buildProvidesArray($srcinfo); + } + } + } + $this->_packageName = $pn = $this->getPackage(); + $pnl = strlen($pn); + if (isset($this->_packageInfo['provides'])) { + foreach ((array) $this->_packageInfo['provides'] as $key => $what) { + if (isset($what['explicit'])) { + // skip conformance checks if the provides entry is + // specified in the package.xml file + continue; + } + extract($what); + if ($type == 'class') { + if (!strncasecmp($name, $pn, $pnl)) { + continue; + } + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, + array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); + } elseif ($type == 'function') { + if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) { + continue; + } + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, + array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); + } + } + } + return $this->_isValid; + } + + /** + * Get the default xml generator object + * + * @return PEAR_PackageFile_Generator_v1 + */ + function &getDefaultGenerator() + { + if (!class_exists('PEAR_PackageFile_Generator_v1')) { + require_once 'PEAR/PackageFile/Generator/v1.php'; + } + $a = &new PEAR_PackageFile_Generator_v1($this); + return $a; + } + + /** + * Get the contents of a file listed within the package.xml + * @param string + * @return string + */ + function getFileContents($file) + { + if ($this->_archiveFile == $this->_packageFile) { // unpacked + $dir = dirname($this->_packageFile); + $file = $dir . DIRECTORY_SEPARATOR . $file; + $file = str_replace(array('/', '\\'), + array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); + if (file_exists($file) && is_readable($file)) { + return implode('', file($file)); + } + } else { // tgz + if (!class_exists('Archive_Tar')) { + require_once 'Archive/Tar.php'; + } + $tar = &new Archive_Tar($this->_archiveFile); + $tar->pushErrorHandling(PEAR_ERROR_RETURN); + if ($file != 'package.xml' && $file != 'package2.xml') { + $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; + } + $file = $tar->extractInString($file); + $tar->popErrorHandling(); + if (PEAR::isError($file)) { + return PEAR::raiseError("Cannot locate file '$file' in archive"); + } + return $file; + } + } + + // {{{ analyzeSourceCode() + /** + * Analyze the source code of the given PHP file + * + * @param string Filename of the PHP file + * @return mixed + * @access private + */ + function _analyzeSourceCode($file) + { + if (!function_exists("token_get_all")) { + return false; + } + if (!defined('T_DOC_COMMENT')) { + define('T_DOC_COMMENT', T_COMMENT); + } + if (!defined('T_INTERFACE')) { + define('T_INTERFACE', -1); + } + if (!defined('T_IMPLEMENTS')) { + define('T_IMPLEMENTS', -1); + } + if (!$fp = @fopen($file, "r")) { + return false; + } + fclose($fp); + $contents = file_get_contents($file); + $tokens = token_get_all($contents); +/* + for ($i = 0; $i < sizeof($tokens); $i++) { + @list($token, $data) = $tokens[$i]; + if (is_string($token)) { + var_dump($token); + } else { + print token_name($token) . ' '; + var_dump(rtrim($data)); + } + } +*/ + $look_for = 0; + $paren_level = 0; + $bracket_level = 0; + $brace_level = 0; + $lastphpdoc = ''; + $current_class = ''; + $current_interface = ''; + $current_class_level = -1; + $current_function = ''; + $current_function_level = -1; + $declared_classes = array(); + $declared_interfaces = array(); + $declared_functions = array(); + $declared_methods = array(); + $used_classes = array(); + $used_functions = array(); + $extends = array(); + $implements = array(); + $nodeps = array(); + $inquote = false; + $interface = false; + for ($i = 0; $i < sizeof($tokens); $i++) { + if (is_array($tokens[$i])) { + list($token, $data) = $tokens[$i]; + } else { + $token = $tokens[$i]; + $data = ''; + } + if ($inquote) { + if ($token != '"' && $token != T_END_HEREDOC) { + continue; + } else { + $inquote = false; + continue; + } + } + switch ($token) { + case T_WHITESPACE : + continue; + case ';': + if ($interface) { + $current_function = ''; + $current_function_level = -1; + } + break; + case '"': + case T_START_HEREDOC: + $inquote = true; + break; + case T_CURLY_OPEN: + case T_DOLLAR_OPEN_CURLY_BRACES: + case '{': $brace_level++; continue 2; + case '}': + $brace_level--; + if ($current_class_level == $brace_level) { + $current_class = ''; + $current_class_level = -1; + } + if ($current_function_level == $brace_level) { + $current_function = ''; + $current_function_level = -1; + } + continue 2; + case '[': $bracket_level++; continue 2; + case ']': $bracket_level--; continue 2; + case '(': $paren_level++; continue 2; + case ')': $paren_level--; continue 2; + case T_INTERFACE: + $interface = true; + case T_CLASS: + if (($current_class_level != -1) || ($current_function_level != -1)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, + array('file' => $file)); + return false; + } + case T_FUNCTION: + case T_NEW: + case T_EXTENDS: + case T_IMPLEMENTS: + $look_for = $token; + continue 2; + case T_STRING: + if (version_compare(zend_version(), '2.0', '<')) { + if (in_array(strtolower($data), + array('public', 'private', 'protected', 'abstract', + 'interface', 'implements', 'throw') + )) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_PHP5, + array($file)); + } + } + if ($look_for == T_CLASS) { + $current_class = $data; + $current_class_level = $brace_level; + $declared_classes[] = $current_class; + } elseif ($look_for == T_INTERFACE) { + $current_interface = $data; + $current_class_level = $brace_level; + $declared_interfaces[] = $current_interface; + } elseif ($look_for == T_IMPLEMENTS) { + $implements[$current_class] = $data; + } elseif ($look_for == T_EXTENDS) { + $extends[$current_class] = $data; + } elseif ($look_for == T_FUNCTION) { + if ($current_class) { + $current_function = "$current_class::$data"; + $declared_methods[$current_class][] = $data; + } elseif ($current_interface) { + $current_function = "$current_interface::$data"; + $declared_methods[$current_interface][] = $data; + } else { + $current_function = $data; + $declared_functions[] = $current_function; + } + $current_function_level = $brace_level; + $m = array(); + } elseif ($look_for == T_NEW) { + $used_classes[$data] = true; + } + $look_for = 0; + continue 2; + case T_VARIABLE: + $look_for = 0; + continue 2; + case T_DOC_COMMENT: + case T_COMMENT: + if (preg_match('!^/\*\*\s!', $data)) { + $lastphpdoc = $data; + if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { + $nodeps = array_merge($nodeps, $m[1]); + } + } + continue 2; + case T_DOUBLE_COLON: + if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, + array('file' => $file)); + return false; + } + $class = $tokens[$i - 1][1]; + if (strtolower($class) != 'parent') { + $used_classes[$class] = true; + } + continue 2; + } + } + return array( + "source_file" => $file, + "declared_classes" => $declared_classes, + "declared_interfaces" => $declared_interfaces, + "declared_methods" => $declared_methods, + "declared_functions" => $declared_functions, + "used_classes" => array_diff(array_keys($used_classes), $nodeps), + "inheritance" => $extends, + "implements" => $implements, + ); + } + + /** + * Build a "provides" array from data returned by + * analyzeSourceCode(). The format of the built array is like + * this: + * + * array( + * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), + * ... + * ) + * + * + * @param array $srcinfo array with information about a source file + * as returned by the analyzeSourceCode() method. + * + * @return void + * + * @access private + * + */ + function _buildProvidesArray($srcinfo) + { + if (!$this->_isValid) { + return false; + } + $file = basename($srcinfo['source_file']); + $pn = $this->getPackage(); + $pnl = strlen($pn); + foreach ($srcinfo['declared_classes'] as $class) { + $key = "class;$class"; + if (isset($this->_packageInfo['provides'][$key])) { + continue; + } + $this->_packageInfo['provides'][$key] = + array('file'=> $file, 'type' => 'class', 'name' => $class); + if (isset($srcinfo['inheritance'][$class])) { + $this->_packageInfo['provides'][$key]['extends'] = + $srcinfo['inheritance'][$class]; + } + } + foreach ($srcinfo['declared_methods'] as $class => $methods) { + foreach ($methods as $method) { + $function = "$class::$method"; + $key = "function;$function"; + if ($method{0} == '_' || !strcasecmp($method, $class) || + isset($this->_packageInfo['provides'][$key])) { + continue; + } + $this->_packageInfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } + } + + foreach ($srcinfo['declared_functions'] as $function) { + $key = "function;$function"; + if ($function{0} == '_' || isset($this->_packageInfo['provides'][$key])) { + continue; + } + if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { + $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; + } + $this->_packageInfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } + } + + // }}} +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v2.php b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v2.php new file mode 100644 index 0000000..4a94a3c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v2.php @@ -0,0 +1,2049 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: v2.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * For error handling + */ +require_once 'PEAR/ErrorStack.php'; +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile_v2 +{ + + /** + * Parsed package information + * @var array + * @access private + */ + var $_packageInfo = array(); + + /** + * path to package .tgz or false if this is a local/extracted package.xml + * @var string|false + * @access private + */ + var $_archiveFile; + + /** + * path to package .xml or false if this is an abstract parsed-from-string xml + * @var string|false + * @access private + */ + var $_packageFile; + + /** + * This is used by file analysis routines to log progress information + * @var PEAR_Common + * @access protected + */ + var $_logger; + + /** + * This is set to the highest validation level that has been validated + * + * If the package.xml is invalid or unknown, this is set to 0. If + * normal validation has occurred, this is set to PEAR_VALIDATE_NORMAL. If + * downloading/installation validation has occurred it is set to PEAR_VALIDATE_DOWNLOADING + * or INSTALLING, and so on up to PEAR_VALIDATE_PACKAGING. This allows validation + * "caching" to occur, which is particularly important for package validation, so + * that PHP files are not validated twice + * @var int + * @access private + */ + var $_isValid = 0; + + /** + * True if the filelist has been validated + * @param bool + */ + var $_filesValid = false; + + /** + * @var PEAR_Registry + * @access protected + */ + var $_registry; + + /** + * @var PEAR_Config + * @access protected + */ + var $_config; + + /** + * Optional Dependency group requested for installation + * @var string + * @access private + */ + var $_requestedGroup = false; + + /** + * @var PEAR_ErrorStack + * @access protected + */ + var $_stack; + + /** + * Namespace prefix used for tasks in this package.xml - use tasks: whenever possible + */ + var $_tasksNs; + + /** + * Determines whether this packagefile was initialized only with partial package info + * + * If this package file was constructed via parsing REST, it will only contain + * + * - package name + * - channel name + * - dependencies + * @var boolean + * @access private + */ + var $_incomplete = true; + + /** + * @var PEAR_PackageFile_v2_Validator + */ + var $_v2Validator; + + /** + * The constructor merely sets up the private error stack + */ + function PEAR_PackageFile_v2() + { + $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v2', false, null); + $this->_isValid = false; + } + + /** + * To make unit-testing easier + * @param PEAR_Frontend_* + * @param array options + * @param PEAR_Config + * @return PEAR_Downloader + * @access protected + */ + function &getPEARDownloader(&$i, $o, &$c) + { + $z = &new PEAR_Downloader($i, $o, $c); + return $z; + } + + /** + * To make unit-testing easier + * @param PEAR_Config + * @param array options + * @param array package name as returned from {@link PEAR_Registry::parsePackageName()} + * @param int PEAR_VALIDATE_* constant + * @return PEAR_Dependency2 + * @access protected + */ + function &getPEARDependency2(&$c, $o, $p, $s = PEAR_VALIDATE_INSTALLING) + { + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; + } + $z = &new PEAR_Dependency2($c, $o, $p, $s); + return $z; + } + + function getInstalledBinary() + { + return isset($this->_packageInfo['#binarypackage']) ? $this->_packageInfo['#binarypackage'] : + false; + } + + /** + * Installation of source package has failed, attempt to download and install the + * binary version of this package. + * @param PEAR_Installer + * @return array|false + */ + function installBinary(&$installer) + { + if (!OS_WINDOWS) { + $a = false; + return $a; + } + if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') { + $releasetype = $this->getPackageType() . 'release'; + if (!is_array($installer->getInstallPackages())) { + $a = false; + return $a; + } + foreach ($installer->getInstallPackages() as $p) { + if ($p->isExtension($this->_packageInfo['providesextension'])) { + if ($p->getPackageType() != 'extsrc' && $p->getPackageType() != 'zendextsrc') { + $a = false; + return $a; // the user probably downloaded it separately + } + } + } + if (isset($this->_packageInfo[$releasetype]['binarypackage'])) { + $installer->log(0, 'Attempting to download binary version of extension "' . + $this->_packageInfo['providesextension'] . '"'); + $params = $this->_packageInfo[$releasetype]['binarypackage']; + if (!is_array($params) || !isset($params[0])) { + $params = array($params); + } + if (isset($this->_packageInfo['channel'])) { + foreach ($params as $i => $param) { + $params[$i] = array('channel' => $this->_packageInfo['channel'], + 'package' => $param, 'version' => $this->getVersion()); + } + } + $dl = &$this->getPEARDownloader($installer->ui, $installer->getOptions(), + $installer->config); + $verbose = $dl->config->get('verbose'); + $dl->config->set('verbose', -1); + foreach ($params as $param) { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $ret = $dl->download(array($param)); + PEAR::popErrorHandling(); + if (is_array($ret) && count($ret)) { + break; + } + } + $dl->config->set('verbose', $verbose); + if (is_array($ret)) { + if (count($ret) == 1) { + $pf = $ret[0]->getPackageFile(); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $installer->install($ret[0]); + PEAR::popErrorHandling(); + if (is_array($err)) { + $this->_packageInfo['#binarypackage'] = $ret[0]->getPackage(); + // "install" self, so all dependencies will work transparently + $this->_registry->addPackage2($this); + $installer->log(0, 'Download and install of binary extension "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pf->getChannel(), + 'package' => $pf->getPackage()), true) . '" successful'); + $a = array($ret[0], $err); + return $a; + } + $installer->log(0, 'Download and install of binary extension "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pf->getChannel(), + 'package' => $pf->getPackage()), true) . '" failed'); + } + } + } + } + $a = false; + return $a; + } + + /** + * @return string|false Extension name + */ + function getProvidesExtension() + { + if (in_array($this->getPackageType(), + array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { + if (isset($this->_packageInfo['providesextension'])) { + return $this->_packageInfo['providesextension']; + } + } + return false; + } + + /** + * @param string Extension name + * @return bool + */ + function isExtension($extension) + { + if (in_array($this->getPackageType(), + array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { + return $this->_packageInfo['providesextension'] == $extension; + } + return false; + } + + /** + * Tests whether every part of the package.xml 1.0 is represented in + * this package.xml 2.0 + * @param PEAR_PackageFile_v1 + * @return bool + */ + function isEquivalent($pf1) + { + if (!$pf1) { + return true; + } + if ($this->getPackageType() == 'bundle') { + return false; + } + $this->_stack->getErrors(true); + if (!$pf1->validate(PEAR_VALIDATE_NORMAL)) { + return false; + } + $pass = true; + if ($pf1->getPackage() != $this->getPackage()) { + $this->_differentPackage($pf1->getPackage()); + $pass = false; + } + if ($pf1->getVersion() != $this->getVersion()) { + $this->_differentVersion($pf1->getVersion()); + $pass = false; + } + if (trim($pf1->getSummary()) != $this->getSummary()) { + $this->_differentSummary($pf1->getSummary()); + $pass = false; + } + if (preg_replace('/\s+/', '', $pf1->getDescription()) != + preg_replace('/\s+/', '', $this->getDescription())) { + $this->_differentDescription($pf1->getDescription()); + $pass = false; + } + if ($pf1->getState() != $this->getState()) { + $this->_differentState($pf1->getState()); + $pass = false; + } + if (!strstr(preg_replace('/\s+/', '', $this->getNotes()), + preg_replace('/\s+/', '', $pf1->getNotes()))) { + $this->_differentNotes($pf1->getNotes()); + $pass = false; + } + $mymaintainers = $this->getMaintainers(); + $yourmaintainers = $pf1->getMaintainers(); + for ($i1 = 0; $i1 < count($yourmaintainers); $i1++) { + $reset = false; + for ($i2 = 0; $i2 < count($mymaintainers); $i2++) { + if ($mymaintainers[$i2]['handle'] == $yourmaintainers[$i1]['handle']) { + if ($mymaintainers[$i2]['role'] != $yourmaintainers[$i1]['role']) { + $this->_differentRole($mymaintainers[$i2]['handle'], + $yourmaintainers[$i1]['role'], $mymaintainers[$i2]['role']); + $pass = false; + } + if ($mymaintainers[$i2]['email'] != $yourmaintainers[$i1]['email']) { + $this->_differentEmail($mymaintainers[$i2]['handle'], + $yourmaintainers[$i1]['email'], $mymaintainers[$i2]['email']); + $pass = false; + } + if ($mymaintainers[$i2]['name'] != $yourmaintainers[$i1]['name']) { + $this->_differentName($mymaintainers[$i2]['handle'], + $yourmaintainers[$i1]['name'], $mymaintainers[$i2]['name']); + $pass = false; + } + unset($mymaintainers[$i2]); + $mymaintainers = array_values($mymaintainers); + unset($yourmaintainers[$i1]); + $yourmaintainers = array_values($yourmaintainers); + $reset = true; + break; + } + } + if ($reset) { + $i1 = -1; + } + } + $this->_unmatchedMaintainers($mymaintainers, $yourmaintainers); + $filelist = $this->getFilelist(); + foreach ($pf1->getFilelist() as $file => $atts) { + if (!isset($filelist[$file])) { + $this->_missingFile($file); + $pass = false; + } + } + return $pass; + } + + function _differentPackage($package) + { + $this->_stack->push(__FUNCTION__, 'error', array('package' => $package, + 'self' => $this->getPackage()), + 'package.xml 1.0 package "%package%" does not match "%self%"'); + } + + function _differentVersion($version) + { + $this->_stack->push(__FUNCTION__, 'error', array('version' => $version, + 'self' => $this->getVersion()), + 'package.xml 1.0 version "%version%" does not match "%self%"'); + } + + function _differentState($state) + { + $this->_stack->push(__FUNCTION__, 'error', array('state' => $state, + 'self' => $this->getState()), + 'package.xml 1.0 state "%state%" does not match "%self%"'); + } + + function _differentRole($handle, $role, $selfrole) + { + $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, + 'role' => $role, 'self' => $selfrole), + 'package.xml 1.0 maintainer "%handle%" role "%role%" does not match "%self%"'); + } + + function _differentEmail($handle, $email, $selfemail) + { + $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, + 'email' => $email, 'self' => $selfemail), + 'package.xml 1.0 maintainer "%handle%" email "%email%" does not match "%self%"'); + } + + function _differentName($handle, $name, $selfname) + { + $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, + 'name' => $name, 'self' => $selfname), + 'package.xml 1.0 maintainer "%handle%" name "%name%" does not match "%self%"'); + } + + function _unmatchedMaintainers($my, $yours) + { + if ($my) { + array_walk($my, create_function('&$i, $k', '$i = $i["handle"];')); + $this->_stack->push(__FUNCTION__, 'error', array('handles' => $my), + 'package.xml 2.0 has unmatched extra maintainers "%handles%"'); + } + if ($yours) { + array_walk($yours, create_function('&$i, $k', '$i = $i["handle"];')); + $this->_stack->push(__FUNCTION__, 'error', array('handles' => $yours), + 'package.xml 1.0 has unmatched extra maintainers "%handles%"'); + } + } + + function _differentNotes($notes) + { + $truncnotes = strlen($notes) < 25 ? $notes : substr($notes, 0, 24) . '...'; + $truncmynotes = strlen($this->getNotes()) < 25 ? $this->getNotes() : + substr($this->getNotes(), 0, 24) . '...'; + $this->_stack->push(__FUNCTION__, 'error', array('notes' => $truncnotes, + 'self' => $truncmynotes), + 'package.xml 1.0 release notes "%notes%" do not match "%self%"'); + } + + function _differentSummary($summary) + { + $truncsummary = strlen($summary) < 25 ? $summary : substr($summary, 0, 24) . '...'; + $truncmysummary = strlen($this->getsummary()) < 25 ? $this->getSummary() : + substr($this->getsummary(), 0, 24) . '...'; + $this->_stack->push(__FUNCTION__, 'error', array('summary' => $truncsummary, + 'self' => $truncmysummary), + 'package.xml 1.0 summary "%summary%" does not match "%self%"'); + } + + function _differentDescription($description) + { + $truncdescription = trim(strlen($description) < 25 ? $description : substr($description, 0, 24) . '...'); + $truncmydescription = trim(strlen($this->getDescription()) < 25 ? $this->getDescription() : + substr($this->getdescription(), 0, 24) . '...'); + $this->_stack->push(__FUNCTION__, 'error', array('description' => $truncdescription, + 'self' => $truncmydescription), + 'package.xml 1.0 description "%description%" does not match "%self%"'); + } + + function _missingFile($file) + { + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'package.xml 1.0 file "%file%" is not present in '); + } + + /** + * WARNING - do not use this function unless you know what you're doing + */ + function setRawState($state) + { + if (!isset($this->_packageInfo['stability'])) { + $this->_packageInfo['stability'] = array(); + } + $this->_packageInfo['stability']['release'] = $state; + } + + /** + * WARNING - do not use this function unless you know what you're doing + */ + function setRawCompatible($compatible) + { + $this->_packageInfo['compatible'] = $compatible; + } + + /** + * WARNING - do not use this function unless you know what you're doing + */ + function setRawPackage($package) + { + $this->_packageInfo['name'] = $package; + } + + /** + * WARNING - do not use this function unless you know what you're doing + */ + function setRawChannel($channel) + { + $this->_packageInfo['channel'] = $channel; + } + + function setRequestedGroup($group) + { + $this->_requestedGroup = $group; + } + + function getRequestedGroup() + { + if (isset($this->_requestedGroup)) { + return $this->_requestedGroup; + } + return false; + } + + /** + * For saving in the registry. + * + * Set the last version that was installed + * @param string + */ + function setLastInstalledVersion($version) + { + $this->_packageInfo['_lastversion'] = $version; + } + + /** + * @return string|false + */ + function getLastInstalledVersion() + { + if (isset($this->_packageInfo['_lastversion'])) { + return $this->_packageInfo['_lastversion']; + } + return false; + } + + /** + * Determines whether this package.xml has post-install scripts or not + * @return array|false + */ + function listPostinstallScripts() + { + $filelist = $this->getFilelist(); + $contents = $this->getContents(); + $contents = $contents['dir']['file']; + if (!is_array($contents) || !isset($contents[0])) { + $contents = array($contents); + } + $taskfiles = array(); + foreach ($contents as $file) { + $atts = $file['attribs']; + unset($file['attribs']); + if (count($file)) { + $taskfiles[$atts['name']] = $file; + } + } + $common = new PEAR_Common; + $common->debug = $this->_config->get('verbose'); + $this->_scripts = array(); + $ret = array(); + foreach ($taskfiles as $name => $tasks) { + if (!isset($filelist[$name])) { + // ignored files will not be in the filelist + continue; + } + $atts = $filelist[$name]; + foreach ($tasks as $tag => $raw) { + $task = $this->getTask($tag); + $task = &new $task($this->_config, $common, PEAR_TASK_INSTALL); + if ($task->isScript()) { + $ret[] = $filelist[$name]['installed_as']; + } + } + } + if (count($ret)) { + return $ret; + } + return false; + } + + /** + * Initialize post-install scripts for running + * + * This method can be used to detect post-install scripts, as the return value + * indicates whether any exist + * @return bool + */ + function initPostinstallScripts() + { + $filelist = $this->getFilelist(); + $contents = $this->getContents(); + $contents = $contents['dir']['file']; + if (!is_array($contents) || !isset($contents[0])) { + $contents = array($contents); + } + $taskfiles = array(); + foreach ($contents as $file) { + $atts = $file['attribs']; + unset($file['attribs']); + if (count($file)) { + $taskfiles[$atts['name']] = $file; + } + } + $common = new PEAR_Common; + $common->debug = $this->_config->get('verbose'); + $this->_scripts = array(); + foreach ($taskfiles as $name => $tasks) { + if (!isset($filelist[$name])) { + // file was not installed due to installconditions + continue; + } + $atts = $filelist[$name]; + foreach ($tasks as $tag => $raw) { + $taskname = $this->getTask($tag); + $task = &new $taskname($this->_config, $common, PEAR_TASK_INSTALL); + if (!$task->isScript()) { + continue; // scripts are only handled after installation + } + $lastversion = isset($this->_packageInfo['_lastversion']) ? + $this->_packageInfo['_lastversion'] : null; + $task->init($raw, $atts, $lastversion); + $res = $task->startSession($this, $atts['installed_as']); + if (!$res) { + continue; // skip this file + } + if (PEAR::isError($res)) { + return $res; + } + $assign = &$task; + $this->_scripts[] = &$assign; + } + } + if (count($this->_scripts)) { + return true; + } + return false; + } + + function runPostinstallScripts() + { + if ($this->initPostinstallScripts()) { + $ui = &PEAR_Frontend::singleton(); + if ($ui) { + $ui->runPostinstallScripts($this->_scripts, $this); + } + } + } + + + /** + * Convert a recursive set of and tags into a single tag with + * tags. + */ + function flattenFilelist() + { + if (isset($this->_packageInfo['bundle'])) { + return; + } + $filelist = array(); + if (isset($this->_packageInfo['contents']['dir']['dir'])) { + $this->_getFlattenedFilelist($filelist, $this->_packageInfo['contents']['dir']); + if (!isset($filelist[1])) { + $filelist = $filelist[0]; + } + $this->_packageInfo['contents']['dir']['file'] = $filelist; + unset($this->_packageInfo['contents']['dir']['dir']); + } else { + // else already flattened but check for baseinstalldir propagation + if (isset($this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'])) { + if (isset($this->_packageInfo['contents']['dir']['file'][0])) { + foreach ($this->_packageInfo['contents']['dir']['file'] as $i => $file) { + if (isset($file['attribs']['baseinstalldir'])) { + continue; + } + $this->_packageInfo['contents']['dir']['file'][$i]['attribs']['baseinstalldir'] + = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir']; + } + } else { + if (!isset($this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'])) { + $this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'] + = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir']; + } + } + } + } + } + + /** + * @param array the final flattened file list + * @param array the current directory being processed + * @param string|false any recursively inherited baeinstalldir attribute + * @param string private recursion variable + * @return array + * @access protected + */ + function _getFlattenedFilelist(&$files, $dir, $baseinstall = false, $path = '') + { + if (isset($dir['attribs']) && isset($dir['attribs']['baseinstalldir'])) { + $baseinstall = $dir['attribs']['baseinstalldir']; + } + if (isset($dir['dir'])) { + if (!isset($dir['dir'][0])) { + $dir['dir'] = array($dir['dir']); + } + foreach ($dir['dir'] as $subdir) { + if (!isset($subdir['attribs']) || !isset($subdir['attribs']['name'])) { + $name = '*unknown*'; + } else { + $name = $subdir['attribs']['name']; + } + $newpath = empty($path) ? $name : + $path . '/' . $name; + $this->_getFlattenedFilelist($files, $subdir, + $baseinstall, $newpath); + } + } + if (isset($dir['file'])) { + if (!isset($dir['file'][0])) { + $dir['file'] = array($dir['file']); + } + foreach ($dir['file'] as $file) { + $attrs = $file['attribs']; + $name = $attrs['name']; + if ($baseinstall && !isset($attrs['baseinstalldir'])) { + $attrs['baseinstalldir'] = $baseinstall; + } + $attrs['name'] = empty($path) ? $name : $path . '/' . $name; + $attrs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), + $attrs['name']); + $file['attribs'] = $attrs; + $files[] = $file; + } + } + } + + function setConfig(&$config) + { + $this->_config = &$config; + $this->_registry = &$config->getRegistry(); + } + + function setLogger(&$logger) + { + if (!is_object($logger) || !method_exists($logger, 'log')) { + return PEAR::raiseError('Logger must be compatible with PEAR_Common::log'); + } + $this->_logger = &$logger; + } + + /** + * WARNING - do not use this function directly unless you know what you're doing + */ + function setDeps($deps) + { + $this->_packageInfo['dependencies'] = $deps; + } + + /** + * WARNING - do not use this function directly unless you know what you're doing + */ + function setCompatible($compat) + { + $this->_packageInfo['compatible'] = $compat; + } + + function setPackagefile($file, $archive = false) + { + $this->_packageFile = $file; + $this->_archiveFile = $archive ? $archive : $file; + } + + /** + * Wrapper to {@link PEAR_ErrorStack::getErrors()} + * @param boolean determines whether to purge the error stack after retrieving + * @return array + */ + function getValidationWarnings($purge = true) + { + return $this->_stack->getErrors($purge); + } + + function getPackageFile() + { + return $this->_packageFile; + } + + function getArchiveFile() + { + return $this->_archiveFile; + } + + + /** + * Directly set the array that defines this packagefile + * + * WARNING: no validation. This should only be performed by internal methods + * inside PEAR or by inputting an array saved from an existing PEAR_PackageFile_v2 + * @param array + */ + function fromArray($pinfo) + { + unset($pinfo['old']); + unset($pinfo['xsdversion']); + // If the changelog isn't an array then it was passed in as an empty tag + if (isset($pinfo['changelog']) && !is_array($pinfo['changelog'])) { + unset($pinfo['changelog']); + } + $this->_incomplete = false; + $this->_packageInfo = $pinfo; + } + + function isIncomplete() + { + return $this->_incomplete; + } + + /** + * @return array + */ + function toArray($forreg = false) + { + if (!$this->validate(PEAR_VALIDATE_NORMAL)) { + return false; + } + return $this->getArray($forreg); + } + + function getArray($forReg = false) + { + if ($forReg) { + $arr = $this->_packageInfo; + $arr['old'] = array(); + $arr['old']['version'] = $this->getVersion(); + $arr['old']['release_date'] = $this->getDate(); + $arr['old']['release_state'] = $this->getState(); + $arr['old']['release_license'] = $this->getLicense(); + $arr['old']['release_notes'] = $this->getNotes(); + $arr['old']['release_deps'] = $this->getDeps(); + $arr['old']['maintainers'] = $this->getMaintainers(); + $arr['xsdversion'] = '2.0'; + return $arr; + } else { + $info = $this->_packageInfo; + unset($info['dirtree']); + if (isset($info['_lastversion'])) { + unset($info['_lastversion']); + } + if (isset($info['#binarypackage'])) { + unset($info['#binarypackage']); + } + return $info; + } + } + + function packageInfo($field) + { + $arr = $this->getArray(true); + if ($field == 'state') { + return $arr['stability']['release']; + } + if ($field == 'api-version') { + return $arr['version']['api']; + } + if ($field == 'api-state') { + return $arr['stability']['api']; + } + if (isset($arr['old'][$field])) { + if (!is_string($arr['old'][$field])) { + return null; + } + return $arr['old'][$field]; + } + if (isset($arr[$field])) { + if (!is_string($arr[$field])) { + return null; + } + return $arr[$field]; + } + return null; + } + + function getName() + { + return $this->getPackage(); + } + + function getPackage() + { + if (isset($this->_packageInfo['name'])) { + return $this->_packageInfo['name']; + } + return false; + } + + function getChannel() + { + if (isset($this->_packageInfo['uri'])) { + return '__uri'; + } + if (isset($this->_packageInfo['channel'])) { + return strtolower($this->_packageInfo['channel']); + } + return false; + } + + function getUri() + { + if (isset($this->_packageInfo['uri'])) { + return $this->_packageInfo['uri']; + } + return false; + } + + function getExtends() + { + if (isset($this->_packageInfo['extends'])) { + return $this->_packageInfo['extends']; + } + return false; + } + + function getSummary() + { + if (isset($this->_packageInfo['summary'])) { + return $this->_packageInfo['summary']; + } + return false; + } + + function getDescription() + { + if (isset($this->_packageInfo['description'])) { + return $this->_packageInfo['description']; + } + return false; + } + + function getMaintainers($raw = false) + { + if (!isset($this->_packageInfo['lead'])) { + return false; + } + if ($raw) { + $ret = array('lead' => $this->_packageInfo['lead']); + (isset($this->_packageInfo['developer'])) ? + $ret['developer'] = $this->_packageInfo['developer'] :null; + (isset($this->_packageInfo['contributor'])) ? + $ret['contributor'] = $this->_packageInfo['contributor'] :null; + (isset($this->_packageInfo['helper'])) ? + $ret['helper'] = $this->_packageInfo['helper'] :null; + return $ret; + } else { + $ret = array(); + $leads = isset($this->_packageInfo['lead'][0]) ? $this->_packageInfo['lead'] : + array($this->_packageInfo['lead']); + foreach ($leads as $lead) { + $s = $lead; + $s['handle'] = $s['user']; + unset($s['user']); + $s['role'] = 'lead'; + $ret[] = $s; + } + if (isset($this->_packageInfo['developer'])) { + $leads = isset($this->_packageInfo['developer'][0]) ? + $this->_packageInfo['developer'] : + array($this->_packageInfo['developer']); + foreach ($leads as $maintainer) { + $s = $maintainer; + $s['handle'] = $s['user']; + unset($s['user']); + $s['role'] = 'developer'; + $ret[] = $s; + } + } + if (isset($this->_packageInfo['contributor'])) { + $leads = isset($this->_packageInfo['contributor'][0]) ? + $this->_packageInfo['contributor'] : + array($this->_packageInfo['contributor']); + foreach ($leads as $maintainer) { + $s = $maintainer; + $s['handle'] = $s['user']; + unset($s['user']); + $s['role'] = 'contributor'; + $ret[] = $s; + } + } + if (isset($this->_packageInfo['helper'])) { + $leads = isset($this->_packageInfo['helper'][0]) ? + $this->_packageInfo['helper'] : + array($this->_packageInfo['helper']); + foreach ($leads as $maintainer) { + $s = $maintainer; + $s['handle'] = $s['user']; + unset($s['user']); + $s['role'] = 'helper'; + $ret[] = $s; + } + } + return $ret; + } + return false; + } + + function getLeads() + { + if (isset($this->_packageInfo['lead'])) { + return $this->_packageInfo['lead']; + } + return false; + } + + function getDevelopers() + { + if (isset($this->_packageInfo['developer'])) { + return $this->_packageInfo['developer']; + } + return false; + } + + function getContributors() + { + if (isset($this->_packageInfo['contributor'])) { + return $this->_packageInfo['contributor']; + } + return false; + } + + function getHelpers() + { + if (isset($this->_packageInfo['helper'])) { + return $this->_packageInfo['helper']; + } + return false; + } + + function setDate($date) + { + if (!isset($this->_packageInfo['date'])) { + // ensure that the extends tag is set up in the right location + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('time', 'version', + 'stability', 'license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', + 'zendextbinrelease', 'bundle', 'changelog'), array(), 'date'); + } + $this->_packageInfo['date'] = $date; + $this->_isValid = 0; + } + + function setTime($time) + { + $this->_isValid = 0; + if (!isset($this->_packageInfo['time'])) { + // ensure that the time tag is set up in the right location + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('version', + 'stability', 'license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', + 'zendextbinrelease', 'bundle', 'changelog'), $time, 'time'); + } + $this->_packageInfo['time'] = $time; + } + + function getDate() + { + if (isset($this->_packageInfo['date'])) { + return $this->_packageInfo['date']; + } + return false; + } + + function getTime() + { + if (isset($this->_packageInfo['time'])) { + return $this->_packageInfo['time']; + } + return false; + } + + /** + * @param package|api version category to return + */ + function getVersion($key = 'release') + { + if (isset($this->_packageInfo['version'][$key])) { + return $this->_packageInfo['version'][$key]; + } + return false; + } + + function getStability() + { + if (isset($this->_packageInfo['stability'])) { + return $this->_packageInfo['stability']; + } + return false; + } + + function getState($key = 'release') + { + if (isset($this->_packageInfo['stability'][$key])) { + return $this->_packageInfo['stability'][$key]; + } + return false; + } + + function getLicense($raw = false) + { + if (isset($this->_packageInfo['license'])) { + if ($raw) { + return $this->_packageInfo['license']; + } + if (is_array($this->_packageInfo['license'])) { + return $this->_packageInfo['license']['_content']; + } else { + return $this->_packageInfo['license']; + } + } + return false; + } + + function getLicenseLocation() + { + if (!isset($this->_packageInfo['license']) || !is_array($this->_packageInfo['license'])) { + return false; + } + return $this->_packageInfo['license']['attribs']; + } + + function getNotes() + { + if (isset($this->_packageInfo['notes'])) { + return $this->_packageInfo['notes']; + } + return false; + } + + /** + * Return the tag contents, if any + * @return array|false + */ + function getUsesrole() + { + if (isset($this->_packageInfo['usesrole'])) { + return $this->_packageInfo['usesrole']; + } + return false; + } + + /** + * Return the tag contents, if any + * @return array|false + */ + function getUsestask() + { + if (isset($this->_packageInfo['usestask'])) { + return $this->_packageInfo['usestask']; + } + return false; + } + + /** + * This should only be used to retrieve filenames and install attributes + */ + function getFilelist($preserve = false) + { + if (isset($this->_packageInfo['filelist']) && !$preserve) { + return $this->_packageInfo['filelist']; + } + $this->flattenFilelist(); + if ($contents = $this->getContents()) { + $ret = array(); + if (!isset($contents['dir'])) { + return false; + } + if (!isset($contents['dir']['file'][0])) { + $contents['dir']['file'] = array($contents['dir']['file']); + } + foreach ($contents['dir']['file'] as $file) { + $name = $file['attribs']['name']; + if (!$preserve) { + $file = $file['attribs']; + } + $ret[$name] = $file; + } + if (!$preserve) { + $this->_packageInfo['filelist'] = $ret; + } + return $ret; + } + return false; + } + + /** + * Return configure options array, if any + * + * @return array|false + */ + function getConfigureOptions() + { + if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') { + return false; + } + + $releases = $this->getReleases(); + if (isset($releases[0])) { + $releases = $releases[0]; + } + + if (isset($releases['configureoption'])) { + if (!isset($releases['configureoption'][0])) { + $releases['configureoption'] = array($releases['configureoption']); + } + + for ($i = 0; $i < count($releases['configureoption']); $i++) { + $releases['configureoption'][$i] = $releases['configureoption'][$i]['attribs']; + } + + return $releases['configureoption']; + } + + return false; + } + + /** + * This is only used at install-time, after all serialization + * is over. + */ + function resetFilelist() + { + $this->_packageInfo['filelist'] = array(); + } + + /** + * Retrieve a list of files that should be installed on this computer + * @return array + */ + function getInstallationFilelist($forfilecheck = false) + { + $contents = $this->getFilelist(true); + if (isset($contents['dir']['attribs']['baseinstalldir'])) { + $base = $contents['dir']['attribs']['baseinstalldir']; + } + if (isset($this->_packageInfo['bundle'])) { + return PEAR::raiseError( + 'Exception: bundles should be handled in download code only'); + } + $release = $this->getReleases(); + if ($release) { + if (!isset($release[0])) { + if (!isset($release['installconditions']) && !isset($release['filelist'])) { + if ($forfilecheck) { + return $this->getFilelist(); + } + return $contents; + } + $release = array($release); + } + $depchecker = &$this->getPEARDependency2($this->_config, array(), + array('channel' => $this->getChannel(), 'package' => $this->getPackage()), + PEAR_VALIDATE_INSTALLING); + foreach ($release as $instance) { + if (isset($instance['installconditions'])) { + $installconditions = $instance['installconditions']; + if (is_array($installconditions)) { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + foreach ($installconditions as $type => $conditions) { + if (!isset($conditions[0])) { + $conditions = array($conditions); + } + foreach ($conditions as $condition) { + $ret = $depchecker->{"validate{$type}Dependency"}($condition); + if (PEAR::isError($ret)) { + PEAR::popErrorHandling(); + continue 3; // skip this release + } + } + } + PEAR::popErrorHandling(); + } + } + // this is the release to use + if (isset($instance['filelist'])) { + // ignore files + if (isset($instance['filelist']['ignore'])) { + $ignore = isset($instance['filelist']['ignore'][0]) ? + $instance['filelist']['ignore'] : + array($instance['filelist']['ignore']); + foreach ($ignore as $ig) { + unset ($contents[$ig['attribs']['name']]); + } + } + // install files as this name + if (isset($instance['filelist']['install'])) { + $installas = isset($instance['filelist']['install'][0]) ? + $instance['filelist']['install'] : + array($instance['filelist']['install']); + foreach ($installas as $as) { + $contents[$as['attribs']['name']]['attribs']['install-as'] = + $as['attribs']['as']; + } + } + } + if ($forfilecheck) { + foreach ($contents as $file => $attrs) { + $contents[$file] = $attrs['attribs']; + } + } + return $contents; + } + } else { // simple release - no installconditions or install-as + if ($forfilecheck) { + return $this->getFilelist(); + } + return $contents; + } + // no releases matched + return PEAR::raiseError('No releases in package.xml matched the existing operating ' . + 'system, extensions installed, or architecture, cannot install'); + } + + /** + * This is only used at install-time, after all serialization + * is over. + * @param string file name + * @param string installed path + */ + function setInstalledAs($file, $path) + { + if ($path) { + return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; + } + unset($this->_packageInfo['filelist'][$file]['installed_as']); + } + + function getInstalledLocation($file) + { + if (isset($this->_packageInfo['filelist'][$file]['installed_as'])) { + return $this->_packageInfo['filelist'][$file]['installed_as']; + } + return false; + } + + /** + * This is only used at install-time, after all serialization + * is over. + */ + function installedFile($file, $atts) + { + if (isset($this->_packageInfo['filelist'][$file])) { + $this->_packageInfo['filelist'][$file] = + array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']); + } else { + $this->_packageInfo['filelist'][$file] = $atts['attribs']; + } + } + + /** + * Retrieve the contents tag + */ + function getContents() + { + if (isset($this->_packageInfo['contents'])) { + return $this->_packageInfo['contents']; + } + return false; + } + + /** + * @param string full path to file + * @param string attribute name + * @param string attribute value + * @param int risky but fast - use this to choose a file based on its position in the list + * of files. Index is zero-based like PHP arrays. + * @return bool success of operation + */ + function setFileAttribute($filename, $attr, $value, $index = false) + { + $this->_isValid = 0; + if (in_array($attr, array('role', 'name', 'baseinstalldir'))) { + $this->_filesValid = false; + } + if ($index !== false && + isset($this->_packageInfo['contents']['dir']['file'][$index]['attribs'])) { + $this->_packageInfo['contents']['dir']['file'][$index]['attribs'][$attr] = $value; + return true; + } + if (!isset($this->_packageInfo['contents']['dir']['file'])) { + return false; + } + $files = $this->_packageInfo['contents']['dir']['file']; + if (!isset($files[0])) { + $files = array($files); + $ind = false; + } else { + $ind = true; + } + foreach ($files as $i => $file) { + if (isset($file['attribs'])) { + if ($file['attribs']['name'] == $filename) { + if ($ind) { + $this->_packageInfo['contents']['dir']['file'][$i]['attribs'][$attr] = $value; + } else { + $this->_packageInfo['contents']['dir']['file']['attribs'][$attr] = $value; + } + return true; + } + } + } + return false; + } + + function setDirtree($path) + { + if (!isset($this->_packageInfo['dirtree'])) { + $this->_packageInfo['dirtree'] = array(); + } + $this->_packageInfo['dirtree'][$path] = true; + } + + function getDirtree() + { + if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) { + return $this->_packageInfo['dirtree']; + } + return false; + } + + function resetDirtree() + { + unset($this->_packageInfo['dirtree']); + } + + /** + * Determines whether this package claims it is compatible with the version of + * the package that has a recommended version dependency + * @param PEAR_PackageFile_v2|PEAR_PackageFile_v1|PEAR_Downloader_Package + * @return boolean + */ + function isCompatible($pf) + { + if (!isset($this->_packageInfo['compatible'])) { + return false; + } + if (!isset($this->_packageInfo['channel'])) { + return false; + } + $me = $pf->getVersion(); + $compatible = $this->_packageInfo['compatible']; + if (!isset($compatible[0])) { + $compatible = array($compatible); + } + $found = false; + foreach ($compatible as $info) { + if (strtolower($info['name']) == strtolower($pf->getPackage())) { + if (strtolower($info['channel']) == strtolower($pf->getChannel())) { + $found = true; + break; + } + } + } + if (!$found) { + return false; + } + if (isset($info['exclude'])) { + if (!isset($info['exclude'][0])) { + $info['exclude'] = array($info['exclude']); + } + foreach ($info['exclude'] as $exclude) { + if (version_compare($me, $exclude, '==')) { + return false; + } + } + } + if (version_compare($me, $info['min'], '>=') && version_compare($me, $info['max'], '<=')) { + return true; + } + return false; + } + + /** + * @return array|false + */ + function getCompatible() + { + if (isset($this->_packageInfo['compatible'])) { + return $this->_packageInfo['compatible']; + } + return false; + } + + function getDependencies() + { + if (isset($this->_packageInfo['dependencies'])) { + return $this->_packageInfo['dependencies']; + } + return false; + } + + function isSubpackageOf($p) + { + return $p->isSubpackage($this); + } + + /** + * Determines whether the passed in package is a subpackage of this package. + * + * No version checking is done, only name verification. + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @return bool + */ + function isSubpackage($p) + { + $sub = array(); + if (isset($this->_packageInfo['dependencies']['required']['subpackage'])) { + $sub = $this->_packageInfo['dependencies']['required']['subpackage']; + if (!isset($sub[0])) { + $sub = array($sub); + } + } + if (isset($this->_packageInfo['dependencies']['optional']['subpackage'])) { + $sub1 = $this->_packageInfo['dependencies']['optional']['subpackage']; + if (!isset($sub1[0])) { + $sub1 = array($sub1); + } + $sub = array_merge($sub, $sub1); + } + if (isset($this->_packageInfo['dependencies']['group'])) { + $group = $this->_packageInfo['dependencies']['group']; + if (!isset($group[0])) { + $group = array($group); + } + foreach ($group as $deps) { + if (isset($deps['subpackage'])) { + $sub2 = $deps['subpackage']; + if (!isset($sub2[0])) { + $sub2 = array($sub2); + } + $sub = array_merge($sub, $sub2); + } + } + } + foreach ($sub as $dep) { + if (strtolower($dep['name']) == strtolower($p->getPackage())) { + if (isset($dep['channel'])) { + if (strtolower($dep['channel']) == strtolower($p->getChannel())) { + return true; + } + } else { + if ($dep['uri'] == $p->getURI()) { + return true; + } + } + } + } + return false; + } + + function dependsOn($package, $channel) + { + if (!($deps = $this->getDependencies())) { + return false; + } + foreach (array('package', 'subpackage') as $type) { + foreach (array('required', 'optional') as $needed) { + if (isset($deps[$needed][$type])) { + if (!isset($deps[$needed][$type][0])) { + $deps[$needed][$type] = array($deps[$needed][$type]); + } + foreach ($deps[$needed][$type] as $dep) { + $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; + if (strtolower($dep['name']) == strtolower($package) && + $depchannel == $channel) { + return true; + } + } + } + } + if (isset($deps['group'])) { + if (!isset($deps['group'][0])) { + $dep['group'] = array($deps['group']); + } + foreach ($deps['group'] as $group) { + if (isset($group[$type])) { + if (!is_array($group[$type])) { + $group[$type] = array($group[$type]); + } + foreach ($group[$type] as $dep) { + $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; + if (strtolower($dep['name']) == strtolower($package) && + $depchannel == $channel) { + return true; + } + } + } + } + } + } + return false; + } + + /** + * Get the contents of a dependency group + * @param string + * @return array|false + */ + function getDependencyGroup($name) + { + $name = strtolower($name); + if (!isset($this->_packageInfo['dependencies']['group'])) { + return false; + } + $groups = $this->_packageInfo['dependencies']['group']; + if (!isset($groups[0])) { + $groups = array($groups); + } + foreach ($groups as $group) { + if (strtolower($group['attribs']['name']) == $name) { + return $group; + } + } + return false; + } + + /** + * Retrieve a partial package.xml 1.0 representation of dependencies + * + * a very limited representation of dependencies is returned by this method. + * The tag for excluding certain versions of a dependency is + * completely ignored. In addition, dependency groups are ignored, with the + * assumption that all dependencies in dependency groups are also listed in + * the optional group that work with all dependency groups + * @param boolean return package.xml 2.0 tag + * @return array|false + */ + function getDeps($raw = false, $nopearinstaller = false) + { + if (isset($this->_packageInfo['dependencies'])) { + if ($raw) { + return $this->_packageInfo['dependencies']; + } + $ret = array(); + $map = array( + 'php' => 'php', + 'package' => 'pkg', + 'subpackage' => 'pkg', + 'extension' => 'ext', + 'os' => 'os', + 'pearinstaller' => 'pkg', + ); + foreach (array('required', 'optional') as $type) { + $optional = ($type == 'optional') ? 'yes' : 'no'; + if (!isset($this->_packageInfo['dependencies'][$type]) + || empty($this->_packageInfo['dependencies'][$type])) { + continue; + } + foreach ($this->_packageInfo['dependencies'][$type] as $dtype => $deps) { + if ($dtype == 'pearinstaller' && $nopearinstaller) { + continue; + } + if (!isset($deps[0])) { + $deps = array($deps); + } + foreach ($deps as $dep) { + if (!isset($map[$dtype])) { + // no support for arch type + continue; + } + if ($dtype == 'pearinstaller') { + $dep['name'] = 'PEAR'; + $dep['channel'] = 'pear.php.net'; + } + $s = array('type' => $map[$dtype]); + if (isset($dep['channel'])) { + $s['channel'] = $dep['channel']; + } + if (isset($dep['uri'])) { + $s['uri'] = $dep['uri']; + } + if (isset($dep['name'])) { + $s['name'] = $dep['name']; + } + if (isset($dep['conflicts'])) { + $s['rel'] = 'not'; + } else { + if (!isset($dep['min']) && + !isset($dep['max'])) { + $s['rel'] = 'has'; + $s['optional'] = $optional; + } elseif (isset($dep['min']) && + isset($dep['max'])) { + $s['rel'] = 'ge'; + $s1 = $s; + $s1['rel'] = 'le'; + $s['version'] = $dep['min']; + $s1['version'] = $dep['max']; + if (isset($dep['channel'])) { + $s1['channel'] = $dep['channel']; + } + if ($dtype != 'php') { + $s['name'] = $dep['name']; + $s1['name'] = $dep['name']; + } + $s['optional'] = $optional; + $s1['optional'] = $optional; + $ret[] = $s1; + } elseif (isset($dep['min'])) { + if (isset($dep['exclude']) && + $dep['exclude'] == $dep['min']) { + $s['rel'] = 'gt'; + } else { + $s['rel'] = 'ge'; + } + $s['version'] = $dep['min']; + $s['optional'] = $optional; + if ($dtype != 'php') { + $s['name'] = $dep['name']; + } + } elseif (isset($dep['max'])) { + if (isset($dep['exclude']) && + $dep['exclude'] == $dep['max']) { + $s['rel'] = 'lt'; + } else { + $s['rel'] = 'le'; + } + $s['version'] = $dep['max']; + $s['optional'] = $optional; + if ($dtype != 'php') { + $s['name'] = $dep['name']; + } + } + } + $ret[] = $s; + } + } + } + if (count($ret)) { + return $ret; + } + } + return false; + } + + /** + * @return php|extsrc|extbin|zendextsrc|zendextbin|bundle|false + */ + function getPackageType() + { + if (isset($this->_packageInfo['phprelease'])) { + return 'php'; + } + if (isset($this->_packageInfo['extsrcrelease'])) { + return 'extsrc'; + } + if (isset($this->_packageInfo['extbinrelease'])) { + return 'extbin'; + } + if (isset($this->_packageInfo['zendextsrcrelease'])) { + return 'zendextsrc'; + } + if (isset($this->_packageInfo['zendextbinrelease'])) { + return 'zendextbin'; + } + if (isset($this->_packageInfo['bundle'])) { + return 'bundle'; + } + return false; + } + + /** + * @return array|false + */ + function getReleases() + { + $type = $this->getPackageType(); + if ($type != 'bundle') { + $type .= 'release'; + } + if ($this->getPackageType() && isset($this->_packageInfo[$type])) { + return $this->_packageInfo[$type]; + } + return false; + } + + /** + * @return array + */ + function getChangelog() + { + if (isset($this->_packageInfo['changelog'])) { + return $this->_packageInfo['changelog']; + } + return false; + } + + function hasDeps() + { + return isset($this->_packageInfo['dependencies']); + } + + function getPackagexmlVersion() + { + if (isset($this->_packageInfo['zendextsrcrelease'])) { + return '2.1'; + } + if (isset($this->_packageInfo['zendextbinrelease'])) { + return '2.1'; + } + return '2.0'; + } + + /** + * @return array|false + */ + function getSourcePackage() + { + if (isset($this->_packageInfo['extbinrelease']) || + isset($this->_packageInfo['zendextbinrelease'])) { + return array('channel' => $this->_packageInfo['srcchannel'], + 'package' => $this->_packageInfo['srcpackage']); + } + return false; + } + + function getBundledPackages() + { + if (isset($this->_packageInfo['bundle'])) { + return $this->_packageInfo['contents']['bundledpackage']; + } + return false; + } + + function getLastModified() + { + if (isset($this->_packageInfo['_lastmodified'])) { + return $this->_packageInfo['_lastmodified']; + } + return false; + } + + /** + * Get the contents of a file listed within the package.xml + * @param string + * @return string + */ + function getFileContents($file) + { + if ($this->_archiveFile == $this->_packageFile) { // unpacked + $dir = dirname($this->_packageFile); + $file = $dir . DIRECTORY_SEPARATOR . $file; + $file = str_replace(array('/', '\\'), + array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); + if (file_exists($file) && is_readable($file)) { + return implode('', file($file)); + } + } else { // tgz + $tar = &new Archive_Tar($this->_archiveFile); + $tar->pushErrorHandling(PEAR_ERROR_RETURN); + if ($file != 'package.xml' && $file != 'package2.xml') { + $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; + } + $file = $tar->extractInString($file); + $tar->popErrorHandling(); + if (PEAR::isError($file)) { + return PEAR::raiseError("Cannot locate file '$file' in archive"); + } + return $file; + } + } + + function &getRW() + { + if (!class_exists('PEAR_PackageFile_v2_rw')) { + require_once 'PEAR/PackageFile/v2/rw.php'; + } + $a = new PEAR_PackageFile_v2_rw; + foreach (get_object_vars($this) as $name => $unused) { + if (!isset($this->$name)) { + continue; + } + if ($name == '_config' || $name == '_logger'|| $name == '_registry' || + $name == '_stack') { + $a->$name = &$this->$name; + } else { + $a->$name = $this->$name; + } + } + return $a; + } + + function &getDefaultGenerator() + { + if (!class_exists('PEAR_PackageFile_Generator_v2')) { + require_once 'PEAR/PackageFile/Generator/v2.php'; + } + $a = &new PEAR_PackageFile_Generator_v2($this); + return $a; + } + + function analyzeSourceCode($file, $string = false) + { + if (!isset($this->_v2Validator) || + !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) { + if (!class_exists('PEAR_PackageFile_v2_Validator')) { + require_once 'PEAR/PackageFile/v2/Validator.php'; + } + $this->_v2Validator = new PEAR_PackageFile_v2_Validator; + } + return $this->_v2Validator->analyzeSourceCode($file, $string); + } + + function validate($state = PEAR_VALIDATE_NORMAL) + { + if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) { + return false; + } + if (!isset($this->_v2Validator) || + !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) { + if (!class_exists('PEAR_PackageFile_v2_Validator')) { + require_once 'PEAR/PackageFile/v2/Validator.php'; + } + $this->_v2Validator = new PEAR_PackageFile_v2_Validator; + } + if (isset($this->_packageInfo['xsdversion'])) { + unset($this->_packageInfo['xsdversion']); + } + return $this->_v2Validator->validate($this, $state); + } + + function getTasksNs() + { + if (!isset($this->_tasksNs)) { + if (isset($this->_packageInfo['attribs'])) { + foreach ($this->_packageInfo['attribs'] as $name => $value) { + if ($value == 'http://pear.php.net/dtd/tasks-1.0') { + $this->_tasksNs = str_replace('xmlns:', '', $name); + break; + } + } + } + } + return $this->_tasksNs; + } + + /** + * Determine whether a task name is a valid task. Custom tasks may be defined + * using subdirectories by putting a "-" in the name, as in + * + * Note that this method will auto-load the task class file and test for the existence + * of the name with "-" replaced by "_" as in PEAR/Task/mycustom/task.php makes class + * PEAR_Task_mycustom_task + * @param string + * @return boolean + */ + function getTask($task) + { + $this->getTasksNs(); + // transform all '-' to '/' and 'tasks:' to '' so tasks:replace becomes replace + $task = str_replace(array($this->_tasksNs . ':', '-'), array('', ' '), $task); + $taskfile = str_replace(' ', '/', ucwords($task)); + $task = str_replace(array(' ', '/'), '_', ucwords($task)); + if (class_exists("PEAR_Task_$task")) { + return "PEAR_Task_$task"; + } + $fp = @fopen("PEAR/Task/$taskfile.php", 'r', true); + if ($fp) { + fclose($fp); + require_once "PEAR/Task/$taskfile.php"; + return "PEAR_Task_$task"; + } + return false; + } + + /** + * Key-friendly array_splice + * @param tagname to splice a value in before + * @param mixed the value to splice in + * @param string the new tag name + */ + function _ksplice($array, $key, $value, $newkey) + { + $offset = array_search($key, array_keys($array)); + $after = array_slice($array, $offset); + $before = array_slice($array, 0, $offset); + $before[$newkey] = $value; + return array_merge($before, $after); + } + + /** + * @param array a list of possible keys, in the order they may occur + * @param mixed contents of the new package.xml tag + * @param string tag name + * @access private + */ + function _insertBefore($array, $keys, $contents, $newkey) + { + foreach ($keys as $key) { + if (isset($array[$key])) { + return $array = $this->_ksplice($array, $key, $contents, $newkey); + } + } + $array[$newkey] = $contents; + return $array; + } + + /** + * @param subsection of {@link $_packageInfo} + * @param array|string tag contents + * @param array format: + *
    +     * array(
    +     *   tagname => array(list of tag names that follow this one),
    +     *   childtagname => array(list of child tag names that follow this one),
    +     * )
    +     * 
    + * + * This allows construction of nested tags + * @access private + */ + function _mergeTag($manip, $contents, $order) + { + if (count($order)) { + foreach ($order as $tag => $curorder) { + if (!isset($manip[$tag])) { + // ensure that the tag is set up + $manip = $this->_insertBefore($manip, $curorder, array(), $tag); + } + if (count($order) > 1) { + $manip[$tag] = $this->_mergeTag($manip[$tag], $contents, array_slice($order, 1)); + return $manip; + } + } + } else { + return $manip; + } + if (is_array($manip[$tag]) && !empty($manip[$tag]) && isset($manip[$tag][0])) { + $manip[$tag][] = $contents; + } else { + if (!count($manip[$tag])) { + $manip[$tag] = $contents; + } else { + $manip[$tag] = array($manip[$tag]); + $manip[$tag][] = $contents; + } + } + return $manip; + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v2/Validator.php b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v2/Validator.php new file mode 100644 index 0000000..cd72738 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v2/Validator.php @@ -0,0 +1,2154 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Validator.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a8 + */ +/** + * Private validation class used by PEAR_PackageFile_v2 - do not use directly, its + * sole purpose is to split up the PEAR/PackageFile/v2.php file to make it smaller + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a8 + * @access private + */ +class PEAR_PackageFile_v2_Validator +{ + /** + * @var array + */ + var $_packageInfo; + /** + * @var PEAR_PackageFile_v2 + */ + var $_pf; + /** + * @var PEAR_ErrorStack + */ + var $_stack; + /** + * @var int + */ + var $_isValid = 0; + /** + * @var int + */ + var $_filesValid = 0; + /** + * @var int + */ + var $_curState = 0; + /** + * @param PEAR_PackageFile_v2 + * @param int + */ + function validate(&$pf, $state = PEAR_VALIDATE_NORMAL) + { + $this->_pf = &$pf; + $this->_curState = $state; + $this->_packageInfo = $this->_pf->getArray(); + $this->_isValid = $this->_pf->_isValid; + $this->_filesValid = $this->_pf->_filesValid; + $this->_stack = &$pf->_stack; + $this->_stack->getErrors(true); + if (($this->_isValid & $state) == $state) { + return true; + } + if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) { + return false; + } + if (!isset($this->_packageInfo['attribs']['version']) || + ($this->_packageInfo['attribs']['version'] != '2.0' && + $this->_packageInfo['attribs']['version'] != '2.1') + ) { + $this->_noPackageVersion(); + } + $structure = + array( + 'name', + 'channel|uri', + '*extends', // can't be multiple, but this works fine + 'summary', + 'description', + '+lead', // these all need content checks + '*developer', + '*contributor', + '*helper', + 'date', + '*time', + 'version', + 'stability', + 'license->?uri->?filesource', + 'notes', + 'contents', //special validation needed + '*compatible', + 'dependencies', //special validation needed + '*usesrole', + '*usestask', // reserve these for 1.4.0a1 to implement + // this will allow a package.xml to gracefully say it + // needs a certain package installed in order to implement a role or task + '*providesextension', + '*srcpackage|*srcuri', + '+phprelease|+extsrcrelease|+extbinrelease|' . + '+zendextsrcrelease|+zendextbinrelease|bundle', //special validation needed + '*changelog', + ); + $test = $this->_packageInfo; + if (isset($test['dependencies']) && + isset($test['dependencies']['required']) && + isset($test['dependencies']['required']['pearinstaller']) && + isset($test['dependencies']['required']['pearinstaller']['min']) && + version_compare('1.9.3', + $test['dependencies']['required']['pearinstaller']['min'], '<') + ) { + $this->_pearVersionTooLow($test['dependencies']['required']['pearinstaller']['min']); + return false; + } + // ignore post-installation array fields + if (array_key_exists('filelist', $test)) { + unset($test['filelist']); + } + if (array_key_exists('_lastmodified', $test)) { + unset($test['_lastmodified']); + } + if (array_key_exists('#binarypackage', $test)) { + unset($test['#binarypackage']); + } + if (array_key_exists('old', $test)) { + unset($test['old']); + } + if (array_key_exists('_lastversion', $test)) { + unset($test['_lastversion']); + } + if (!$this->_stupidSchemaValidate($structure, $test, '')) { + return false; + } + if (empty($this->_packageInfo['name'])) { + $this->_tagCannotBeEmpty('name'); + } + $test = isset($this->_packageInfo['uri']) ? 'uri' :'channel'; + if (empty($this->_packageInfo[$test])) { + $this->_tagCannotBeEmpty($test); + } + if (is_array($this->_packageInfo['license']) && + (!isset($this->_packageInfo['license']['_content']) || + empty($this->_packageInfo['license']['_content']))) { + $this->_tagCannotBeEmpty('license'); + } elseif (empty($this->_packageInfo['license'])) { + $this->_tagCannotBeEmpty('license'); + } + if (empty($this->_packageInfo['summary'])) { + $this->_tagCannotBeEmpty('summary'); + } + if (empty($this->_packageInfo['description'])) { + $this->_tagCannotBeEmpty('description'); + } + if (empty($this->_packageInfo['date'])) { + $this->_tagCannotBeEmpty('date'); + } + if (empty($this->_packageInfo['notes'])) { + $this->_tagCannotBeEmpty('notes'); + } + if (isset($this->_packageInfo['time']) && empty($this->_packageInfo['time'])) { + $this->_tagCannotBeEmpty('time'); + } + if (isset($this->_packageInfo['dependencies'])) { + $this->_validateDependencies(); + } + if (isset($this->_packageInfo['compatible'])) { + $this->_validateCompatible(); + } + if (!isset($this->_packageInfo['bundle'])) { + if (empty($this->_packageInfo['contents'])) { + $this->_tagCannotBeEmpty('contents'); + } + if (!isset($this->_packageInfo['contents']['dir'])) { + $this->_filelistMustContainDir('contents'); + return false; + } + if (isset($this->_packageInfo['contents']['file'])) { + $this->_filelistCannotContainFile('contents'); + return false; + } + } + $this->_validateMaintainers(); + $this->_validateStabilityVersion(); + $fail = false; + if (array_key_exists('usesrole', $this->_packageInfo)) { + $roles = $this->_packageInfo['usesrole']; + if (!is_array($roles) || !isset($roles[0])) { + $roles = array($roles); + } + foreach ($roles as $role) { + if (!isset($role['role'])) { + $this->_usesroletaskMustHaveRoleTask('usesrole', 'role'); + $fail = true; + } else { + if (!isset($role['channel'])) { + if (!isset($role['uri'])) { + $this->_usesroletaskMustHaveChannelOrUri($role['role'], 'usesrole'); + $fail = true; + } + } elseif (!isset($role['package'])) { + $this->_usesroletaskMustHavePackage($role['role'], 'usesrole'); + $fail = true; + } + } + } + } + if (array_key_exists('usestask', $this->_packageInfo)) { + $roles = $this->_packageInfo['usestask']; + if (!is_array($roles) || !isset($roles[0])) { + $roles = array($roles); + } + foreach ($roles as $role) { + if (!isset($role['task'])) { + $this->_usesroletaskMustHaveRoleTask('usestask', 'task'); + $fail = true; + } else { + if (!isset($role['channel'])) { + if (!isset($role['uri'])) { + $this->_usesroletaskMustHaveChannelOrUri($role['task'], 'usestask'); + $fail = true; + } + } elseif (!isset($role['package'])) { + $this->_usesroletaskMustHavePackage($role['task'], 'usestask'); + $fail = true; + } + } + } + } + + if ($fail) { + return false; + } + + $list = $this->_packageInfo['contents']; + if (isset($list['dir']) && is_array($list['dir']) && isset($list['dir'][0])) { + $this->_multipleToplevelDirNotAllowed(); + return $this->_isValid = 0; + } + + $this->_validateFilelist(); + $this->_validateRelease(); + if (!$this->_stack->hasErrors()) { + $chan = $this->_pf->_registry->getChannel($this->_pf->getChannel(), true); + if (PEAR::isError($chan)) { + $this->_unknownChannel($this->_pf->getChannel()); + } else { + $valpack = $chan->getValidationPackage(); + // for channel validator packages, always use the default PEAR validator. + // otherwise, they can't be installed or packaged + $validator = $chan->getValidationObject($this->_pf->getPackage()); + if (!$validator) { + $this->_stack->push(__FUNCTION__, 'error', + array('channel' => $chan->getName(), + 'package' => $this->_pf->getPackage(), + 'name' => $valpack['_content'], + 'version' => $valpack['attribs']['version']), + 'package "%channel%/%package%" cannot be properly validated without ' . + 'validation package "%channel%/%name%-%version%"'); + return $this->_isValid = 0; + } + $validator->setPackageFile($this->_pf); + $validator->validate($state); + $failures = $validator->getFailures(); + foreach ($failures['errors'] as $error) { + $this->_stack->push(__FUNCTION__, 'error', $error, + 'Channel validator error: field "%field%" - %reason%'); + } + foreach ($failures['warnings'] as $warning) { + $this->_stack->push(__FUNCTION__, 'warning', $warning, + 'Channel validator warning: field "%field%" - %reason%'); + } + } + } + + $this->_pf->_isValid = $this->_isValid = !$this->_stack->hasErrors('error'); + if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$this->_filesValid) { + if ($this->_pf->getPackageType() == 'bundle') { + if ($this->_analyzeBundledPackages()) { + $this->_filesValid = $this->_pf->_filesValid = true; + } else { + $this->_pf->_isValid = $this->_isValid = 0; + } + } else { + if (!$this->_analyzePhpFiles()) { + $this->_pf->_isValid = $this->_isValid = 0; + } else { + $this->_filesValid = $this->_pf->_filesValid = true; + } + } + } + + if ($this->_isValid) { + return $this->_pf->_isValid = $this->_isValid = $state; + } + + return $this->_pf->_isValid = $this->_isValid = 0; + } + + function _stupidSchemaValidate($structure, $xml, $root) + { + if (!is_array($xml)) { + $xml = array(); + } + $keys = array_keys($xml); + reset($keys); + $key = current($keys); + while ($key == 'attribs' || $key == '_contents') { + $key = next($keys); + } + $unfoundtags = $optionaltags = array(); + $ret = true; + $mismatch = false; + foreach ($structure as $struc) { + if ($key) { + $tag = $xml[$key]; + } + $test = $this->_processStructure($struc); + if (isset($test['choices'])) { + $loose = true; + foreach ($test['choices'] as $choice) { + if ($key == $choice['tag']) { + $key = next($keys); + while ($key == 'attribs' || $key == '_contents') { + $key = next($keys); + } + $unfoundtags = $optionaltags = array(); + $mismatch = false; + if ($key && $key != $choice['tag'] && isset($choice['multiple'])) { + $unfoundtags[] = $choice['tag']; + $optionaltags[] = $choice['tag']; + if ($key) { + $mismatch = true; + } + } + $ret &= $this->_processAttribs($choice, $tag, $root); + continue 2; + } else { + $unfoundtags[] = $choice['tag']; + $mismatch = true; + } + if (!isset($choice['multiple']) || $choice['multiple'] != '*') { + $loose = false; + } else { + $optionaltags[] = $choice['tag']; + } + } + if (!$loose) { + $this->_invalidTagOrder($unfoundtags, $key, $root); + return false; + } + } else { + if ($key != $test['tag']) { + if (isset($test['multiple']) && $test['multiple'] != '*') { + $unfoundtags[] = $test['tag']; + $this->_invalidTagOrder($unfoundtags, $key, $root); + return false; + } else { + if ($key) { + $mismatch = true; + } + $unfoundtags[] = $test['tag']; + $optionaltags[] = $test['tag']; + } + if (!isset($test['multiple'])) { + $this->_invalidTagOrder($unfoundtags, $key, $root); + return false; + } + continue; + } else { + $unfoundtags = $optionaltags = array(); + $mismatch = false; + } + $key = next($keys); + while ($key == 'attribs' || $key == '_contents') { + $key = next($keys); + } + if ($key && $key != $test['tag'] && isset($test['multiple'])) { + $unfoundtags[] = $test['tag']; + $optionaltags[] = $test['tag']; + $mismatch = true; + } + $ret &= $this->_processAttribs($test, $tag, $root); + continue; + } + } + if (!$mismatch && count($optionaltags)) { + // don't error out on any optional tags + $unfoundtags = array_diff($unfoundtags, $optionaltags); + } + if (count($unfoundtags)) { + $this->_invalidTagOrder($unfoundtags, $key, $root); + } elseif ($key) { + // unknown tags + $this->_invalidTagOrder('*no tags allowed here*', $key, $root); + while ($key = next($keys)) { + $this->_invalidTagOrder('*no tags allowed here*', $key, $root); + } + } + return $ret; + } + + function _processAttribs($choice, $tag, $context) + { + if (isset($choice['attribs'])) { + if (!is_array($tag)) { + $tag = array($tag); + } + $tags = $tag; + if (!isset($tags[0])) { + $tags = array($tags); + } + $ret = true; + foreach ($tags as $i => $tag) { + if (!is_array($tag) || !isset($tag['attribs'])) { + foreach ($choice['attribs'] as $attrib) { + if ($attrib{0} != '?') { + $ret &= $this->_tagHasNoAttribs($choice['tag'], + $context); + continue 2; + } + } + } + foreach ($choice['attribs'] as $attrib) { + if ($attrib{0} != '?') { + if (!isset($tag['attribs'][$attrib])) { + $ret &= $this->_tagMissingAttribute($choice['tag'], + $attrib, $context); + } + } + } + } + return $ret; + } + return true; + } + + function _processStructure($key) + { + $ret = array(); + if (count($pieces = explode('|', $key)) > 1) { + $ret['choices'] = array(); + foreach ($pieces as $piece) { + $ret['choices'][] = $this->_processStructure($piece); + } + return $ret; + } + $multi = $key{0}; + if ($multi == '+' || $multi == '*') { + $ret['multiple'] = $key{0}; + $key = substr($key, 1); + } + if (count($attrs = explode('->', $key)) > 1) { + $ret['tag'] = array_shift($attrs); + $ret['attribs'] = $attrs; + } else { + $ret['tag'] = $key; + } + return $ret; + } + + function _validateStabilityVersion() + { + $structure = array('release', 'api'); + $a = $this->_stupidSchemaValidate($structure, $this->_packageInfo['version'], ''); + $a &= $this->_stupidSchemaValidate($structure, $this->_packageInfo['stability'], ''); + if ($a) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $this->_packageInfo['version']['release'])) { + $this->_invalidVersion('release', $this->_packageInfo['version']['release']); + } + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $this->_packageInfo['version']['api'])) { + $this->_invalidVersion('api', $this->_packageInfo['version']['api']); + } + if (!in_array($this->_packageInfo['stability']['release'], + array('snapshot', 'devel', 'alpha', 'beta', 'stable'))) { + $this->_invalidState('release', $this->_packageInfo['stability']['release']); + } + if (!in_array($this->_packageInfo['stability']['api'], + array('devel', 'alpha', 'beta', 'stable'))) { + $this->_invalidState('api', $this->_packageInfo['stability']['api']); + } + } + } + + function _validateMaintainers() + { + $structure = + array( + 'name', + 'user', + 'email', + 'active', + ); + foreach (array('lead', 'developer', 'contributor', 'helper') as $type) { + if (!isset($this->_packageInfo[$type])) { + continue; + } + if (isset($this->_packageInfo[$type][0])) { + foreach ($this->_packageInfo[$type] as $lead) { + $this->_stupidSchemaValidate($structure, $lead, '<' . $type . '>'); + } + } else { + $this->_stupidSchemaValidate($structure, $this->_packageInfo[$type], + '<' . $type . '>'); + } + } + } + + function _validatePhpDep($dep, $installcondition = false) + { + $structure = array( + 'min', + '*max', + '*exclude', + ); + $type = $installcondition ? '' : ''; + $this->_stupidSchemaValidate($structure, $dep, $type); + if (isset($dep['min'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', + $dep['min'])) { + $this->_invalidVersion($type . '', $dep['min']); + } + } + if (isset($dep['max'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', + $dep['max'])) { + $this->_invalidVersion($type . '', $dep['max']); + } + } + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + foreach ($dep['exclude'] as $exclude) { + if (!preg_match( + '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', + $exclude)) { + $this->_invalidVersion($type . '', $exclude); + } + } + } + } + + function _validatePearinstallerDep($dep) + { + $structure = array( + 'min', + '*max', + '*recommended', + '*exclude', + ); + $this->_stupidSchemaValidate($structure, $dep, ''); + if (isset($dep['min'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['min'])) { + $this->_invalidVersion('', + $dep['min']); + } + } + if (isset($dep['max'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['max'])) { + $this->_invalidVersion('', + $dep['max']); + } + } + if (isset($dep['recommended'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['recommended'])) { + $this->_invalidVersion('', + $dep['recommended']); + } + } + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + foreach ($dep['exclude'] as $exclude) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $exclude)) { + $this->_invalidVersion('', + $exclude); + } + } + } + } + + function _validatePackageDep($dep, $group, $type = '') + { + if (isset($dep['uri'])) { + if (isset($dep['conflicts'])) { + $structure = array( + 'name', + 'uri', + 'conflicts', + '*providesextension', + ); + } else { + $structure = array( + 'name', + 'uri', + '*providesextension', + ); + } + } else { + if (isset($dep['conflicts'])) { + $structure = array( + 'name', + 'channel', + '*min', + '*max', + '*exclude', + 'conflicts', + '*providesextension', + ); + } else { + $structure = array( + 'name', + 'channel', + '*min', + '*max', + '*recommended', + '*exclude', + '*nodefault', + '*providesextension', + ); + } + } + if (isset($dep['name'])) { + $type .= '' . $dep['name'] . ''; + } + $this->_stupidSchemaValidate($structure, $dep, '' . $group . $type); + if (isset($dep['uri']) && (isset($dep['min']) || isset($dep['max']) || + isset($dep['recommended']) || isset($dep['exclude']))) { + $this->_uriDepsCannotHaveVersioning('' . $group . $type); + } + if (isset($dep['channel']) && strtolower($dep['channel']) == '__uri') { + $this->_DepchannelCannotBeUri('' . $group . $type); + } + if (isset($dep['min'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['min'])) { + $this->_invalidVersion('' . $group . $type . '', $dep['min']); + } + } + if (isset($dep['max'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['max'])) { + $this->_invalidVersion('' . $group . $type . '', $dep['max']); + } + } + if (isset($dep['recommended'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['recommended'])) { + $this->_invalidVersion('' . $group . $type . '', + $dep['recommended']); + } + } + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + foreach ($dep['exclude'] as $exclude) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $exclude)) { + $this->_invalidVersion('' . $group . $type . '', + $exclude); + } + } + } + } + + function _validateSubpackageDep($dep, $group) + { + $this->_validatePackageDep($dep, $group, ''); + if (isset($dep['providesextension'])) { + $this->_subpackageCannotProvideExtension(isset($dep['name']) ? $dep['name'] : ''); + } + if (isset($dep['conflicts'])) { + $this->_subpackagesCannotConflict(isset($dep['name']) ? $dep['name'] : ''); + } + } + + function _validateExtensionDep($dep, $group = false, $installcondition = false) + { + if (isset($dep['conflicts'])) { + $structure = array( + 'name', + '*min', + '*max', + '*exclude', + 'conflicts', + ); + } else { + $structure = array( + 'name', + '*min', + '*max', + '*recommended', + '*exclude', + ); + } + if ($installcondition) { + $type = ''; + } else { + $type = '' . $group . ''; + } + if (isset($dep['name'])) { + $type .= '' . $dep['name'] . ''; + } + $this->_stupidSchemaValidate($structure, $dep, $type); + if (isset($dep['min'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['min'])) { + $this->_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '' : ''; + if ($this->_stupidSchemaValidate($structure, $dep, $type)) { + if ($dep['name'] == '*') { + if (array_key_exists('conflicts', $dep)) { + $this->_cannotConflictWithAllOs($type); + } + } + } + } + + function _validateArchDep($dep, $installcondition = false) + { + $structure = array( + 'pattern', + '*conflicts', + ); + $type = $installcondition ? '' : ''; + $this->_stupidSchemaValidate($structure, $dep, $type); + } + + function _validateInstallConditions($cond, $release) + { + $structure = array( + '*php', + '*extension', + '*os', + '*arch', + ); + if (!$this->_stupidSchemaValidate($structure, + $cond, $release)) { + return false; + } + foreach (array('php', 'extension', 'os', 'arch') as $type) { + if (isset($cond[$type])) { + $iter = $cond[$type]; + if (!is_array($iter) || !isset($iter[0])) { + $iter = array($iter); + } + foreach ($iter as $package) { + if ($type == 'extension') { + $this->{"_validate{$type}Dep"}($package, false, true); + } else { + $this->{"_validate{$type}Dep"}($package, true); + } + } + } + } + } + + function _validateDependencies() + { + $structure = array( + 'required', + '*optional', + '*group->name->hint' + ); + if (!$this->_stupidSchemaValidate($structure, + $this->_packageInfo['dependencies'], '')) { + return false; + } + foreach (array('required', 'optional') as $simpledep) { + if (isset($this->_packageInfo['dependencies'][$simpledep])) { + if ($simpledep == 'optional') { + $structure = array( + '*package', + '*subpackage', + '*extension', + ); + } else { + $structure = array( + 'php', + 'pearinstaller', + '*package', + '*subpackage', + '*extension', + '*os', + '*arch', + ); + } + if ($this->_stupidSchemaValidate($structure, + $this->_packageInfo['dependencies'][$simpledep], + "<$simpledep>")) { + foreach (array('package', 'subpackage', 'extension') as $type) { + if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) { + $iter = $this->_packageInfo['dependencies'][$simpledep][$type]; + if (!isset($iter[0])) { + $iter = array($iter); + } + foreach ($iter as $package) { + if ($type != 'extension') { + if (isset($package['uri'])) { + if (isset($package['channel'])) { + $this->_UrlOrChannel($type, + $package['name']); + } + } else { + if (!isset($package['channel'])) { + $this->_NoChannel($type, $package['name']); + } + } + } + $this->{"_validate{$type}Dep"}($package, "<$simpledep>"); + } + } + } + if ($simpledep == 'optional') { + continue; + } + foreach (array('php', 'pearinstaller', 'os', 'arch') as $type) { + if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) { + $iter = $this->_packageInfo['dependencies'][$simpledep][$type]; + if (!isset($iter[0])) { + $iter = array($iter); + } + foreach ($iter as $package) { + $this->{"_validate{$type}Dep"}($package); + } + } + } + } + } + } + if (isset($this->_packageInfo['dependencies']['group'])) { + $groups = $this->_packageInfo['dependencies']['group']; + if (!isset($groups[0])) { + $groups = array($groups); + } + $structure = array( + '*package', + '*subpackage', + '*extension', + ); + foreach ($groups as $group) { + if ($this->_stupidSchemaValidate($structure, $group, '')) { + if (!PEAR_Validate::validGroupName($group['attribs']['name'])) { + $this->_invalidDepGroupName($group['attribs']['name']); + } + foreach (array('package', 'subpackage', 'extension') as $type) { + if (isset($group[$type])) { + $iter = $group[$type]; + if (!isset($iter[0])) { + $iter = array($iter); + } + foreach ($iter as $package) { + if ($type != 'extension') { + if (isset($package['uri'])) { + if (isset($package['channel'])) { + $this->_UrlOrChannelGroup($type, + $package['name'], + $group['name']); + } + } else { + if (!isset($package['channel'])) { + $this->_NoChannelGroup($type, + $package['name'], + $group['name']); + } + } + } + $this->{"_validate{$type}Dep"}($package, ''); + } + } + } + } + } + } + } + + function _validateCompatible() + { + $compat = $this->_packageInfo['compatible']; + if (!isset($compat[0])) { + $compat = array($compat); + } + $required = array('name', 'channel', 'min', 'max', '*exclude'); + foreach ($compat as $package) { + $type = ''; + if (is_array($package) && array_key_exists('name', $package)) { + $type .= '' . $package['name'] . ''; + } + $this->_stupidSchemaValidate($required, $package, $type); + if (is_array($package) && array_key_exists('min', $package)) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $package['min'])) { + $this->_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_NoBundledPackages(); + } + if (!is_array($list['bundledpackage']) || !isset($list['bundledpackage'][0])) { + return $this->_AtLeast2BundledPackages(); + } + foreach ($list['bundledpackage'] as $package) { + if (!is_string($package)) { + $this->_bundledPackagesMustBeFilename(); + } + } + } + + function _validateFilelist($list = false, $allowignore = false, $dirs = '') + { + $iscontents = false; + if (!$list) { + $iscontents = true; + $list = $this->_packageInfo['contents']; + if (isset($this->_packageInfo['bundle'])) { + return $this->_validateBundle($list); + } + } + if ($allowignore) { + $struc = array( + '*install->name->as', + '*ignore->name' + ); + } else { + $struc = array( + '*dir->name->?baseinstalldir', + '*file->name->role->?baseinstalldir->?md5sum' + ); + if (isset($list['dir']) && isset($list['file'])) { + // stave off validation errors without requiring a set order. + $_old = $list; + if (isset($list['attribs'])) { + $list = array('attribs' => $_old['attribs']); + } + $list['dir'] = $_old['dir']; + $list['file'] = $_old['file']; + } + } + if (!isset($list['attribs']) || !isset($list['attribs']['name'])) { + $unknown = $allowignore ? '' : ''; + $dirname = $iscontents ? '' : $unknown; + } else { + $dirname = ''; + if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', + str_replace('\\', '/', $list['attribs']['name']))) { + // file contains .. parent directory or . cur directory + $this->_invalidDirName($list['attribs']['name']); + } + } + $res = $this->_stupidSchemaValidate($struc, $list, $dirname); + if ($allowignore && $res) { + $ignored_or_installed = array(); + $this->_pf->getFilelist(); + $fcontents = $this->_pf->getContents(); + $filelist = array(); + if (!isset($fcontents['dir']['file'][0])) { + $fcontents['dir']['file'] = array($fcontents['dir']['file']); + } + foreach ($fcontents['dir']['file'] as $file) { + $filelist[$file['attribs']['name']] = true; + } + if (isset($list['install'])) { + if (!isset($list['install'][0])) { + $list['install'] = array($list['install']); + } + foreach ($list['install'] as $file) { + if (!isset($filelist[$file['attribs']['name']])) { + $this->_notInContents($file['attribs']['name'], 'install'); + continue; + } + if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) { + $this->_multipleInstallAs($file['attribs']['name']); + } + if (!isset($ignored_or_installed[$file['attribs']['name']])) { + $ignored_or_installed[$file['attribs']['name']] = array(); + } + $ignored_or_installed[$file['attribs']['name']][] = 1; + if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', + str_replace('\\', '/', $file['attribs']['as']))) { + // file contains .. parent directory or . cur directory references + $this->_invalidFileInstallAs($file['attribs']['name'], + $file['attribs']['as']); + } + } + } + if (isset($list['ignore'])) { + if (!isset($list['ignore'][0])) { + $list['ignore'] = array($list['ignore']); + } + foreach ($list['ignore'] as $file) { + if (!isset($filelist[$file['attribs']['name']])) { + $this->_notInContents($file['attribs']['name'], 'ignore'); + continue; + } + if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) { + $this->_ignoreAndInstallAs($file['attribs']['name']); + } + } + } + } + if (!$allowignore && isset($list['file'])) { + if (is_string($list['file'])) { + $this->_oldStyleFileNotAllowed(); + return false; + } + if (!isset($list['file'][0])) { + // single file + $list['file'] = array($list['file']); + } + foreach ($list['file'] as $i => $file) + { + if (isset($file['attribs']) && isset($file['attribs']['name'])) { + if ($file['attribs']['name']{0} == '.' && + $file['attribs']['name']{1} == '/') { + // name is something like "./doc/whatever.txt" + $this->_invalidFileName($file['attribs']['name'], $dirname); + } + if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', + str_replace('\\', '/', $file['attribs']['name']))) { + // file contains .. parent directory or . cur directory + $this->_invalidFileName($file['attribs']['name'], $dirname); + } + } + if (isset($file['attribs']) && isset($file['attribs']['role'])) { + if (!$this->_validateRole($file['attribs']['role'])) { + if (isset($this->_packageInfo['usesrole'])) { + $roles = $this->_packageInfo['usesrole']; + if (!isset($roles[0])) { + $roles = array($roles); + } + foreach ($roles as $role) { + if ($role['role'] = $file['attribs']['role']) { + $msg = 'This package contains role "%role%" and requires ' . + 'package "%package%" to be used'; + if (isset($role['uri'])) { + $params = array('role' => $role['role'], + 'package' => $role['uri']); + } else { + $params = array('role' => $role['role'], + 'package' => $this->_pf->_registry-> + parsedPackageNameToString(array('package' => + $role['package'], 'channel' => $role['channel']), + true)); + } + $this->_stack->push('_mustInstallRole', 'error', $params, $msg); + } + } + } + $this->_invalidFileRole($file['attribs']['name'], + $dirname, $file['attribs']['role']); + } + } + if (!isset($file['attribs'])) { + continue; + } + $save = $file['attribs']; + if ($dirs) { + $save['name'] = $dirs . '/' . $save['name']; + } + unset($file['attribs']); + if (count($file) && $this->_curState != PEAR_VALIDATE_DOWNLOADING) { // has tasks + foreach ($file as $task => $value) { + if ($tagClass = $this->_pf->getTask($task)) { + if (!is_array($value) || !isset($value[0])) { + $value = array($value); + } + foreach ($value as $v) { + $ret = call_user_func(array($tagClass, 'validateXml'), + $this->_pf, $v, $this->_pf->_config, $save); + if (is_array($ret)) { + $this->_invalidTask($task, $ret, isset($save['name']) ? + $save['name'] : ''); + } + } + } else { + if (isset($this->_packageInfo['usestask'])) { + $roles = $this->_packageInfo['usestask']; + if (!isset($roles[0])) { + $roles = array($roles); + } + foreach ($roles as $role) { + if ($role['task'] = $task) { + $msg = 'This package contains task "%task%" and requires ' . + 'package "%package%" to be used'; + if (isset($role['uri'])) { + $params = array('task' => $role['task'], + 'package' => $role['uri']); + } else { + $params = array('task' => $role['task'], + 'package' => $this->_pf->_registry-> + parsedPackageNameToString(array('package' => + $role['package'], 'channel' => $role['channel']), + true)); + } + $this->_stack->push('_mustInstallTask', 'error', + $params, $msg); + } + } + } + $this->_unknownTask($task, $save['name']); + } + } + } + } + } + if (isset($list['ignore'])) { + if (!$allowignore) { + $this->_ignoreNotAllowed('ignore'); + } + } + if (isset($list['install'])) { + if (!$allowignore) { + $this->_ignoreNotAllowed('install'); + } + } + if (isset($list['file'])) { + if ($allowignore) { + $this->_fileNotAllowed('file'); + } + } + if (isset($list['dir'])) { + if ($allowignore) { + $this->_fileNotAllowed('dir'); + } else { + if (!isset($list['dir'][0])) { + $list['dir'] = array($list['dir']); + } + foreach ($list['dir'] as $dir) { + if (isset($dir['attribs']) && isset($dir['attribs']['name'])) { + if ($dir['attribs']['name'] == '/' || + !isset($this->_packageInfo['contents']['dir']['dir'])) { + // always use nothing if the filelist has already been flattened + $newdirs = ''; + } elseif ($dirs == '') { + $newdirs = $dir['attribs']['name']; + } else { + $newdirs = $dirs . '/' . $dir['attribs']['name']; + } + } else { + $newdirs = $dirs; + } + $this->_validateFilelist($dir, $allowignore, $newdirs); + } + } + } + } + + function _validateRelease() + { + if (isset($this->_packageInfo['phprelease'])) { + $release = 'phprelease'; + if (isset($this->_packageInfo['providesextension'])) { + $this->_cannotProvideExtension($release); + } + if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { + $this->_cannotHaveSrcpackage($release); + } + $releases = $this->_packageInfo['phprelease']; + if (!is_array($releases)) { + return true; + } + if (!isset($releases[0])) { + $releases = array($releases); + } + foreach ($releases as $rel) { + $this->_stupidSchemaValidate(array( + '*installconditions', + '*filelist', + ), $rel, ''); + } + } + foreach (array('', 'zend') as $prefix) { + $releasetype = $prefix . 'extsrcrelease'; + if (isset($this->_packageInfo[$releasetype])) { + $release = $releasetype; + if (!isset($this->_packageInfo['providesextension'])) { + $this->_mustProvideExtension($release); + } + if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { + $this->_cannotHaveSrcpackage($release); + } + $releases = $this->_packageInfo[$releasetype]; + if (!is_array($releases)) { + return true; + } + if (!isset($releases[0])) { + $releases = array($releases); + } + foreach ($releases as $rel) { + $this->_stupidSchemaValidate(array( + '*installconditions', + '*configureoption->name->prompt->?default', + '*binarypackage', + '*filelist', + ), $rel, '<' . $releasetype . '>'); + if (isset($rel['binarypackage'])) { + if (!is_array($rel['binarypackage']) || !isset($rel['binarypackage'][0])) { + $rel['binarypackage'] = array($rel['binarypackage']); + } + foreach ($rel['binarypackage'] as $bin) { + if (!is_string($bin)) { + $this->_binaryPackageMustBePackagename(); + } + } + } + } + } + $releasetype = 'extbinrelease'; + if (isset($this->_packageInfo[$releasetype])) { + $release = $releasetype; + if (!isset($this->_packageInfo['providesextension'])) { + $this->_mustProvideExtension($release); + } + if (isset($this->_packageInfo['channel']) && + !isset($this->_packageInfo['srcpackage'])) { + $this->_mustSrcPackage($release); + } + if (isset($this->_packageInfo['uri']) && !isset($this->_packageInfo['srcuri'])) { + $this->_mustSrcuri($release); + } + $releases = $this->_packageInfo[$releasetype]; + if (!is_array($releases)) { + return true; + } + if (!isset($releases[0])) { + $releases = array($releases); + } + foreach ($releases as $rel) { + $this->_stupidSchemaValidate(array( + '*installconditions', + '*filelist', + ), $rel, '<' . $releasetype . '>'); + } + } + } + if (isset($this->_packageInfo['bundle'])) { + $release = 'bundle'; + if (isset($this->_packageInfo['providesextension'])) { + $this->_cannotProvideExtension($release); + } + if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { + $this->_cannotHaveSrcpackage($release); + } + $releases = $this->_packageInfo['bundle']; + if (!is_array($releases) || !isset($releases[0])) { + $releases = array($releases); + } + foreach ($releases as $rel) { + $this->_stupidSchemaValidate(array( + '*installconditions', + '*filelist', + ), $rel, ''); + } + } + foreach ($releases as $rel) { + if (is_array($rel) && array_key_exists('installconditions', $rel)) { + $this->_validateInstallConditions($rel['installconditions'], + "<$release>"); + } + if (is_array($rel) && array_key_exists('filelist', $rel)) { + if ($rel['filelist']) { + + $this->_validateFilelist($rel['filelist'], true); + } + } + } + } + + /** + * This is here to allow role extension through plugins + * @param string + */ + function _validateRole($role) + { + return in_array($role, PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())); + } + + function _pearVersionTooLow($version) + { + $this->_stack->push(__FUNCTION__, 'error', + array('version' => $version), + 'This package.xml requires PEAR version %version% to parse properly, we are ' . + 'version 1.9.3'); + } + + function _invalidTagOrder($oktags, $actual, $root) + { + $this->_stack->push(__FUNCTION__, 'error', + array('oktags' => $oktags, 'actual' => $actual, 'root' => $root), + 'Invalid tag order in %root%, found <%actual%> expected one of "%oktags%"'); + } + + function _ignoreNotAllowed($type) + { + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), + '<%type%> is not allowed inside global , only inside ' . + '//, use and only'); + } + + function _fileNotAllowed($type) + { + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), + '<%type%> is not allowed inside release , only inside ' . + ', use and only'); + } + + function _oldStyleFileNotAllowed() + { + $this->_stack->push(__FUNCTION__, 'error', array(), + 'Old-style name is not allowed. Use' . + ''); + } + + function _tagMissingAttribute($tag, $attr, $context) + { + $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, + 'attribute' => $attr, 'context' => $context), + 'tag <%tag%> in context "%context%" has no attribute "%attribute%"'); + } + + function _tagHasNoAttribs($tag, $context) + { + $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, + 'context' => $context), + 'tag <%tag%> has no attributes in context "%context%"'); + } + + function _invalidInternalStructure() + { + $this->_stack->push(__FUNCTION__, 'exception', array(), + 'internal array was not generated by compatible parser, or extreme parser error, cannot continue'); + } + + function _invalidFileRole($file, $dir, $role) + { + $this->_stack->push(__FUNCTION__, 'error', array( + 'file' => $file, 'dir' => $dir, 'role' => $role, + 'roles' => PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())), + 'File "%file%" in directory "%dir%" has invalid role "%role%", should be one of %roles%'); + } + + function _invalidFileName($file, $dir) + { + $this->_stack->push(__FUNCTION__, 'error', array( + 'file' => $file), + 'File "%file%" in directory "%dir%" cannot begin with "./" or contain ".."'); + } + + function _invalidFileInstallAs($file, $as) + { + $this->_stack->push(__FUNCTION__, 'error', array( + 'file' => $file, 'as' => $as), + 'File "%file%" cannot contain "./" or contain ".."'); + } + + function _invalidDirName($dir) + { + $this->_stack->push(__FUNCTION__, 'error', array( + 'dir' => $file), + 'Directory "%dir%" cannot begin with "./" or contain ".."'); + } + + function _filelistCannotContainFile($filelist) + { + $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist), + '<%tag%> can only contain , contains . Use ' . + ' as the first dir element'); + } + + function _filelistMustContainDir($filelist) + { + $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist), + '<%tag%> must contain . Use as the ' . + 'first dir element'); + } + + function _tagCannotBeEmpty($tag) + { + $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag), + '<%tag%> cannot be empty (<%tag%/>)'); + } + + function _UrlOrChannel($type, $name) + { + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, + 'name' => $name), + 'Required dependency <%type%> "%name%" can have either url OR ' . + 'channel attributes, and not both'); + } + + function _NoChannel($type, $name) + { + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, + 'name' => $name), + 'Required dependency <%type%> "%name%" must have either url OR ' . + 'channel attributes'); + } + + function _UrlOrChannelGroup($type, $name, $group) + { + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, + 'name' => $name, 'group' => $group), + 'Group "%group%" dependency <%type%> "%name%" can have either url OR ' . + 'channel attributes, and not both'); + } + + function _NoChannelGroup($type, $name, $group) + { + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, + 'name' => $name, 'group' => $group), + 'Group "%group%" dependency <%type%> "%name%" must have either url OR ' . + 'channel attributes'); + } + + function _unknownChannel($channel) + { + $this->_stack->push(__FUNCTION__, 'error', array('channel' => $channel), + 'Unknown channel "%channel%"'); + } + + function _noPackageVersion() + { + $this->_stack->push(__FUNCTION__, 'error', array(), + 'package.xml tag has no version attribute, or version is not 2.0'); + } + + function _NoBundledPackages() + { + $this->_stack->push(__FUNCTION__, 'error', array(), + 'No tag was found in , required for bundle packages'); + } + + function _AtLeast2BundledPackages() + { + $this->_stack->push(__FUNCTION__, 'error', array(), + 'At least 2 packages must be bundled in a bundle package'); + } + + function _ChannelOrUri($name) + { + $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), + 'Bundled package "%name%" can have either a uri or a channel, not both'); + } + + function _noChildTag($child, $tag) + { + $this->_stack->push(__FUNCTION__, 'error', array('child' => $child, 'tag' => $tag), + 'Tag <%tag%> is missing child tag <%child%>'); + } + + function _invalidVersion($type, $value) + { + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value), + 'Version type <%type%> is not a valid version (%value%)'); + } + + function _invalidState($type, $value) + { + $states = array('stable', 'beta', 'alpha', 'devel'); + if ($type != 'api') { + $states[] = 'snapshot'; + } + if (strtolower($value) == 'rc') { + $this->_stack->push(__FUNCTION__, 'error', + array('version' => $this->_packageInfo['version']['release']), + 'RC is not a state, it is a version postfix, try %version%RC1, stability beta'); + } + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value, + 'types' => $states), + 'Stability type <%type%> is not a valid stability (%value%), must be one of ' . + '%types%'); + } + + function _invalidTask($task, $ret, $file) + { + switch ($ret[0]) { + case PEAR_TASK_ERROR_MISSING_ATTRIB : + $info = array('attrib' => $ret[1], 'task' => $task, 'file' => $file); + $msg = 'task <%task%> is missing attribute "%attrib%" in file %file%'; + break; + case PEAR_TASK_ERROR_NOATTRIBS : + $info = array('task' => $task, 'file' => $file); + $msg = 'task <%task%> has no attributes in file %file%'; + break; + case PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE : + $info = array('attrib' => $ret[1], 'values' => $ret[3], + 'was' => $ret[2], 'task' => $task, 'file' => $file); + $msg = 'task <%task%> attribute "%attrib%" has the wrong value "%was%" '. + 'in file %file%, expecting one of "%values%"'; + break; + case PEAR_TASK_ERROR_INVALID : + $info = array('reason' => $ret[1], 'task' => $task, 'file' => $file); + $msg = 'task <%task%> in file %file% is invalid because of "%reason%"'; + break; + } + $this->_stack->push(__FUNCTION__, 'error', $info, $msg); + } + + function _unknownTask($task, $file) + { + $this->_stack->push(__FUNCTION__, 'error', array('task' => $task, 'file' => $file), + 'Unknown task "%task%" passed in file '); + } + + function _subpackageCannotProvideExtension($name) + { + $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), + 'Subpackage dependency "%name%" cannot use , ' . + 'only package dependencies can use this tag'); + } + + function _subpackagesCannotConflict($name) + { + $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), + 'Subpackage dependency "%name%" cannot use , ' . + 'only package dependencies can use this tag'); + } + + function _cannotProvideExtension($release) + { + $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), + '<%release%> packages cannot use , only extbinrelease, extsrcrelease, zendextsrcrelease, and zendextbinrelease can provide a PHP extension'); + } + + function _mustProvideExtension($release) + { + $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), + '<%release%> packages must use to indicate which PHP extension is provided'); + } + + function _cannotHaveSrcpackage($release) + { + $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), + '<%release%> packages cannot specify a source code package, only extension binaries may use the tag'); + } + + function _mustSrcPackage($release) + { + $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), + '/ packages must specify a source code package with '); + } + + function _mustSrcuri($release) + { + $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), + '/ packages must specify a source code package with '); + } + + function _uriDepsCannotHaveVersioning($type) + { + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), + '%type%: dependencies with a tag cannot have any versioning information'); + } + + function _conflictingDepsCannotHaveVersioning($type) + { + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), + '%type%: conflicting dependencies cannot have versioning info, use to ' . + 'exclude specific versions of a dependency'); + } + + function _DepchannelCannotBeUri($type) + { + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), + '%type%: channel cannot be __uri, this is a pseudo-channel reserved for uri ' . + 'dependencies only'); + } + + function _bundledPackagesMustBeFilename() + { + $this->_stack->push(__FUNCTION__, 'error', array(), + ' tags must contain only the filename of a package release ' . + 'in the bundle'); + } + + function _binaryPackageMustBePackagename() + { + $this->_stack->push(__FUNCTION__, 'error', array(), + ' tags must contain the name of a package that is ' . + 'a compiled version of this extsrc/zendextsrc package'); + } + + function _fileNotFound($file) + { + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'File "%file%" in package.xml does not exist'); + } + + function _notInContents($file, $tag) + { + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file, 'tag' => $tag), + '<%tag% name="%file%"> is invalid, file is not in '); + } + + function _cannotValidateNoPathSet() + { + $this->_stack->push(__FUNCTION__, 'error', array(), + 'Cannot validate files, no path to package file is set (use setPackageFile())'); + } + + function _usesroletaskMustHaveChannelOrUri($role, $tag) + { + $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag), + '<%tag%> for role "%role%" must contain either , or and '); + } + + function _usesroletaskMustHavePackage($role, $tag) + { + $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag), + '<%tag%> for role "%role%" must contain '); + } + + function _usesroletaskMustHaveRoleTask($tag, $type) + { + $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, 'type' => $type), + '<%tag%> must contain <%type%> defining the %type% to be used'); + } + + function _cannotConflictWithAllOs($type) + { + $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag), + '%tag% cannot conflict with all OSes'); + } + + function _invalidDepGroupName($name) + { + $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), + 'Invalid dependency group name "%name%"'); + } + + function _multipleToplevelDirNotAllowed() + { + $this->_stack->push(__FUNCTION__, 'error', array(), + 'Multiple top-level tags are not allowed. Enclose them ' . + 'in a '); + } + + function _multipleInstallAs($file) + { + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'Only one tag is allowed for file "%file%"'); + } + + function _ignoreAndInstallAs($file) + { + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'Cannot have both and tags for file "%file%"'); + } + + function _analyzeBundledPackages() + { + if (!$this->_isValid) { + return false; + } + if (!$this->_pf->getPackageType() == 'bundle') { + return false; + } + if (!isset($this->_pf->_packageFile)) { + return false; + } + $dir_prefix = dirname($this->_pf->_packageFile); + $common = new PEAR_Common; + $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') : + array($common, 'log'); + $info = $this->_pf->getContents(); + $info = $info['bundledpackage']; + if (!is_array($info)) { + $info = array($info); + } + $pkg = &new PEAR_PackageFile($this->_pf->_config); + foreach ($info as $package) { + if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $package)) { + $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $package); + $this->_isValid = 0; + continue; + } + call_user_func_array($log, array(1, "Analyzing bundled package $package")); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $ret = $pkg->fromAnyFile($dir_prefix . DIRECTORY_SEPARATOR . $package, + PEAR_VALIDATE_NORMAL); + PEAR::popErrorHandling(); + if (PEAR::isError($ret)) { + call_user_func_array($log, array(0, "ERROR: package $package is not a valid " . + 'package')); + $inf = $ret->getUserInfo(); + if (is_array($inf)) { + foreach ($inf as $err) { + call_user_func_array($log, array(1, $err['message'])); + } + } + return false; + } + } + return true; + } + + function _analyzePhpFiles() + { + if (!$this->_isValid) { + return false; + } + if (!isset($this->_pf->_packageFile)) { + $this->_cannotValidateNoPathSet(); + return false; + } + $dir_prefix = dirname($this->_pf->_packageFile); + $common = new PEAR_Common; + $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') : + array(&$common, 'log'); + $info = $this->_pf->getContents(); + if (!$info || !isset($info['dir']['file'])) { + $this->_tagCannotBeEmpty('contents>_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $file); + $this->_isValid = 0; + continue; + } + if (in_array($fa['role'], PEAR_Installer_Role::getPhpRoles()) && $dir_prefix) { + call_user_func_array($log, array(1, "Analyzing $file")); + $srcinfo = $this->analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); + if ($srcinfo) { + $provides = array_merge($provides, $this->_buildProvidesArray($srcinfo)); + } + } + } + $this->_packageName = $pn = $this->_pf->getPackage(); + $pnl = strlen($pn); + foreach ($provides as $key => $what) { + if (isset($what['explicit']) || !$what) { + // skip conformance checks if the provides entry is + // specified in the package.xml file + continue; + } + extract($what); + if ($type == 'class') { + if (!strncasecmp($name, $pn, $pnl)) { + continue; + } + $this->_stack->push(__FUNCTION__, 'warning', + array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn), + 'in %file%: %type% "%name%" not prefixed with package name "%package%"'); + } elseif ($type == 'function') { + if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) { + continue; + } + $this->_stack->push(__FUNCTION__, 'warning', + array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn), + 'in %file%: %type% "%name%" not prefixed with package name "%package%"'); + } + } + return $this->_isValid; + } + + /** + * Analyze the source code of the given PHP file + * + * @param string Filename of the PHP file + * @param boolean whether to analyze $file as the file contents + * @return mixed + */ + function analyzeSourceCode($file, $string = false) + { + if (!function_exists("token_get_all")) { + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'Parser error: token_get_all() function must exist to analyze source code, PHP may have been compiled with --disable-tokenizer'); + return false; + } + + if (!defined('T_DOC_COMMENT')) { + define('T_DOC_COMMENT', T_COMMENT); + } + + if (!defined('T_INTERFACE')) { + define('T_INTERFACE', -1); + } + + if (!defined('T_IMPLEMENTS')) { + define('T_IMPLEMENTS', -1); + } + + if ($string) { + $contents = $file; + } else { + if (!$fp = @fopen($file, "r")) { + return false; + } + fclose($fp); + $contents = file_get_contents($file); + } + + // Silence this function so we can catch PHP Warnings and show our own custom message + $tokens = @token_get_all($contents); + if (isset($php_errormsg)) { + if (isset($this->_stack)) { + $pn = $this->_pf->getPackage(); + $this->_stack->push(__FUNCTION__, 'warning', + array('file' => $file, 'package' => $pn), + 'in %file%: Could not process file for unkown reasons,' . + ' possibly a PHP parse error in %file% from %package%'); + } + } +/* + for ($i = 0; $i < sizeof($tokens); $i++) { + @list($token, $data) = $tokens[$i]; + if (is_string($token)) { + var_dump($token); + } else { + print token_name($token) . ' '; + var_dump(rtrim($data)); + } + } +*/ + $look_for = 0; + $paren_level = 0; + $bracket_level = 0; + $brace_level = 0; + $lastphpdoc = ''; + $current_class = ''; + $current_interface = ''; + $current_class_level = -1; + $current_function = ''; + $current_function_level = -1; + $declared_classes = array(); + $declared_interfaces = array(); + $declared_functions = array(); + $declared_methods = array(); + $used_classes = array(); + $used_functions = array(); + $extends = array(); + $implements = array(); + $nodeps = array(); + $inquote = false; + $interface = false; + for ($i = 0; $i < sizeof($tokens); $i++) { + if (is_array($tokens[$i])) { + list($token, $data) = $tokens[$i]; + } else { + $token = $tokens[$i]; + $data = ''; + } + + if ($inquote) { + if ($token != '"' && $token != T_END_HEREDOC) { + continue; + } else { + $inquote = false; + continue; + } + } + + switch ($token) { + case T_WHITESPACE : + continue; + case ';': + if ($interface) { + $current_function = ''; + $current_function_level = -1; + } + break; + case '"': + case T_START_HEREDOC: + $inquote = true; + break; + case T_CURLY_OPEN: + case T_DOLLAR_OPEN_CURLY_BRACES: + case '{': $brace_level++; continue 2; + case '}': + $brace_level--; + if ($current_class_level == $brace_level) { + $current_class = ''; + $current_class_level = -1; + } + if ($current_function_level == $brace_level) { + $current_function = ''; + $current_function_level = -1; + } + continue 2; + case '[': $bracket_level++; continue 2; + case ']': $bracket_level--; continue 2; + case '(': $paren_level++; continue 2; + case ')': $paren_level--; continue 2; + case T_INTERFACE: + $interface = true; + case T_CLASS: + if (($current_class_level != -1) || ($current_function_level != -1)) { + if (isset($this->_stack)) { + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'Parser error: invalid PHP found in file "%file%"'); + } else { + PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"", + PEAR_COMMON_ERROR_INVALIDPHP); + } + + return false; + } + case T_FUNCTION: + case T_NEW: + case T_EXTENDS: + case T_IMPLEMENTS: + $look_for = $token; + continue 2; + case T_STRING: + if (version_compare(zend_version(), '2.0', '<')) { + if (in_array(strtolower($data), + array('public', 'private', 'protected', 'abstract', + 'interface', 'implements', 'throw') + ) + ) { + if (isset($this->_stack)) { + $this->_stack->push(__FUNCTION__, 'warning', array( + 'file' => $file), + 'Error, PHP5 token encountered in %file%,' . + ' analysis should be in PHP5'); + } else { + PEAR::raiseError('Error: PHP5 token encountered in ' . $file . + 'packaging should be done in PHP 5'); + return false; + } + } + } + + if ($look_for == T_CLASS) { + $current_class = $data; + $current_class_level = $brace_level; + $declared_classes[] = $current_class; + } elseif ($look_for == T_INTERFACE) { + $current_interface = $data; + $current_class_level = $brace_level; + $declared_interfaces[] = $current_interface; + } elseif ($look_for == T_IMPLEMENTS) { + $implements[$current_class] = $data; + } elseif ($look_for == T_EXTENDS) { + $extends[$current_class] = $data; + } elseif ($look_for == T_FUNCTION) { + if ($current_class) { + $current_function = "$current_class::$data"; + $declared_methods[$current_class][] = $data; + } elseif ($current_interface) { + $current_function = "$current_interface::$data"; + $declared_methods[$current_interface][] = $data; + } else { + $current_function = $data; + $declared_functions[] = $current_function; + } + + $current_function_level = $brace_level; + $m = array(); + } elseif ($look_for == T_NEW) { + $used_classes[$data] = true; + } + + $look_for = 0; + continue 2; + case T_VARIABLE: + $look_for = 0; + continue 2; + case T_DOC_COMMENT: + case T_COMMENT: + if (preg_match('!^/\*\*\s!', $data)) { + $lastphpdoc = $data; + if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { + $nodeps = array_merge($nodeps, $m[1]); + } + } + continue 2; + case T_DOUBLE_COLON: + $token = $tokens[$i - 1][0]; + if (!($token == T_WHITESPACE || $token == T_STRING || $token == T_STATIC)) { + if (isset($this->_stack)) { + $this->_stack->push(__FUNCTION__, 'warning', array('file' => $file), + 'Parser error: invalid PHP found in file "%file%"'); + } else { + PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"", + PEAR_COMMON_ERROR_INVALIDPHP); + } + + return false; + } + + $class = $tokens[$i - 1][1]; + if (strtolower($class) != 'parent') { + $used_classes[$class] = true; + } + + continue 2; + } + } + + return array( + "source_file" => $file, + "declared_classes" => $declared_classes, + "declared_interfaces" => $declared_interfaces, + "declared_methods" => $declared_methods, + "declared_functions" => $declared_functions, + "used_classes" => array_diff(array_keys($used_classes), $nodeps), + "inheritance" => $extends, + "implements" => $implements, + ); + } + + /** + * Build a "provides" array from data returned by + * analyzeSourceCode(). The format of the built array is like + * this: + * + * array( + * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), + * ... + * ) + * + * + * @param array $srcinfo array with information about a source file + * as returned by the analyzeSourceCode() method. + * + * @return void + * + * @access private + * + */ + function _buildProvidesArray($srcinfo) + { + if (!$this->_isValid) { + return array(); + } + + $providesret = array(); + $file = basename($srcinfo['source_file']); + $pn = isset($this->_pf) ? $this->_pf->getPackage() : ''; + $pnl = strlen($pn); + foreach ($srcinfo['declared_classes'] as $class) { + $key = "class;$class"; + if (isset($providesret[$key])) { + continue; + } + + $providesret[$key] = + array('file'=> $file, 'type' => 'class', 'name' => $class); + if (isset($srcinfo['inheritance'][$class])) { + $providesret[$key]['extends'] = + $srcinfo['inheritance'][$class]; + } + } + + foreach ($srcinfo['declared_methods'] as $class => $methods) { + foreach ($methods as $method) { + $function = "$class::$method"; + $key = "function;$function"; + if ($method{0} == '_' || !strcasecmp($method, $class) || + isset($providesret[$key])) { + continue; + } + + $providesret[$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } + } + + foreach ($srcinfo['declared_functions'] as $function) { + $key = "function;$function"; + if ($function{0} == '_' || isset($providesret[$key])) { + continue; + } + + if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { + $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; + } + + $providesret[$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } + + return $providesret; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v2/rw.php b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v2/rw.php new file mode 100644 index 0000000..e169975 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/PackageFile/v2/rw.php @@ -0,0 +1,1604 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: rw.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a8 + */ +/** + * For base class + */ +require_once 'PEAR/PackageFile/v2.php'; +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a8 + */ +class PEAR_PackageFile_v2_rw extends PEAR_PackageFile_v2 +{ + /** + * @param string Extension name + * @return bool success of operation + */ + function setProvidesExtension($extension) + { + if (in_array($this->getPackageType(), + array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { + if (!isset($this->_packageInfo['providesextension'])) { + // ensure that the channel tag is set up in the right location + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('usesrole', 'usestask', 'srcpackage', 'srcuri', 'phprelease', + 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'bundle', 'changelog'), + $extension, 'providesextension'); + } + $this->_packageInfo['providesextension'] = $extension; + return true; + } + return false; + } + + function setPackage($package) + { + $this->_isValid = 0; + if (!isset($this->_packageInfo['attribs'])) { + $this->_packageInfo = array_merge(array('attribs' => array( + 'version' => '2.0', + 'xmlns' => 'http://pear.php.net/dtd/package-2.0', + 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0', + 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0 + http://pear.php.net/dtd/tasks-1.0.xsd + http://pear.php.net/dtd/package-2.0 + http://pear.php.net/dtd/package-2.0.xsd', + )), $this->_packageInfo); + } + if (!isset($this->_packageInfo['name'])) { + return $this->_packageInfo = array_merge(array('name' => $package), + $this->_packageInfo); + } + $this->_packageInfo['name'] = $package; + } + + /** + * set this as a package.xml version 2.1 + * @access private + */ + function _setPackageVersion2_1() + { + $info = array( + 'version' => '2.1', + 'xmlns' => 'http://pear.php.net/dtd/package-2.1', + 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0', + 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0 + http://pear.php.net/dtd/tasks-1.0.xsd + http://pear.php.net/dtd/package-2.1 + http://pear.php.net/dtd/package-2.1.xsd', + ); + if (!isset($this->_packageInfo['attribs'])) { + $this->_packageInfo = array_merge(array('attribs' => $info), $this->_packageInfo); + } else { + $this->_packageInfo['attribs'] = $info; + } + } + + function setUri($uri) + { + unset($this->_packageInfo['channel']); + $this->_isValid = 0; + if (!isset($this->_packageInfo['uri'])) { + // ensure that the uri tag is set up in the right location + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('extends', 'summary', 'description', 'lead', + 'developer', 'contributor', 'helper', 'date', 'time', 'version', + 'stability', 'license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'extbinrelease', 'bundle', 'changelog'), $uri, 'uri'); + } + $this->_packageInfo['uri'] = $uri; + } + + function setChannel($channel) + { + unset($this->_packageInfo['uri']); + $this->_isValid = 0; + if (!isset($this->_packageInfo['channel'])) { + // ensure that the channel tag is set up in the right location + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('extends', 'summary', 'description', 'lead', + 'developer', 'contributor', 'helper', 'date', 'time', 'version', + 'stability', 'license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'extbinrelease', 'bundle', 'changelog'), $channel, 'channel'); + } + $this->_packageInfo['channel'] = $channel; + } + + function setExtends($extends) + { + $this->_isValid = 0; + if (!isset($this->_packageInfo['extends'])) { + // ensure that the extends tag is set up in the right location + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('summary', 'description', 'lead', + 'developer', 'contributor', 'helper', 'date', 'time', 'version', + 'stability', 'license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'extbinrelease', 'bundle', 'changelog'), $extends, 'extends'); + } + $this->_packageInfo['extends'] = $extends; + } + + function setSummary($summary) + { + $this->_isValid = 0; + if (!isset($this->_packageInfo['summary'])) { + // ensure that the summary tag is set up in the right location + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('description', 'lead', + 'developer', 'contributor', 'helper', 'date', 'time', 'version', + 'stability', 'license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'extbinrelease', 'bundle', 'changelog'), $summary, 'summary'); + } + $this->_packageInfo['summary'] = $summary; + } + + function setDescription($desc) + { + $this->_isValid = 0; + if (!isset($this->_packageInfo['description'])) { + // ensure that the description tag is set up in the right location + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('lead', + 'developer', 'contributor', 'helper', 'date', 'time', 'version', + 'stability', 'license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'extbinrelease', 'bundle', 'changelog'), $desc, 'description'); + } + $this->_packageInfo['description'] = $desc; + } + + /** + * Adds a new maintainer - no checking of duplicates is performed, use + * updatemaintainer for that purpose. + */ + function addMaintainer($role, $handle, $name, $email, $active = 'yes') + { + if (!in_array($role, array('lead', 'developer', 'contributor', 'helper'))) { + return false; + } + if (isset($this->_packageInfo[$role])) { + if (!isset($this->_packageInfo[$role][0])) { + $this->_packageInfo[$role] = array($this->_packageInfo[$role]); + } + $this->_packageInfo[$role][] = + array( + 'name' => $name, + 'user' => $handle, + 'email' => $email, + 'active' => $active, + ); + } else { + $testarr = array('lead', + 'developer', 'contributor', 'helper', 'date', 'time', 'version', + 'stability', 'license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', + 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'); + foreach (array('lead', 'developer', 'contributor', 'helper') as $testrole) { + array_shift($testarr); + if ($role == $testrole) { + break; + } + } + if (!isset($this->_packageInfo[$role])) { + // ensure that the extends tag is set up in the right location + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, $testarr, + array(), $role); + } + $this->_packageInfo[$role] = + array( + 'name' => $name, + 'user' => $handle, + 'email' => $email, + 'active' => $active, + ); + } + $this->_isValid = 0; + } + + function updateMaintainer($newrole, $handle, $name, $email, $active = 'yes') + { + $found = false; + foreach (array('lead', 'developer', 'contributor', 'helper') as $role) { + if (!isset($this->_packageInfo[$role])) { + continue; + } + $info = $this->_packageInfo[$role]; + if (!isset($info[0])) { + if ($info['user'] == $handle) { + $found = true; + break; + } + } + foreach ($info as $i => $maintainer) { + if ($maintainer['user'] == $handle) { + $found = $i; + break 2; + } + } + } + if ($found === false) { + return $this->addMaintainer($newrole, $handle, $name, $email, $active); + } + if ($found !== false) { + if ($found === true) { + unset($this->_packageInfo[$role]); + } else { + unset($this->_packageInfo[$role][$found]); + $this->_packageInfo[$role] = array_values($this->_packageInfo[$role]); + } + } + $this->addMaintainer($newrole, $handle, $name, $email, $active); + $this->_isValid = 0; + } + + function deleteMaintainer($handle) + { + $found = false; + foreach (array('lead', 'developer', 'contributor', 'helper') as $role) { + if (!isset($this->_packageInfo[$role])) { + continue; + } + if (!isset($this->_packageInfo[$role][0])) { + $this->_packageInfo[$role] = array($this->_packageInfo[$role]); + } + foreach ($this->_packageInfo[$role] as $i => $maintainer) { + if ($maintainer['user'] == $handle) { + $found = $i; + break; + } + } + if ($found !== false) { + unset($this->_packageInfo[$role][$found]); + if (!count($this->_packageInfo[$role]) && $role == 'lead') { + $this->_isValid = 0; + } + if (!count($this->_packageInfo[$role])) { + unset($this->_packageInfo[$role]); + return true; + } + $this->_packageInfo[$role] = + array_values($this->_packageInfo[$role]); + if (count($this->_packageInfo[$role]) == 1) { + $this->_packageInfo[$role] = $this->_packageInfo[$role][0]; + } + return true; + } + if (count($this->_packageInfo[$role]) == 1) { + $this->_packageInfo[$role] = $this->_packageInfo[$role][0]; + } + } + return false; + } + + function setReleaseVersion($version) + { + if (isset($this->_packageInfo['version']) && + isset($this->_packageInfo['version']['release'])) { + unset($this->_packageInfo['version']['release']); + } + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $version, array( + 'version' => array('stability', 'license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'extbinrelease', 'bundle', 'changelog'), + 'release' => array('api'))); + $this->_isValid = 0; + } + + function setAPIVersion($version) + { + if (isset($this->_packageInfo['version']) && + isset($this->_packageInfo['version']['api'])) { + unset($this->_packageInfo['version']['api']); + } + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $version, array( + 'version' => array('stability', 'license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'extbinrelease', 'bundle', 'changelog'), + 'api' => array())); + $this->_isValid = 0; + } + + /** + * snapshot|devel|alpha|beta|stable + */ + function setReleaseStability($state) + { + if (isset($this->_packageInfo['stability']) && + isset($this->_packageInfo['stability']['release'])) { + unset($this->_packageInfo['stability']['release']); + } + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $state, array( + 'stability' => array('license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'extbinrelease', 'bundle', 'changelog'), + 'release' => array('api'))); + $this->_isValid = 0; + } + + /** + * @param devel|alpha|beta|stable + */ + function setAPIStability($state) + { + if (isset($this->_packageInfo['stability']) && + isset($this->_packageInfo['stability']['api'])) { + unset($this->_packageInfo['stability']['api']); + } + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $state, array( + 'stability' => array('license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'extbinrelease', 'bundle', 'changelog'), + 'api' => array())); + $this->_isValid = 0; + } + + function setLicense($license, $uri = false, $filesource = false) + { + if (!isset($this->_packageInfo['license'])) { + // ensure that the license tag is set up in the right location + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'extbinrelease', 'bundle', 'changelog'), 0, 'license'); + } + if ($uri || $filesource) { + $attribs = array(); + if ($uri) { + $attribs['uri'] = $uri; + } + $uri = true; // for test below + if ($filesource) { + $attribs['filesource'] = $filesource; + } + } + $license = $uri ? array('attribs' => $attribs, '_content' => $license) : $license; + $this->_packageInfo['license'] = $license; + $this->_isValid = 0; + } + + function setNotes($notes) + { + $this->_isValid = 0; + if (!isset($this->_packageInfo['notes'])) { + // ensure that the notes tag is set up in the right location + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('contents', 'compatible', + 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'extbinrelease', 'bundle', 'changelog'), $notes, 'notes'); + } + $this->_packageInfo['notes'] = $notes; + } + + /** + * This is only used at install-time, after all serialization + * is over. + * @param string file name + * @param string installed path + */ + function setInstalledAs($file, $path) + { + if ($path) { + return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; + } + unset($this->_packageInfo['filelist'][$file]['installed_as']); + } + + /** + * This is only used at install-time, after all serialization + * is over. + */ + function installedFile($file, $atts) + { + if (isset($this->_packageInfo['filelist'][$file])) { + $this->_packageInfo['filelist'][$file] = + array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']); + } else { + $this->_packageInfo['filelist'][$file] = $atts['attribs']; + } + } + + /** + * Reset the listing of package contents + * @param string base installation dir for the whole package, if any + */ + function clearContents($baseinstall = false) + { + $this->_filesValid = false; + $this->_isValid = 0; + if (!isset($this->_packageInfo['contents'])) { + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('compatible', + 'dependencies', 'providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', + 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'bundle', 'changelog'), array(), 'contents'); + } + if ($this->getPackageType() != 'bundle') { + $this->_packageInfo['contents'] = + array('dir' => array('attribs' => array('name' => '/'))); + if ($baseinstall) { + $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'] = $baseinstall; + } + } else { + $this->_packageInfo['contents'] = array('bundledpackage' => array()); + } + } + + /** + * @param string relative path of the bundled package. + */ + function addBundledPackage($path) + { + if ($this->getPackageType() != 'bundle') { + return false; + } + $this->_filesValid = false; + $this->_isValid = 0; + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $path, array( + 'contents' => array('compatible', 'dependencies', 'providesextension', + 'usesrole', 'usestask', 'srcpackage', 'srcuri', 'phprelease', + 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'bundle', 'changelog'), + 'bundledpackage' => array())); + } + + /** + * @param string file name + * @param PEAR_Task_Common a read/write task + */ + function addTaskToFile($filename, $task) + { + if (!method_exists($task, 'getXml')) { + return false; + } + if (!method_exists($task, 'getName')) { + return false; + } + if (!method_exists($task, 'validate')) { + return false; + } + if (!$task->validate()) { + return false; + } + if (!isset($this->_packageInfo['contents']['dir']['file'])) { + return false; + } + $this->getTasksNs(); // discover the tasks namespace if not done already + $files = $this->_packageInfo['contents']['dir']['file']; + if (!isset($files[0])) { + $files = array($files); + $ind = false; + } else { + $ind = true; + } + foreach ($files as $i => $file) { + if (isset($file['attribs'])) { + if ($file['attribs']['name'] == $filename) { + if ($ind) { + $t = isset($this->_packageInfo['contents']['dir']['file'][$i] + ['attribs'][$this->_tasksNs . + ':' . $task->getName()]) ? + $this->_packageInfo['contents']['dir']['file'][$i] + ['attribs'][$this->_tasksNs . + ':' . $task->getName()] : false; + if ($t && !isset($t[0])) { + $this->_packageInfo['contents']['dir']['file'][$i] + [$this->_tasksNs . ':' . $task->getName()] = array($t); + } + $this->_packageInfo['contents']['dir']['file'][$i][$this->_tasksNs . + ':' . $task->getName()][] = $task->getXml(); + } else { + $t = isset($this->_packageInfo['contents']['dir']['file'] + ['attribs'][$this->_tasksNs . + ':' . $task->getName()]) ? $this->_packageInfo['contents']['dir']['file'] + ['attribs'][$this->_tasksNs . + ':' . $task->getName()] : false; + if ($t && !isset($t[0])) { + $this->_packageInfo['contents']['dir']['file'] + [$this->_tasksNs . ':' . $task->getName()] = array($t); + } + $this->_packageInfo['contents']['dir']['file'][$this->_tasksNs . + ':' . $task->getName()][] = $task->getXml(); + } + return true; + } + } + } + return false; + } + + /** + * @param string path to the file + * @param string filename + * @param array extra attributes + */ + function addFile($dir, $file, $attrs) + { + if ($this->getPackageType() == 'bundle') { + return false; + } + $this->_filesValid = false; + $this->_isValid = 0; + $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir); + if ($dir == '/' || $dir == '') { + $dir = ''; + } else { + $dir .= '/'; + } + $attrs['name'] = $dir . $file; + if (!isset($this->_packageInfo['contents'])) { + // ensure that the contents tag is set up + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('compatible', 'dependencies', 'providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', + 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'bundle', 'changelog'), array(), 'contents'); + } + if (isset($this->_packageInfo['contents']['dir']['file'])) { + if (!isset($this->_packageInfo['contents']['dir']['file'][0])) { + $this->_packageInfo['contents']['dir']['file'] = + array($this->_packageInfo['contents']['dir']['file']); + } + $this->_packageInfo['contents']['dir']['file'][]['attribs'] = $attrs; + } else { + $this->_packageInfo['contents']['dir']['file']['attribs'] = $attrs; + } + } + + /** + * @param string Dependent package name + * @param string Dependent package's channel name + * @param string minimum version of specified package that this release is guaranteed to be + * compatible with + * @param string maximum version of specified package that this release is guaranteed to be + * compatible with + * @param string versions of specified package that this release is not compatible with + */ + function addCompatiblePackage($name, $channel, $min, $max, $exclude = false) + { + $this->_isValid = 0; + $set = array( + 'name' => $name, + 'channel' => $channel, + 'min' => $min, + 'max' => $max, + ); + if ($exclude) { + $set['exclude'] = $exclude; + } + $this->_isValid = 0; + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $set, array( + 'compatible' => array('dependencies', 'providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog') + )); + } + + /** + * Removes the tag entirely + */ + function resetUsesrole() + { + if (isset($this->_packageInfo['usesrole'])) { + unset($this->_packageInfo['usesrole']); + } + } + + /** + * @param string + * @param string package name or uri + * @param string channel name if non-uri + */ + function addUsesrole($role, $packageOrUri, $channel = false) { + $set = array('role' => $role); + if ($channel) { + $set['package'] = $packageOrUri; + $set['channel'] = $channel; + } else { + $set['uri'] = $packageOrUri; + } + $this->_isValid = 0; + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $set, array( + 'usesrole' => array('usestask', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog') + )); + } + + /** + * Removes the tag entirely + */ + function resetUsestask() + { + if (isset($this->_packageInfo['usestask'])) { + unset($this->_packageInfo['usestask']); + } + } + + + /** + * @param string + * @param string package name or uri + * @param string channel name if non-uri + */ + function addUsestask($task, $packageOrUri, $channel = false) { + $set = array('task' => $task); + if ($channel) { + $set['package'] = $packageOrUri; + $set['channel'] = $channel; + } else { + $set['uri'] = $packageOrUri; + } + $this->_isValid = 0; + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $set, array( + 'usestask' => array('srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog') + )); + } + + /** + * Remove all compatible tags + */ + function clearCompatible() + { + unset($this->_packageInfo['compatible']); + } + + /** + * Reset dependencies prior to adding new ones + */ + function clearDeps() + { + if (!isset($this->_packageInfo['dependencies'])) { + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, array(), + array( + 'dependencies' => array('providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'))); + } + $this->_packageInfo['dependencies'] = array(); + } + + /** + * @param string minimum PHP version allowed + * @param string maximum PHP version allowed + * @param array $exclude incompatible PHP versions + */ + function setPhpDep($min, $max = false, $exclude = false) + { + $this->_isValid = 0; + $dep = + array( + 'min' => $min, + ); + if ($max) { + $dep['max'] = $max; + } + if ($exclude) { + if (count($exclude) == 1) { + $exclude = $exclude[0]; + } + $dep['exclude'] = $exclude; + } + if (isset($this->_packageInfo['dependencies']['required']['php'])) { + $this->_stack->push(__FUNCTION__, 'warning', array('dep' => + $this->_packageInfo['dependencies']['required']['php']), + 'warning: PHP dependency already exists, overwriting'); + unset($this->_packageInfo['dependencies']['required']['php']); + } + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, + array( + 'dependencies' => array('providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), + 'required' => array('optional', 'group'), + 'php' => array('pearinstaller', 'package', 'subpackage', 'extension', 'os', 'arch') + )); + return true; + } + + /** + * @param string minimum allowed PEAR installer version + * @param string maximum allowed PEAR installer version + * @param string recommended PEAR installer version + * @param array incompatible version of the PEAR installer + */ + function setPearinstallerDep($min, $max = false, $recommended = false, $exclude = false) + { + $this->_isValid = 0; + $dep = + array( + 'min' => $min, + ); + if ($max) { + $dep['max'] = $max; + } + if ($recommended) { + $dep['recommended'] = $recommended; + } + if ($exclude) { + if (count($exclude) == 1) { + $exclude = $exclude[0]; + } + $dep['exclude'] = $exclude; + } + if (isset($this->_packageInfo['dependencies']['required']['pearinstaller'])) { + $this->_stack->push(__FUNCTION__, 'warning', array('dep' => + $this->_packageInfo['dependencies']['required']['pearinstaller']), + 'warning: PEAR Installer dependency already exists, overwriting'); + unset($this->_packageInfo['dependencies']['required']['pearinstaller']); + } + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, + array( + 'dependencies' => array('providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), + 'required' => array('optional', 'group'), + 'pearinstaller' => array('package', 'subpackage', 'extension', 'os', 'arch') + )); + } + + /** + * Mark a package as conflicting with this package + * @param string package name + * @param string package channel + * @param string extension this package provides, if any + * @param string|false minimum version required + * @param string|false maximum version allowed + * @param array|false versions to exclude from installation + */ + function addConflictingPackageDepWithChannel($name, $channel, + $providesextension = false, $min = false, $max = false, $exclude = false) + { + $this->_isValid = 0; + $dep = $this->_constructDep($name, $channel, false, $min, $max, false, + $exclude, $providesextension, false, true); + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, + array( + 'dependencies' => array('providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), + 'required' => array('optional', 'group'), + 'package' => array('subpackage', 'extension', 'os', 'arch') + )); + } + + /** + * Mark a package as conflicting with this package + * @param string package name + * @param string package channel + * @param string extension this package provides, if any + */ + function addConflictingPackageDepWithUri($name, $uri, $providesextension = false) + { + $this->_isValid = 0; + $dep = + array( + 'name' => $name, + 'uri' => $uri, + 'conflicts' => '', + ); + if ($providesextension) { + $dep['providesextension'] = $providesextension; + } + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, + array( + 'dependencies' => array('providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), + 'required' => array('optional', 'group'), + 'package' => array('subpackage', 'extension', 'os', 'arch') + )); + } + + function addDependencyGroup($name, $hint) + { + $this->_isValid = 0; + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, + array('attribs' => array('name' => $name, 'hint' => $hint)), + array( + 'dependencies' => array('providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), + 'group' => array(), + )); + } + + /** + * @param string package name + * @param string|false channel name, false if this is a uri + * @param string|false uri name, false if this is a channel + * @param string|false minimum version required + * @param string|false maximum version allowed + * @param string|false recommended installation version + * @param array|false versions to exclude from installation + * @param string extension this package provides, if any + * @param bool if true, tells the installer to ignore the default optional dependency group + * when installing this package + * @param bool if true, tells the installer to negate this dependency (conflicts) + * @return array + * @access private + */ + function _constructDep($name, $channel, $uri, $min, $max, $recommended, $exclude, + $providesextension = false, $nodefault = false, + $conflicts = false) + { + $dep = + array( + 'name' => $name, + ); + if ($channel) { + $dep['channel'] = $channel; + } elseif ($uri) { + $dep['uri'] = $uri; + } + if ($min) { + $dep['min'] = $min; + } + if ($max) { + $dep['max'] = $max; + } + if ($recommended) { + $dep['recommended'] = $recommended; + } + if ($exclude) { + if (is_array($exclude) && count($exclude) == 1) { + $exclude = $exclude[0]; + } + $dep['exclude'] = $exclude; + } + if ($conflicts) { + $dep['conflicts'] = ''; + } + if ($nodefault) { + $dep['nodefault'] = ''; + } + if ($providesextension) { + $dep['providesextension'] = $providesextension; + } + return $dep; + } + + /** + * @param package|subpackage + * @param string group name + * @param string package name + * @param string package channel + * @param string minimum version + * @param string maximum version + * @param string recommended version + * @param array|false optional excluded versions + * @param string extension this package provides, if any + * @param bool if true, tells the installer to ignore the default optional dependency group + * when installing this package + * @return bool false if the dependency group has not been initialized with + * {@link addDependencyGroup()}, or a subpackage is added with + * a providesextension + */ + function addGroupPackageDepWithChannel($type, $groupname, $name, $channel, $min = false, + $max = false, $recommended = false, $exclude = false, + $providesextension = false, $nodefault = false) + { + if ($type == 'subpackage' && $providesextension) { + return false; // subpackages must be php packages + } + $dep = $this->_constructDep($name, $channel, false, $min, $max, $recommended, $exclude, + $providesextension, $nodefault); + return $this->_addGroupDependency($type, $dep, $groupname); + } + + /** + * @param package|subpackage + * @param string group name + * @param string package name + * @param string package uri + * @param string extension this package provides, if any + * @param bool if true, tells the installer to ignore the default optional dependency group + * when installing this package + * @return bool false if the dependency group has not been initialized with + * {@link addDependencyGroup()} + */ + function addGroupPackageDepWithURI($type, $groupname, $name, $uri, $providesextension = false, + $nodefault = false) + { + if ($type == 'subpackage' && $providesextension) { + return false; // subpackages must be php packages + } + $dep = $this->_constructDep($name, false, $uri, false, false, false, false, + $providesextension, $nodefault); + return $this->_addGroupDependency($type, $dep, $groupname); + } + + /** + * @param string group name (must be pre-existing) + * @param string extension name + * @param string minimum version allowed + * @param string maximum version allowed + * @param string recommended version + * @param array incompatible versions + */ + function addGroupExtensionDep($groupname, $name, $min = false, $max = false, + $recommended = false, $exclude = false) + { + $this->_isValid = 0; + $dep = $this->_constructDep($name, false, false, $min, $max, $recommended, $exclude); + return $this->_addGroupDependency('extension', $dep, $groupname); + } + + /** + * @param package|subpackage|extension + * @param array dependency contents + * @param string name of the dependency group to add this to + * @return boolean + * @access private + */ + function _addGroupDependency($type, $dep, $groupname) + { + $arr = array('subpackage', 'extension'); + if ($type != 'package') { + array_shift($arr); + } + if ($type == 'extension') { + array_shift($arr); + } + if (!isset($this->_packageInfo['dependencies']['group'])) { + return false; + } else { + if (!isset($this->_packageInfo['dependencies']['group'][0])) { + if ($this->_packageInfo['dependencies']['group']['attribs']['name'] == $groupname) { + $this->_packageInfo['dependencies']['group'] = $this->_mergeTag( + $this->_packageInfo['dependencies']['group'], $dep, + array( + $type => $arr + )); + $this->_isValid = 0; + return true; + } else { + return false; + } + } else { + foreach ($this->_packageInfo['dependencies']['group'] as $i => $group) { + if ($group['attribs']['name'] == $groupname) { + $this->_packageInfo['dependencies']['group'][$i] = $this->_mergeTag( + $this->_packageInfo['dependencies']['group'][$i], $dep, + array( + $type => $arr + )); + $this->_isValid = 0; + return true; + } + } + return false; + } + } + } + + /** + * @param optional|required + * @param string package name + * @param string package channel + * @param string minimum version + * @param string maximum version + * @param string recommended version + * @param string extension this package provides, if any + * @param bool if true, tells the installer to ignore the default optional dependency group + * when installing this package + * @param array|false optional excluded versions + */ + function addPackageDepWithChannel($type, $name, $channel, $min = false, $max = false, + $recommended = false, $exclude = false, + $providesextension = false, $nodefault = false) + { + if (!in_array($type, array('optional', 'required'), true)) { + $type = 'required'; + } + $this->_isValid = 0; + $arr = array('optional', 'group'); + if ($type != 'required') { + array_shift($arr); + } + $dep = $this->_constructDep($name, $channel, false, $min, $max, $recommended, $exclude, + $providesextension, $nodefault); + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, + array( + 'dependencies' => array('providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), + $type => $arr, + 'package' => array('subpackage', 'extension', 'os', 'arch') + )); + } + + /** + * @param optional|required + * @param string name of the package + * @param string uri of the package + * @param string extension this package provides, if any + * @param bool if true, tells the installer to ignore the default optional dependency group + * when installing this package + */ + function addPackageDepWithUri($type, $name, $uri, $providesextension = false, + $nodefault = false) + { + $this->_isValid = 0; + $arr = array('optional', 'group'); + if ($type != 'required') { + array_shift($arr); + } + $dep = $this->_constructDep($name, false, $uri, false, false, false, false, + $providesextension, $nodefault); + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, + array( + 'dependencies' => array('providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), + $type => $arr, + 'package' => array('subpackage', 'extension', 'os', 'arch') + )); + } + + /** + * @param optional|required optional, required + * @param string package name + * @param string package channel + * @param string minimum version + * @param string maximum version + * @param string recommended version + * @param array incompatible versions + * @param bool if true, tells the installer to ignore the default optional dependency group + * when installing this package + */ + function addSubpackageDepWithChannel($type, $name, $channel, $min = false, $max = false, + $recommended = false, $exclude = false, + $nodefault = false) + { + $this->_isValid = 0; + $arr = array('optional', 'group'); + if ($type != 'required') { + array_shift($arr); + } + $dep = $this->_constructDep($name, $channel, false, $min, $max, $recommended, $exclude, + $nodefault); + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, + array( + 'dependencies' => array('providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), + $type => $arr, + 'subpackage' => array('extension', 'os', 'arch') + )); + } + + /** + * @param optional|required optional, required + * @param string package name + * @param string package uri for download + * @param bool if true, tells the installer to ignore the default optional dependency group + * when installing this package + */ + function addSubpackageDepWithUri($type, $name, $uri, $nodefault = false) + { + $this->_isValid = 0; + $arr = array('optional', 'group'); + if ($type != 'required') { + array_shift($arr); + } + $dep = $this->_constructDep($name, false, $uri, false, false, false, false, $nodefault); + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, + array( + 'dependencies' => array('providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), + $type => $arr, + 'subpackage' => array('extension', 'os', 'arch') + )); + } + + /** + * @param optional|required optional, required + * @param string extension name + * @param string minimum version + * @param string maximum version + * @param string recommended version + * @param array incompatible versions + */ + function addExtensionDep($type, $name, $min = false, $max = false, $recommended = false, + $exclude = false) + { + $this->_isValid = 0; + $arr = array('optional', 'group'); + if ($type != 'required') { + array_shift($arr); + } + $dep = $this->_constructDep($name, false, false, $min, $max, $recommended, $exclude); + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, + array( + 'dependencies' => array('providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), + $type => $arr, + 'extension' => array('os', 'arch') + )); + } + + /** + * @param string Operating system name + * @param boolean true if this package cannot be installed on this OS + */ + function addOsDep($name, $conflicts = false) + { + $this->_isValid = 0; + $dep = array('name' => $name); + if ($conflicts) { + $dep['conflicts'] = ''; + } + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, + array( + 'dependencies' => array('providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), + 'required' => array('optional', 'group'), + 'os' => array('arch') + )); + } + + /** + * @param string Architecture matching pattern + * @param boolean true if this package cannot be installed on this architecture + */ + function addArchDep($pattern, $conflicts = false) + { + $this->_isValid = 0; + $dep = array('pattern' => $pattern); + if ($conflicts) { + $dep['conflicts'] = ''; + } + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, + array( + 'dependencies' => array('providesextension', 'usesrole', 'usestask', + 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), + 'required' => array('optional', 'group'), + 'arch' => array() + )); + } + + /** + * Set the kind of package, and erase all release tags + * + * - a php package is a PEAR-style package + * - an extbin package is a PECL-style extension binary + * - an extsrc package is a PECL-style source for a binary + * - an zendextbin package is a PECL-style zend extension binary + * - an zendextsrc package is a PECL-style source for a zend extension binary + * - a bundle package is a collection of other pre-packaged packages + * @param php|extbin|extsrc|zendextsrc|zendextbin|bundle + * @return bool success + */ + function setPackageType($type) + { + $this->_isValid = 0; + if (!in_array($type, array('php', 'extbin', 'extsrc', 'zendextsrc', + 'zendextbin', 'bundle'))) { + return false; + } + + if (in_array($type, array('zendextsrc', 'zendextbin'))) { + $this->_setPackageVersion2_1(); + } + + if ($type != 'bundle') { + $type .= 'release'; + } + + foreach (array('phprelease', 'extbinrelease', 'extsrcrelease', + 'zendextsrcrelease', 'zendextbinrelease', 'bundle') as $test) { + unset($this->_packageInfo[$test]); + } + + if (!isset($this->_packageInfo[$type])) { + // ensure that the release tag is set up + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, array('changelog'), + array(), $type); + } + + $this->_packageInfo[$type] = array(); + return true; + } + + /** + * @return bool true if package type is set up + */ + function addRelease() + { + if ($type = $this->getPackageType()) { + if ($type != 'bundle') { + $type .= 'release'; + } + $this->_packageInfo = $this->_mergeTag($this->_packageInfo, array(), + array($type => array('changelog'))); + return true; + } + return false; + } + + /** + * Get the current release tag in order to add to it + * @param bool returns only releases that have installcondition if true + * @return array|null + */ + function &_getCurrentRelease($strict = true) + { + if ($p = $this->getPackageType()) { + if ($strict) { + if ($p == 'extsrc' || $p == 'zendextsrc') { + $a = null; + return $a; + } + } + if ($p != 'bundle') { + $p .= 'release'; + } + if (isset($this->_packageInfo[$p][0])) { + return $this->_packageInfo[$p][count($this->_packageInfo[$p]) - 1]; + } else { + return $this->_packageInfo[$p]; + } + } else { + $a = null; + return $a; + } + } + + /** + * Add a file to the current release that should be installed under a different name + * @param string path to file + * @param string name the file should be installed as + */ + function addInstallAs($path, $as) + { + $r = &$this->_getCurrentRelease(); + if ($r === null) { + return false; + } + $this->_isValid = 0; + $r = $this->_mergeTag($r, array('attribs' => array('name' => $path, 'as' => $as)), + array( + 'filelist' => array(), + 'install' => array('ignore') + )); + } + + /** + * Add a file to the current release that should be ignored + * @param string path to file + * @return bool success of operation + */ + function addIgnore($path) + { + $r = &$this->_getCurrentRelease(); + if ($r === null) { + return false; + } + $this->_isValid = 0; + $r = $this->_mergeTag($r, array('attribs' => array('name' => $path)), + array( + 'filelist' => array(), + 'ignore' => array() + )); + } + + /** + * Add an extension binary package for this extension source code release + * + * Note that the package must be from the same channel as the extension source package + * @param string + */ + function addBinarypackage($package) + { + if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') { + return false; + } + $r = &$this->_getCurrentRelease(false); + if ($r === null) { + return false; + } + $this->_isValid = 0; + $r = $this->_mergeTag($r, $package, + array( + 'binarypackage' => array('filelist'), + )); + } + + /** + * Add a configureoption to an extension source package + * @param string + * @param string + * @param string + */ + function addConfigureOption($name, $prompt, $default = null) + { + if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') { + return false; + } + + $r = &$this->_getCurrentRelease(false); + if ($r === null) { + return false; + } + + $opt = array('attribs' => array('name' => $name, 'prompt' => $prompt)); + if ($default !== null) { + $opt['attribs']['default'] = $default; + } + + $this->_isValid = 0; + $r = $this->_mergeTag($r, $opt, + array( + 'configureoption' => array('binarypackage', 'filelist'), + )); + } + + /** + * Set an installation condition based on php version for the current release set + * @param string minimum version + * @param string maximum version + * @param false|array incompatible versions of PHP + */ + function setPhpInstallCondition($min, $max, $exclude = false) + { + $r = &$this->_getCurrentRelease(); + if ($r === null) { + return false; + } + $this->_isValid = 0; + if (isset($r['installconditions']['php'])) { + unset($r['installconditions']['php']); + } + $dep = array('min' => $min, 'max' => $max); + if ($exclude) { + if (is_array($exclude) && count($exclude) == 1) { + $exclude = $exclude[0]; + } + $dep['exclude'] = $exclude; + } + if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') { + $r = $this->_mergeTag($r, $dep, + array( + 'installconditions' => array('configureoption', 'binarypackage', + 'filelist'), + 'php' => array('extension', 'os', 'arch') + )); + } else { + $r = $this->_mergeTag($r, $dep, + array( + 'installconditions' => array('filelist'), + 'php' => array('extension', 'os', 'arch') + )); + } + } + + /** + * @param optional|required optional, required + * @param string extension name + * @param string minimum version + * @param string maximum version + * @param string recommended version + * @param array incompatible versions + */ + function addExtensionInstallCondition($name, $min = false, $max = false, $recommended = false, + $exclude = false) + { + $r = &$this->_getCurrentRelease(); + if ($r === null) { + return false; + } + $this->_isValid = 0; + $dep = $this->_constructDep($name, false, false, $min, $max, $recommended, $exclude); + if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') { + $r = $this->_mergeTag($r, $dep, + array( + 'installconditions' => array('configureoption', 'binarypackage', + 'filelist'), + 'extension' => array('os', 'arch') + )); + } else { + $r = $this->_mergeTag($r, $dep, + array( + 'installconditions' => array('filelist'), + 'extension' => array('os', 'arch') + )); + } + } + + /** + * Set an installation condition based on operating system for the current release set + * @param string OS name + * @param bool whether this OS is incompatible with the current release + */ + function setOsInstallCondition($name, $conflicts = false) + { + $r = &$this->_getCurrentRelease(); + if ($r === null) { + return false; + } + $this->_isValid = 0; + if (isset($r['installconditions']['os'])) { + unset($r['installconditions']['os']); + } + $dep = array('name' => $name); + if ($conflicts) { + $dep['conflicts'] = ''; + } + if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') { + $r = $this->_mergeTag($r, $dep, + array( + 'installconditions' => array('configureoption', 'binarypackage', + 'filelist'), + 'os' => array('arch') + )); + } else { + $r = $this->_mergeTag($r, $dep, + array( + 'installconditions' => array('filelist'), + 'os' => array('arch') + )); + } + } + + /** + * Set an installation condition based on architecture for the current release set + * @param string architecture pattern + * @param bool whether this arch is incompatible with the current release + */ + function setArchInstallCondition($pattern, $conflicts = false) + { + $r = &$this->_getCurrentRelease(); + if ($r === null) { + return false; + } + $this->_isValid = 0; + if (isset($r['installconditions']['arch'])) { + unset($r['installconditions']['arch']); + } + $dep = array('pattern' => $pattern); + if ($conflicts) { + $dep['conflicts'] = ''; + } + if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') { + $r = $this->_mergeTag($r, $dep, + array( + 'installconditions' => array('configureoption', 'binarypackage', + 'filelist'), + 'arch' => array() + )); + } else { + $r = $this->_mergeTag($r, $dep, + array( + 'installconditions' => array('filelist'), + 'arch' => array() + )); + } + } + + /** + * For extension binary releases, this is used to specify either the + * static URI to a source package, or the package name and channel of the extsrc/zendextsrc + * package it is based on. + * @param string Package name, or full URI to source package (extsrc/zendextsrc type) + */ + function setSourcePackage($packageOrUri) + { + $this->_isValid = 0; + if (isset($this->_packageInfo['channel'])) { + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, array('phprelease', + 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'bundle', 'changelog'), + $packageOrUri, 'srcpackage'); + } else { + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, array('phprelease', + 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', + 'bundle', 'changelog'), $packageOrUri, 'srcuri'); + } + } + + /** + * Generate a valid change log entry from the current package.xml + * @param string|false + */ + function generateChangeLogEntry($notes = false) + { + return array( + 'version' => + array( + 'release' => $this->getVersion('release'), + 'api' => $this->getVersion('api'), + ), + 'stability' => + $this->getStability(), + 'date' => $this->getDate(), + 'license' => $this->getLicense(true), + 'notes' => $notes ? $notes : $this->getNotes() + ); + } + + /** + * @param string release version to set change log notes for + * @param array output of {@link generateChangeLogEntry()} + */ + function setChangelogEntry($releaseversion, $contents) + { + if (!isset($this->_packageInfo['changelog'])) { + $this->_packageInfo['changelog']['release'] = $contents; + return; + } + if (!isset($this->_packageInfo['changelog']['release'][0])) { + if ($this->_packageInfo['changelog']['release']['version']['release'] == $releaseversion) { + $this->_packageInfo['changelog']['release'] = array( + $this->_packageInfo['changelog']['release']); + } else { + $this->_packageInfo['changelog']['release'] = array( + $this->_packageInfo['changelog']['release']); + return $this->_packageInfo['changelog']['release'][] = $contents; + } + } + foreach($this->_packageInfo['changelog']['release'] as $index => $changelog) { + if (isset($changelog['version']) && + strnatcasecmp($changelog['version']['release'], $releaseversion) == 0) { + $curlog = $index; + } + } + if (isset($curlog)) { + $this->_packageInfo['changelog']['release'][$curlog] = $contents; + } else { + $this->_packageInfo['changelog']['release'][] = $contents; + } + } + + /** + * Remove the changelog entirely + */ + function clearChangeLog() + { + unset($this->_packageInfo['changelog']); + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Packager.php b/typo3conf/ext/phpunit/PEAR/PEAR/Packager.php new file mode 100644 index 0000000..6cf2b25 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Packager.php @@ -0,0 +1,201 @@ + + * @author Tomas V. V. Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Packager.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Common.php'; +require_once 'PEAR/PackageFile.php'; +require_once 'System.php'; + +/** + * Administration class used to make a PEAR release tarball. + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Packager extends PEAR_Common +{ + /** + * @var PEAR_Registry + */ + var $_registry; + + function package($pkgfile = null, $compress = true, $pkg2 = null) + { + // {{{ validate supplied package.xml file + if (empty($pkgfile)) { + $pkgfile = 'package.xml'; + } + + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $pkg = &new PEAR_PackageFile($this->config, $this->debug); + $pf = &$pkg->fromPackageFile($pkgfile, PEAR_VALIDATE_NORMAL); + $main = &$pf; + PEAR::staticPopErrorHandling(); + if (PEAR::isError($pf)) { + if (is_array($pf->getUserInfo())) { + foreach ($pf->getUserInfo() as $error) { + $this->log(0, 'Error: ' . $error['message']); + } + } + + $this->log(0, $pf->getMessage()); + return $this->raiseError("Cannot package, errors in package file"); + } + + foreach ($pf->getValidationWarnings() as $warning) { + $this->log(1, 'Warning: ' . $warning['message']); + } + + // }}} + if ($pkg2) { + $this->log(0, 'Attempting to process the second package file'); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $pf2 = &$pkg->fromPackageFile($pkg2, PEAR_VALIDATE_NORMAL); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($pf2)) { + if (is_array($pf2->getUserInfo())) { + foreach ($pf2->getUserInfo() as $error) { + $this->log(0, 'Error: ' . $error['message']); + } + } + $this->log(0, $pf2->getMessage()); + return $this->raiseError("Cannot package, errors in second package file"); + } + + foreach ($pf2->getValidationWarnings() as $warning) { + $this->log(1, 'Warning: ' . $warning['message']); + } + + if ($pf2->getPackagexmlVersion() == '2.0' || + $pf2->getPackagexmlVersion() == '2.1' + ) { + $main = &$pf2; + $other = &$pf; + } else { + $main = &$pf; + $other = &$pf2; + } + + if ($main->getPackagexmlVersion() != '2.0' && + $main->getPackagexmlVersion() != '2.1') { + return PEAR::raiseError('Error: cannot package two package.xml version 1.0, can ' . + 'only package together a package.xml 1.0 and package.xml 2.0'); + } + + if ($other->getPackagexmlVersion() != '1.0') { + return PEAR::raiseError('Error: cannot package two package.xml version 2.0, can ' . + 'only package together a package.xml 1.0 and package.xml 2.0'); + } + } + + $main->setLogger($this); + if (!$main->validate(PEAR_VALIDATE_PACKAGING)) { + foreach ($main->getValidationWarnings() as $warning) { + $this->log(0, 'Error: ' . $warning['message']); + } + return $this->raiseError("Cannot package, errors in package"); + } + + foreach ($main->getValidationWarnings() as $warning) { + $this->log(1, 'Warning: ' . $warning['message']); + } + + if ($pkg2) { + $other->setLogger($this); + $a = false; + if (!$other->validate(PEAR_VALIDATE_NORMAL) || $a = !$main->isEquivalent($other)) { + foreach ($other->getValidationWarnings() as $warning) { + $this->log(0, 'Error: ' . $warning['message']); + } + + foreach ($main->getValidationWarnings() as $warning) { + $this->log(0, 'Error: ' . $warning['message']); + } + + if ($a) { + return $this->raiseError('The two package.xml files are not equivalent!'); + } + + return $this->raiseError("Cannot package, errors in package"); + } + + foreach ($other->getValidationWarnings() as $warning) { + $this->log(1, 'Warning: ' . $warning['message']); + } + + $gen = &$main->getDefaultGenerator(); + $tgzfile = $gen->toTgz2($this, $other, $compress); + if (PEAR::isError($tgzfile)) { + return $tgzfile; + } + + $dest_package = basename($tgzfile); + $pkgdir = dirname($pkgfile); + + // TAR the Package ------------------------------------------- + $this->log(1, "Package $dest_package done"); + if (file_exists("$pkgdir/CVS/Root")) { + $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pf->getVersion()); + $cvstag = "RELEASE_$cvsversion"; + $this->log(1, 'Tag the released code with "pear cvstag ' . + $main->getPackageFile() . '"'); + $this->log(1, "(or set the CVS tag $cvstag by hand)"); + } elseif (file_exists("$pkgdir/.svn")) { + $svnversion = preg_replace('/[^a-z0-9]/i', '.', $pf->getVersion()); + $svntag = $pf->getName() . "-$svnversion"; + $this->log(1, 'Tag the released code with "pear svntag ' . + $main->getPackageFile() . '"'); + $this->log(1, "(or set the SVN tag $svntag by hand)"); + } + } else { // this branch is executed for single packagefile packaging + $gen = &$pf->getDefaultGenerator(); + $tgzfile = $gen->toTgz($this, $compress); + if (PEAR::isError($tgzfile)) { + $this->log(0, $tgzfile->getMessage()); + return $this->raiseError("Cannot package, errors in package"); + } + + $dest_package = basename($tgzfile); + $pkgdir = dirname($pkgfile); + + // TAR the Package ------------------------------------------- + $this->log(1, "Package $dest_package done"); + if (file_exists("$pkgdir/CVS/Root")) { + $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pf->getVersion()); + $cvstag = "RELEASE_$cvsversion"; + $this->log(1, "Tag the released code with `pear cvstag $pkgfile'"); + $this->log(1, "(or set the CVS tag $cvstag by hand)"); + } elseif (file_exists("$pkgdir/.svn")) { + $svnversion = preg_replace('/[^a-z0-9]/i', '.', $pf->getVersion()); + $svntag = $pf->getName() . "-$svnversion"; + $this->log(1, "Tag the released code with `pear svntag $pkgfile'"); + $this->log(1, "(or set the SVN tag $svntag by hand)"); + } + } + + return $dest_package; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/REST.php b/typo3conf/ext/phpunit/PEAR/PEAR/REST.php new file mode 100644 index 0000000..196413a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/REST.php @@ -0,0 +1,483 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: REST.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * For downloading xml files + */ +require_once 'PEAR.php'; +require_once 'PEAR/XMLParser.php'; + +/** + * Intelligently retrieve data, following hyperlinks if necessary, and re-directing + * as well + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_REST +{ + var $config; + var $_options; + + function PEAR_REST(&$config, $options = array()) + { + $this->config = &$config; + $this->_options = $options; + } + + /** + * Retrieve REST data, but always retrieve the local cache if it is available. + * + * This is useful for elements that should never change, such as information on a particular + * release + * @param string full URL to this resource + * @param array|false contents of the accept-encoding header + * @param boolean if true, xml will be returned as a string, otherwise, xml will be + * parsed using PEAR_XMLParser + * @return string|array + */ + function retrieveCacheFirst($url, $accept = false, $forcestring = false, $channel = false) + { + $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . + md5($url) . 'rest.cachefile'; + + if (file_exists($cachefile)) { + return unserialize(implode('', file($cachefile))); + } + + return $this->retrieveData($url, $accept, $forcestring, $channel); + } + + /** + * Retrieve a remote REST resource + * @param string full URL to this resource + * @param array|false contents of the accept-encoding header + * @param boolean if true, xml will be returned as a string, otherwise, xml will be + * parsed using PEAR_XMLParser + * @return string|array + */ + function retrieveData($url, $accept = false, $forcestring = false, $channel = false) + { + $cacheId = $this->getCacheId($url); + if ($ret = $this->useLocalCache($url, $cacheId)) { + return $ret; + } + + $file = $trieddownload = false; + if (!isset($this->_options['offline'])) { + $trieddownload = true; + $file = $this->downloadHttp($url, $cacheId ? $cacheId['lastChange'] : false, $accept, $channel); + } + + if (PEAR::isError($file)) { + if ($file->getCode() !== -9276) { + return $file; + } + + $trieddownload = false; + $file = false; // use local copy if available on socket connect error + } + + if (!$file) { + $ret = $this->getCache($url); + if (!PEAR::isError($ret) && $trieddownload) { + // reset the age of the cache if the server says it was unmodified + $result = $this->saveCache($url, $ret, null, true, $cacheId); + if (PEAR::isError($result)) { + return PEAR::raiseError($result->getMessage()); + } + } + + return $ret; + } + + if (is_array($file)) { + $headers = $file[2]; + $lastmodified = $file[1]; + $content = $file[0]; + } else { + $headers = array(); + $lastmodified = false; + $content = $file; + } + + if ($forcestring) { + $result = $this->saveCache($url, $content, $lastmodified, false, $cacheId); + if (PEAR::isError($result)) { + return PEAR::raiseError($result->getMessage()); + } + + return $content; + } + + if (isset($headers['content-type'])) { + switch ($headers['content-type']) { + case 'text/xml' : + case 'application/xml' : + case 'text/plain' : + if ($headers['content-type'] === 'text/plain') { + $check = substr($content, 0, 5); + if ($check !== 'parse($content); + PEAR::popErrorHandling(); + if (PEAR::isError($err)) { + return PEAR::raiseError('Invalid xml downloaded from "' . $url . '": ' . + $err->getMessage()); + } + $content = $parser->getData(); + case 'text/html' : + default : + // use it as a string + } + } else { + // assume XML + $parser = new PEAR_XMLParser; + $parser->parse($content); + $content = $parser->getData(); + } + + $result = $this->saveCache($url, $content, $lastmodified, false, $cacheId); + if (PEAR::isError($result)) { + return PEAR::raiseError($result->getMessage()); + } + + return $content; + } + + function useLocalCache($url, $cacheid = null) + { + if ($cacheid === null) { + $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . + md5($url) . 'rest.cacheid'; + if (!file_exists($cacheidfile)) { + return false; + } + + $cacheid = unserialize(implode('', file($cacheidfile))); + } + + $cachettl = $this->config->get('cache_ttl'); + // If cache is newer than $cachettl seconds, we use the cache! + if (time() - $cacheid['age'] < $cachettl) { + return $this->getCache($url); + } + + return false; + } + + function getCacheId($url) + { + $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . + md5($url) . 'rest.cacheid'; + + if (!file_exists($cacheidfile)) { + return false; + } + + $ret = unserialize(implode('', file($cacheidfile))); + return $ret; + } + + function getCache($url) + { + $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . + md5($url) . 'rest.cachefile'; + + if (!file_exists($cachefile)) { + return PEAR::raiseError('No cached content available for "' . $url . '"'); + } + + return unserialize(implode('', file($cachefile))); + } + + /** + * @param string full URL to REST resource + * @param string original contents of the REST resource + * @param array HTTP Last-Modified and ETag headers + * @param bool if true, then the cache id file should be regenerated to + * trigger a new time-to-live value + */ + function saveCache($url, $contents, $lastmodified, $nochange = false, $cacheid = null) + { + $cache_dir = $this->config->get('cache_dir'); + $d = $cache_dir . DIRECTORY_SEPARATOR . md5($url); + $cacheidfile = $d . 'rest.cacheid'; + $cachefile = $d . 'rest.cachefile'; + + if (!is_dir($cache_dir)) { + if (System::mkdir(array('-p', $cache_dir)) === false) { + return PEAR::raiseError("The value of config option cache_dir ($cache_dir) is not a directory and attempts to create the directory failed."); + } + } + + if ($cacheid === null && $nochange) { + $cacheid = unserialize(implode('', file($cacheidfile))); + } + + $idData = serialize(array( + 'age' => time(), + 'lastChange' => ($nochange ? $cacheid['lastChange'] : $lastmodified), + )); + + $result = $this->saveCacheFile($cacheidfile, $idData); + if (PEAR::isError($result)) { + return $result; + } elseif ($nochange) { + return true; + } + + $result = $this->saveCacheFile($cachefile, serialize($contents)); + if (PEAR::isError($result)) { + if (file_exists($cacheidfile)) { + @unlink($cacheidfile); + } + + return $result; + } + + return true; + } + + function saveCacheFile($file, $contents) + { + $len = strlen($contents); + + $cachefile_fp = @fopen($file, 'xb'); // x is the O_CREAT|O_EXCL mode + if ($cachefile_fp !== false) { // create file + if (fwrite($cachefile_fp, $contents, $len) < $len) { + fclose($cachefile_fp); + return PEAR::raiseError("Could not write $file."); + } + } else { // update file + $cachefile_lstat = lstat($file); + $cachefile_fp = @fopen($file, 'wb'); + if (!$cachefile_fp) { + return PEAR::raiseError("Could not open $file for writing."); + } + + $cachefile_fstat = fstat($cachefile_fp); + if ( + $cachefile_lstat['mode'] == $cachefile_fstat['mode'] && + $cachefile_lstat['ino'] == $cachefile_fstat['ino'] && + $cachefile_lstat['dev'] == $cachefile_fstat['dev'] && + $cachefile_fstat['nlink'] === 1 + ) { + if (fwrite($cachefile_fp, $contents, $len) < $len) { + fclose($cachefile_fp); + return PEAR::raiseError("Could not write $file."); + } + } else { + fclose($cachefile_fp); + $link = function_exists('readlink') ? readlink($file) : $file; + return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $file . ' as it is symlinked to ' . $link . ' - Possible symlink attack'); + } + } + + fclose($cachefile_fp); + return true; + } + + /** + * Efficiently Download a file through HTTP. Returns downloaded file as a string in-memory + * This is best used for small files + * + * If an HTTP proxy has been configured (http_proxy PEAR_Config + * setting), the proxy will be used. + * + * @param string $url the URL to download + * @param string $save_dir directory to save file in + * @param false|string|array $lastmodified header values to check against for caching + * use false to return the header values from this download + * @param false|array $accept Accept headers to send + * @return string|array Returns the contents of the downloaded file or a PEAR + * error on failure. If the error is caused by + * socket-related errors, the error object will + * have the fsockopen error code available through + * getCode(). If caching is requested, then return the header + * values. + * + * @access public + */ + function downloadHttp($url, $lastmodified = null, $accept = false, $channel = false) + { + static $redirect = 0; + // always reset , so we are clean case of error + $wasredirect = $redirect; + $redirect = 0; + + $info = parse_url($url); + if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) { + return PEAR::raiseError('Cannot download non-http URL "' . $url . '"'); + } + + if (!isset($info['host'])) { + return PEAR::raiseError('Cannot download from non-URL "' . $url . '"'); + } + + $host = isset($info['host']) ? $info['host'] : null; + $port = isset($info['port']) ? $info['port'] : null; + $path = isset($info['path']) ? $info['path'] : null; + $schema = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http'; + + $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; + if ($this->config->get('http_proxy')&& + $proxy = parse_url($this->config->get('http_proxy')) + ) { + $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; + if ($schema === 'https') { + $proxy_host = 'ssl://' . $proxy_host; + } + + $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; + $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; + $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; + $proxy_schema = (isset($proxy['scheme']) && $proxy['scheme'] == 'https') ? 'https' : 'http'; + } + + if (empty($port)) { + $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80; + } + + if (isset($proxy['host'])) { + $request = "GET $url HTTP/1.1\r\n"; + } else { + $request = "GET $path HTTP/1.1\r\n"; + } + + $request .= "Host: $host\r\n"; + $ifmodifiedsince = ''; + if (is_array($lastmodified)) { + if (isset($lastmodified['Last-Modified'])) { + $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n"; + } + + if (isset($lastmodified['ETag'])) { + $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n"; + } + } else { + $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : ''); + } + + $request .= $ifmodifiedsince . + "User-Agent: PEAR/1.9.3/PHP/" . PHP_VERSION . "\r\n"; + + $username = $this->config->get('username', null, $channel); + $password = $this->config->get('password', null, $channel); + + if ($username && $password) { + $tmp = base64_encode("$username:$password"); + $request .= "Authorization: Basic $tmp\r\n"; + } + + if ($proxy_host != '' && $proxy_user != '') { + $request .= 'Proxy-Authorization: Basic ' . + base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; + } + + if ($accept) { + $request .= 'Accept: ' . implode(', ', $accept) . "\r\n"; + } + + $request .= "Accept-Encoding:\r\n"; + $request .= "Connection: close\r\n"; + $request .= "\r\n"; + + if ($proxy_host != '') { + $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr, 15); + if (!$fp) { + return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", -9276); + } + } else { + if ($schema === 'https') { + $host = 'ssl://' . $host; + } + + $fp = @fsockopen($host, $port, $errno, $errstr); + if (!$fp) { + return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); + } + } + + fwrite($fp, $request); + + $headers = array(); + $reply = 0; + while ($line = trim(fgets($fp, 1024))) { + if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) { + $headers[strtolower($matches[1])] = trim($matches[2]); + } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { + $reply = (int)$matches[1]; + if ($reply == 304 && ($lastmodified || ($lastmodified === false))) { + return false; + } + + if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) { + return PEAR::raiseError("File $schema://$host:$port$path not valid (received: $line)"); + } + } + } + + if ($reply != 200) { + if (!isset($headers['location'])) { + return PEAR::raiseError("File $schema://$host:$port$path not valid (redirected but no location)"); + } + + if ($wasredirect > 4) { + return PEAR::raiseError("File $schema://$host:$port$path not valid (redirection looped more than 5 times)"); + } + + $redirect = $wasredirect + 1; + return $this->downloadHttp($headers['location'], $lastmodified, $accept, $channel); + } + + $length = isset($headers['content-length']) ? $headers['content-length'] : -1; + + $data = ''; + while ($chunk = @fread($fp, 8192)) { + $data .= $chunk; + } + fclose($fp); + + if ($lastmodified === false || $lastmodified) { + if (isset($headers['etag'])) { + $lastmodified = array('ETag' => $headers['etag']); + } + + if (isset($headers['last-modified'])) { + if (is_array($lastmodified)) { + $lastmodified['Last-Modified'] = $headers['last-modified']; + } else { + $lastmodified = $headers['last-modified']; + } + } + + return array($data, $lastmodified, $headers); + } + + return $data; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/REST/10.php b/typo3conf/ext/phpunit/PEAR/PEAR/REST/10.php new file mode 100644 index 0000000..85da419 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/REST/10.php @@ -0,0 +1,871 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: 10.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a12 + */ + +/** + * For downloading REST xml/txt files + */ +require_once 'PEAR/REST.php'; + +/** + * Implement REST 1.0 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a12 + */ +class PEAR_REST_10 +{ + /** + * @var PEAR_REST + */ + var $_rest; + function PEAR_REST_10($config, $options = array()) + { + $this->_rest = &new PEAR_REST($config, $options); + } + + /** + * Retrieve information about a remote package to be downloaded from a REST server + * + * @param string $base The uri to prepend to all REST calls + * @param array $packageinfo an array of format: + *
    +     *  array(
    +     *   'package' => 'packagename',
    +     *   'channel' => 'channelname',
    +     *  ['state' => 'alpha' (or valid state),]
    +     *  -or-
    +     *  ['version' => '1.whatever']
    +     * 
    + * @param string $prefstate Current preferred_state config variable value + * @param bool $installed the installed version of this package to compare against + * @return array|false|PEAR_Error see {@link _returnDownloadURL()} + */ + function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false) + { + $states = $this->betterStates($prefstate, true); + if (!$states) { + return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); + } + + $channel = $packageinfo['channel']; + $package = $packageinfo['package']; + $state = isset($packageinfo['state']) ? $packageinfo['state'] : null; + $version = isset($packageinfo['version']) ? $packageinfo['version'] : null; + $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml'; + + $info = $this->_rest->retrieveData($restFile, false, false, $channel); + if (PEAR::isError($info)) { + return PEAR::raiseError('No releases available for package "' . + $channel . '/' . $package . '"'); + } + + if (!isset($info['r'])) { + return false; + } + + $release = $found = false; + if (!is_array($info['r']) || !isset($info['r'][0])) { + $info['r'] = array($info['r']); + } + + foreach ($info['r'] as $release) { + if (!isset($this->_rest->_options['force']) && ($installed && + version_compare($release['v'], $installed, '<'))) { + continue; + } + + if (isset($state)) { + // try our preferred state first + if ($release['s'] == $state) { + $found = true; + break; + } + // see if there is something newer and more stable + // bug #7221 + if (in_array($release['s'], $this->betterStates($state), true)) { + $found = true; + break; + } + } elseif (isset($version)) { + if ($release['v'] == $version) { + $found = true; + break; + } + } else { + if (in_array($release['s'], $states)) { + $found = true; + break; + } + } + } + + return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel); + } + + function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage, + $prefstate = 'stable', $installed = false, $channel = false) + { + $states = $this->betterStates($prefstate, true); + if (!$states) { + return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); + } + + $channel = $dependency['channel']; + $package = $dependency['name']; + $state = isset($dependency['state']) ? $dependency['state'] : null; + $version = isset($dependency['version']) ? $dependency['version'] : null; + $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml'; + + $info = $this->_rest->retrieveData($restFile, false, false, $channel); + if (PEAR::isError($info)) { + return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package'] + . '" dependency "' . $channel . '/' . $package . '" has no releases'); + } + + if (!is_array($info) || !isset($info['r'])) { + return false; + } + + $exclude = array(); + $min = $max = $recommended = false; + if ($xsdversion == '1.0') { + switch ($dependency['rel']) { + case 'ge' : + $min = $dependency['version']; + break; + case 'gt' : + $min = $dependency['version']; + $exclude = array($dependency['version']); + break; + case 'eq' : + $recommended = $dependency['version']; + break; + case 'lt' : + $max = $dependency['version']; + $exclude = array($dependency['version']); + break; + case 'le' : + $max = $dependency['version']; + break; + case 'ne' : + $exclude = array($dependency['version']); + break; + } + } else { + $min = isset($dependency['min']) ? $dependency['min'] : false; + $max = isset($dependency['max']) ? $dependency['max'] : false; + $recommended = isset($dependency['recommended']) ? + $dependency['recommended'] : false; + if (isset($dependency['exclude'])) { + if (!isset($dependency['exclude'][0])) { + $exclude = array($dependency['exclude']); + } + } + } + $release = $found = false; + if (!is_array($info['r']) || !isset($info['r'][0])) { + $info['r'] = array($info['r']); + } + foreach ($info['r'] as $release) { + if (!isset($this->_rest->_options['force']) && ($installed && + version_compare($release['v'], $installed, '<'))) { + continue; + } + if (in_array($release['v'], $exclude)) { // skip excluded versions + continue; + } + // allow newer releases to say "I'm OK with the dependent package" + if ($xsdversion == '2.0' && isset($release['co'])) { + if (!is_array($release['co']) || !isset($release['co'][0])) { + $release['co'] = array($release['co']); + } + foreach ($release['co'] as $entry) { + if (isset($entry['x']) && !is_array($entry['x'])) { + $entry['x'] = array($entry['x']); + } elseif (!isset($entry['x'])) { + $entry['x'] = array(); + } + if ($entry['c'] == $deppackage['channel'] && + strtolower($entry['p']) == strtolower($deppackage['package']) && + version_compare($deppackage['version'], $entry['min'], '>=') && + version_compare($deppackage['version'], $entry['max'], '<=') && + !in_array($release['v'], $entry['x'])) { + $recommended = $release['v']; + break; + } + } + } + if ($recommended) { + if ($release['v'] != $recommended) { // if we want a specific + // version, then skip all others + continue; + } else { + if (!in_array($release['s'], $states)) { + // the stability is too low, but we must return the + // recommended version if possible + return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel); + } + } + } + if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions + continue; + } + if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions + continue; + } + if ($installed && version_compare($release['v'], $installed, '<')) { + continue; + } + if (in_array($release['s'], $states)) { // if in the preferred state... + $found = true; // ... then use it + break; + } + } + return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel); + } + + /** + * Take raw data and return the array needed for processing a download URL + * + * @param string $base REST base uri + * @param string $package Package name + * @param array $release an array of format array('v' => version, 's' => state) + * describing the release to download + * @param array $info list of all releases as defined by allreleases.xml + * @param bool|null $found determines whether the release was found or this is the next + * best alternative. If null, then versions were skipped because + * of PHP dependency + * @return array|PEAR_Error + * @access private + */ + function _returnDownloadURL($base, $package, $release, $info, $found, $phpversion = false, $channel = false) + { + if (!$found) { + $release = $info['r'][0]; + } + + $packageLower = strtolower($package); + $pinfo = $this->_rest->retrieveCacheFirst($base . 'p/' . $packageLower . '/' . + 'info.xml', false, false, $channel); + if (PEAR::isError($pinfo)) { + return PEAR::raiseError('Package "' . $package . + '" does not have REST info xml available'); + } + + $releaseinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' . + $release['v'] . '.xml', false, false, $channel); + if (PEAR::isError($releaseinfo)) { + return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] . + '" does not have REST xml available'); + } + + $packagexml = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' . + 'deps.' . $release['v'] . '.txt', false, true, $channel); + if (PEAR::isError($packagexml)) { + return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] . + '" does not have REST dependency information available'); + } + + $packagexml = unserialize($packagexml); + if (!$packagexml) { + $packagexml = array(); + } + + $allinfo = $this->_rest->retrieveData($base . 'r/' . $packageLower . + '/allreleases.xml', false, false, $channel); + if (PEAR::isError($allinfo)) { + return $allinfo; + } + + if (!is_array($allinfo['r']) || !isset($allinfo['r'][0])) { + $allinfo['r'] = array($allinfo['r']); + } + + $compatible = false; + foreach ($allinfo['r'] as $release) { + if ($release['v'] != $releaseinfo['v']) { + continue; + } + + if (!isset($release['co'])) { + break; + } + + $compatible = array(); + if (!is_array($release['co']) || !isset($release['co'][0])) { + $release['co'] = array($release['co']); + } + + foreach ($release['co'] as $entry) { + $comp = array(); + $comp['name'] = $entry['p']; + $comp['channel'] = $entry['c']; + $comp['min'] = $entry['min']; + $comp['max'] = $entry['max']; + if (isset($entry['x']) && !is_array($entry['x'])) { + $comp['exclude'] = $entry['x']; + } + + $compatible[] = $comp; + } + + if (count($compatible) == 1) { + $compatible = $compatible[0]; + } + + break; + } + + $deprecated = false; + if (isset($pinfo['dc']) && isset($pinfo['dp'])) { + if (is_array($pinfo['dp'])) { + $deprecated = array('channel' => (string) $pinfo['dc'], + 'package' => trim($pinfo['dp']['_content'])); + } else { + $deprecated = array('channel' => (string) $pinfo['dc'], + 'package' => trim($pinfo['dp'])); + } + } + + $return = array( + 'version' => $releaseinfo['v'], + 'info' => $packagexml, + 'package' => $releaseinfo['p']['_content'], + 'stability' => $releaseinfo['st'], + 'compatible' => $compatible, + 'deprecated' => $deprecated, + ); + + if ($found) { + $return['url'] = $releaseinfo['g']; + return $return; + } + + $return['php'] = $phpversion; + return $return; + } + + function listPackages($base, $channel = false) + { + $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); + if (PEAR::isError($packagelist)) { + return $packagelist; + } + + if (!is_array($packagelist) || !isset($packagelist['p'])) { + return array(); + } + + if (!is_array($packagelist['p'])) { + $packagelist['p'] = array($packagelist['p']); + } + + return $packagelist['p']; + } + + /** + * List all categories of a REST server + * + * @param string $base base URL of the server + * @return array of categorynames + */ + function listCategories($base, $channel = false) + { + $categories = array(); + + // c/categories.xml does not exist; + // check for every package its category manually + // This is SLOOOWWWW : /// + $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); + if (PEAR::isError($packagelist)) { + return $packagelist; + } + + if (!is_array($packagelist) || !isset($packagelist['p'])) { + $ret = array(); + return $ret; + } + + if (!is_array($packagelist['p'])) { + $packagelist['p'] = array($packagelist['p']); + } + + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + foreach ($packagelist['p'] as $package) { + $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel); + if (PEAR::isError($inf)) { + PEAR::popErrorHandling(); + return $inf; + } + $cat = $inf['ca']['_content']; + if (!isset($categories[$cat])) { + $categories[$cat] = $inf['ca']; + } + } + + return array_values($categories); + } + + /** + * List a category of a REST server + * + * @param string $base base URL of the server + * @param string $category name of the category + * @param boolean $info also download full package info + * @return array of packagenames + */ + function listCategory($base, $category, $info = false, $channel = false) + { + // gives '404 Not Found' error when category doesn't exist + $packagelist = $this->_rest->retrieveData($base.'c/'.urlencode($category).'/packages.xml', false, false, $channel); + if (PEAR::isError($packagelist)) { + return $packagelist; + } + + if (!is_array($packagelist) || !isset($packagelist['p'])) { + return array(); + } + + if (!is_array($packagelist['p']) || + !isset($packagelist['p'][0])) { // only 1 pkg + $packagelist = array($packagelist['p']); + } else { + $packagelist = $packagelist['p']; + } + + if ($info == true) { + // get individual package info + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + foreach ($packagelist as $i => $packageitem) { + $url = sprintf('%s'.'r/%s/latest.txt', + $base, + strtolower($packageitem['_content'])); + $version = $this->_rest->retrieveData($url, false, false, $channel); + if (PEAR::isError($version)) { + break; // skipit + } + $url = sprintf('%s'.'r/%s/%s.xml', + $base, + strtolower($packageitem['_content']), + $version); + $info = $this->_rest->retrieveData($url, false, false, $channel); + if (PEAR::isError($info)) { + break; // skipit + } + $packagelist[$i]['info'] = $info; + } + PEAR::popErrorHandling(); + } + + return $packagelist; + } + + + function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false) + { + $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); + if (PEAR::isError($packagelist)) { + return $packagelist; + } + if ($this->_rest->config->get('verbose') > 0) { + $ui = &PEAR_Frontend::singleton(); + $ui->log('Retrieving data...0%', true); + } + $ret = array(); + if (!is_array($packagelist) || !isset($packagelist['p'])) { + return $ret; + } + if (!is_array($packagelist['p'])) { + $packagelist['p'] = array($packagelist['p']); + } + + // only search-packagename = quicksearch ! + if ($searchpackage && (!$searchsummary || empty($searchpackage))) { + $newpackagelist = array(); + foreach ($packagelist['p'] as $package) { + if (!empty($searchpackage) && stristr($package, $searchpackage) !== false) { + $newpackagelist[] = $package; + } + } + $packagelist['p'] = $newpackagelist; + } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $next = .1; + foreach ($packagelist['p'] as $progress => $package) { + if ($this->_rest->config->get('verbose') > 0) { + if ($progress / count($packagelist['p']) >= $next) { + if ($next == .5) { + $ui->log('50%', false); + } else { + $ui->log('.', false); + } + $next += .1; + } + } + + if ($basic) { // remote-list command + if ($dostable) { + $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . + '/stable.txt', false, false, $channel); + } else { + $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . + '/latest.txt', false, false, $channel); + } + if (PEAR::isError($latest)) { + $latest = false; + } + $info = array('stable' => $latest); + } else { // list-all command + $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel); + if (PEAR::isError($inf)) { + PEAR::popErrorHandling(); + return $inf; + } + if ($searchpackage) { + $found = (!empty($searchpackage) && stristr($package, $searchpackage) !== false); + if (!$found && !(isset($searchsummary) && !empty($searchsummary) + && (stristr($inf['s'], $searchsummary) !== false + || stristr($inf['d'], $searchsummary) !== false))) + { + continue; + }; + } + $releases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . + '/allreleases.xml', false, false, $channel); + if (PEAR::isError($releases)) { + continue; + } + if (!isset($releases['r'][0])) { + $releases['r'] = array($releases['r']); + } + unset($latest); + unset($unstable); + unset($stable); + unset($state); + foreach ($releases['r'] as $release) { + if (!isset($latest)) { + if ($dostable && $release['s'] == 'stable') { + $latest = $release['v']; + $state = 'stable'; + } + if (!$dostable) { + $latest = $release['v']; + $state = $release['s']; + } + } + if (!isset($stable) && $release['s'] == 'stable') { + $stable = $release['v']; + if (!isset($unstable)) { + $unstable = $stable; + } + } + if (!isset($unstable) && $release['s'] != 'stable') { + $latest = $unstable = $release['v']; + $state = $release['s']; + } + if (isset($latest) && !isset($state)) { + $state = $release['s']; + } + if (isset($latest) && isset($stable) && isset($unstable)) { + break; + } + } + $deps = array(); + if (!isset($unstable)) { + $unstable = false; + $state = 'stable'; + if (isset($stable)) { + $latest = $unstable = $stable; + } + } else { + $latest = $unstable; + } + if (!isset($latest)) { + $latest = false; + } + if ($latest) { + $d = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' . + $latest . '.txt', false, false, $channel); + if (!PEAR::isError($d)) { + $d = unserialize($d); + if ($d) { + if (isset($d['required'])) { + if (!class_exists('PEAR_PackageFile_v2')) { + require_once 'PEAR/PackageFile/v2.php'; + } + if (!isset($pf)) { + $pf = new PEAR_PackageFile_v2; + } + $pf->setDeps($d); + $tdeps = $pf->getDeps(); + } else { + $tdeps = $d; + } + foreach ($tdeps as $dep) { + if ($dep['type'] !== 'pkg') { + continue; + } + $deps[] = $dep; + } + } + } + } + if (!isset($stable)) { + $stable = '-n/a-'; + } + if (!$searchpackage) { + $info = array('stable' => $latest, 'summary' => $inf['s'], 'description' => + $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'], + 'unstable' => $unstable, 'state' => $state); + } else { + $info = array('stable' => $stable, 'summary' => $inf['s'], 'description' => + $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'], + 'unstable' => $unstable, 'state' => $state); + } + } + $ret[$package] = $info; + } + PEAR::popErrorHandling(); + return $ret; + } + + function listLatestUpgrades($base, $pref_state, $installed, $channel, &$reg) + { + $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); + if (PEAR::isError($packagelist)) { + return $packagelist; + } + + $ret = array(); + if (!is_array($packagelist) || !isset($packagelist['p'])) { + return $ret; + } + + if (!is_array($packagelist['p'])) { + $packagelist['p'] = array($packagelist['p']); + } + + foreach ($packagelist['p'] as $package) { + if (!isset($installed[strtolower($package)])) { + continue; + } + + $inst_version = $reg->packageInfo($package, 'version', $channel); + $inst_state = $reg->packageInfo($package, 'release_state', $channel); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . + '/allreleases.xml', false, false, $channel); + PEAR::popErrorHandling(); + if (PEAR::isError($info)) { + continue; // no remote releases + } + + if (!isset($info['r'])) { + continue; + } + + $release = $found = false; + if (!is_array($info['r']) || !isset($info['r'][0])) { + $info['r'] = array($info['r']); + } + + // $info['r'] is sorted by version number + usort($info['r'], array($this, '_sortReleasesByVersionNumber')); + foreach ($info['r'] as $release) { + if ($inst_version && version_compare($release['v'], $inst_version, '<=')) { + // not newer than the one installed + break; + } + + // new version > installed version + if (!$pref_state) { + // every state is a good state + $found = true; + break; + } else { + $new_state = $release['s']; + // if new state >= installed state: go + if (in_array($new_state, $this->betterStates($inst_state, true))) { + $found = true; + break; + } else { + // only allow to lower the state of package, + // if new state >= preferred state: go + if (in_array($new_state, $this->betterStates($pref_state, true))) { + $found = true; + break; + } + } + } + } + + if (!$found) { + continue; + } + + $relinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' . + $release['v'] . '.xml', false, false, $channel); + if (PEAR::isError($relinfo)) { + return $relinfo; + } + + $ret[$package] = array( + 'version' => $release['v'], + 'state' => $release['s'], + 'filesize' => $relinfo['f'], + ); + } + + return $ret; + } + + function packageInfo($base, $package, $channel = false) + { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pinfo = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel); + if (PEAR::isError($pinfo)) { + PEAR::popErrorHandling(); + return PEAR::raiseError('Unknown package: "' . $package . '" in channel "' . $channel . '"' . "\n". 'Debug: ' . + $pinfo->getMessage()); + } + + $releases = array(); + $allreleases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . + '/allreleases.xml', false, false, $channel); + if (!PEAR::isError($allreleases)) { + if (!class_exists('PEAR_PackageFile_v2')) { + require_once 'PEAR/PackageFile/v2.php'; + } + + if (!is_array($allreleases['r']) || !isset($allreleases['r'][0])) { + $allreleases['r'] = array($allreleases['r']); + } + + $pf = new PEAR_PackageFile_v2; + foreach ($allreleases['r'] as $release) { + $ds = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' . + $release['v'] . '.txt', false, false, $channel); + if (PEAR::isError($ds)) { + continue; + } + + if (!isset($latest)) { + $latest = $release['v']; + } + + $pf->setDeps(unserialize($ds)); + $ds = $pf->getDeps(); + $info = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) + . '/' . $release['v'] . '.xml', false, false, $channel); + + if (PEAR::isError($info)) { + continue; + } + + $releases[$release['v']] = array( + 'doneby' => $info['m'], + 'license' => $info['l'], + 'summary' => $info['s'], + 'description' => $info['d'], + 'releasedate' => $info['da'], + 'releasenotes' => $info['n'], + 'state' => $release['s'], + 'deps' => $ds ? $ds : array(), + ); + } + } else { + $latest = ''; + } + + PEAR::popErrorHandling(); + if (isset($pinfo['dc']) && isset($pinfo['dp'])) { + if (is_array($pinfo['dp'])) { + $deprecated = array('channel' => (string) $pinfo['dc'], + 'package' => trim($pinfo['dp']['_content'])); + } else { + $deprecated = array('channel' => (string) $pinfo['dc'], + 'package' => trim($pinfo['dp'])); + } + } else { + $deprecated = false; + } + + if (!isset($latest)) { + $latest = ''; + } + + return array( + 'name' => $pinfo['n'], + 'channel' => $pinfo['c'], + 'category' => $pinfo['ca']['_content'], + 'stable' => $latest, + 'license' => $pinfo['l'], + 'summary' => $pinfo['s'], + 'description' => $pinfo['d'], + 'releases' => $releases, + 'deprecated' => $deprecated, + ); + } + + /** + * Return an array containing all of the states that are more stable than + * or equal to the passed in state + * + * @param string Release state + * @param boolean Determines whether to include $state in the list + * @return false|array False if $state is not a valid release state + */ + function betterStates($state, $include = false) + { + static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); + $i = array_search($state, $states); + if ($i === false) { + return false; + } + + if ($include) { + $i--; + } + + return array_slice($states, $i + 1); + } + + /** + * Sort releases by version number + * + * @access private + */ + function _sortReleasesByVersionNumber($a, $b) + { + if (version_compare($a['v'], $b['v'], '=')) { + return 0; + } + + if (version_compare($a['v'], $b['v'], '>')) { + return -1; + } + + if (version_compare($a['v'], $b['v'], '<')) { + return 1; + } + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/REST/11.php b/typo3conf/ext/phpunit/PEAR/PEAR/REST/11.php new file mode 100644 index 0000000..0b9e666 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/REST/11.php @@ -0,0 +1,341 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: 11.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.3 + */ + +/** + * For downloading REST xml/txt files + */ +require_once 'PEAR/REST.php'; + +/** + * Implement REST 1.1 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.3 + */ +class PEAR_REST_11 +{ + /** + * @var PEAR_REST + */ + var $_rest; + + function PEAR_REST_11($config, $options = array()) + { + $this->_rest = &new PEAR_REST($config, $options); + } + + function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false) + { + $categorylist = $this->_rest->retrieveData($base . 'c/categories.xml', false, false, $channel); + if (PEAR::isError($categorylist)) { + return $categorylist; + } + + $ret = array(); + if (!is_array($categorylist['c']) || !isset($categorylist['c'][0])) { + $categorylist['c'] = array($categorylist['c']); + } + + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + + foreach ($categorylist['c'] as $progress => $category) { + $category = $category['_content']; + $packagesinfo = $this->_rest->retrieveData($base . + 'c/' . urlencode($category) . '/packagesinfo.xml', false, false, $channel); + + if (PEAR::isError($packagesinfo)) { + continue; + } + + if (!is_array($packagesinfo) || !isset($packagesinfo['pi'])) { + continue; + } + + if (!is_array($packagesinfo['pi']) || !isset($packagesinfo['pi'][0])) { + $packagesinfo['pi'] = array($packagesinfo['pi']); + } + + foreach ($packagesinfo['pi'] as $packageinfo) { + if (empty($packageinfo)) { + continue; + } + + $info = $packageinfo['p']; + $package = $info['n']; + $releases = isset($packageinfo['a']) ? $packageinfo['a'] : false; + unset($latest); + unset($unstable); + unset($stable); + unset($state); + + if ($releases) { + if (!isset($releases['r'][0])) { + $releases['r'] = array($releases['r']); + } + + foreach ($releases['r'] as $release) { + if (!isset($latest)) { + if ($dostable && $release['s'] == 'stable') { + $latest = $release['v']; + $state = 'stable'; + } + if (!$dostable) { + $latest = $release['v']; + $state = $release['s']; + } + } + + if (!isset($stable) && $release['s'] == 'stable') { + $stable = $release['v']; + if (!isset($unstable)) { + $unstable = $stable; + } + } + + if (!isset($unstable) && $release['s'] != 'stable') { + $unstable = $release['v']; + $state = $release['s']; + } + + if (isset($latest) && !isset($state)) { + $state = $release['s']; + } + + if (isset($latest) && isset($stable) && isset($unstable)) { + break; + } + } + } + + if ($basic) { // remote-list command + if (!isset($latest)) { + $latest = false; + } + + if ($dostable) { + // $state is not set if there are no releases + if (isset($state) && $state == 'stable') { + $ret[$package] = array('stable' => $latest); + } else { + $ret[$package] = array('stable' => '-n/a-'); + } + } else { + $ret[$package] = array('stable' => $latest); + } + + continue; + } + + // list-all command + if (!isset($unstable)) { + $unstable = false; + $state = 'stable'; + if (isset($stable)) { + $latest = $unstable = $stable; + } + } else { + $latest = $unstable; + } + + if (!isset($latest)) { + $latest = false; + } + + $deps = array(); + if ($latest && isset($packageinfo['deps'])) { + if (!is_array($packageinfo['deps']) || + !isset($packageinfo['deps'][0]) + ) { + $packageinfo['deps'] = array($packageinfo['deps']); + } + + $d = false; + foreach ($packageinfo['deps'] as $dep) { + if ($dep['v'] == $latest) { + $d = unserialize($dep['d']); + } + } + + if ($d) { + if (isset($d['required'])) { + if (!class_exists('PEAR_PackageFile_v2')) { + require_once 'PEAR/PackageFile/v2.php'; + } + + if (!isset($pf)) { + $pf = new PEAR_PackageFile_v2; + } + + $pf->setDeps($d); + $tdeps = $pf->getDeps(); + } else { + $tdeps = $d; + } + + foreach ($tdeps as $dep) { + if ($dep['type'] !== 'pkg') { + continue; + } + + $deps[] = $dep; + } + } + } + + $info = array( + 'stable' => $latest, + 'summary' => $info['s'], + 'description' => $info['d'], + 'deps' => $deps, + 'category' => $info['ca']['_content'], + 'unstable' => $unstable, + 'state' => $state + ); + $ret[$package] = $info; + } + } + + PEAR::popErrorHandling(); + return $ret; + } + + /** + * List all categories of a REST server + * + * @param string $base base URL of the server + * @return array of categorynames + */ + function listCategories($base, $channel = false) + { + $categorylist = $this->_rest->retrieveData($base . 'c/categories.xml', false, false, $channel); + if (PEAR::isError($categorylist)) { + return $categorylist; + } + + if (!is_array($categorylist) || !isset($categorylist['c'])) { + return array(); + } + + if (isset($categorylist['c']['_content'])) { + // only 1 category + $categorylist['c'] = array($categorylist['c']); + } + + return $categorylist['c']; + } + + /** + * List packages in a category of a REST server + * + * @param string $base base URL of the server + * @param string $category name of the category + * @param boolean $info also download full package info + * @return array of packagenames + */ + function listCategory($base, $category, $info = false, $channel = false) + { + if ($info == false) { + $url = '%s'.'c/%s/packages.xml'; + } else { + $url = '%s'.'c/%s/packagesinfo.xml'; + } + $url = sprintf($url, + $base, + urlencode($category)); + + // gives '404 Not Found' error when category doesn't exist + $packagelist = $this->_rest->retrieveData($url, false, false, $channel); + if (PEAR::isError($packagelist)) { + return $packagelist; + } + if (!is_array($packagelist)) { + return array(); + } + + if ($info == false) { + if (!isset($packagelist['p'])) { + return array(); + } + if (!is_array($packagelist['p']) || + !isset($packagelist['p'][0])) { // only 1 pkg + $packagelist = array($packagelist['p']); + } else { + $packagelist = $packagelist['p']; + } + return $packagelist; + } + + // info == true + if (!isset($packagelist['pi'])) { + return array(); + } + + if (!is_array($packagelist['pi']) || + !isset($packagelist['pi'][0])) { // only 1 pkg + $packagelist_pre = array($packagelist['pi']); + } else { + $packagelist_pre = $packagelist['pi']; + } + + $packagelist = array(); + foreach ($packagelist_pre as $i => $item) { + // compatibility with r/.xml + if (isset($item['a']['r'][0])) { + // multiple releases + $item['p']['v'] = $item['a']['r'][0]['v']; + $item['p']['st'] = $item['a']['r'][0]['s']; + } elseif (isset($item['a'])) { + // first and only release + $item['p']['v'] = $item['a']['r']['v']; + $item['p']['st'] = $item['a']['r']['s']; + } + + $packagelist[$i] = array('attribs' => $item['p']['r'], + '_content' => $item['p']['n'], + 'info' => $item['p']); + } + + return $packagelist; + } + + /** + * Return an array containing all of the states that are more stable than + * or equal to the passed in state + * + * @param string Release state + * @param boolean Determines whether to include $state in the list + * @return false|array False if $state is not a valid release state + */ + function betterStates($state, $include = false) + { + static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); + $i = array_search($state, $states); + if ($i === false) { + return false; + } + if ($include) { + $i--; + } + return array_slice($states, $i + 1); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/REST/13.php b/typo3conf/ext/phpunit/PEAR/PEAR/REST/13.php new file mode 100644 index 0000000..c22c7b6 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/REST/13.php @@ -0,0 +1,299 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: 13.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a12 + */ + +/** + * For downloading REST xml/txt files + */ +require_once 'PEAR/REST.php'; +require_once 'PEAR/REST/10.php'; + +/** + * Implement REST 1.3 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a12 + */ +class PEAR_REST_13 extends PEAR_REST_10 +{ + /** + * Retrieve information about a remote package to be downloaded from a REST server + * + * This is smart enough to resolve the minimum PHP version dependency prior to download + * @param string $base The uri to prepend to all REST calls + * @param array $packageinfo an array of format: + *
    +     *  array(
    +     *   'package' => 'packagename',
    +     *   'channel' => 'channelname',
    +     *  ['state' => 'alpha' (or valid state),]
    +     *  -or-
    +     *  ['version' => '1.whatever']
    +     * 
    + * @param string $prefstate Current preferred_state config variable value + * @param bool $installed the installed version of this package to compare against + * @return array|false|PEAR_Error see {@link _returnDownloadURL()} + */ + function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false) + { + $states = $this->betterStates($prefstate, true); + if (!$states) { + return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); + } + + $channel = $packageinfo['channel']; + $package = $packageinfo['package']; + $state = isset($packageinfo['state']) ? $packageinfo['state'] : null; + $version = isset($packageinfo['version']) ? $packageinfo['version'] : null; + $restFile = $base . 'r/' . strtolower($package) . '/allreleases2.xml'; + + $info = $this->_rest->retrieveData($restFile, false, false, $channel); + if (PEAR::isError($info)) { + return PEAR::raiseError('No releases available for package "' . + $channel . '/' . $package . '"'); + } + + if (!isset($info['r'])) { + return false; + } + + $release = $found = false; + if (!is_array($info['r']) || !isset($info['r'][0])) { + $info['r'] = array($info['r']); + } + + $skippedphp = false; + foreach ($info['r'] as $release) { + if (!isset($this->_rest->_options['force']) && ($installed && + version_compare($release['v'], $installed, '<'))) { + continue; + } + + if (isset($state)) { + // try our preferred state first + if ($release['s'] == $state) { + if (!isset($version) && version_compare($release['m'], phpversion(), '>')) { + // skip releases that require a PHP version newer than our PHP version + $skippedphp = $release; + continue; + } + $found = true; + break; + } + + // see if there is something newer and more stable + // bug #7221 + if (in_array($release['s'], $this->betterStates($state), true)) { + if (!isset($version) && version_compare($release['m'], phpversion(), '>')) { + // skip releases that require a PHP version newer than our PHP version + $skippedphp = $release; + continue; + } + $found = true; + break; + } + } elseif (isset($version)) { + if ($release['v'] == $version) { + if (!isset($this->_rest->_options['force']) && + !isset($version) && + version_compare($release['m'], phpversion(), '>')) { + // skip releases that require a PHP version newer than our PHP version + $skippedphp = $release; + continue; + } + $found = true; + break; + } + } else { + if (in_array($release['s'], $states)) { + if (version_compare($release['m'], phpversion(), '>')) { + // skip releases that require a PHP version newer than our PHP version + $skippedphp = $release; + continue; + } + $found = true; + break; + } + } + } + + if (!$found && $skippedphp) { + $found = null; + } + + return $this->_returnDownloadURL($base, $package, $release, $info, $found, $skippedphp, $channel); + } + + function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage, + $prefstate = 'stable', $installed = false, $channel = false) + { + $states = $this->betterStates($prefstate, true); + if (!$states) { + return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); + } + + $channel = $dependency['channel']; + $package = $dependency['name']; + $state = isset($dependency['state']) ? $dependency['state'] : null; + $version = isset($dependency['version']) ? $dependency['version'] : null; + $restFile = $base . 'r/' . strtolower($package) .'/allreleases2.xml'; + + $info = $this->_rest->retrieveData($restFile, false, false, $channel); + if (PEAR::isError($info)) { + return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package'] + . '" dependency "' . $channel . '/' . $package . '" has no releases'); + } + + if (!is_array($info) || !isset($info['r'])) { + return false; + } + + $exclude = array(); + $min = $max = $recommended = false; + if ($xsdversion == '1.0') { + $pinfo['package'] = $dependency['name']; + $pinfo['channel'] = 'pear.php.net'; // this is always true - don't change this + switch ($dependency['rel']) { + case 'ge' : + $min = $dependency['version']; + break; + case 'gt' : + $min = $dependency['version']; + $exclude = array($dependency['version']); + break; + case 'eq' : + $recommended = $dependency['version']; + break; + case 'lt' : + $max = $dependency['version']; + $exclude = array($dependency['version']); + break; + case 'le' : + $max = $dependency['version']; + break; + case 'ne' : + $exclude = array($dependency['version']); + break; + } + } else { + $pinfo['package'] = $dependency['name']; + $min = isset($dependency['min']) ? $dependency['min'] : false; + $max = isset($dependency['max']) ? $dependency['max'] : false; + $recommended = isset($dependency['recommended']) ? + $dependency['recommended'] : false; + if (isset($dependency['exclude'])) { + if (!isset($dependency['exclude'][0])) { + $exclude = array($dependency['exclude']); + } + } + } + + $skippedphp = $found = $release = false; + if (!is_array($info['r']) || !isset($info['r'][0])) { + $info['r'] = array($info['r']); + } + + foreach ($info['r'] as $release) { + if (!isset($this->_rest->_options['force']) && ($installed && + version_compare($release['v'], $installed, '<'))) { + continue; + } + + if (in_array($release['v'], $exclude)) { // skip excluded versions + continue; + } + + // allow newer releases to say "I'm OK with the dependent package" + if ($xsdversion == '2.0' && isset($release['co'])) { + if (!is_array($release['co']) || !isset($release['co'][0])) { + $release['co'] = array($release['co']); + } + + foreach ($release['co'] as $entry) { + if (isset($entry['x']) && !is_array($entry['x'])) { + $entry['x'] = array($entry['x']); + } elseif (!isset($entry['x'])) { + $entry['x'] = array(); + } + + if ($entry['c'] == $deppackage['channel'] && + strtolower($entry['p']) == strtolower($deppackage['package']) && + version_compare($deppackage['version'], $entry['min'], '>=') && + version_compare($deppackage['version'], $entry['max'], '<=') && + !in_array($release['v'], $entry['x'])) { + if (version_compare($release['m'], phpversion(), '>')) { + // skip dependency releases that require a PHP version + // newer than our PHP version + $skippedphp = $release; + continue; + } + + $recommended = $release['v']; + break; + } + } + } + + if ($recommended) { + if ($release['v'] != $recommended) { // if we want a specific + // version, then skip all others + continue; + } + + if (!in_array($release['s'], $states)) { + // the stability is too low, but we must return the + // recommended version if possible + return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel); + } + } + + if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions + continue; + } + + if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions + continue; + } + + if ($installed && version_compare($release['v'], $installed, '<')) { + continue; + } + + if (in_array($release['s'], $states)) { // if in the preferred state... + if (version_compare($release['m'], phpversion(), '>')) { + // skip dependency releases that require a PHP version + // newer than our PHP version + $skippedphp = $release; + continue; + } + + $found = true; // ... then use it + break; + } + } + + if (!$found && $skippedphp) { + $found = null; + } + + return $this->_returnDownloadURL($base, $package, $release, $info, $found, $skippedphp, $channel); + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Registry.php b/typo3conf/ext/phpunit/PEAR/PEAR/Registry.php new file mode 100644 index 0000000..a7cd009 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Registry.php @@ -0,0 +1,2395 @@ + + * @author Tomas V. V. Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Registry.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * for PEAR_Error + */ +require_once 'PEAR.php'; +require_once 'PEAR/DependencyDB.php'; + +define('PEAR_REGISTRY_ERROR_LOCK', -2); +define('PEAR_REGISTRY_ERROR_FORMAT', -3); +define('PEAR_REGISTRY_ERROR_FILE', -4); +define('PEAR_REGISTRY_ERROR_CONFLICT', -5); +define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', -6); + +/** + * Administration class used to maintain the installed package database. + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V. V. Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Registry extends PEAR +{ + /** + * File containing all channel information. + * @var string + */ + var $channels = ''; + + /** Directory where registry files are stored. + * @var string + */ + var $statedir = ''; + + /** File where the file map is stored + * @var string + */ + var $filemap = ''; + + /** Directory where registry files for channels are stored. + * @var string + */ + var $channelsdir = ''; + + /** Name of file used for locking the registry + * @var string + */ + var $lockfile = ''; + + /** File descriptor used during locking + * @var resource + */ + var $lock_fp = null; + + /** Mode used during locking + * @var int + */ + var $lock_mode = 0; // XXX UNUSED + + /** Cache of package information. Structure: + * array( + * 'package' => array('id' => ... ), + * ... ) + * @var array + */ + var $pkginfo_cache = array(); + + /** Cache of file map. Structure: + * array( '/path/to/file' => 'package', ... ) + * @var array + */ + var $filemap_cache = array(); + + /** + * @var false|PEAR_ChannelFile + */ + var $_pearChannel; + + /** + * @var false|PEAR_ChannelFile + */ + var $_peclChannel; + + /** + * @var false|PEAR_ChannelFile + */ + var $_docChannel; + + /** + * @var PEAR_DependencyDB + */ + var $_dependencyDB; + + /** + * @var PEAR_Config + */ + var $_config; + + /** + * PEAR_Registry constructor. + * + * @param string (optional) PEAR install directory (for .php files) + * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if + * default values are not desired. Only used the very first time a PEAR + * repository is initialized + * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if + * default values are not desired. Only used the very first time a PEAR + * repository is initialized + * + * @access public + */ + function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false, + $pecl_channel = false) + { + parent::PEAR(); + $this->setInstallDir($pear_install_dir); + $this->_pearChannel = $pear_channel; + $this->_peclChannel = $pecl_channel; + $this->_config = false; + } + + function setInstallDir($pear_install_dir = PEAR_INSTALL_DIR) + { + $ds = DIRECTORY_SEPARATOR; + $this->install_dir = $pear_install_dir; + $this->channelsdir = $pear_install_dir.$ds.'.channels'; + $this->statedir = $pear_install_dir.$ds.'.registry'; + $this->filemap = $pear_install_dir.$ds.'.filemap'; + $this->lockfile = $pear_install_dir.$ds.'.lock'; + } + + function hasWriteAccess() + { + if (!file_exists($this->install_dir)) { + $dir = $this->install_dir; + while ($dir && $dir != '.') { + $olddir = $dir; + $dir = dirname($dir); + if ($dir != '.' && file_exists($dir)) { + if (is_writeable($dir)) { + return true; + } + + return false; + } + + if ($dir == $olddir) { // this can happen in safe mode + return @is_writable($dir); + } + } + + return false; + } + + return is_writeable($this->install_dir); + } + + function setConfig(&$config, $resetInstallDir = true) + { + $this->_config = &$config; + if ($resetInstallDir) { + $this->setInstallDir($config->get('php_dir')); + } + } + + function _initializeChannelDirs() + { + static $running = false; + if (!$running) { + $running = true; + $ds = DIRECTORY_SEPARATOR; + if (!is_dir($this->channelsdir) || + !file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || + !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || + !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || + !file_exists($this->channelsdir . $ds . '__uri.reg')) { + if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { + $pear_channel = $this->_pearChannel; + if (!is_a($pear_channel, 'PEAR_ChannelFile') || !$pear_channel->validate()) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $pear_channel = new PEAR_ChannelFile; + $pear_channel->setAlias('pear'); + $pear_channel->setServer('pear.php.net'); + $pear_channel->setSummary('PHP Extension and Application Repository'); + $pear_channel->setDefaultPEARProtocols(); + $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); + $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); + $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/'); + //$pear_channel->setBaseURL('REST1.4', 'http://pear.php.net/rest/'); + } else { + $pear_channel->setServer('pear.php.net'); + $pear_channel->setAlias('pear'); + } + + $pear_channel->validate(); + $this->_addChannel($pear_channel); + } + + if (!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg')) { + $pecl_channel = $this->_peclChannel; + if (!is_a($pecl_channel, 'PEAR_ChannelFile') || !$pecl_channel->validate()) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $pecl_channel = new PEAR_ChannelFile; + $pecl_channel->setAlias('pecl'); + $pecl_channel->setServer('pecl.php.net'); + $pecl_channel->setSummary('PHP Extension Community Library'); + $pecl_channel->setDefaultPEARProtocols(); + $pecl_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); + $pecl_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); + $pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); + } else { + $pecl_channel->setServer('pecl.php.net'); + $pecl_channel->setAlias('pecl'); + } + + $pecl_channel->validate(); + $this->_addChannel($pecl_channel); + } + + if (!file_exists($this->channelsdir . $ds . 'doc.php.net.reg')) { + $doc_channel = $this->_docChannel; + if (!is_a($doc_channel, 'PEAR_ChannelFile') || !$doc_channel->validate()) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $doc_channel = new PEAR_ChannelFile; + $doc_channel->setAlias('phpdocs'); + $doc_channel->setServer('doc.php.net'); + $doc_channel->setSummary('PHP Documentation Team'); + $doc_channel->setDefaultPEARProtocols(); + $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/'); + $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/'); + $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/'); + } else { + $doc_channel->setServer('doc.php.net'); + $doc_channel->setAlias('doc'); + } + + $doc_channel->validate(); + $this->_addChannel($doc_channel); + } + + if (!file_exists($this->channelsdir . $ds . '__uri.reg')) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $private = new PEAR_ChannelFile; + $private->setName('__uri'); + $private->setDefaultPEARProtocols(); + $private->setBaseURL('REST1.0', '****'); + $private->setSummary('Pseudo-channel for static packages'); + $this->_addChannel($private); + } + $this->_rebuildFileMap(); + } + + $running = false; + } + } + + function _initializeDirs() + { + $ds = DIRECTORY_SEPARATOR; + // XXX Compatibility code should be removed in the future + // rename all registry files if any to lowercase + if (!OS_WINDOWS && file_exists($this->statedir) && is_dir($this->statedir) && + $handle = opendir($this->statedir)) { + $dest = $this->statedir . $ds; + while (false !== ($file = readdir($handle))) { + if (preg_match('/^.*[A-Z].*\.reg\\z/', $file)) { + rename($dest . $file, $dest . strtolower($file)); + } + } + closedir($handle); + } + + $this->_initializeChannelDirs(); + if (!file_exists($this->filemap)) { + $this->_rebuildFileMap(); + } + $this->_initializeDepDB(); + } + + function _initializeDepDB() + { + if (!isset($this->_dependencyDB)) { + static $initializing = false; + if (!$initializing) { + $initializing = true; + if (!$this->_config) { // never used? + $file = OS_WINDOWS ? 'pear.ini' : '.pearrc'; + $this->_config = &new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR . + $file); + $this->_config->setRegistry($this); + $this->_config->set('php_dir', $this->install_dir); + } + + $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); + if (PEAR::isError($this->_dependencyDB)) { + // attempt to recover by removing the dep db + if (file_exists($this->_config->get('php_dir', null, 'pear.php.net') . + DIRECTORY_SEPARATOR . '.depdb')) { + @unlink($this->_config->get('php_dir', null, 'pear.php.net') . + DIRECTORY_SEPARATOR . '.depdb'); + } + + $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); + if (PEAR::isError($this->_dependencyDB)) { + echo $this->_dependencyDB->getMessage(); + echo 'Unrecoverable error'; + exit(1); + } + } + + $initializing = false; + } + } + } + + /** + * PEAR_Registry destructor. Makes sure no locks are forgotten. + * + * @access private + */ + function _PEAR_Registry() + { + parent::_PEAR(); + if (is_resource($this->lock_fp)) { + $this->_unlock(); + } + } + + /** + * Make sure the directory where we keep registry files exists. + * + * @return bool TRUE if directory exists, FALSE if it could not be + * created + * + * @access private + */ + function _assertStateDir($channel = false) + { + if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { + return $this->_assertChannelStateDir($channel); + } + + static $init = false; + if (!file_exists($this->statedir)) { + if (!$this->hasWriteAccess()) { + return false; + } + + require_once 'System.php'; + if (!System::mkdir(array('-p', $this->statedir))) { + return $this->raiseError("could not create directory '{$this->statedir}'"); + } + $init = true; + } elseif (!is_dir($this->statedir)) { + return $this->raiseError('Cannot create directory ' . $this->statedir . ', ' . + 'it already exists and is not a directory'); + } + + $ds = DIRECTORY_SEPARATOR; + if (!file_exists($this->channelsdir)) { + if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || + !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || + !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || + !file_exists($this->channelsdir . $ds . '__uri.reg')) { + $init = true; + } + } elseif (!is_dir($this->channelsdir)) { + return $this->raiseError('Cannot create directory ' . $this->channelsdir . ', ' . + 'it already exists and is not a directory'); + } + + if ($init) { + static $running = false; + if (!$running) { + $running = true; + $this->_initializeDirs(); + $running = false; + $init = false; + } + } else { + $this->_initializeDepDB(); + } + + return true; + } + + /** + * Make sure the directory where we keep registry files exists for a non-standard channel. + * + * @param string channel name + * @return bool TRUE if directory exists, FALSE if it could not be + * created + * + * @access private + */ + function _assertChannelStateDir($channel) + { + $ds = DIRECTORY_SEPARATOR; + if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { + if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { + $this->_initializeChannelDirs(); + } + return $this->_assertStateDir($channel); + } + + $channelDir = $this->_channelDirectoryName($channel); + if (!is_dir($this->channelsdir) || + !file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { + $this->_initializeChannelDirs(); + } + + if (!file_exists($channelDir)) { + if (!$this->hasWriteAccess()) { + return false; + } + + require_once 'System.php'; + if (!System::mkdir(array('-p', $channelDir))) { + return $this->raiseError("could not create directory '" . $channelDir . + "'"); + } + } elseif (!is_dir($channelDir)) { + return $this->raiseError("could not create directory '" . $channelDir . + "', already exists and is not a directory"); + } + + return true; + } + + /** + * Make sure the directory where we keep registry files for channels exists + * + * @return bool TRUE if directory exists, FALSE if it could not be + * created + * + * @access private + */ + function _assertChannelDir() + { + if (!file_exists($this->channelsdir)) { + if (!$this->hasWriteAccess()) { + return false; + } + + require_once 'System.php'; + if (!System::mkdir(array('-p', $this->channelsdir))) { + return $this->raiseError("could not create directory '{$this->channelsdir}'"); + } + } elseif (!is_dir($this->channelsdir)) { + return $this->raiseError("could not create directory '{$this->channelsdir}" . + "', it already exists and is not a directory"); + } + + if (!file_exists($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { + if (!$this->hasWriteAccess()) { + return false; + } + + require_once 'System.php'; + if (!System::mkdir(array('-p', $this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))) { + return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'"); + } + } elseif (!is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { + return $this->raiseError("could not create directory '{$this->channelsdir}" . + "/.alias', it already exists and is not a directory"); + } + + return true; + } + + /** + * Get the name of the file where data for a given package is stored. + * + * @param string channel name, or false if this is a PEAR package + * @param string package name + * + * @return string registry file name + * + * @access public + */ + function _packageFileName($package, $channel = false) + { + if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { + return $this->_channelDirectoryName($channel) . DIRECTORY_SEPARATOR . + strtolower($package) . '.reg'; + } + + return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg'; + } + + /** + * Get the name of the file where data for a given channel is stored. + * @param string channel name + * @return string registry file name + */ + function _channelFileName($channel, $noaliases = false) + { + if (!$noaliases) { + if (file_exists($this->_getChannelAliasFileName($channel))) { + $channel = implode('', file($this->_getChannelAliasFileName($channel))); + } + } + return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/', '_', + strtolower($channel)) . '.reg'; + } + + /** + * @param string + * @return string + */ + function _getChannelAliasFileName($alias) + { + return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' . + DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt'; + } + + /** + * Get the name of a channel from its alias + */ + function _getChannelFromAlias($channel) + { + if (!$this->_channelExists($channel)) { + if ($channel == 'pear.php.net') { + return 'pear.php.net'; + } + + if ($channel == 'pecl.php.net') { + return 'pecl.php.net'; + } + + if ($channel == 'doc.php.net') { + return 'doc.php.net'; + } + + if ($channel == '__uri') { + return '__uri'; + } + + return false; + } + + $channel = strtolower($channel); + if (file_exists($this->_getChannelAliasFileName($channel))) { + // translate an alias to an actual channel + return implode('', file($this->_getChannelAliasFileName($channel))); + } + + return $channel; + } + + /** + * Get the alias of a channel from its alias or its name + */ + function _getAlias($channel) + { + if (!$this->_channelExists($channel)) { + if ($channel == 'pear.php.net') { + return 'pear'; + } + + if ($channel == 'pecl.php.net') { + return 'pecl'; + } + + if ($channel == 'doc.php.net') { + return 'phpdocs'; + } + + return false; + } + + $channel = $this->_getChannel($channel); + if (PEAR::isError($channel)) { + return $channel; + } + + return $channel->getAlias(); + } + + /** + * Get the name of the file where data for a given package is stored. + * + * @param string channel name, or false if this is a PEAR package + * @param string package name + * + * @return string registry file name + * + * @access public + */ + function _channelDirectoryName($channel) + { + if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { + return $this->statedir; + } + + $ch = $this->_getChannelFromAlias($channel); + if (!$ch) { + $ch = $channel; + } + + return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' . + str_replace('/', '_', $ch)); + } + + function _openPackageFile($package, $mode, $channel = false) + { + if (!$this->_assertStateDir($channel)) { + return null; + } + + if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { + return null; + } + + $file = $this->_packageFileName($package, $channel); + if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { + return null; + } + + $fp = @fopen($file, $mode); + if (!$fp) { + return null; + } + + return $fp; + } + + function _closePackageFile($fp) + { + fclose($fp); + } + + function _openChannelFile($channel, $mode) + { + if (!$this->_assertChannelDir()) { + return null; + } + + if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { + return null; + } + + $file = $this->_channelFileName($channel); + if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { + return null; + } + + $fp = @fopen($file, $mode); + if (!$fp) { + return null; + } + + return $fp; + } + + function _closeChannelFile($fp) + { + fclose($fp); + } + + function _rebuildFileMap() + { + if (!class_exists('PEAR_Installer_Role')) { + require_once 'PEAR/Installer/Role.php'; + } + + $channels = $this->_listAllPackages(); + $files = array(); + foreach ($channels as $channel => $packages) { + foreach ($packages as $package) { + $version = $this->_packageInfo($package, 'version', $channel); + $filelist = $this->_packageInfo($package, 'filelist', $channel); + if (!is_array($filelist)) { + continue; + } + + foreach ($filelist as $name => $attrs) { + if (isset($attrs['attribs'])) { + $attrs = $attrs['attribs']; + } + + // it is possible for conflicting packages in different channels to + // conflict with data files/doc files + if ($name == 'dirtree') { + continue; + } + + if (isset($attrs['role']) && !in_array($attrs['role'], + PEAR_Installer_Role::getInstallableRoles())) { + // these are not installed + continue; + } + + if (isset($attrs['role']) && !in_array($attrs['role'], + PEAR_Installer_Role::getBaseinstallRoles())) { + $attrs['baseinstalldir'] = $package; + } + + if (isset($attrs['baseinstalldir'])) { + $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name; + } else { + $file = $name; + } + + $file = preg_replace(',^/+,', '', $file); + if ($channel != 'pear.php.net') { + if (!isset($files[$attrs['role']])) { + $files[$attrs['role']] = array(); + } + $files[$attrs['role']][$file] = array(strtolower($channel), + strtolower($package)); + } else { + if (!isset($files[$attrs['role']])) { + $files[$attrs['role']] = array(); + } + $files[$attrs['role']][$file] = strtolower($package); + } + } + } + } + + + $this->_assertStateDir(); + if (!$this->hasWriteAccess()) { + return false; + } + + $fp = @fopen($this->filemap, 'wb'); + if (!$fp) { + return false; + } + + $this->filemap_cache = $files; + fwrite($fp, serialize($files)); + fclose($fp); + return true; + } + + function _readFileMap() + { + if (!file_exists($this->filemap)) { + return array(); + } + + $fp = @fopen($this->filemap, 'r'); + if (!$fp) { + return $this->raiseError('PEAR_Registry: could not open filemap "' . $this->filemap . '"', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg); + } + + clearstatcache(); + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + $fsize = filesize($this->filemap); + fclose($fp); + $data = file_get_contents($this->filemap); + set_magic_quotes_runtime($rt); + $tmp = unserialize($data); + if (!$tmp && $fsize > 7) { + return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data); + } + + $this->filemap_cache = $tmp; + return true; + } + + /** + * Lock the registry. + * + * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN. + * See flock manual for more information. + * + * @return bool TRUE on success, FALSE if locking failed, or a + * PEAR error if some other error occurs (such as the + * lock file not being writable). + * + * @access private + */ + function _lock($mode = LOCK_EX) + { + if (stristr(php_uname(), 'Windows 9')) { + return true; + } + + if ($mode != LOCK_UN && is_resource($this->lock_fp)) { + // XXX does not check type of lock (LOCK_SH/LOCK_EX) + return true; + } + + if (!$this->_assertStateDir()) { + if ($mode == LOCK_EX) { + return $this->raiseError('Registry directory is not writeable by the current user'); + } + + return true; + } + + $open_mode = 'w'; + // XXX People reported problems with LOCK_SH and 'w' + if ($mode === LOCK_SH || $mode === LOCK_UN) { + if (!file_exists($this->lockfile)) { + touch($this->lockfile); + } + $open_mode = 'r'; + } + + if (!is_resource($this->lock_fp)) { + $this->lock_fp = @fopen($this->lockfile, $open_mode); + } + + if (!is_resource($this->lock_fp)) { + $this->lock_fp = null; + return $this->raiseError("could not create lock file" . + (isset($php_errormsg) ? ": " . $php_errormsg : "")); + } + + if (!(int)flock($this->lock_fp, $mode)) { + switch ($mode) { + case LOCK_SH: $str = 'shared'; break; + case LOCK_EX: $str = 'exclusive'; break; + case LOCK_UN: $str = 'unlock'; break; + default: $str = 'unknown'; break; + } + + //is resource at this point, close it on error. + fclose($this->lock_fp); + $this->lock_fp = null; + return $this->raiseError("could not acquire $str lock ($this->lockfile)", + PEAR_REGISTRY_ERROR_LOCK); + } + + return true; + } + + function _unlock() + { + $ret = $this->_lock(LOCK_UN); + if (is_resource($this->lock_fp)) { + fclose($this->lock_fp); + } + + $this->lock_fp = null; + return $ret; + } + + function _packageExists($package, $channel = false) + { + return file_exists($this->_packageFileName($package, $channel)); + } + + /** + * Determine whether a channel exists in the registry + * + * @param string Channel name + * @param bool if true, then aliases will be ignored + * @return boolean + */ + function _channelExists($channel, $noaliases = false) + { + $a = file_exists($this->_channelFileName($channel, $noaliases)); + if (!$a && $channel == 'pear.php.net') { + return true; + } + + if (!$a && $channel == 'pecl.php.net') { + return true; + } + + if (!$a && $channel == 'doc.php.net') { + return true; + } + + return $a; + } + + /** + * Determine whether a mirror exists within the deafult channel in the registry + * + * @param string Channel name + * @param string Mirror name + * + * @return boolean + */ + function _mirrorExists($channel, $mirror) + { + $data = $this->_channelInfo($channel); + if (!isset($data['servers']['mirror'])) { + return false; + } + + foreach ($data['servers']['mirror'] as $m) { + if ($m['attribs']['host'] == $mirror) { + return true; + } + } + + return false; + } + + /** + * @param PEAR_ChannelFile Channel object + * @param donotuse + * @param string Last-Modified HTTP tag from remote request + * @return boolean|PEAR_Error True on creation, false if it already exists + */ + function _addChannel($channel, $update = false, $lastmodified = false) + { + if (!is_a($channel, 'PEAR_ChannelFile')) { + return false; + } + + if (!$channel->validate()) { + return false; + } + + if (file_exists($this->_channelFileName($channel->getName()))) { + if (!$update) { + return false; + } + + $checker = $this->_getChannel($channel->getName()); + if (PEAR::isError($checker)) { + return $checker; + } + + if ($channel->getAlias() != $checker->getAlias()) { + if (file_exists($this->_getChannelAliasFileName($checker->getAlias()))) { + @unlink($this->_getChannelAliasFileName($checker->getAlias())); + } + } + } else { + if ($update && !in_array($channel->getName(), array('pear.php.net', 'pecl.php.net', 'doc.php.net'))) { + return false; + } + } + + $ret = $this->_assertChannelDir(); + if (PEAR::isError($ret)) { + return $ret; + } + + $ret = $this->_assertChannelStateDir($channel->getName()); + if (PEAR::isError($ret)) { + return $ret; + } + + if ($channel->getAlias() != $channel->getName()) { + if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) && + $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) { + $channel->setAlias($channel->getName()); + } + + if (!$this->hasWriteAccess()) { + return false; + } + + $fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w'); + if (!$fp) { + return false; + } + + fwrite($fp, $channel->getName()); + fclose($fp); + } + + if (!$this->hasWriteAccess()) { + return false; + } + + $fp = @fopen($this->_channelFileName($channel->getName()), 'wb'); + if (!$fp) { + return false; + } + + $info = $channel->toArray(); + if ($lastmodified) { + $info['_lastmodified'] = $lastmodified; + } else { + $info['_lastmodified'] = date('r'); + } + + fwrite($fp, serialize($info)); + fclose($fp); + return true; + } + + /** + * Deletion fails if there are any packages installed from the channel + * @param string|PEAR_ChannelFile channel name + * @return boolean|PEAR_Error True on deletion, false if it doesn't exist + */ + function _deleteChannel($channel) + { + if (!is_string($channel)) { + if (!is_a($channel, 'PEAR_ChannelFile')) { + return false; + } + + if (!$channel->validate()) { + return false; + } + $channel = $channel->getName(); + } + + if ($this->_getChannelFromAlias($channel) == '__uri') { + return false; + } + + if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { + return false; + } + + if ($this->_getChannelFromAlias($channel) == 'doc.php.net') { + return false; + } + + if (!$this->_channelExists($channel)) { + return false; + } + + if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { + return false; + } + + $channel = $this->_getChannelFromAlias($channel); + if ($channel == 'pear.php.net') { + return false; + } + + $test = $this->_listChannelPackages($channel); + if (count($test)) { + return false; + } + + $test = @rmdir($this->_channelDirectoryName($channel)); + if (!$test) { + return false; + } + + $file = $this->_getChannelAliasFileName($this->_getAlias($channel)); + if (file_exists($file)) { + $test = @unlink($file); + if (!$test) { + return false; + } + } + + $file = $this->_channelFileName($channel); + $ret = true; + if (file_exists($file)) { + $ret = @unlink($file); + } + + return $ret; + } + + /** + * Determine whether a channel exists in the registry + * @param string Channel Alias + * @return boolean + */ + function _isChannelAlias($alias) + { + return file_exists($this->_getChannelAliasFileName($alias)); + } + + /** + * @param string|null + * @param string|null + * @param string|null + * @return array|null + * @access private + */ + function _packageInfo($package = null, $key = null, $channel = 'pear.php.net') + { + if ($package === null) { + if ($channel === null) { + $channels = $this->_listChannels(); + $ret = array(); + foreach ($channels as $channel) { + $channel = strtolower($channel); + $ret[$channel] = array(); + $packages = $this->_listPackages($channel); + foreach ($packages as $package) { + $ret[$channel][] = $this->_packageInfo($package, null, $channel); + } + } + + return $ret; + } + + $ps = $this->_listPackages($channel); + if (!count($ps)) { + return array(); + } + return array_map(array(&$this, '_packageInfo'), + $ps, array_fill(0, count($ps), null), + array_fill(0, count($ps), $channel)); + } + + $fp = $this->_openPackageFile($package, 'r', $channel); + if ($fp === null) { + return null; + } + + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + clearstatcache(); + $this->_closePackageFile($fp); + $data = file_get_contents($this->_packageFileName($package, $channel)); + set_magic_quotes_runtime($rt); + $data = unserialize($data); + if ($key === null) { + return $data; + } + + // compatibility for package.xml version 2.0 + if (isset($data['old'][$key])) { + return $data['old'][$key]; + } + + if (isset($data[$key])) { + return $data[$key]; + } + + return null; + } + + /** + * @param string Channel name + * @param bool whether to strictly retrieve info of channels, not just aliases + * @return array|null + */ + function _channelInfo($channel, $noaliases = false) + { + if (!$this->_channelExists($channel, $noaliases)) { + return null; + } + + $fp = $this->_openChannelFile($channel, 'r'); + if ($fp === null) { + return null; + } + + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + clearstatcache(); + $this->_closeChannelFile($fp); + $data = file_get_contents($this->_channelFileName($channel)); + set_magic_quotes_runtime($rt); + $data = unserialize($data); + return $data; + } + + function _listChannels() + { + $channellist = array(); + if (!file_exists($this->channelsdir) || !is_dir($this->channelsdir)) { + return array('pear.php.net', 'pecl.php.net', 'doc.php.net', '__uri'); + } + + $dp = opendir($this->channelsdir); + while ($ent = readdir($dp)) { + if ($ent{0} == '.' || substr($ent, -4) != '.reg') { + continue; + } + + if ($ent == '__uri.reg') { + $channellist[] = '__uri'; + continue; + } + + $channellist[] = str_replace('_', '/', substr($ent, 0, -4)); + } + + closedir($dp); + if (!in_array('pear.php.net', $channellist)) { + $channellist[] = 'pear.php.net'; + } + + if (!in_array('pecl.php.net', $channellist)) { + $channellist[] = 'pecl.php.net'; + } + + if (!in_array('doc.php.net', $channellist)) { + $channellist[] = 'doc.php.net'; + } + + + if (!in_array('__uri', $channellist)) { + $channellist[] = '__uri'; + } + + natsort($channellist); + return $channellist; + } + + function _listPackages($channel = false) + { + if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { + return $this->_listChannelPackages($channel); + } + + if (!file_exists($this->statedir) || !is_dir($this->statedir)) { + return array(); + } + + $pkglist = array(); + $dp = opendir($this->statedir); + if (!$dp) { + return $pkglist; + } + + while ($ent = readdir($dp)) { + if ($ent{0} == '.' || substr($ent, -4) != '.reg') { + continue; + } + + $pkglist[] = substr($ent, 0, -4); + } + closedir($dp); + return $pkglist; + } + + function _listChannelPackages($channel) + { + $pkglist = array(); + if (!file_exists($this->_channelDirectoryName($channel)) || + !is_dir($this->_channelDirectoryName($channel))) { + return array(); + } + + $dp = opendir($this->_channelDirectoryName($channel)); + if (!$dp) { + return $pkglist; + } + + while ($ent = readdir($dp)) { + if ($ent{0} == '.' || substr($ent, -4) != '.reg') { + continue; + } + $pkglist[] = substr($ent, 0, -4); + } + + closedir($dp); + return $pkglist; + } + + function _listAllPackages() + { + $ret = array(); + foreach ($this->_listChannels() as $channel) { + $ret[$channel] = $this->_listPackages($channel); + } + + return $ret; + } + + /** + * Add an installed package to the registry + * @param string package name + * @param array package info (parsed by PEAR_Common::infoFrom*() methods) + * @return bool success of saving + * @access private + */ + function _addPackage($package, $info) + { + if ($this->_packageExists($package)) { + return false; + } + + $fp = $this->_openPackageFile($package, 'wb'); + if ($fp === null) { + return false; + } + + $info['_lastmodified'] = time(); + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + if (isset($info['filelist'])) { + $this->_rebuildFileMap(); + } + + return true; + } + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @return bool + * @access private + */ + function _addPackage2($info) + { + if (!is_a($info, 'PEAR_PackageFile_v1') && !is_a($info, 'PEAR_PackageFile_v2')) { + return false; + } + + if (!$info->validate()) { + if (class_exists('PEAR_Common')) { + $ui = PEAR_Frontend::singleton(); + if ($ui) { + foreach ($info->getValidationWarnings() as $err) { + $ui->log($err['message'], true); + } + } + } + return false; + } + + $channel = $info->getChannel(); + $package = $info->getPackage(); + $save = $info; + if ($this->_packageExists($package, $channel)) { + return false; + } + + if (!$this->_channelExists($channel, true)) { + return false; + } + + $info = $info->toArray(true); + if (!$info) { + return false; + } + + $fp = $this->_openPackageFile($package, 'wb', $channel); + if ($fp === null) { + return false; + } + + $info['_lastmodified'] = time(); + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + $this->_rebuildFileMap(); + return true; + } + + /** + * @param string Package name + * @param array parsed package.xml 1.0 + * @param bool this parameter is only here for BC. Don't use it. + * @access private + */ + function _updatePackage($package, $info, $merge = true) + { + $oldinfo = $this->_packageInfo($package); + if (empty($oldinfo)) { + return false; + } + + $fp = $this->_openPackageFile($package, 'w'); + if ($fp === null) { + return false; + } + + if (is_object($info)) { + $info = $info->toArray(); + } + $info['_lastmodified'] = time(); + + $newinfo = $info; + if ($merge) { + $info = array_merge($oldinfo, $info); + } else { + $diff = $info; + } + + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + if (isset($newinfo['filelist'])) { + $this->_rebuildFileMap(); + } + + return true; + } + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @return bool + * @access private + */ + function _updatePackage2($info) + { + if (!$this->_packageExists($info->getPackage(), $info->getChannel())) { + return false; + } + + $fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel()); + if ($fp === null) { + return false; + } + + $save = $info; + $info = $save->getArray(true); + $info['_lastmodified'] = time(); + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + $this->_rebuildFileMap(); + return true; + } + + /** + * @param string Package name + * @param string Channel name + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null + * @access private + */ + function &_getPackage($package, $channel = 'pear.php.net') + { + $info = $this->_packageInfo($package, null, $channel); + if ($info === null) { + return $info; + } + + $a = $this->_config; + if (!$a) { + $this->_config = &new PEAR_Config; + $this->_config->set('php_dir', $this->statedir); + } + + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } + + $pkg = &new PEAR_PackageFile($this->_config); + $pf = &$pkg->fromArray($info); + return $pf; + } + + /** + * @param string channel name + * @param bool whether to strictly retrieve channel names + * @return PEAR_ChannelFile|PEAR_Error + * @access private + */ + function &_getChannel($channel, $noaliases = false) + { + $ch = false; + if ($this->_channelExists($channel, $noaliases)) { + $chinfo = $this->_channelInfo($channel, $noaliases); + if ($chinfo) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $ch = &PEAR_ChannelFile::fromArrayWithErrors($chinfo); + } + } + + if ($ch) { + if ($ch->validate()) { + return $ch; + } + + foreach ($ch->getErrors(true) as $err) { + $message = $err['message'] . "\n"; + } + + $ch = PEAR::raiseError($message); + return $ch; + } + + if ($this->_getChannelFromAlias($channel) == 'pear.php.net') { + // the registry is not properly set up, so use defaults + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $pear_channel = new PEAR_ChannelFile; + $pear_channel->setServer('pear.php.net'); + $pear_channel->setAlias('pear'); + $pear_channel->setSummary('PHP Extension and Application Repository'); + $pear_channel->setDefaultPEARProtocols(); + $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); + $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); + $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/'); + return $pear_channel; + } + + if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { + // the registry is not properly set up, so use defaults + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + $pear_channel = new PEAR_ChannelFile; + $pear_channel->setServer('pecl.php.net'); + $pear_channel->setAlias('pecl'); + $pear_channel->setSummary('PHP Extension Community Library'); + $pear_channel->setDefaultPEARProtocols(); + $pear_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); + $pear_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); + $pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); + return $pear_channel; + } + + if ($this->_getChannelFromAlias($channel) == 'doc.php.net') { + // the registry is not properly set up, so use defaults + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $doc_channel = new PEAR_ChannelFile; + $doc_channel->setServer('doc.php.net'); + $doc_channel->setAlias('phpdocs'); + $doc_channel->setSummary('PHP Documentation Team'); + $doc_channel->setDefaultPEARProtocols(); + $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/'); + $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/'); + $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/'); + return $doc_channel; + } + + + if ($this->_getChannelFromAlias($channel) == '__uri') { + // the registry is not properly set up, so use defaults + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $private = new PEAR_ChannelFile; + $private->setName('__uri'); + $private->setDefaultPEARProtocols(); + $private->setBaseURL('REST1.0', '****'); + $private->setSummary('Pseudo-channel for static packages'); + return $private; + } + + return $ch; + } + + /** + * @param string Package name + * @param string Channel name + * @return bool + */ + function packageExists($package, $channel = 'pear.php.net') + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_packageExists($package, $channel); + $this->_unlock(); + return $ret; + } + + // }}} + + // {{{ channelExists() + + /** + * @param string channel name + * @param bool if true, then aliases will be ignored + * @return bool + */ + function channelExists($channel, $noaliases = false) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_channelExists($channel, $noaliases); + $this->_unlock(); + return $ret; + } + + // }}} + + /** + * @param string channel name mirror is in + * @param string mirror name + * + * @return bool + */ + function mirrorExists($channel, $mirror) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + + $ret = $this->_mirrorExists($channel, $mirror); + $this->_unlock(); + return $ret; + } + + // {{{ isAlias() + + /** + * Determines whether the parameter is an alias of a channel + * @param string + * @return bool + */ + function isAlias($alias) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_isChannelAlias($alias); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ packageInfo() + + /** + * @param string|null + * @param string|null + * @param string + * @return array|null + */ + function packageInfo($package = null, $key = null, $channel = 'pear.php.net') + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_packageInfo($package, $key, $channel); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ channelInfo() + + /** + * Retrieve a raw array of channel data. + * + * Do not use this, instead use {@link getChannel()} for normal + * operations. Array structure is undefined in this method + * @param string channel name + * @param bool whether to strictly retrieve information only on non-aliases + * @return array|null|PEAR_Error + */ + function channelInfo($channel = null, $noaliases = false) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_channelInfo($channel, $noaliases); + $this->_unlock(); + return $ret; + } + + // }}} + + /** + * @param string + */ + function channelName($channel) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_getChannelFromAlias($channel); + $this->_unlock(); + return $ret; + } + + /** + * @param string + */ + function channelAlias($channel) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_getAlias($channel); + $this->_unlock(); + return $ret; + } + // {{{ listPackages() + + function listPackages($channel = false) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_listPackages($channel); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ listAllPackages() + + function listAllPackages() + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_listAllPackages(); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ listChannel() + + function listChannels() + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_listChannels(); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ addPackage() + + /** + * Add an installed package to the registry + * @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2 package name or object + * that will be passed to {@link addPackage2()} + * @param array package info (parsed by PEAR_Common::infoFrom*() methods) + * @return bool success of saving + */ + function addPackage($package, $info) + { + if (is_object($info)) { + return $this->addPackage2($info); + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $ret = $this->_addPackage($package, $info); + $this->_unlock(); + if ($ret) { + if (!class_exists('PEAR_PackageFile_v1')) { + require_once 'PEAR/PackageFile/v1.php'; + } + $pf = new PEAR_PackageFile_v1; + $pf->setConfig($this->_config); + $pf->fromArray($info); + $this->_dependencyDB->uninstallPackage($pf); + $this->_dependencyDB->installPackage($pf); + } + return $ret; + } + + // }}} + // {{{ addPackage2() + + function addPackage2($info) + { + if (!is_object($info)) { + return $this->addPackage($info['package'], $info); + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $ret = $this->_addPackage2($info); + $this->_unlock(); + if ($ret) { + $this->_dependencyDB->uninstallPackage($info); + $this->_dependencyDB->installPackage($info); + } + return $ret; + } + + // }}} + // {{{ updateChannel() + + /** + * For future expandibility purposes, separate this + * @param PEAR_ChannelFile + */ + function updateChannel($channel, $lastmodified = null) + { + if ($channel->getName() == '__uri') { + return false; + } + return $this->addChannel($channel, $lastmodified, true); + } + + // }}} + // {{{ deleteChannel() + + /** + * Deletion fails if there are any packages installed from the channel + * @param string|PEAR_ChannelFile channel name + * @return boolean|PEAR_Error True on deletion, false if it doesn't exist + */ + function deleteChannel($channel) + { + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + + $ret = $this->_deleteChannel($channel); + $this->_unlock(); + if ($ret && is_a($this->_config, 'PEAR_Config')) { + $this->_config->setChannels($this->listChannels()); + } + + return $ret; + } + + // }}} + // {{{ addChannel() + + /** + * @param PEAR_ChannelFile Channel object + * @param string Last-Modified header from HTTP for caching + * @return boolean|PEAR_Error True on creation, false if it already exists + */ + function addChannel($channel, $lastmodified = false, $update = false) + { + if (!is_a($channel, 'PEAR_ChannelFile') || !$channel->validate()) { + return false; + } + + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + + $ret = $this->_addChannel($channel, $update, $lastmodified); + $this->_unlock(); + if (!$update && $ret && is_a($this->_config, 'PEAR_Config')) { + $this->_config->setChannels($this->listChannels()); + } + + return $ret; + } + + // }}} + // {{{ deletePackage() + + function deletePackage($package, $channel = 'pear.php.net') + { + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + + $file = $this->_packageFileName($package, $channel); + $ret = file_exists($file) ? @unlink($file) : false; + $this->_rebuildFileMap(); + $this->_unlock(); + $p = array('channel' => $channel, 'package' => $package); + $this->_dependencyDB->uninstallPackage($p); + return $ret; + } + + // }}} + // {{{ updatePackage() + + function updatePackage($package, $info, $merge = true) + { + if (is_object($info)) { + return $this->updatePackage2($info, $merge); + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $ret = $this->_updatePackage($package, $info, $merge); + $this->_unlock(); + if ($ret) { + if (!class_exists('PEAR_PackageFile_v1')) { + require_once 'PEAR/PackageFile/v1.php'; + } + $pf = new PEAR_PackageFile_v1; + $pf->setConfig($this->_config); + $pf->fromArray($this->packageInfo($package)); + $this->_dependencyDB->uninstallPackage($pf); + $this->_dependencyDB->installPackage($pf); + } + return $ret; + } + + // }}} + // {{{ updatePackage2() + + function updatePackage2($info) + { + + if (!is_object($info)) { + return $this->updatePackage($info['package'], $info, $merge); + } + + if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) { + return false; + } + + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + + $ret = $this->_updatePackage2($info); + $this->_unlock(); + if ($ret) { + $this->_dependencyDB->uninstallPackage($info); + $this->_dependencyDB->installPackage($info); + } + + return $ret; + } + + // }}} + // {{{ getChannel() + /** + * @param string channel name + * @param bool whether to strictly return raw channels (no aliases) + * @return PEAR_ChannelFile|PEAR_Error + */ + function &getChannel($channel, $noaliases = false) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = &$this->_getChannel($channel, $noaliases); + $this->_unlock(); + if (!$ret) { + return PEAR::raiseError('Unknown channel: ' . $channel); + } + return $ret; + } + + // }}} + // {{{ getPackage() + /** + * @param string package name + * @param string channel name + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null + */ + function &getPackage($package, $channel = 'pear.php.net') + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $pf = &$this->_getPackage($package, $channel); + $this->_unlock(); + return $pf; + } + + // }}} + + /** + * Get PEAR_PackageFile_v[1/2] objects representing the contents of + * a dependency group that are installed. + * + * This is used at uninstall-time + * @param array + * @return array|false + */ + function getInstalledGroup($group) + { + $ret = array(); + if (isset($group['package'])) { + if (!isset($group['package'][0])) { + $group['package'] = array($group['package']); + } + foreach ($group['package'] as $package) { + $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; + $p = &$this->getPackage($package['name'], $depchannel); + if ($p) { + $save = &$p; + $ret[] = &$save; + } + } + } + if (isset($group['subpackage'])) { + if (!isset($group['subpackage'][0])) { + $group['subpackage'] = array($group['subpackage']); + } + foreach ($group['subpackage'] as $package) { + $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; + $p = &$this->getPackage($package['name'], $depchannel); + if ($p) { + $save = &$p; + $ret[] = &$save; + } + } + } + if (!count($ret)) { + return false; + } + return $ret; + } + + // {{{ getChannelValidator() + /** + * @param string channel name + * @return PEAR_Validate|false + */ + function &getChannelValidator($channel) + { + $chan = $this->getChannel($channel); + if (PEAR::isError($chan)) { + return $chan; + } + $val = $chan->getValidationObject(); + return $val; + } + // }}} + // {{{ getChannels() + /** + * @param string channel name + * @return array an array of PEAR_ChannelFile objects representing every installed channel + */ + function &getChannels() + { + $ret = array(); + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + foreach ($this->_listChannels() as $channel) { + $e = &$this->_getChannel($channel); + if (!$e || PEAR::isError($e)) { + continue; + } + $ret[] = $e; + } + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ checkFileMap() + + /** + * Test whether a file or set of files belongs to a package. + * + * If an array is passed in + * @param string|array file path, absolute or relative to the pear + * install dir + * @param string|array name of PEAR package or array('package' => name, 'channel' => + * channel) of a package that will be ignored + * @param string API version - 1.1 will exclude any files belonging to a package + * @param array private recursion variable + * @return array|false which package and channel the file belongs to, or an empty + * string if the file does not belong to an installed package, + * or belongs to the second parameter's package + */ + function checkFileMap($path, $package = false, $api = '1.0', $attrs = false) + { + if (is_array($path)) { + static $notempty; + if (empty($notempty)) { + if (!class_exists('PEAR_Installer_Role')) { + require_once 'PEAR/Installer/Role.php'; + } + $notempty = create_function('$a','return !empty($a);'); + } + $package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1])) + : strtolower($package); + $pkgs = array(); + foreach ($path as $name => $attrs) { + if (is_array($attrs)) { + if (isset($attrs['install-as'])) { + $name = $attrs['install-as']; + } + if (!in_array($attrs['role'], PEAR_Installer_Role::getInstallableRoles())) { + // these are not installed + continue; + } + if (!in_array($attrs['role'], PEAR_Installer_Role::getBaseinstallRoles())) { + $attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package; + } + if (isset($attrs['baseinstalldir'])) { + $name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name; + } + } + $pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs); + if (PEAR::isError($pkgs[$name])) { + return $pkgs[$name]; + } + } + return array_filter($pkgs, $notempty); + } + if (empty($this->filemap_cache)) { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $err = $this->_readFileMap(); + $this->_unlock(); + if (PEAR::isError($err)) { + return $err; + } + } + if (!$attrs) { + $attrs = array('role' => 'php'); // any old call would be for PHP role only + } + if (isset($this->filemap_cache[$attrs['role']][$path])) { + if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { + return false; + } + return $this->filemap_cache[$attrs['role']][$path]; + } + $l = strlen($this->install_dir); + if (substr($path, 0, $l) == $this->install_dir) { + $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l)); + } + if (isset($this->filemap_cache[$attrs['role']][$path])) { + if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { + return false; + } + return $this->filemap_cache[$attrs['role']][$path]; + } + return false; + } + + // }}} + // {{{ flush() + /** + * Force a reload of the filemap + * @since 1.5.0RC3 + */ + function flushFileMap() + { + $this->filemap_cache = null; + clearstatcache(); // ensure that the next read gets the full, current filemap + } + + // }}} + // {{{ apiVersion() + /** + * Get the expected API version. Channels API is version 1.1, as it is backwards + * compatible with 1.0 + * @return string + */ + function apiVersion() + { + return '1.1'; + } + // }}} + + + /** + * Parse a package name, or validate a parsed package name array + * @param string|array pass in an array of format + * array( + * 'package' => 'pname', + * ['channel' => 'channame',] + * ['version' => 'version',] + * ['state' => 'state',] + * ['group' => 'groupname']) + * or a string of format + * [channel://][channame/]pname[-version|-state][/group=groupname] + * @return array|PEAR_Error + */ + function parsePackageName($param, $defaultchannel = 'pear.php.net') + { + $saveparam = $param; + if (is_array($param)) { + // convert to string for error messages + $saveparam = $this->parsedPackageNameToString($param); + // process the array + if (!isset($param['package'])) { + return PEAR::raiseError('parsePackageName(): array $param ' . + 'must contain a valid package name in index "param"', + 'package', null, null, $param); + } + if (!isset($param['uri'])) { + if (!isset($param['channel'])) { + $param['channel'] = $defaultchannel; + } + } else { + $param['channel'] = '__uri'; + } + } else { + $components = @parse_url((string) $param); + if (isset($components['scheme'])) { + if ($components['scheme'] == 'http') { + // uri package + $param = array('uri' => $param, 'channel' => '__uri'); + } elseif($components['scheme'] != 'channel') { + return PEAR::raiseError('parsePackageName(): only channel:// uris may ' . + 'be downloaded, not "' . $param . '"', 'invalid', null, null, $param); + } + } + if (!isset($components['path'])) { + return PEAR::raiseError('parsePackageName(): array $param ' . + 'must contain a valid package name in "' . $param . '"', + 'package', null, null, $param); + } + if (isset($components['host'])) { + // remove the leading "/" + $components['path'] = substr($components['path'], 1); + } + if (!isset($components['scheme'])) { + if (strpos($components['path'], '/') !== false) { + if ($components['path']{0} == '/') { + return PEAR::raiseError('parsePackageName(): this is not ' . + 'a package name, it begins with "/" in "' . $param . '"', + 'invalid', null, null, $param); + } + $parts = explode('/', $components['path']); + $components['host'] = array_shift($parts); + if (count($parts) > 1) { + $components['path'] = array_pop($parts); + $components['host'] .= '/' . implode('/', $parts); + } else { + $components['path'] = implode('/', $parts); + } + } else { + $components['host'] = $defaultchannel; + } + } else { + if (strpos($components['path'], '/')) { + $parts = explode('/', $components['path']); + $components['path'] = array_pop($parts); + $components['host'] .= '/' . implode('/', $parts); + } + } + + if (is_array($param)) { + $param['package'] = $components['path']; + } else { + $param = array( + 'package' => $components['path'] + ); + if (isset($components['host'])) { + $param['channel'] = $components['host']; + } + } + if (isset($components['fragment'])) { + $param['group'] = $components['fragment']; + } + if (isset($components['user'])) { + $param['user'] = $components['user']; + } + if (isset($components['pass'])) { + $param['pass'] = $components['pass']; + } + if (isset($components['query'])) { + parse_str($components['query'], $param['opts']); + } + // check for extension + $pathinfo = pathinfo($param['package']); + if (isset($pathinfo['extension']) && + in_array(strtolower($pathinfo['extension']), array('tgz', 'tar'))) { + $param['extension'] = $pathinfo['extension']; + $param['package'] = substr($pathinfo['basename'], 0, + strlen($pathinfo['basename']) - 4); + } + // check for version + if (strpos($param['package'], '-')) { + $test = explode('-', $param['package']); + if (count($test) != 2) { + return PEAR::raiseError('parsePackageName(): only one version/state ' . + 'delimiter "-" is allowed in "' . $saveparam . '"', + 'version', null, null, $param); + } + list($param['package'], $param['version']) = $test; + } + } + // validation + $info = $this->channelExists($param['channel']); + if (PEAR::isError($info)) { + return $info; + } + if (!$info) { + return PEAR::raiseError('unknown channel "' . $param['channel'] . + '" in "' . $saveparam . '"', 'channel', null, null, $param); + } + $chan = $this->getChannel($param['channel']); + if (PEAR::isError($chan)) { + return $chan; + } + if (!$chan) { + return PEAR::raiseError("Exception: corrupt registry, could not " . + "retrieve channel " . $param['channel'] . " information", + 'registry', null, null, $param); + } + $param['channel'] = $chan->getName(); + $validate = $chan->getValidationObject(); + $vpackage = $chan->getValidationPackage(); + // validate package name + if (!$validate->validPackageName($param['package'], $vpackage['_content'])) { + return PEAR::raiseError('parsePackageName(): invalid package name "' . + $param['package'] . '" in "' . $saveparam . '"', + 'package', null, null, $param); + } + if (isset($param['group'])) { + if (!PEAR_Validate::validGroupName($param['group'])) { + return PEAR::raiseError('parsePackageName(): dependency group "' . $param['group'] . + '" is not a valid group name in "' . $saveparam . '"', 'group', null, null, + $param); + } + } + if (isset($param['state'])) { + if (!in_array(strtolower($param['state']), $validate->getValidStates())) { + return PEAR::raiseError('parsePackageName(): state "' . $param['state'] + . '" is not a valid state in "' . $saveparam . '"', + 'state', null, null, $param); + } + } + if (isset($param['version'])) { + if (isset($param['state'])) { + return PEAR::raiseError('parsePackageName(): cannot contain both ' . + 'a version and a stability (state) in "' . $saveparam . '"', + 'version/state', null, null, $param); + } + // check whether version is actually a state + if (in_array(strtolower($param['version']), $validate->getValidStates())) { + $param['state'] = strtolower($param['version']); + unset($param['version']); + } else { + if (!$validate->validVersion($param['version'])) { + return PEAR::raiseError('parsePackageName(): "' . $param['version'] . + '" is neither a valid version nor a valid state in "' . + $saveparam . '"', 'version/state', null, null, $param); + } + } + } + return $param; + } + + /** + * @param array + * @return string + */ + function parsedPackageNameToString($parsed, $brief = false) + { + if (is_string($parsed)) { + return $parsed; + } + if (is_object($parsed)) { + $p = $parsed; + $parsed = array( + 'package' => $p->getPackage(), + 'channel' => $p->getChannel(), + 'version' => $p->getVersion(), + ); + } + if (isset($parsed['uri'])) { + return $parsed['uri']; + } + if ($brief) { + if ($channel = $this->channelAlias($parsed['channel'])) { + return $channel . '/' . $parsed['package']; + } + } + $upass = ''; + if (isset($parsed['user'])) { + $upass = $parsed['user']; + if (isset($parsed['pass'])) { + $upass .= ':' . $parsed['pass']; + } + $upass = "$upass@"; + } + $ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package']; + if (isset($parsed['version']) || isset($parsed['state'])) { + $ver = isset($parsed['version']) ? $parsed['version'] : ''; + $ver .= isset($parsed['state']) ? $parsed['state'] : ''; + $ret .= '-' . $ver; + } + if (isset($parsed['extension'])) { + $ret .= '.' . $parsed['extension']; + } + if (isset($parsed['opts'])) { + $ret .= '?'; + foreach ($parsed['opts'] as $name => $value) { + $parsed['opts'][$name] = "$name=$value"; + } + $ret .= implode('&', $parsed['opts']); + } + if (isset($parsed['group'])) { + $ret .= '#' . $parsed['group']; + } + return $ret; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/RunTest.php b/typo3conf/ext/phpunit/PEAR/PEAR/RunTest.php new file mode 100644 index 0000000..ec23977 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/RunTest.php @@ -0,0 +1,966 @@ + + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: RunTest.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.3.3 + */ + +/** + * for error handling + */ +require_once 'PEAR.php'; +require_once 'PEAR/Config.php'; + +define('DETAILED', 1); +putenv("PHP_PEAR_RUNTESTS=1"); + +/** + * Simplified version of PHP's test suite + * + * Try it with: + * + * $ php -r 'include "../PEAR/RunTest.php"; $t=new PEAR_RunTest; $o=$t->run("./pear_system.phpt");print_r($o);' + * + * + * @category pear + * @package PEAR + * @author Tomas V.V.Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.3.3 + */ +class PEAR_RunTest +{ + var $_headers = array(); + var $_logger; + var $_options; + var $_php; + var $tests_count; + var $xdebug_loaded; + /** + * Saved value of php executable, used to reset $_php when we + * have a test that uses cgi + * + * @var unknown_type + */ + var $_savephp; + var $ini_overwrites = array( + 'output_handler=', + 'open_basedir=', + 'safe_mode=0', + 'disable_functions=', + 'output_buffering=Off', + 'display_errors=1', + 'log_errors=0', + 'html_errors=0', + 'track_errors=1', + 'report_memleaks=0', + 'report_zend_debug=0', + 'docref_root=', + 'docref_ext=.html', + 'error_prepend_string=', + 'error_append_string=', + 'auto_prepend_file=', + 'auto_append_file=', + 'magic_quotes_runtime=0', + 'xdebug.default_enable=0', + 'allow_url_fopen=1', + ); + + /** + * An object that supports the PEAR_Common->log() signature, or null + * @param PEAR_Common|null + */ + function PEAR_RunTest($logger = null, $options = array()) + { + if (!defined('E_DEPRECATED')) { + define('E_DEPRECATED', 0); + } + if (!defined('E_STRICT')) { + define('E_STRICT', 0); + } + $this->ini_overwrites[] = 'error_reporting=' . (E_ALL & ~(E_DEPRECATED | E_STRICT)); + if (is_null($logger)) { + require_once 'PEAR/Common.php'; + $logger = new PEAR_Common; + } + $this->_logger = $logger; + $this->_options = $options; + + $conf = &PEAR_Config::singleton(); + $this->_php = $conf->get('php_bin'); + } + + /** + * Taken from php-src/run-tests.php + * + * @param string $commandline command name + * @param array $env + * @param string $stdin standard input to pass to the command + * @return unknown + */ + function system_with_timeout($commandline, $env = null, $stdin = null) + { + $data = ''; + if (version_compare(phpversion(), '5.0.0', '<')) { + $proc = proc_open($commandline, array( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w') + ), $pipes); + } else { + $proc = proc_open($commandline, array( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w') + ), $pipes, null, $env, array('suppress_errors' => true)); + } + + if (!$proc) { + return false; + } + + if (is_string($stdin)) { + fwrite($pipes[0], $stdin); + } + fclose($pipes[0]); + + while (true) { + /* hide errors from interrupted syscalls */ + $r = $pipes; + $e = $w = null; + $n = @stream_select($r, $w, $e, 60); + + if ($n === 0) { + /* timed out */ + $data .= "\n ** ERROR: process timed out **\n"; + proc_terminate($proc); + return array(1234567890, $data); + } else if ($n > 0) { + $line = fread($pipes[1], 8192); + if (strlen($line) == 0) { + /* EOF */ + break; + } + $data .= $line; + } + } + if (function_exists('proc_get_status')) { + $stat = proc_get_status($proc); + if ($stat['signaled']) { + $data .= "\nTermsig=".$stat['stopsig']; + } + } + $code = proc_close($proc); + if (function_exists('proc_get_status')) { + $code = $stat['exitcode']; + } + return array($code, $data); + } + + /** + * Turns a PHP INI string into an array + * + * Turns -d "include_path=/foo/bar" into this: + * array( + * 'include_path' => array( + * 'operator' => '-d', + * 'value' => '/foo/bar', + * ) + * ) + * Works both with quotes and without + * + * @param string an PHP INI string, -d "include_path=/foo/bar" + * @return array + */ + function iniString2array($ini_string) + { + if (!$ini_string) { + return array(); + } + $split = preg_split('/[\s]|=/', $ini_string, -1, PREG_SPLIT_NO_EMPTY); + $key = $split[1][0] == '"' ? substr($split[1], 1) : $split[1]; + $value = $split[2][strlen($split[2]) - 1] == '"' ? substr($split[2], 0, -1) : $split[2]; + // FIXME review if this is really the struct to go with + $array = array($key => array('operator' => $split[0], 'value' => $value)); + return $array; + } + + function settings2array($settings, $ini_settings) + { + foreach ($settings as $setting) { + if (strpos($setting, '=') !== false) { + $setting = explode('=', $setting, 2); + $name = trim(strtolower($setting[0])); + $value = trim($setting[1]); + $ini_settings[$name] = $value; + } + } + return $ini_settings; + } + + function settings2params($ini_settings) + { + $settings = ''; + foreach ($ini_settings as $name => $value) { + if (is_array($value)) { + $operator = $value['operator']; + $value = $value['value']; + } else { + $operator = '-d'; + } + $value = addslashes($value); + $settings .= " $operator \"$name=$value\""; + } + return $settings; + } + + function _preparePhpBin($php, $file, $ini_settings) + { + $file = escapeshellarg($file); + // This was fixed in php 5.3 and is not needed after that + if (OS_WINDOWS && version_compare(PHP_VERSION, '5.3', '<')) { + $cmd = '"'.escapeshellarg($php).' '.$ini_settings.' -f ' . $file .'"'; + } else { + $cmd = $php . $ini_settings . ' -f ' . $file; + } + + return $cmd; + } + + function runPHPUnit($file, $ini_settings = '') + { + if (!file_exists($file) && file_exists(getcwd() . DIRECTORY_SEPARATOR . $file)) { + $file = realpath(getcwd() . DIRECTORY_SEPARATOR . $file); + } elseif (file_exists($file)) { + $file = realpath($file); + } + + $cmd = $this->_preparePhpBin($this->_php, $file, $ini_settings); + if (isset($this->_logger)) { + $this->_logger->log(2, 'Running command "' . $cmd . '"'); + } + + $savedir = getcwd(); // in case the test moves us around + chdir(dirname($file)); + echo `$cmd`; + chdir($savedir); + return 'PASSED'; // we have no way of knowing this information so assume passing + } + + /** + * Runs an individual test case. + * + * @param string The filename of the test + * @param array|string INI settings to be applied to the test run + * @param integer Number what the current running test is of the + * whole test suite being runned. + * + * @return string|object Returns PASSED, WARNED, FAILED depending on how the + * test came out. + * PEAR Error when the tester it self fails + */ + function run($file, $ini_settings = array(), $test_number = 1) + { + if (isset($this->_savephp)) { + $this->_php = $this->_savephp; + unset($this->_savephp); + } + if (empty($this->_options['cgi'])) { + // try to see if php-cgi is in the path + $res = $this->system_with_timeout('php-cgi -v'); + if (false !== $res && !(is_array($res) && in_array($res[0], array(-1, 127)))) { + $this->_options['cgi'] = 'php-cgi'; + } + } + if (1 < $len = strlen($this->tests_count)) { + $test_number = str_pad($test_number, $len, ' ', STR_PAD_LEFT); + $test_nr = "[$test_number/$this->tests_count] "; + } else { + $test_nr = ''; + } + + $file = realpath($file); + $section_text = $this->_readFile($file); + if (PEAR::isError($section_text)) { + return $section_text; + } + + if (isset($section_text['POST_RAW']) && isset($section_text['UPLOAD'])) { + return PEAR::raiseError("Cannot contain both POST_RAW and UPLOAD in test file: $file"); + } + + $cwd = getcwd(); + + $pass_options = ''; + if (!empty($this->_options['ini'])) { + $pass_options = $this->_options['ini']; + } + + if (is_string($ini_settings)) { + $ini_settings = $this->iniString2array($ini_settings); + } + + $ini_settings = $this->settings2array($this->ini_overwrites, $ini_settings); + if ($section_text['INI']) { + if (strpos($section_text['INI'], '{PWD}') !== false) { + $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']); + } + $ini = preg_split( "/[\n\r]+/", $section_text['INI']); + $ini_settings = $this->settings2array($ini, $ini_settings); + } + $ini_settings = $this->settings2params($ini_settings); + $shortname = str_replace($cwd . DIRECTORY_SEPARATOR, '', $file); + + $tested = trim($section_text['TEST']); + $tested.= !isset($this->_options['simple']) ? "[$shortname]" : ' '; + + if (!empty($section_text['POST']) || !empty($section_text['POST_RAW']) || + !empty($section_text['UPLOAD']) || !empty($section_text['GET']) || + !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) { + if (empty($this->_options['cgi'])) { + if (!isset($this->_options['quiet'])) { + $this->_logger->log(0, "SKIP $test_nr$tested (reason: --cgi option needed for this test, type 'pear help run-tests')"); + } + if (isset($this->_options['tapoutput'])) { + return array('ok', ' # skip --cgi option needed for this test, "pear help run-tests" for info'); + } + return 'SKIPPED'; + } + $this->_savephp = $this->_php; + $this->_php = $this->_options['cgi']; + } + + $temp_dir = realpath(dirname($file)); + $main_file_name = basename($file, 'phpt'); + $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'diff'; + $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'log'; + $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'exp'; + $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'out'; + $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'mem'; + $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'php'; + $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'skip.php'; + $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'clean.php'; + $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.'); + + // unlink old test results + $this->_cleanupOldFiles($file); + + // Check if test should be skipped. + $res = $this->_runSkipIf($section_text, $temp_skipif, $tested, $ini_settings); + if (count($res) != 2) { + return $res; + } + $info = $res['info']; + $warn = $res['warn']; + + // We've satisfied the preconditions - run the test! + if (isset($this->_options['coverage']) && $this->xdebug_loaded) { + $xdebug_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'xdebug'; + $text = "\n" . 'function coverage_shutdown() {' . + "\n" . ' $xdebug = var_export(xdebug_get_code_coverage(), true);'; + if (!function_exists('file_put_contents')) { + $text .= "\n" . ' $fh = fopen(\'' . $xdebug_file . '\', "wb");' . + "\n" . ' if ($fh !== false) {' . + "\n" . ' fwrite($fh, $xdebug);' . + "\n" . ' fclose($fh);' . + "\n" . ' }'; + } else { + $text .= "\n" . ' file_put_contents(\'' . $xdebug_file . '\', $xdebug);'; + } + + // Workaround for http://pear.php.net/bugs/bug.php?id=17292 + $lines = explode("\n", $section_text['FILE']); + $numLines = count($lines); + $namespace = ''; + $coverage_shutdown = 'coverage_shutdown'; + + for ($i = 0; $i < $numLines; $i++) { + $lines[$i] = trim($lines[$i]); + + if ($lines[$i] == 'save_text($temp_file, "save_text($temp_file, $section_text['FILE']); + } + + $args = $section_text['ARGS'] ? ' -- '.$section_text['ARGS'] : ''; + $cmd = $this->_preparePhpBin($this->_php, $temp_file, $ini_settings); + $cmd.= "$args 2>&1"; + if (isset($this->_logger)) { + $this->_logger->log(2, 'Running command "' . $cmd . '"'); + } + + // Reset environment from any previous test. + $env = $this->_resetEnv($section_text, $temp_file); + + $section_text = $this->_processUpload($section_text, $file); + if (PEAR::isError($section_text)) { + return $section_text; + } + + if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) { + $post = trim($section_text['POST_RAW']); + $raw_lines = explode("\n", $post); + + $request = ''; + $started = false; + foreach ($raw_lines as $i => $line) { + if (empty($env['CONTENT_TYPE']) && + preg_match('/^Content-Type:(.*)/i', $line, $res)) { + $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1])); + continue; + } + if ($started) { + $request .= "\n"; + } + $started = true; + $request .= $line; + } + + $env['CONTENT_LENGTH'] = strlen($request); + $env['REQUEST_METHOD'] = 'POST'; + + $this->save_text($tmp_post, $request); + $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post"; + } elseif (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { + $post = trim($section_text['POST']); + $this->save_text($tmp_post, $post); + $content_length = strlen($post); + + $env['REQUEST_METHOD'] = 'POST'; + $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; + $env['CONTENT_LENGTH'] = $content_length; + + $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post"; + } else { + $env['REQUEST_METHOD'] = 'GET'; + $env['CONTENT_TYPE'] = ''; + $env['CONTENT_LENGTH'] = ''; + } + + if (OS_WINDOWS && isset($section_text['RETURNS'])) { + ob_start(); + system($cmd, $return_value); + $out = ob_get_contents(); + ob_end_clean(); + $section_text['RETURNS'] = (int) trim($section_text['RETURNS']); + $returnfail = ($return_value != $section_text['RETURNS']); + } else { + $returnfail = false; + $stdin = isset($section_text['STDIN']) ? $section_text['STDIN'] : null; + $out = $this->system_with_timeout($cmd, $env, $stdin); + $return_value = $out[0]; + $out = $out[1]; + } + + $output = preg_replace('/\r\n/', "\n", trim($out)); + + if (isset($tmp_post) && realpath($tmp_post) && file_exists($tmp_post)) { + @unlink(realpath($tmp_post)); + } + chdir($cwd); // in case the test moves us around + + $this->_testCleanup($section_text, $temp_clean); + + /* when using CGI, strip the headers from the output */ + $output = $this->_stripHeadersCGI($output); + + if (isset($section_text['EXPECTHEADERS'])) { + $testheaders = $this->_processHeaders($section_text['EXPECTHEADERS']); + $missing = array_diff_assoc($testheaders, $this->_headers); + $changed = ''; + foreach ($missing as $header => $value) { + if (isset($this->_headers[$header])) { + $changed .= "-$header: $value\n+$header: "; + $changed .= $this->_headers[$header]; + } else { + $changed .= "-$header: $value\n"; + } + } + if ($missing) { + // tack on failed headers to output: + $output .= "\n====EXPECTHEADERS FAILURE====:\n$changed"; + } + } + // Does the output match what is expected? + do { + if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) { + if (isset($section_text['EXPECTF'])) { + $wanted = trim($section_text['EXPECTF']); + } else { + $wanted = trim($section_text['EXPECTREGEX']); + } + $wanted_re = preg_replace('/\r\n/', "\n", $wanted); + if (isset($section_text['EXPECTF'])) { + $wanted_re = preg_quote($wanted_re, '/'); + // Stick to basics + $wanted_re = str_replace("%s", ".+?", $wanted_re); //not greedy + $wanted_re = str_replace("%i", "[+\-]?[0-9]+", $wanted_re); + $wanted_re = str_replace("%d", "[0-9]+", $wanted_re); + $wanted_re = str_replace("%x", "[0-9a-fA-F]+", $wanted_re); + $wanted_re = str_replace("%f", "[+\-]?\.?[0-9]+\.?[0-9]*(E-?[0-9]+)?", $wanted_re); + $wanted_re = str_replace("%c", ".", $wanted_re); + // %f allows two points "-.0.0" but that is the best *simple* expression + } + + /* DEBUG YOUR REGEX HERE + var_dump($wanted_re); + print(str_repeat('=', 80) . "\n"); + var_dump($output); + */ + if (!$returnfail && preg_match("/^$wanted_re\$/s", $output)) { + if (file_exists($temp_file)) { + unlink($temp_file); + } + if (array_key_exists('FAIL', $section_text)) { + break; + } + if (!isset($this->_options['quiet'])) { + $this->_logger->log(0, "PASS $test_nr$tested$info"); + } + if (isset($this->_options['tapoutput'])) { + return array('ok', ' - ' . $tested); + } + return 'PASSED'; + } + } else { + if (isset($section_text['EXPECTFILE'])) { + $f = $temp_dir . '/' . trim($section_text['EXPECTFILE']); + if (!($fp = @fopen($f, 'rb'))) { + return PEAR::raiseError('--EXPECTFILE-- section file ' . + $f . ' not found'); + } + fclose($fp); + $section_text['EXPECT'] = file_get_contents($f); + } + + if (isset($section_text['EXPECT'])) { + $wanted = preg_replace('/\r\n/', "\n", trim($section_text['EXPECT'])); + } else { + $wanted = ''; + } + + // compare and leave on success + if (!$returnfail && 0 == strcmp($output, $wanted)) { + if (file_exists($temp_file)) { + unlink($temp_file); + } + if (array_key_exists('FAIL', $section_text)) { + break; + } + if (!isset($this->_options['quiet'])) { + $this->_logger->log(0, "PASS $test_nr$tested$info"); + } + if (isset($this->_options['tapoutput'])) { + return array('ok', ' - ' . $tested); + } + return 'PASSED'; + } + } + } while (false); + + if (array_key_exists('FAIL', $section_text)) { + // we expect a particular failure + // this is only used for testing PEAR_RunTest + $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null; + $faildiff = $this->generate_diff($wanted, $output, null, $expectf); + $faildiff = preg_replace('/\r/', '', $faildiff); + $wanted = preg_replace('/\r/', '', trim($section_text['FAIL'])); + if ($faildiff == $wanted) { + if (!isset($this->_options['quiet'])) { + $this->_logger->log(0, "PASS $test_nr$tested$info"); + } + if (isset($this->_options['tapoutput'])) { + return array('ok', ' - ' . $tested); + } + return 'PASSED'; + } + unset($section_text['EXPECTF']); + $output = $faildiff; + if (isset($section_text['RETURNS'])) { + return PEAR::raiseError('Cannot have both RETURNS and FAIL in the same test: ' . + $file); + } + } + + // Test failed so we need to report details. + $txt = $warn ? 'WARN ' : 'FAIL '; + $this->_logger->log(0, $txt . $test_nr . $tested . $info); + + // write .exp + $res = $this->_writeLog($exp_filename, $wanted); + if (PEAR::isError($res)) { + return $res; + } + + // write .out + $res = $this->_writeLog($output_filename, $output); + if (PEAR::isError($res)) { + return $res; + } + + // write .diff + $returns = isset($section_text['RETURNS']) ? + array(trim($section_text['RETURNS']), $return_value) : null; + $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null; + $data = $this->generate_diff($wanted, $output, $returns, $expectf); + $res = $this->_writeLog($diff_filename, $data); + if (PEAR::isError($res)) { + return $res; + } + + // write .log + $data = " +---- EXPECTED OUTPUT +$wanted +---- ACTUAL OUTPUT +$output +---- FAILED +"; + + if ($returnfail) { + $data .= " +---- EXPECTED RETURN +$section_text[RETURNS] +---- ACTUAL RETURN +$return_value +"; + } + + $res = $this->_writeLog($log_filename, $data); + if (PEAR::isError($res)) { + return $res; + } + + if (isset($this->_options['tapoutput'])) { + $wanted = explode("\n", $wanted); + $wanted = "# Expected output:\n#\n#" . implode("\n#", $wanted); + $output = explode("\n", $output); + $output = "#\n#\n# Actual output:\n#\n#" . implode("\n#", $output); + return array($wanted . $output . 'not ok', ' - ' . $tested); + } + return $warn ? 'WARNED' : 'FAILED'; + } + + function generate_diff($wanted, $output, $rvalue, $wanted_re) + { + $w = explode("\n", $wanted); + $o = explode("\n", $output); + $wr = explode("\n", $wanted_re); + $w1 = array_diff_assoc($w, $o); + $o1 = array_diff_assoc($o, $w); + $o2 = $w2 = array(); + foreach ($w1 as $idx => $val) { + if (!$wanted_re || !isset($wr[$idx]) || !isset($o1[$idx]) || + !preg_match('/^' . $wr[$idx] . '\\z/', $o1[$idx])) { + $w2[sprintf("%03d<", $idx)] = sprintf("%03d- ", $idx + 1) . $val; + } + } + foreach ($o1 as $idx => $val) { + if (!$wanted_re || !isset($wr[$idx]) || + !preg_match('/^' . $wr[$idx] . '\\z/', $val)) { + $o2[sprintf("%03d>", $idx)] = sprintf("%03d+ ", $idx + 1) . $val; + } + } + $diff = array_merge($w2, $o2); + ksort($diff); + $extra = $rvalue ? "##EXPECTED: $rvalue[0]\r\n##RETURNED: $rvalue[1]" : ''; + return implode("\r\n", $diff) . $extra; + } + + // Write the given text to a temporary file, and return the filename. + function save_text($filename, $text) + { + if (!$fp = fopen($filename, 'w')) { + return PEAR::raiseError("Cannot open file '" . $filename . "' (save_text)"); + } + fwrite($fp, $text); + fclose($fp); + if (1 < DETAILED) echo " +FILE $filename {{{ +$text +}}} +"; + } + + function _cleanupOldFiles($file) + { + $temp_dir = realpath(dirname($file)); + $mainFileName = basename($file, 'phpt'); + $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'diff'; + $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'log'; + $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'exp'; + $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'out'; + $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'mem'; + $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'php'; + $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'skip.php'; + $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'clean.php'; + $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.'); + + // unlink old test results + @unlink($diff_filename); + @unlink($log_filename); + @unlink($exp_filename); + @unlink($output_filename); + @unlink($memcheck_filename); + @unlink($temp_file); + @unlink($temp_skipif); + @unlink($tmp_post); + @unlink($temp_clean); + } + + function _runSkipIf($section_text, $temp_skipif, $tested, $ini_settings) + { + $info = ''; + $warn = false; + if (array_key_exists('SKIPIF', $section_text) && trim($section_text['SKIPIF'])) { + $this->save_text($temp_skipif, $section_text['SKIPIF']); + $output = $this->system_with_timeout("$this->_php$ini_settings -f \"$temp_skipif\""); + $output = $output[1]; + $loutput = ltrim($output); + unlink($temp_skipif); + if (!strncasecmp('skip', $loutput, 4)) { + $skipreason = "SKIP $tested"; + if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) { + $skipreason .= '(reason: ' . $m[1] . ')'; + } + if (!isset($this->_options['quiet'])) { + $this->_logger->log(0, $skipreason); + } + if (isset($this->_options['tapoutput'])) { + return array('ok', ' # skip ' . $reason); + } + return 'SKIPPED'; + } + + if (!strncasecmp('info', $loutput, 4) + && preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) { + $info = " (info: $m[1])"; + } + + if (!strncasecmp('warn', $loutput, 4) + && preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) { + $warn = true; /* only if there is a reason */ + $info = " (warn: $m[1])"; + } + } + + return array('warn' => $warn, 'info' => $info); + } + + function _stripHeadersCGI($output) + { + $this->headers = array(); + if (!empty($this->_options['cgi']) && + $this->_php == $this->_options['cgi'] && + preg_match("/^(.*?)(?:\n\n(.*)|\\z)/s", $output, $match)) { + $output = isset($match[2]) ? trim($match[2]) : ''; + $this->_headers = $this->_processHeaders($match[1]); + } + + return $output; + } + + /** + * Return an array that can be used with array_diff() to compare headers + * + * @param string $text + */ + function _processHeaders($text) + { + $headers = array(); + $rh = preg_split("/[\n\r]+/", $text); + foreach ($rh as $line) { + if (strpos($line, ':')!== false) { + $line = explode(':', $line, 2); + $headers[trim($line[0])] = trim($line[1]); + } + } + return $headers; + } + + function _readFile($file) + { + // Load the sections of the test file. + $section_text = array( + 'TEST' => '(unnamed test)', + 'SKIPIF' => '', + 'GET' => '', + 'COOKIE' => '', + 'POST' => '', + 'ARGS' => '', + 'INI' => '', + 'CLEAN' => '', + ); + + if (!is_file($file) || !$fp = fopen($file, "r")) { + return PEAR::raiseError("Cannot open test file: $file"); + } + + $section = ''; + while (!feof($fp)) { + $line = fgets($fp); + + // Match the beginning of a section. + if (preg_match('/^--([_A-Z]+)--/', $line, $r)) { + $section = $r[1]; + $section_text[$section] = ''; + continue; + } elseif (empty($section)) { + fclose($fp); + return PEAR::raiseError("Invalid sections formats in test file: $file"); + } + + // Add to the section text. + $section_text[$section] .= $line; + } + fclose($fp); + + return $section_text; + } + + function _writeLog($logname, $data) + { + if (!$log = fopen($logname, 'w')) { + return PEAR::raiseError("Cannot create test log - $logname"); + } + fwrite($log, $data); + fclose($log); + } + + function _resetEnv($section_text, $temp_file) + { + $env = $_ENV; + $env['REDIRECT_STATUS'] = ''; + $env['QUERY_STRING'] = ''; + $env['PATH_TRANSLATED'] = ''; + $env['SCRIPT_FILENAME'] = ''; + $env['REQUEST_METHOD'] = ''; + $env['CONTENT_TYPE'] = ''; + $env['CONTENT_LENGTH'] = ''; + if (!empty($section_text['ENV'])) { + if (strpos($section_text['ENV'], '{PWD}') !== false) { + $section_text['ENV'] = str_replace('{PWD}', dirname($temp_file), $section_text['ENV']); + } + foreach (explode("\n", trim($section_text['ENV'])) as $e) { + $e = explode('=', trim($e), 2); + if (!empty($e[0]) && isset($e[1])) { + $env[$e[0]] = $e[1]; + } + } + } + if (array_key_exists('GET', $section_text)) { + $env['QUERY_STRING'] = trim($section_text['GET']); + } else { + $env['QUERY_STRING'] = ''; + } + if (array_key_exists('COOKIE', $section_text)) { + $env['HTTP_COOKIE'] = trim($section_text['COOKIE']); + } else { + $env['HTTP_COOKIE'] = ''; + } + $env['REDIRECT_STATUS'] = '1'; + $env['PATH_TRANSLATED'] = $temp_file; + $env['SCRIPT_FILENAME'] = $temp_file; + + return $env; + } + + function _processUpload($section_text, $file) + { + if (array_key_exists('UPLOAD', $section_text) && !empty($section_text['UPLOAD'])) { + $upload_files = trim($section_text['UPLOAD']); + $upload_files = explode("\n", $upload_files); + + $request = "Content-Type: multipart/form-data; boundary=---------------------------20896060251896012921717172737\n" . + "-----------------------------20896060251896012921717172737\n"; + foreach ($upload_files as $fileinfo) { + $fileinfo = explode('=', $fileinfo); + if (count($fileinfo) != 2) { + return PEAR::raiseError("Invalid UPLOAD section in test file: $file"); + } + if (!realpath(dirname($file) . '/' . $fileinfo[1])) { + return PEAR::raiseError("File for upload does not exist: $fileinfo[1] " . + "in test file: $file"); + } + $file_contents = file_get_contents(dirname($file) . '/' . $fileinfo[1]); + $fileinfo[1] = basename($fileinfo[1]); + $request .= "Content-Disposition: form-data; name=\"$fileinfo[0]\"; filename=\"$fileinfo[1]\"\n"; + $request .= "Content-Type: text/plain\n\n"; + $request .= $file_contents . "\n" . + "-----------------------------20896060251896012921717172737\n"; + } + + if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { + // encode POST raw + $post = trim($section_text['POST']); + $post = explode('&', $post); + foreach ($post as $i => $post_info) { + $post_info = explode('=', $post_info); + if (count($post_info) != 2) { + return PEAR::raiseError("Invalid POST data in test file: $file"); + } + $post_info[0] = rawurldecode($post_info[0]); + $post_info[1] = rawurldecode($post_info[1]); + $post[$i] = $post_info; + } + foreach ($post as $post_info) { + $request .= "Content-Disposition: form-data; name=\"$post_info[0]\"\n\n"; + $request .= $post_info[1] . "\n" . + "-----------------------------20896060251896012921717172737\n"; + } + unset($section_text['POST']); + } + $section_text['POST_RAW'] = $request; + } + + return $section_text; + } + + function _testCleanup($section_text, $temp_clean) + { + if ($section_text['CLEAN']) { + // perform test cleanup + $this->save_text($temp_clean, $section_text['CLEAN']); + $output = $this->system_with_timeout("$this->_php $temp_clean 2>&1"); + if (strlen($output[1])) { + echo "BORKED --CLEAN-- section! output:\n", $output[1]; + } + if (file_exists($temp_clean)) { + unlink($temp_clean); + } + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Task/Common.php b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Common.php new file mode 100644 index 0000000..e7ad936 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Common.php @@ -0,0 +1,202 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Common.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/**#@+ + * Error codes for task validation routines + */ +define('PEAR_TASK_ERROR_NOATTRIBS', 1); +define('PEAR_TASK_ERROR_MISSING_ATTRIB', 2); +define('PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE', 3); +define('PEAR_TASK_ERROR_INVALID', 4); +/**#@-*/ +define('PEAR_TASK_PACKAGE', 1); +define('PEAR_TASK_INSTALL', 2); +define('PEAR_TASK_PACKAGEANDINSTALL', 3); +/** + * A task is an operation that manipulates the contents of a file. + * + * Simple tasks operate on 1 file. Multiple tasks are executed after all files have been + * processed and installed, and are designed to operate on all files containing the task. + * The Post-install script task simply takes advantage of the fact that it will be run + * after installation, replace is a simple task. + * + * Combining tasks is possible, but ordering is significant. + * + * + * + * + * + * + * This will first replace any instance of @data-dir@ in the test.php file + * with the path to the current data directory. Then, it will include the + * test.php file and run the script it contains to configure the package post-installation. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + * @abstract + */ +class PEAR_Task_Common +{ + /** + * Valid types for this version are 'simple' and 'multiple' + * + * - simple tasks operate on the contents of a file and write out changes to disk + * - multiple tasks operate on the contents of many files and write out the + * changes directly to disk + * + * Child task classes must override this property. + * @access protected + */ + var $type = 'simple'; + /** + * Determines which install phase this task is executed under + */ + var $phase = PEAR_TASK_INSTALL; + /** + * @access protected + */ + var $config; + /** + * @access protected + */ + var $registry; + /** + * @access protected + */ + var $logger; + /** + * @access protected + */ + var $installphase; + /** + * @param PEAR_Config + * @param PEAR_Common + */ + function PEAR_Task_Common(&$config, &$logger, $phase) + { + $this->config = &$config; + $this->registry = &$config->getRegistry(); + $this->logger = &$logger; + $this->installphase = $phase; + if ($this->type == 'multiple') { + $GLOBALS['_PEAR_TASK_POSTINSTANCES'][get_class($this)][] = &$this; + } + } + + /** + * Validate the basic contents of a task tag. + * @param PEAR_PackageFile_v2 + * @param array + * @param PEAR_Config + * @param array the entire parsed tag + * @return true|array On error, return an array in format: + * array(PEAR_TASK_ERROR_???[, param1][, param2][, ...]) + * + * For PEAR_TASK_ERROR_MISSING_ATTRIB, pass the attribute name in + * For PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, pass the attribute name and an array + * of legal values in + * @static + * @abstract + */ + function validateXml($pkg, $xml, $config, $fileXml) + { + } + + /** + * Initialize a task instance with the parameters + * @param array raw, parsed xml + * @param array attributes from the tag containing this task + * @param string|null last installed version of this package + * @abstract + */ + function init($xml, $fileAttributes, $lastVersion) + { + } + + /** + * Begin a task processing session. All multiple tasks will be processed after each file + * has been successfully installed, all simple tasks should perform their task here and + * return any errors using the custom throwError() method to allow forward compatibility + * + * This method MUST NOT write out any changes to disk + * @param PEAR_PackageFile_v2 + * @param string file contents + * @param string the eventual final file location (informational only) + * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail + * (use $this->throwError), otherwise return the new contents + * @abstract + */ + function startSession($pkg, $contents, $dest) + { + } + + /** + * This method is used to process each of the tasks for a particular multiple class + * type. Simple tasks need not implement this method. + * @param array an array of tasks + * @access protected + * @static + * @abstract + */ + function run($tasks) + { + } + + /** + * @static + * @final + */ + function hasPostinstallTasks() + { + return isset($GLOBALS['_PEAR_TASK_POSTINSTANCES']); + } + + /** + * @static + * @final + */ + function runPostinstallTasks() + { + foreach ($GLOBALS['_PEAR_TASK_POSTINSTANCES'] as $class => $tasks) { + $err = call_user_func(array($class, 'run'), + $GLOBALS['_PEAR_TASK_POSTINSTANCES'][$class]); + if ($err) { + return PEAR_Task_Common::throwError($err); + } + } + unset($GLOBALS['_PEAR_TASK_POSTINSTANCES']); + } + + /** + * Determines whether a role is a script + * @return bool + */ + function isScript() + { + return $this->type == 'script'; + } + + function throwError($msg, $code = -1) + { + include_once 'PEAR.php'; + return PEAR::raiseError($msg, $code); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Task/Postinstallscript.php b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Postinstallscript.php new file mode 100644 index 0000000..1b50d21 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Postinstallscript.php @@ -0,0 +1,323 @@ + + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Postinstallscript.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Common.php'; +/** + * Implements the postinstallscript file task. + * + * Note that post-install scripts are handled separately from installation, by the + * "pear run-scripts" command + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Task_Postinstallscript extends PEAR_Task_Common +{ + var $type = 'script'; + var $_class; + var $_params; + var $_obj; + /** + * + * @var PEAR_PackageFile_v2 + */ + var $_pkg; + var $_contents; + var $phase = PEAR_TASK_INSTALL; + + /** + * Validate the raw xml at parsing-time. + * + * This also attempts to validate the script to make sure it meets the criteria + * for a post-install script + * @param PEAR_PackageFile_v2 + * @param array The XML contents of the tag + * @param PEAR_Config + * @param array the entire parsed tag + * @static + */ + function validateXml($pkg, $xml, $config, $fileXml) + { + if ($fileXml['role'] != 'php') { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" must be role="php"'); + } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $file = $pkg->getFileContents($fileXml['name']); + if (PEAR::isError($file)) { + PEAR::popErrorHandling(); + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" is not valid: ' . + $file->getMessage()); + } elseif ($file === null) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" could not be retrieved for processing!'); + } else { + $analysis = $pkg->analyzeSourceCode($file, true); + if (!$analysis) { + PEAR::popErrorHandling(); + $warnings = ''; + foreach ($pkg->getValidationWarnings() as $warn) { + $warnings .= $warn['message'] . "\n"; + } + return array(PEAR_TASK_ERROR_INVALID, 'Analysis of post-install script "' . + $fileXml['name'] . '" failed: ' . $warnings); + } + if (count($analysis['declared_classes']) != 1) { + PEAR::popErrorHandling(); + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" must declare exactly 1 class'); + } + $class = $analysis['declared_classes'][0]; + if ($class != str_replace(array('/', '.php'), array('_', ''), + $fileXml['name']) . '_postinstall') { + PEAR::popErrorHandling(); + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" class "' . $class . '" must be named "' . + str_replace(array('/', '.php'), array('_', ''), + $fileXml['name']) . '_postinstall"'); + } + if (!isset($analysis['declared_methods'][$class])) { + PEAR::popErrorHandling(); + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" must declare methods init() and run()'); + } + $methods = array('init' => 0, 'run' => 1); + foreach ($analysis['declared_methods'][$class] as $method) { + if (isset($methods[$method])) { + unset($methods[$method]); + } + } + if (count($methods)) { + PEAR::popErrorHandling(); + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" must declare methods init() and run()'); + } + } + PEAR::popErrorHandling(); + $definedparams = array(); + $tasksNamespace = $pkg->getTasksNs() . ':'; + if (!isset($xml[$tasksNamespace . 'paramgroup']) && isset($xml['paramgroup'])) { + // in order to support the older betas, which did not expect internal tags + // to also use the namespace + $tasksNamespace = ''; + } + if (isset($xml[$tasksNamespace . 'paramgroup'])) { + $params = $xml[$tasksNamespace . 'paramgroup']; + if (!is_array($params) || !isset($params[0])) { + $params = array($params); + } + foreach ($params as $param) { + if (!isset($param[$tasksNamespace . 'id'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" must have ' . + 'an ' . $tasksNamespace . 'id> tag'); + } + if (isset($param[$tasksNamespace . 'name'])) { + if (!in_array($param[$tasksNamespace . 'name'], $definedparams)) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" ' . $tasksNamespace . + 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . + '" parameter "' . $param[$tasksNamespace . 'name'] . + '" has not been previously defined'); + } + if (!isset($param[$tasksNamespace . 'conditiontype'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" ' . $tasksNamespace . + 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . + '" must have a ' . $tasksNamespace . + 'conditiontype> tag containing either "=", ' . + '"!=", or "preg_match"'); + } + if (!in_array($param[$tasksNamespace . 'conditiontype'], + array('=', '!=', 'preg_match'))) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" ' . $tasksNamespace . + 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . + '" must have a ' . $tasksNamespace . + 'conditiontype> tag containing either "=", ' . + '"!=", or "preg_match"'); + } + if (!isset($param[$tasksNamespace . 'value'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" ' . $tasksNamespace . + 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . + '" must have a ' . $tasksNamespace . + 'value> tag containing expected parameter value'); + } + } + if (isset($param[$tasksNamespace . 'instructions'])) { + if (!is_string($param[$tasksNamespace . 'instructions'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" ' . $tasksNamespace . + 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . + '" ' . $tasksNamespace . 'instructions> must be simple text'); + } + } + if (!isset($param[$tasksNamespace . 'param'])) { + continue; // is no longer required + } + $subparams = $param[$tasksNamespace . 'param']; + if (!is_array($subparams) || !isset($subparams[0])) { + $subparams = array($subparams); + } + foreach ($subparams as $subparam) { + if (!isset($subparam[$tasksNamespace . 'name'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" parameter for ' . + $tasksNamespace . 'paramgroup> id "' . + $param[$tasksNamespace . 'id'] . '" must have ' . + 'a ' . $tasksNamespace . 'name> tag'); + } + if (!preg_match('/[a-zA-Z0-9]+/', + $subparam[$tasksNamespace . 'name'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" parameter "' . + $subparam[$tasksNamespace . 'name'] . + '" for ' . $tasksNamespace . 'paramgroup> id "' . + $param[$tasksNamespace . 'id'] . + '" is not a valid name. Must contain only alphanumeric characters'); + } + if (!isset($subparam[$tasksNamespace . 'prompt'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" parameter "' . + $subparam[$tasksNamespace . 'name'] . + '" for ' . $tasksNamespace . 'paramgroup> id "' . + $param[$tasksNamespace . 'id'] . + '" must have a ' . $tasksNamespace . 'prompt> tag'); + } + if (!isset($subparam[$tasksNamespace . 'type'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" parameter "' . + $subparam[$tasksNamespace . 'name'] . + '" for ' . $tasksNamespace . 'paramgroup> id "' . + $param[$tasksNamespace . 'id'] . + '" must have a ' . $tasksNamespace . 'type> tag'); + } + $definedparams[] = $param[$tasksNamespace . 'id'] . '::' . + $subparam[$tasksNamespace . 'name']; + } + } + } + return true; + } + + /** + * Initialize a task instance with the parameters + * @param array raw, parsed xml + * @param array attributes from the tag containing this task + * @param string|null last installed version of this package, if any (useful for upgrades) + */ + function init($xml, $fileattribs, $lastversion) + { + $this->_class = str_replace('/', '_', $fileattribs['name']); + $this->_filename = $fileattribs['name']; + $this->_class = str_replace ('.php', '', $this->_class) . '_postinstall'; + $this->_params = $xml; + $this->_lastversion = $lastversion; + } + + /** + * Strip the tasks: namespace from internal params + * + * @access private + */ + function _stripNamespace($params = null) + { + if ($params === null) { + $params = array(); + if (!is_array($this->_params)) { + return; + } + foreach ($this->_params as $i => $param) { + if (is_array($param)) { + $param = $this->_stripNamespace($param); + } + $params[str_replace($this->_pkg->getTasksNs() . ':', '', $i)] = $param; + } + $this->_params = $params; + } else { + $newparams = array(); + foreach ($params as $i => $param) { + if (is_array($param)) { + $param = $this->_stripNamespace($param); + } + $newparams[str_replace($this->_pkg->getTasksNs() . ':', '', $i)] = $param; + } + return $newparams; + } + } + + /** + * Unlike other tasks, the installed file name is passed in instead of the file contents, + * because this task is handled post-installation + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string file name + * @return bool|PEAR_Error false to skip this file, PEAR_Error to fail + * (use $this->throwError) + */ + function startSession($pkg, $contents) + { + if ($this->installphase != PEAR_TASK_INSTALL) { + return false; + } + // remove the tasks: namespace if present + $this->_pkg = $pkg; + $this->_stripNamespace(); + $this->logger->log(0, 'Including external post-installation script "' . + $contents . '" - any errors are in this script'); + include_once $contents; + if (class_exists($this->_class)) { + $this->logger->log(0, 'Inclusion succeeded'); + } else { + return $this->throwError('init of post-install script class "' . $this->_class + . '" failed'); + } + $this->_obj = new $this->_class; + $this->logger->log(1, 'running post-install script "' . $this->_class . '->init()"'); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $res = $this->_obj->init($this->config, $pkg, $this->_lastversion); + PEAR::popErrorHandling(); + if ($res) { + $this->logger->log(0, 'init succeeded'); + } else { + return $this->throwError('init of post-install script "' . $this->_class . + '->init()" failed'); + } + $this->_contents = $contents; + return true; + } + + /** + * No longer used + * @see PEAR_PackageFile_v2::runPostinstallScripts() + * @param array an array of tasks + * @param string install or upgrade + * @access protected + * @static + */ + function run() + { + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Task/Postinstallscript/rw.php b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Postinstallscript/rw.php new file mode 100644 index 0000000..158cb0d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Postinstallscript/rw.php @@ -0,0 +1,169 @@ + - read/write version + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: rw.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a10 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Postinstallscript.php'; +/** + * Abstracts the postinstallscript file task xml. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a10 + */ +class PEAR_Task_Postinstallscript_rw extends PEAR_Task_Postinstallscript +{ + /** + * parent package file object + * + * @var PEAR_PackageFile_v2_rw + */ + var $_pkg; + /** + * Enter description here... + * + * @param PEAR_PackageFile_v2_rw $pkg + * @param PEAR_Config $config + * @param PEAR_Frontend $logger + * @param array $fileXml + * @return PEAR_Task_Postinstallscript_rw + */ + function PEAR_Task_Postinstallscript_rw(&$pkg, &$config, &$logger, $fileXml) + { + parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); + $this->_contents = $fileXml; + $this->_pkg = &$pkg; + $this->_params = array(); + } + + function validate() + { + return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents); + } + + function getName() + { + return 'postinstallscript'; + } + + /** + * add a simple to the post-install script + * + * Order is significant, so call this method in the same + * sequence the users should see the paramgroups. The $params + * parameter should either be the result of a call to {@link getParam()} + * or an array of calls to getParam(). + * + * Use {@link addConditionTypeGroup()} to add a containing + * a tag + * @param string $id id as seen by the script + * @param array|false $params array of getParam() calls, or false for no params + * @param string|false $instructions + */ + function addParamGroup($id, $params = false, $instructions = false) + { + if ($params && isset($params[0]) && !isset($params[1])) { + $params = $params[0]; + } + $stuff = + array( + $this->_pkg->getTasksNs() . ':id' => $id, + ); + if ($instructions) { + $stuff[$this->_pkg->getTasksNs() . ':instructions'] = $instructions; + } + if ($params) { + $stuff[$this->_pkg->getTasksNs() . ':param'] = $params; + } + $this->_params[$this->_pkg->getTasksNs() . ':paramgroup'][] = $stuff; + } + + /** + * add a complex to the post-install script with conditions + * + * This inserts a with + * + * Order is significant, so call this method in the same + * sequence the users should see the paramgroups. The $params + * parameter should either be the result of a call to {@link getParam()} + * or an array of calls to getParam(). + * + * Use {@link addParamGroup()} to add a simple + * + * @param string $id id as seen by the script + * @param string $oldgroup id of the section referenced by + * + * @param string $param name of the from the older section referenced + * by + * @param string $value value to match of the parameter + * @param string $conditiontype one of '=', '!=', 'preg_match' + * @param array|false $params array of getParam() calls, or false for no params + * @param string|false $instructions + */ + function addConditionTypeGroup($id, $oldgroup, $param, $value, $conditiontype = '=', + $params = false, $instructions = false) + { + if ($params && isset($params[0]) && !isset($params[1])) { + $params = $params[0]; + } + $stuff = array( + $this->_pkg->getTasksNs() . ':id' => $id, + ); + if ($instructions) { + $stuff[$this->_pkg->getTasksNs() . ':instructions'] = $instructions; + } + $stuff[$this->_pkg->getTasksNs() . ':name'] = $oldgroup . '::' . $param; + $stuff[$this->_pkg->getTasksNs() . ':conditiontype'] = $conditiontype; + $stuff[$this->_pkg->getTasksNs() . ':value'] = $value; + if ($params) { + $stuff[$this->_pkg->getTasksNs() . ':param'] = $params; + } + $this->_params[$this->_pkg->getTasksNs() . ':paramgroup'][] = $stuff; + } + + function getXml() + { + return $this->_params; + } + + /** + * Use to set up a param tag for use in creating a paramgroup + * @static + */ + function getParam($name, $prompt, $type = 'string', $default = null) + { + if ($default !== null) { + return + array( + $this->_pkg->getTasksNs() . ':name' => $name, + $this->_pkg->getTasksNs() . ':prompt' => $prompt, + $this->_pkg->getTasksNs() . ':type' => $type, + $this->_pkg->getTasksNs() . ':default' => $default + ); + } + return + array( + $this->_pkg->getTasksNs() . ':name' => $name, + $this->_pkg->getTasksNs() . ':prompt' => $prompt, + $this->_pkg->getTasksNs() . ':type' => $type, + ); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Task/Replace.php b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Replace.php new file mode 100644 index 0000000..154bf70 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Replace.php @@ -0,0 +1,176 @@ + + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Replace.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Common.php'; +/** + * Implements the replace file task. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Task_Replace extends PEAR_Task_Common +{ + var $type = 'simple'; + var $phase = PEAR_TASK_PACKAGEANDINSTALL; + var $_replacements; + + /** + * Validate the raw xml at parsing-time. + * @param PEAR_PackageFile_v2 + * @param array raw, parsed xml + * @param PEAR_Config + * @static + */ + function validateXml($pkg, $xml, $config, $fileXml) + { + if (!isset($xml['attribs'])) { + return array(PEAR_TASK_ERROR_NOATTRIBS); + } + if (!isset($xml['attribs']['type'])) { + return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'type'); + } + if (!isset($xml['attribs']['to'])) { + return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'to'); + } + if (!isset($xml['attribs']['from'])) { + return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'from'); + } + if ($xml['attribs']['type'] == 'pear-config') { + if (!in_array($xml['attribs']['to'], $config->getKeys())) { + return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'], + $config->getKeys()); + } + } elseif ($xml['attribs']['type'] == 'php-const') { + if (defined($xml['attribs']['to'])) { + return true; + } else { + return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'], + array('valid PHP constant')); + } + } elseif ($xml['attribs']['type'] == 'package-info') { + if (in_array($xml['attribs']['to'], + array('name', 'summary', 'channel', 'notes', 'extends', 'description', + 'release_notes', 'license', 'release-license', 'license-uri', + 'version', 'api-version', 'state', 'api-state', 'release_date', + 'date', 'time'))) { + return true; + } else { + return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'], + array('name', 'summary', 'channel', 'notes', 'extends', 'description', + 'release_notes', 'license', 'release-license', 'license-uri', + 'version', 'api-version', 'state', 'api-state', 'release_date', + 'date', 'time')); + } + } else { + return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'type', $xml['attribs']['type'], + array('pear-config', 'package-info', 'php-const')); + } + return true; + } + + /** + * Initialize a task instance with the parameters + * @param array raw, parsed xml + * @param unused + */ + function init($xml, $attribs) + { + $this->_replacements = isset($xml['attribs']) ? array($xml) : $xml; + } + + /** + * Do a package.xml 1.0 replacement, with additional package-info fields available + * + * See validateXml() source for the complete list of allowed fields + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string file contents + * @param string the eventual final file location (informational only) + * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail + * (use $this->throwError), otherwise return the new contents + */ + function startSession($pkg, $contents, $dest) + { + $subst_from = $subst_to = array(); + foreach ($this->_replacements as $a) { + $a = $a['attribs']; + $to = ''; + if ($a['type'] == 'pear-config') { + if ($this->installphase == PEAR_TASK_PACKAGE) { + return false; + } + if ($a['to'] == 'master_server') { + $chan = $this->registry->getChannel($pkg->getChannel()); + if (!PEAR::isError($chan)) { + $to = $chan->getServer(); + } else { + $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]"); + return false; + } + } else { + if ($this->config->isDefinedLayer('ftp')) { + // try the remote config file first + $to = $this->config->get($a['to'], 'ftp', $pkg->getChannel()); + if (is_null($to)) { + // then default to local + $to = $this->config->get($a['to'], null, $pkg->getChannel()); + } + } else { + $to = $this->config->get($a['to'], null, $pkg->getChannel()); + } + } + if (is_null($to)) { + $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]"); + return false; + } + } elseif ($a['type'] == 'php-const') { + if ($this->installphase == PEAR_TASK_PACKAGE) { + return false; + } + if (defined($a['to'])) { + $to = constant($a['to']); + } else { + $this->logger->log(0, "$dest: invalid php-const replacement: $a[to]"); + return false; + } + } else { + if ($t = $pkg->packageInfo($a['to'])) { + $to = $t; + } else { + $this->logger->log(0, "$dest: invalid package-info replacement: $a[to]"); + return false; + } + } + if (!is_null($to)) { + $subst_from[] = $a['from']; + $subst_to[] = $to; + } + } + $this->logger->log(3, "doing " . sizeof($subst_from) . + " substitution(s) for $dest"); + if (sizeof($subst_from)) { + $contents = str_replace($subst_from, $subst_to, $contents); + } + return $contents; + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Task/Replace/rw.php b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Replace/rw.php new file mode 100644 index 0000000..9d5c8ff --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Replace/rw.php @@ -0,0 +1,61 @@ + - read/write version + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: rw.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a10 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Replace.php'; +/** + * Abstracts the replace task xml. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a10 + */ +class PEAR_Task_Replace_rw extends PEAR_Task_Replace +{ + function PEAR_Task_Replace_rw(&$pkg, &$config, &$logger, $fileXml) + { + parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); + $this->_contents = $fileXml; + $this->_pkg = &$pkg; + $this->_params = array(); + } + + function validate() + { + return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents); + } + + function setInfo($from, $to, $type) + { + $this->_params = array('attribs' => array('from' => $from, 'to' => $to, 'type' => $type)); + } + + function getName() + { + return 'replace'; + } + + function getXml() + { + return $this->_params; + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Task/Unixeol.php b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Unixeol.php new file mode 100644 index 0000000..79f9fca --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Unixeol.php @@ -0,0 +1,77 @@ + + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Unixeol.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Common.php'; +/** + * Implements the unix line endings file task. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Task_Unixeol extends PEAR_Task_Common +{ + var $type = 'simple'; + var $phase = PEAR_TASK_PACKAGE; + var $_replacements; + + /** + * Validate the raw xml at parsing-time. + * @param PEAR_PackageFile_v2 + * @param array raw, parsed xml + * @param PEAR_Config + * @static + */ + function validateXml($pkg, $xml, $config, $fileXml) + { + if ($xml != '') { + return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed'); + } + return true; + } + + /** + * Initialize a task instance with the parameters + * @param array raw, parsed xml + * @param unused + */ + function init($xml, $attribs) + { + } + + /** + * Replace all line endings with line endings customized for the current OS + * + * See validateXml() source for the complete list of allowed fields + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string file contents + * @param string the eventual final file location (informational only) + * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail + * (use $this->throwError), otherwise return the new contents + */ + function startSession($pkg, $contents, $dest) + { + $this->logger->log(3, "replacing all line endings with \\n in $dest"); + return preg_replace("/\r\n|\n\r|\r|\n/", "\n", $contents); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Task/Unixeol/rw.php b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Unixeol/rw.php new file mode 100644 index 0000000..a134bc3 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Unixeol/rw.php @@ -0,0 +1,56 @@ + - read/write version + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: rw.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a10 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Unixeol.php'; +/** + * Abstracts the unixeol task xml. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a10 + */ +class PEAR_Task_Unixeol_rw extends PEAR_Task_Unixeol +{ + function PEAR_Task_Unixeol_rw(&$pkg, &$config, &$logger, $fileXml) + { + parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); + $this->_contents = $fileXml; + $this->_pkg = &$pkg; + $this->_params = array(); + } + + function validate() + { + return true; + } + + function getName() + { + return 'unixeol'; + } + + function getXml() + { + return ''; + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Task/Windowseol.php b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Windowseol.php new file mode 100644 index 0000000..59c8ca7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Windowseol.php @@ -0,0 +1,77 @@ + + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Windowseol.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Common.php'; +/** + * Implements the windows line endsings file task. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Task_Windowseol extends PEAR_Task_Common +{ + var $type = 'simple'; + var $phase = PEAR_TASK_PACKAGE; + var $_replacements; + + /** + * Validate the raw xml at parsing-time. + * @param PEAR_PackageFile_v2 + * @param array raw, parsed xml + * @param PEAR_Config + * @static + */ + function validateXml($pkg, $xml, $config, $fileXml) + { + if ($xml != '') { + return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed'); + } + return true; + } + + /** + * Initialize a task instance with the parameters + * @param array raw, parsed xml + * @param unused + */ + function init($xml, $attribs) + { + } + + /** + * Replace all line endings with windows line endings + * + * See validateXml() source for the complete list of allowed fields + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string file contents + * @param string the eventual final file location (informational only) + * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail + * (use $this->throwError), otherwise return the new contents + */ + function startSession($pkg, $contents, $dest) + { + $this->logger->log(3, "replacing all line endings with \\r\\n in $dest"); + return preg_replace("/\r\n|\n\r|\r|\n/", "\r\n", $contents); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Task/Windowseol/rw.php b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Windowseol/rw.php new file mode 100644 index 0000000..acadc1b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Task/Windowseol/rw.php @@ -0,0 +1,56 @@ + - read/write version + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: rw.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a10 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Windowseol.php'; +/** + * Abstracts the windowseol task xml. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a10 + */ +class PEAR_Task_Windowseol_rw extends PEAR_Task_Windowseol +{ + function PEAR_Task_Windowseol_rw(&$pkg, &$config, &$logger, $fileXml) + { + parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); + $this->_contents = $fileXml; + $this->_pkg = &$pkg; + $this->_params = array(); + } + + function validate() + { + return true; + } + + function getName() + { + return 'windowseol'; + } + + function getXml() + { + return ''; + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Validate.php b/typo3conf/ext/phpunit/PEAR/PEAR/Validate.php new file mode 100644 index 0000000..75d8682 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Validate.php @@ -0,0 +1,629 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Validate.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/**#@+ + * Constants for install stage + */ +define('PEAR_VALIDATE_INSTALLING', 1); +define('PEAR_VALIDATE_UNINSTALLING', 2); // this is not bit-mapped like the others +define('PEAR_VALIDATE_NORMAL', 3); +define('PEAR_VALIDATE_DOWNLOADING', 4); // this is not bit-mapped like the others +define('PEAR_VALIDATE_PACKAGING', 7); +/**#@-*/ +require_once 'PEAR/Common.php'; +require_once 'PEAR/Validator/PECL.php'; + +/** + * Validation class for package.xml - channel-level advanced validation + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Validate +{ + var $packageregex = _PEAR_COMMON_PACKAGE_NAME_PREG; + /** + * @var PEAR_PackageFile_v1|PEAR_PackageFile_v2 + */ + var $_packagexml; + /** + * @var int one of the PEAR_VALIDATE_* constants + */ + var $_state = PEAR_VALIDATE_NORMAL; + /** + * Format: ('error' => array('field' => name, 'reason' => reason), 'warning' => same) + * @var array + * @access private + */ + var $_failures = array('error' => array(), 'warning' => array()); + + /** + * Override this method to handle validation of normal package names + * @param string + * @return bool + * @access protected + */ + function _validPackageName($name) + { + return (bool) preg_match('/^' . $this->packageregex . '\\z/', $name); + } + + /** + * @param string package name to validate + * @param string name of channel-specific validation package + * @final + */ + function validPackageName($name, $validatepackagename = false) + { + if ($validatepackagename) { + if (strtolower($name) == strtolower($validatepackagename)) { + return (bool) preg_match('/^[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)*\\z/', $name); + } + } + return $this->_validPackageName($name); + } + + /** + * This validates a bundle name, and bundle names must conform + * to the PEAR naming convention, so the method is final and static. + * @param string + * @final + * @static + */ + function validGroupName($name) + { + return (bool) preg_match('/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/', $name); + } + + /** + * Determine whether $state represents a valid stability level + * @param string + * @return bool + * @static + * @final + */ + function validState($state) + { + return in_array($state, array('snapshot', 'devel', 'alpha', 'beta', 'stable')); + } + + /** + * Get a list of valid stability levels + * @return array + * @static + * @final + */ + function getValidStates() + { + return array('snapshot', 'devel', 'alpha', 'beta', 'stable'); + } + + /** + * Determine whether a version is a properly formatted version number that can be used + * by version_compare + * @param string + * @return bool + * @static + * @final + */ + function validVersion($ver) + { + return (bool) preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); + } + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + */ + function setPackageFile(&$pf) + { + $this->_packagexml = &$pf; + } + + /** + * @access private + */ + function _addFailure($field, $reason) + { + $this->_failures['errors'][] = array('field' => $field, 'reason' => $reason); + } + + /** + * @access private + */ + function _addWarning($field, $reason) + { + $this->_failures['warnings'][] = array('field' => $field, 'reason' => $reason); + } + + function getFailures() + { + $failures = $this->_failures; + $this->_failures = array('warnings' => array(), 'errors' => array()); + return $failures; + } + + /** + * @param int one of the PEAR_VALIDATE_* constants + */ + function validate($state = null) + { + if (!isset($this->_packagexml)) { + return false; + } + if ($state !== null) { + $this->_state = $state; + } + $this->_failures = array('warnings' => array(), 'errors' => array()); + $this->validatePackageName(); + $this->validateVersion(); + $this->validateMaintainers(); + $this->validateDate(); + $this->validateSummary(); + $this->validateDescription(); + $this->validateLicense(); + $this->validateNotes(); + if ($this->_packagexml->getPackagexmlVersion() == '1.0') { + $this->validateState(); + $this->validateFilelist(); + } elseif ($this->_packagexml->getPackagexmlVersion() == '2.0' || + $this->_packagexml->getPackagexmlVersion() == '2.1') { + $this->validateTime(); + $this->validateStability(); + $this->validateDeps(); + $this->validateMainFilelist(); + $this->validateReleaseFilelist(); + //$this->validateGlobalTasks(); + $this->validateChangelog(); + } + return !((bool) count($this->_failures['errors'])); + } + + /** + * @access protected + */ + function validatePackageName() + { + if ($this->_state == PEAR_VALIDATE_PACKAGING || + $this->_state == PEAR_VALIDATE_NORMAL) { + if (($this->_packagexml->getPackagexmlVersion() == '2.0' || + $this->_packagexml->getPackagexmlVersion() == '2.1') && + $this->_packagexml->getExtends()) { + $version = $this->_packagexml->getVersion() . ''; + $name = $this->_packagexml->getPackage(); + $test = array_shift($a = explode('.', $version)); + if ($test == '0') { + return true; + } + $vlen = strlen($test); + $majver = substr($name, strlen($name) - $vlen); + while ($majver && !is_numeric($majver{0})) { + $majver = substr($majver, 1); + } + if ($majver != $test) { + $this->_addWarning('package', "package $name extends package " . + $this->_packagexml->getExtends() . ' and so the name should ' . + 'have a postfix equal to the major version like "' . + $this->_packagexml->getExtends() . $test . '"'); + return true; + } elseif (substr($name, 0, strlen($name) - $vlen) != + $this->_packagexml->getExtends()) { + $this->_addWarning('package', "package $name extends package " . + $this->_packagexml->getExtends() . ' and so the name must ' . + 'be an extension like "' . $this->_packagexml->getExtends() . + $test . '"'); + return true; + } + } + } + if (!$this->validPackageName($this->_packagexml->getPackage())) { + $this->_addFailure('name', 'package name "' . + $this->_packagexml->getPackage() . '" is invalid'); + return false; + } + } + + /** + * @access protected + */ + function validateVersion() + { + if ($this->_state != PEAR_VALIDATE_PACKAGING) { + if (!$this->validVersion($this->_packagexml->getVersion())) { + $this->_addFailure('version', + 'Invalid version number "' . $this->_packagexml->getVersion() . '"'); + } + return false; + } + $version = $this->_packagexml->getVersion(); + $versioncomponents = explode('.', $version); + if (count($versioncomponents) != 3) { + $this->_addWarning('version', + 'A version number should have 3 decimals (x.y.z)'); + return true; + } + $name = $this->_packagexml->getPackage(); + // version must be based upon state + switch ($this->_packagexml->getState()) { + case 'snapshot' : + return true; + case 'devel' : + if ($versioncomponents[0] . 'a' == '0a') { + return true; + } + if ($versioncomponents[0] == 0) { + $versioncomponents[0] = '0'; + $this->_addWarning('version', + 'version "' . $version . '" should be "' . + implode('.' ,$versioncomponents) . '"'); + } else { + $this->_addWarning('version', + 'packages with devel stability must be < version 1.0.0'); + } + return true; + break; + case 'alpha' : + case 'beta' : + // check for a package that extends a package, + // like Foo and Foo2 + if ($this->_state == PEAR_VALIDATE_PACKAGING) { + if (substr($versioncomponents[2], 1, 2) == 'rc') { + $this->_addFailure('version', 'Release Candidate versions ' . + 'must have capital RC, not lower-case rc'); + return false; + } + } + if (!$this->_packagexml->getExtends()) { + if ($versioncomponents[0] == '1') { + if ($versioncomponents[2]{0} == '0') { + if ($versioncomponents[2] == '0') { + // version 1.*.0000 + $this->_addWarning('version', + 'version 1.' . $versioncomponents[1] . + '.0 probably should not be alpha or beta'); + return true; + } elseif (strlen($versioncomponents[2]) > 1) { + // version 1.*.0RC1 or 1.*.0beta24 etc. + return true; + } else { + // version 1.*.0 + $this->_addWarning('version', + 'version 1.' . $versioncomponents[1] . + '.0 probably should not be alpha or beta'); + return true; + } + } else { + $this->_addWarning('version', + 'bugfix versions (1.3.x where x > 0) probably should ' . + 'not be alpha or beta'); + return true; + } + } elseif ($versioncomponents[0] != '0') { + $this->_addWarning('version', + 'major versions greater than 1 are not allowed for packages ' . + 'without an tag or an identical postfix (foo2 v2.0.0)'); + return true; + } + if ($versioncomponents[0] . 'a' == '0a') { + return true; + } + if ($versioncomponents[0] == 0) { + $versioncomponents[0] = '0'; + $this->_addWarning('version', + 'version "' . $version . '" should be "' . + implode('.' ,$versioncomponents) . '"'); + } + } else { + $vlen = strlen($versioncomponents[0] . ''); + $majver = substr($name, strlen($name) - $vlen); + while ($majver && !is_numeric($majver{0})) { + $majver = substr($majver, 1); + } + if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) { + $this->_addWarning('version', 'first version number "' . + $versioncomponents[0] . '" must match the postfix of ' . + 'package name "' . $name . '" (' . + $majver . ')'); + return true; + } + if ($versioncomponents[0] == $majver) { + if ($versioncomponents[2]{0} == '0') { + if ($versioncomponents[2] == '0') { + // version 2.*.0000 + $this->_addWarning('version', + "version $majver." . $versioncomponents[1] . + '.0 probably should not be alpha or beta'); + return false; + } elseif (strlen($versioncomponents[2]) > 1) { + // version 2.*.0RC1 or 2.*.0beta24 etc. + return true; + } else { + // version 2.*.0 + $this->_addWarning('version', + "version $majver." . $versioncomponents[1] . + '.0 cannot be alpha or beta'); + return true; + } + } else { + $this->_addWarning('version', + "bugfix versions ($majver.x.y where y > 0) should " . + 'not be alpha or beta'); + return true; + } + } elseif ($versioncomponents[0] != '0') { + $this->_addWarning('version', + "only versions 0.x.y and $majver.x.y are allowed for alpha/beta releases"); + return true; + } + if ($versioncomponents[0] . 'a' == '0a') { + return true; + } + if ($versioncomponents[0] == 0) { + $versioncomponents[0] = '0'; + $this->_addWarning('version', + 'version "' . $version . '" should be "' . + implode('.' ,$versioncomponents) . '"'); + } + } + return true; + break; + case 'stable' : + if ($versioncomponents[0] == '0') { + $this->_addWarning('version', 'versions less than 1.0.0 cannot ' . + 'be stable'); + return true; + } + if (!is_numeric($versioncomponents[2])) { + if (preg_match('/\d+(rc|a|alpha|b|beta)\d*/i', + $versioncomponents[2])) { + $this->_addWarning('version', 'version "' . $version . '" or any ' . + 'RC/beta/alpha version cannot be stable'); + return true; + } + } + // check for a package that extends a package, + // like Foo and Foo2 + if ($this->_packagexml->getExtends()) { + $vlen = strlen($versioncomponents[0] . ''); + $majver = substr($name, strlen($name) - $vlen); + while ($majver && !is_numeric($majver{0})) { + $majver = substr($majver, 1); + } + if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) { + $this->_addWarning('version', 'first version number "' . + $versioncomponents[0] . '" must match the postfix of ' . + 'package name "' . $name . '" (' . + $majver . ')'); + return true; + } + } elseif ($versioncomponents[0] > 1) { + $this->_addWarning('version', 'major version x in x.y.z may not be greater than ' . + '1 for any package that does not have an tag'); + } + return true; + break; + default : + return false; + break; + } + } + + /** + * @access protected + */ + function validateMaintainers() + { + // maintainers can only be truly validated server-side for most channels + // but allow this customization for those who wish it + return true; + } + + /** + * @access protected + */ + function validateDate() + { + if ($this->_state == PEAR_VALIDATE_NORMAL || + $this->_state == PEAR_VALIDATE_PACKAGING) { + + if (!preg_match('/(\d\d\d\d)\-(\d\d)\-(\d\d)/', + $this->_packagexml->getDate(), $res) || + count($res) < 4 + || !checkdate($res[2], $res[3], $res[1]) + ) { + $this->_addFailure('date', 'invalid release date "' . + $this->_packagexml->getDate() . '"'); + return false; + } + + if ($this->_state == PEAR_VALIDATE_PACKAGING && + $this->_packagexml->getDate() != date('Y-m-d')) { + $this->_addWarning('date', 'Release Date "' . + $this->_packagexml->getDate() . '" is not today'); + } + } + return true; + } + + /** + * @access protected + */ + function validateTime() + { + if (!$this->_packagexml->getTime()) { + // default of no time value set + return true; + } + + // packager automatically sets time, so only validate if pear validate is called + if ($this->_state = PEAR_VALIDATE_NORMAL) { + if (!preg_match('/\d\d:\d\d:\d\d/', + $this->_packagexml->getTime())) { + $this->_addFailure('time', 'invalid release time "' . + $this->_packagexml->getTime() . '"'); + return false; + } + + $result = preg_match('|\d{2}\:\d{2}\:\d{2}|', $this->_packagexml->getTime(), $matches); + if ($result === false || empty($matches)) { + $this->_addFailure('time', 'invalid release time "' . + $this->_packagexml->getTime() . '"'); + return false; + } + } + + return true; + } + + /** + * @access protected + */ + function validateState() + { + // this is the closest to "final" php4 can get + if (!PEAR_Validate::validState($this->_packagexml->getState())) { + if (strtolower($this->_packagexml->getState() == 'rc')) { + $this->_addFailure('state', 'RC is not a state, it is a version ' . + 'postfix, use ' . $this->_packagexml->getVersion() . 'RC1, state beta'); + } + $this->_addFailure('state', 'invalid release state "' . + $this->_packagexml->getState() . '", must be one of: ' . + implode(', ', PEAR_Validate::getValidStates())); + return false; + } + return true; + } + + /** + * @access protected + */ + function validateStability() + { + $ret = true; + $packagestability = $this->_packagexml->getState(); + $apistability = $this->_packagexml->getState('api'); + if (!PEAR_Validate::validState($packagestability)) { + $this->_addFailure('state', 'invalid release stability "' . + $this->_packagexml->getState() . '", must be one of: ' . + implode(', ', PEAR_Validate::getValidStates())); + $ret = false; + } + $apistates = PEAR_Validate::getValidStates(); + array_shift($apistates); // snapshot is not allowed + if (!in_array($apistability, $apistates)) { + $this->_addFailure('state', 'invalid API stability "' . + $this->_packagexml->getState('api') . '", must be one of: ' . + implode(', ', $apistates)); + $ret = false; + } + return $ret; + } + + /** + * @access protected + */ + function validateSummary() + { + return true; + } + + /** + * @access protected + */ + function validateDescription() + { + return true; + } + + /** + * @access protected + */ + function validateLicense() + { + return true; + } + + /** + * @access protected + */ + function validateNotes() + { + return true; + } + + /** + * for package.xml 2.0 only - channels can't use package.xml 1.0 + * @access protected + */ + function validateDependencies() + { + return true; + } + + /** + * for package.xml 1.0 only + * @access private + */ + function _validateFilelist() + { + return true; // placeholder for now + } + + /** + * for package.xml 2.0 only + * @access protected + */ + function validateMainFilelist() + { + return true; // placeholder for now + } + + /** + * for package.xml 2.0 only + * @access protected + */ + function validateReleaseFilelist() + { + return true; // placeholder for now + } + + /** + * @access protected + */ + function validateChangelog() + { + return true; + } + + /** + * @access protected + */ + function validateFilelist() + { + return true; + } + + /** + * @access protected + */ + function validateDeps() + { + return true; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/Validator/PECL.php b/typo3conf/ext/phpunit/PEAR/PEAR/Validator/PECL.php new file mode 100644 index 0000000..1e3868e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/Validator/PECL.php @@ -0,0 +1,63 @@ + + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: PECL.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a5 + */ +/** + * This is the parent class for all validators + */ +require_once 'PEAR/Validate.php'; +/** + * Channel Validator for the pecl.php.net channel + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a5 + */ +class PEAR_Validator_PECL extends PEAR_Validate +{ + function validateVersion() + { + if ($this->_state == PEAR_VALIDATE_PACKAGING) { + $version = $this->_packagexml->getVersion(); + $versioncomponents = explode('.', $version); + $last = array_pop($versioncomponents); + if (substr($last, 1, 2) == 'rc') { + $this->_addFailure('version', 'Release Candidate versions must have ' . + 'upper-case RC, not lower-case rc'); + return false; + } + } + return true; + } + + function validatePackageName() + { + $ret = parent::validatePackageName(); + if ($this->_packagexml->getPackageType() == 'extsrc' || + $this->_packagexml->getPackageType() == 'zendextsrc') { + if (strtolower($this->_packagexml->getPackage()) != + strtolower($this->_packagexml->getProvidesExtension())) { + $this->_addWarning('providesextension', 'package name "' . + $this->_packagexml->getPackage() . '" is different from extension name "' . + $this->_packagexml->getProvidesExtension() . '"'); + } + } + return $ret; + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR/XMLParser.php b/typo3conf/ext/phpunit/PEAR/PEAR/XMLParser.php new file mode 100644 index 0000000..53b7bae --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR/XMLParser.php @@ -0,0 +1,253 @@ + + * @author Stephan Schmidt (original XML_Unserializer code) + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license New BSD License + * @version CVS: $Id: XMLParser.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Parser for any xml file + * @category pear + * @package PEAR + * @author Greg Beaver + * @author Stephan Schmidt (original XML_Unserializer code) + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license New BSD License + * @version Release: 1.9.3 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_XMLParser +{ + /** + * unserilialized data + * @var string $_serializedData + */ + var $_unserializedData = null; + + /** + * name of the root tag + * @var string $_root + */ + var $_root = null; + + /** + * stack for all data that is found + * @var array $_dataStack + */ + var $_dataStack = array(); + + /** + * stack for all values that are generated + * @var array $_valStack + */ + var $_valStack = array(); + + /** + * current tag depth + * @var int $_depth + */ + var $_depth = 0; + + /** + * The XML encoding to use + * @var string $encoding + */ + var $encoding = 'ISO-8859-1'; + + /** + * @return array + */ + function getData() + { + return $this->_unserializedData; + } + + /** + * @param string xml content + * @return true|PEAR_Error + */ + function parse($data) + { + if (!extension_loaded('xml')) { + include_once 'PEAR.php'; + return PEAR::raiseError("XML Extension not found", 1); + } + $this->_dataStack = $this->_valStack = array(); + $this->_depth = 0; + + if ( + strpos($data, 'encoding="UTF-8"') + || strpos($data, 'encoding="utf-8"') + || strpos($data, "encoding='UTF-8'") + || strpos($data, "encoding='utf-8'") + ) { + $this->encoding = 'UTF-8'; + } + + if (version_compare(phpversion(), '5.0.0', 'lt') && $this->encoding == 'UTF-8') { + $data = utf8_decode($data); + $this->encoding = 'ISO-8859-1'; + } + + $xp = xml_parser_create($this->encoding); + xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, 0); + xml_set_object($xp, $this); + xml_set_element_handler($xp, 'startHandler', 'endHandler'); + xml_set_character_data_handler($xp, 'cdataHandler'); + if (!xml_parse($xp, $data)) { + $msg = xml_error_string(xml_get_error_code($xp)); + $line = xml_get_current_line_number($xp); + xml_parser_free($xp); + include_once 'PEAR.php'; + return PEAR::raiseError("XML Error: '$msg' on line '$line'", 2); + } + xml_parser_free($xp); + return true; + } + + /** + * Start element handler for XML parser + * + * @access private + * @param object $parser XML parser object + * @param string $element XML element + * @param array $attribs attributes of XML tag + * @return void + */ + function startHandler($parser, $element, $attribs) + { + $this->_depth++; + $this->_dataStack[$this->_depth] = null; + + $val = array( + 'name' => $element, + 'value' => null, + 'type' => 'string', + 'childrenKeys' => array(), + 'aggregKeys' => array() + ); + + if (count($attribs) > 0) { + $val['children'] = array(); + $val['type'] = 'array'; + $val['children']['attribs'] = $attribs; + } + + array_push($this->_valStack, $val); + } + + /** + * post-process data + * + * @param string $data + * @param string $element element name + */ + function postProcess($data, $element) + { + return trim($data); + } + + /** + * End element handler for XML parser + * + * @access private + * @param object XML parser object + * @param string + * @return void + */ + function endHandler($parser, $element) + { + $value = array_pop($this->_valStack); + $data = $this->postProcess($this->_dataStack[$this->_depth], $element); + + // adjust type of the value + switch (strtolower($value['type'])) { + // unserialize an array + case 'array': + if ($data !== '') { + $value['children']['_content'] = $data; + } + + $value['value'] = isset($value['children']) ? $value['children'] : array(); + break; + + /* + * unserialize a null value + */ + case 'null': + $data = null; + break; + + /* + * unserialize any scalar value + */ + default: + settype($data, $value['type']); + $value['value'] = $data; + break; + } + + $parent = array_pop($this->_valStack); + if ($parent === null) { + $this->_unserializedData = &$value['value']; + $this->_root = &$value['name']; + return true; + } + + // parent has to be an array + if (!isset($parent['children']) || !is_array($parent['children'])) { + $parent['children'] = array(); + if ($parent['type'] != 'array') { + $parent['type'] = 'array'; + } + } + + if (!empty($value['name'])) { + // there already has been a tag with this name + if (in_array($value['name'], $parent['childrenKeys'])) { + // no aggregate has been created for this tag + if (!in_array($value['name'], $parent['aggregKeys'])) { + if (isset($parent['children'][$value['name']])) { + $parent['children'][$value['name']] = array($parent['children'][$value['name']]); + } else { + $parent['children'][$value['name']] = array(); + } + array_push($parent['aggregKeys'], $value['name']); + } + array_push($parent['children'][$value['name']], $value['value']); + } else { + $parent['children'][$value['name']] = &$value['value']; + array_push($parent['childrenKeys'], $value['name']); + } + } else { + array_push($parent['children'],$value['value']); + } + array_push($this->_valStack, $parent); + + $this->_depth--; + } + + /** + * Handler for character data + * + * @access private + * @param object XML parser object + * @param string CDATA + * @return void + */ + function cdataHandler($parser, $cdata) + { + $this->_dataStack[$this->_depth] .= $cdata; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PEAR5.php b/typo3conf/ext/phpunit/PEAR/PEAR5.php new file mode 100644 index 0000000..4286067 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PEAR5.php @@ -0,0 +1,33 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since File available since Release 1.0.0 + */ + +require_once 'PHP/CodeCoverage/Driver/Xdebug.php'; +require_once 'PHP/CodeCoverage/Filter.php'; +require_once 'PHP/CodeCoverage/Util.php'; + +/** + * Provides collection functionality for PHP code coverage information. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.4 + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since Class available since Release 1.0.0 + */ +class PHP_CodeCoverage +{ + /** + * @var PHP_CodeCoverage_Driver + */ + protected $driver; + + /** + * @var PHP_CodeCoverage_Filter + */ + protected $filter; + + /** + * @var boolean + */ + protected $forceCoversAnnotation = FALSE; + + /** + * @var boolean + */ + protected $mapTestClassNameToCoveredClassName = FALSE; + + /** + * @var boolean + */ + protected $processUncoveredFilesFromWhitelist = TRUE; + + /** + * @var mixed + */ + protected $currentId; + + /** + * List of covered files. + * + * @var array + */ + protected $coveredFiles = array(); + + /** + * Raw code coverage data. + * + * @var array + */ + protected $data = array(); + + /** + * Summarized code coverage data. + * + * @var array + */ + protected $summary = array(); + + /** + * Test data. + * + * @var array + */ + protected $tests = array(); + + /** + * @var boolean + */ + protected $isCodeCoverageTestSuite = FALSE; + + /** + * @var boolean + */ + protected $isFileIteratorTestSuite = FALSE; + + /** + * @var boolean + */ + protected $isTimerTestSuite = FALSE; + + /** + * @var boolean + */ + protected $isTokenStreamTestSuite = FALSE; + + /** + * Default PHP_CodeCoverage object. + * + * @var PHP_CodeCoverage + */ + protected static $instance; + + /** + * Constructor. + * + * @param PHP_CodeCoverage_Driver $driver + * @param PHP_CodeCoverage_Filter $filter + * @throws InvalidArgumentException + */ + public function __construct(PHP_CodeCoverage_Driver $driver = NULL, PHP_CodeCoverage_Filter $filter = NULL) + { + if ($driver === NULL) { + $driver = new PHP_CodeCoverage_Driver_Xdebug; + } + + if ($filter === NULL) { + $filter = PHP_CodeCoverage_Filter::getInstance(); + } + + $this->driver = $driver; + $this->filter = $filter; + + if (defined('PHP_CODECOVERAGE_TESTSUITE')) { + $this->isCodeCoverageTestSuite = TRUE; + } + + if (defined('FILE_ITERATOR_TESTSUITE')) { + $this->isFileIteratorTestSuite = TRUE; + } + + if (defined('PHP_TIMER_TESTSUITE')) { + $this->isTimerTestSuite = TRUE; + } + + if (defined('PHP_TOKENSTREAM_TESTSUITE')) { + $this->isTokenStreamTestSuite = TRUE; + } + } + + /** + * Returns the default instance. + * + * @return PHP_CodeCoverage + */ + public static function getInstance() + { + if (self::$instance === NULL) { + // @codeCoverageIgnoreStart + self::$instance = new PHP_CodeCoverage; + } + // @codeCoverageIgnoreEnd + return self::$instance; + } + + /** + * Start collection of code coverage information. + * + * @param mixed $id + * @param boolean $clear + * @throws InvalidArgumentException + */ + public function start($id, $clear = FALSE) + { + if (!is_bool($clear)) { + throw new InvalidArgumentException; + } + + if ($clear) { + $this->clear(); + } + + $this->currentId = $id; + + $this->driver->start(); + } + + /** + * Stop collection of code coverage information. + * + * @param boolean $append + * @return array + * @throws InvalidArgumentException + */ + public function stop($append = TRUE) + { + if (!is_bool($append)) { + throw new InvalidArgumentException; + } + + $data = $this->driver->stop(); + + if ($append) { + $this->append($data); + } + + $this->currentId = NULL; + + return $data; + } + + /** + * Appends code coverage data. + * + * @param array $data + * @param mixed $id + * @param array $filterGroups + */ + public function append(array $data, $id = NULL, array $filterGroups = array('DEFAULT')) + { + if ($id === NULL) { + $id = $this->currentId; + } + + if ($id === NULL) { + throw new InvalidArgumentException; + } + + $this->applySelfFilter($data); + $this->applyListsFilter($data, $filterGroups); + $raw = $data; + $this->applyCoversAnnotationFilter($data, $id); + + if (!empty($data)) { + if ($id instanceof PHPUnit_Framework_TestCase) { + $status = $id->getStatus(); + $id = get_class($id) . '::' . $id->getName(); + $this->tests[$id] = $status; + } + + else if ($id instanceof PHPUnit_Extensions_PhptTestCase) { + $id = $id->getName(); + } + + $this->coveredFiles = array_unique( + array_merge($this->coveredFiles, array_keys($data)) + ); + + $this->data[$id] = array('filtered' => $data, 'raw' => $raw); + $this->summary = array(); + } + } + + /** + * Merges the data from another instance of PHP_CodeCoverage. + * + * @param PHP_CodeCoverage $that + */ + public function merge(PHP_CodeCoverage $that) + { + foreach ($that->data as $id => $data) { + if (!isset($this->data[$id])) { + $this->data[$id] = $data; + } else { + foreach (array('filtered', 'raw') as $type) { + foreach ($data[$type] as $file => $lines) { + if (!isset($this->data[$id][$type][$file])) { + $this->data[$id][$type][$file] = $lines; + } else { + foreach ($lines as $line => $flag) { + if (!isset($this->data[$id][$type][$file][$line]) || + $flag > $this->data[$id][$type][$file][$line]) { + $this->data[$id][$type][$file][$line] = $flag; + } + } + } + } + } + } + } + + foreach ($that->tests as $id => $status) { + if (!isset($this->tests[$id]) || $status > $this->tests[$id]) { + $this->tests[$id] = $status; + } + } + + $this->coveredFiles = array_unique( + array_merge($this->coveredFiles, $that->coveredFiles) + ); + + $this->summary = array(); + } + + /** + * Returns summarized code coverage data. + * + * Format of the result array: + * + * + * array( + * "/tested/code.php" => array( + * linenumber => array(tests that executed the line) + * ) + * ) + * + * + * @return array + */ + public function getSummary() + { + if (empty($this->summary)) { + if ($this->processUncoveredFilesFromWhitelist) { + $this->processUncoveredFilesFromWhitelist(); + } + + foreach ($this->data as $test => $coverage) { + foreach ($coverage['filtered'] as $file => $lines) { + foreach ($lines as $line => $flag) { + if ($flag == 1) { + if (!isset($this->summary[$file][$line][0])) { + $this->summary[$file][$line] = array(); + } + + if (isset($this->tests[$test])) { + $status = $this->tests[$test]; + } else { + $status = NULL; + } + + $this->summary[$file][$line][] = array( + 'id' => $test, 'status' => $status + ); + } + } + } + + foreach ($coverage['raw'] as $file => $lines) { + foreach ($lines as $line => $flag) { + if ($flag != 1 && + !isset($this->summary[$file][$line][0])) { + $this->summary[$file][$line] = $flag; + } + } + } + } + + foreach ($this->summary as &$file) { + ksort($file); + } + + ksort($this->summary); + } + + return $this->summary; + } + + /** + * Clears collected code coverage data. + */ + public function clear() + { + $this->data = array(); + $this->coveredFiles = array(); + $this->summary = array(); + $this->currentId = NULL; + } + + /** + * Returns the PHP_CodeCoverage_Filter used. + * + * @return PHP_CodeCoverage_Filter + */ + public function filter() + { + return $this->filter; + } + + /** + * @param boolean $flag + * @throws InvalidArgumentException + */ + public function setForceCoversAnnotation($flag) + { + if (!is_bool($flag)) { + throw new InvalidArgumentException; + } + + $this->forceCoversAnnotation = $flag; + } + + /** + * @param boolean $flag + * @throws InvalidArgumentException + */ + public function setMapTestClassNameToCoveredClassName($flag) + { + if (!is_bool($flag)) { + throw new InvalidArgumentException; + } + + $this->mapTestClassNameToCoveredClassName = $flag; + } + + /** + * @param boolean $flag + * @throws InvalidArgumentException + */ + public function setProcessUncoveredFilesFromWhitelist($flag) + { + if (!is_bool($flag)) { + throw new InvalidArgumentException; + } + + $this->processUncoveredFilesFromWhitelist = $flag; + } + + /** + * Filters sourcecode files from PHP_CodeCoverage, PHP_TokenStream, + * Text_Template, and File_Iterator. + * + * @param array $data + */ + protected function applySelfFilter(&$data) + { + foreach (array_keys($data) as $filename) { + if (!$this->filter->isFile($filename)) { + unset($data[$filename]); + continue; + } + + if (!$this->isCodeCoverageTestSuite && + strpos($filename, dirname(__FILE__)) === 0) { + unset($data[$filename]); + continue; + } + + if (!$this->isFileIteratorTestSuite && + (substr($filename, -17) == 'File/Iterator.php' || + substr($filename, -25) == 'File/Iterator/Factory.php')) { + unset($data[$filename]); + continue; + } + + if (!$this->isTimerTestSuite && + (substr($filename, -13) == 'PHP/Timer.php')) { + unset($data[$filename]); + continue; + } + + if (!$this->isTokenStreamTestSuite && + (substr($filename, -13) == 'PHP/Token.php' || + substr($filename, -20) == 'PHP/Token/Stream.php' || + substr($filename, -35) == 'PHP/Token/Stream/CachingFactory.php')) { + unset($data[$filename]); + continue; + } + + if (substr($filename, -17) == 'Text/Template.php') { + unset($data[$filename]); + } + } + } + + /** + * Applies the blacklist/whitelist filtering. + * + * @param array $data + * @param array $filterGroups + */ + protected function applyListsFilter(&$data, $filterGroups) + { + foreach (array_keys($data) as $filename) { + if ($this->filter->isFiltered($filename, $filterGroups)) { + unset($data[$filename]); + } + } + } + + /** + * Applies the @covers annotation filtering. + * + * @param array $data + * @param mixed $id + */ + protected function applyCoversAnnotationFilter(&$data, $id) + { + if ($id instanceof PHPUnit_Framework_TestCase) { + $testClassName = get_class($id); + $linesToBeCovered = PHP_CodeCoverage_Util::getLinesToBeCovered( + $testClassName, $id->getName() + ); + + if ($this->mapTestClassNameToCoveredClassName && + empty($linesToBeCovered)) { + $testedClass = substr($testClassName, 0, -4); + + if (class_exists($testedClass)) { + $class = new ReflectionClass($testedClass); + + $linesToBeCovered = array( + $class->getFileName() => range( + $class->getStartLine(), $class->getEndLine() + ) + ); + } + } + } else { + $linesToBeCovered = array(); + } + + if (!empty($linesToBeCovered)) { + $data = array_intersect_key($data, $linesToBeCovered); + + foreach (array_keys($data) as $filename) { + $data[$filename] = array_intersect_key( + $data[$filename], array_flip($linesToBeCovered[$filename]) + ); + } + } + + else if ($this->forceCoversAnnotation) { + $data = array(); + } + } + + /** + * Processes whitelisted files that are not covered. + */ + protected function processUncoveredFilesFromWhitelist() + { + $data = array(); + $includedFiles = array_flip(get_included_files()); + $uncoveredFiles = array_diff( + $this->filter->getWhitelist(), $this->coveredFiles + ); + + foreach ($uncoveredFiles as $uncoveredFile) { + if (isset($includedFiles[$uncoveredFile])) { + foreach (array_keys($this->data) as $test) { + if (isset($this->data[$test]['raw'][$uncoveredFile])) { + $coverage = $this->data[$test]['raw'][$uncoveredFile]; + + foreach (array_keys($coverage) as $key) { + if ($coverage[$key] == 1) { + $coverage[$key] = -1; + } + } + + $data[$uncoveredFile] = $coverage; + + break; + } + } + } else { + $this->driver->start(); + include_once $uncoveredFile; + $coverage = $this->driver->stop(); + + foreach ($coverage as $file => $fileCoverage) { + if (!isset($data[$file]) && + in_array($file, $uncoveredFiles)) { + foreach (array_keys($fileCoverage) as $key) { + if ($fileCoverage[$key] == 1) { + $fileCoverage[$key] = -1; + } + } + + $data[$file] = $fileCoverage; + $includedFiles[$file] = TRUE; + } + } + } + } + + $this->append($data, 'UNCOVERED_FILES_FROM_WHITELIST'); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Driver.php b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Driver.php new file mode 100644 index 0000000..ad5801b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Driver.php @@ -0,0 +1,71 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since File available since Release 1.0.0 + */ + +/** + * Interface for code coverage drivers. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.4 + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since Class available since Release 1.0.0 + */ +interface PHP_CodeCoverage_Driver +{ + /** + * Start collection of code coverage information. + */ + public function start(); + + /** + * Stop collection of code coverage information. + * + * @return array + */ + public function stop(); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Driver/Xdebug.php b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Driver/Xdebug.php new file mode 100644 index 0000000..ceb81c1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Driver/Xdebug.php @@ -0,0 +1,91 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since File available since Release 1.0.0 + */ + +require_once 'PHP/CodeCoverage/Driver.php'; + +if (version_compare(phpversion('xdebug'), '2.2.0-dev', '>=') && + !ini_get('xdebug.coverage_enable')) { + die("You need to set xdebug.coverage_enable=On in your php.ini.\n"); +} + +/** + * Driver for Xdebug's code coverage functionality. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.4 + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since Class available since Release 1.0.0 + */ +class PHP_CodeCoverage_Driver_Xdebug implements PHP_CodeCoverage_Driver +{ + /** + * Start collection of code coverage information. + */ + public function start() + { + // @codeCoverageIgnoreStart + xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE); + // @codeCoverageIgnoreEnd + } + + /** + * Stop collection of code coverage information. + * + * @return array + */ + public function stop() + { + // @codeCoverageIgnoreStart + $codeCoverage = xdebug_get_code_coverage(); + xdebug_stop_code_coverage(); + + return $codeCoverage; + // @codeCoverageIgnoreEnd + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Filter.php b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Filter.php new file mode 100644 index 0000000..f37161d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Filter.php @@ -0,0 +1,334 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since File available since Release 1.0.0 + */ + +require_once 'File/Iterator/Factory.php'; + +/** + * Filter for blacklisting and whitelisting of code coverage information. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.4 + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since Class available since Release 1.0.0 + */ +class PHP_CodeCoverage_Filter +{ + /** + * Source files that are blacklisted. + * + * @var array + */ + protected $blacklistedFiles = array( + 'DEFAULT' => array() + ); + + /** + * Source files that are whitelisted. + * + * @var array + */ + protected $whitelistedFiles = array(); + + /** + * Default PHP_CodeCoverage object. + * + * @var PHP_CodeCoverage + */ + protected static $instance; + + /** + * Returns the default instance. + * + * @return PHP_CodeCoverage_Filter + */ + public static function getInstance() + { + if (self::$instance === NULL) { + // @codeCoverageIgnoreStart + self::$instance = new PHP_CodeCoverage_Filter; + } + // @codeCoverageIgnoreEnd + + return self::$instance; + } + + /** + * Adds a directory to the blacklist (recursively). + * + * @param string $directory + * @param string $suffix + * @param string $prefix + * @param string $group + */ + public function addDirectoryToBlacklist($directory, $suffix = '.php', $prefix = '', $group = 'DEFAULT') + { + $files = File_Iterator_Factory::getFileIterator( + $directory, $suffix, $prefix + ); + + foreach ($files as $file) { + $this->addFileToBlacklist($file->getPathName(), $group, FALSE); + } + } + + /** + * Adds a file to the blacklist. + * + * @param string $filename + * @param string $group + */ + public function addFileToBlacklist($filename, $group = 'DEFAULT') + { + $this->blacklistedFiles[$group][realpath($filename)] = TRUE; + } + + /** + * Adds files to the blacklist. + * + * @param array $files + * @param string $group + */ + public function addFilesToBlacklist(array $files, $group = 'DEFAULT') + { + foreach ($files as $file) { + $this->addFileToBlacklist($file, $group); + } + } + + /** + * Removes a directory from the blacklist (recursively). + * + * @param string $directory + * @param string $suffix + * @param string $prefix + * @param string $group + */ + public function removeDirectoryFromBlacklist($directory, $suffix = '.php', $prefix = '', $group = 'DEFAULT') + { + $files = File_Iterator_Factory::getFileIterator( + $directory, $suffix, $prefix + ); + + foreach ($files as $file) { + $this->removeFileFromBlacklist($file->getPathName(), $group); + } + } + + /** + * Removes a file from the blacklist. + * + * @param string $filename + * @param string $group + */ + public function removeFileFromBlacklist($filename, $group = 'DEFAULT') + { + $filename = realpath($filename); + + if (isset($this->blacklistedFiles[$group][$filename])) { + unset($this->blacklistedFiles[$group][$filename]); + } + } + + /** + * Adds a directory to the whitelist (recursively). + * + * @param string $directory + * @param string $suffix + * @param string $prefix + */ + public function addDirectoryToWhitelist($directory, $suffix = '.php', $prefix = '') + { + $files = File_Iterator_Factory::getFileIterator( + $directory, $suffix, $prefix + ); + + foreach ($files as $file) { + $this->addFileToWhitelist($file->getPathName(), FALSE); + } + } + + /** + * Adds a file to the whitelist. + * + * When the whitelist is empty (default), blacklisting is used. + * When the whitelist is not empty, whitelisting is used. + * + * @param string $filename + */ + public function addFileToWhitelist($filename) + { + $this->whitelistedFiles[realpath($filename)] = TRUE; + } + + /** + * Adds files to the whitelist. + * + * @param array $files + */ + public function addFilesToWhitelist(array $files) + { + foreach ($files as $file) { + $this->addFileToWhitelist($file); + } + } + + /** + * Removes a directory from the whitelist (recursively). + * + * @param string $directory + * @param string $suffix + * @param string $prefix + */ + public function removeDirectoryFromWhitelist($directory, $suffix = '.php', $prefix = '') + { + $files = File_Iterator_Factory::getFileIterator( + $directory, $suffix, $prefix + ); + + foreach ($files as $file) { + $this->removeFileFromWhitelist($file->getPathName()); + } + } + + /** + * Removes a file from the whitelist. + * + * @param string $filename + */ + public function removeFileFromWhitelist($filename) + { + $filename = realpath($filename); + + if (isset($this->whitelistedFiles[$filename])) { + unset($this->whitelistedFiles[$filename]); + } + } + + /** + * Checks whether a filename is a real filename. + * + * @param string $filename + */ + public static function isFile($filename) + { + if ($filename == '-' || + strpos($filename, 'eval()\'d code') !== FALSE || + strpos($filename, 'runtime-created function') !== FALSE || + strpos($filename, 'assert code') !== FALSE || + strpos($filename, 'regexp code') !== FALSE) { + return FALSE; + } + + return TRUE; + } + + /** + * Checks whether or not a file is filtered. + * + * When the whitelist is empty (default), blacklisting is used. + * When the whitelist is not empty, whitelisting is used. + * + * @param string $filename + * @param array $groups + * @param boolean $ignoreWhitelist + * @return boolean + * @throws InvalidArgumentException + */ + public function isFiltered($filename, array $groups = array('DEFAULT'), $ignoreWhitelist = FALSE) + { + if (!is_bool($ignoreWhitelist)) { + throw new InvalidArgumentException; + } + + $filename = realpath($filename); + + if (!$ignoreWhitelist && !empty($this->whitelistedFiles)) { + return !isset($this->whitelistedFiles[$filename]); + } + + $blacklistedFiles = array(); + + foreach ($groups as $group) { + if (isset($this->blacklistedFiles[$group])) { + $blacklistedFiles = array_merge( + $blacklistedFiles, + $this->blacklistedFiles[$group] + ); + } + } + + return isset($blacklistedFiles[$filename]); + } + + /** + * Returns the list of blacklisted files. + * + * @return array + */ + public function getBlacklist() + { + $blacklistedFiles = array(); + + foreach ($this->blacklistedFiles as $group => $list) { + $blacklistedFiles[$group] = array_keys($list); + } + + return $blacklistedFiles; + } + + /** + * Returns the list of whitelisted files. + * + * @return array + */ + public function getWhitelist() + { + return array_keys($this->whitelistedFiles); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/Clover.php b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/Clover.php new file mode 100644 index 0000000..7f05708 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/Clover.php @@ -0,0 +1,467 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since File available since Release 1.0.0 + */ + +require_once 'PHP/CodeCoverage.php'; +require_once 'PHP/Token/Stream/CachingFactory.php'; + +/** + * Generates a Clover XML logfile from an PHP_CodeCoverage object. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.4 + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since Class available since Release 1.0.0 + */ +class PHP_CodeCoverage_Report_Clover +{ + /** + * @param PHP_CodeCoverage $coverage + * @param string $target + * @param string $name + * @return string + */ + public function process(PHP_CodeCoverage $coverage, $target = NULL, $name = NULL) + { + $document = new DOMDocument('1.0', 'UTF-8'); + $document->formatOutput = TRUE; + + $root = $document->createElement('coverage'); + $root->setAttribute('generated', (int)$_SERVER['REQUEST_TIME']); + $document->appendChild($root); + + $project = $document->createElement('project'); + $project->setAttribute('timestamp', (int)$_SERVER['REQUEST_TIME']); + + if (is_string($name)) { + $project->setAttribute('name', $name); + } + + $root->appendChild($project); + + $files = $coverage->getSummary(); + $packages = array(); + + $projectStatistics = array( + 'files' => 0, + 'loc' => 0, + 'ncloc' => 0, + 'classes' => 0, + 'methods' => 0, + 'coveredMethods' => 0, + 'conditionals' => 0, + 'coveredConditionals' => 0, + 'statements' => 0, + 'coveredStatements' => 0 + ); + + foreach ($files as $filename => $data) { + $namespace = 'global'; + + if (file_exists($filename)) { + $fileStatistics = array( + 'classes' => 0, + 'methods' => 0, + 'coveredMethods' => 0, + 'conditionals' => 0, + 'coveredConditionals' => 0, + 'statements' => 0, + 'coveredStatements' => 0 + ); + + $file = $document->createElement('file'); + $file->setAttribute('name', $filename); + + $tokens = PHP_Token_Stream_CachingFactory::get($filename); + $classesInFile = $tokens->getClasses(); + $linesOfCode = $tokens->getLinesOfCode(); + unset($tokens); + + $ignoredLines = PHP_CodeCoverage_Util::getLinesToBeIgnored( + $filename + ); + + $lines = array(); + + foreach ($classesInFile as $className => $_class) { + $classStatistics = array( + 'methods' => 0, + 'coveredMethods' => 0, + 'conditionals' => 0, + 'coveredConditionals' => 0, + 'statements' => 0, + 'coveredStatements' => 0 + ); + + foreach ($_class['methods'] as $methodName => $method) { + $classStatistics['methods']++; + + $methodCount = 0; + $methodLines = 0; + $methodLinesCovered = 0; + + for ($i = $method['startLine']; + $i <= $method['endLine']; + $i++) { + if (isset($ignoredLines[$i])) { + continue; + } + + $add = TRUE; + $count = 0; + + if (isset($files[$filename][$i])) { + if ($files[$filename][$i] != -2) { + $classStatistics['statements']++; + $methodLines++; + } + + if (is_array($files[$filename][$i])) { + $classStatistics['coveredStatements']++; + $methodLinesCovered++; + $count = count($files[$filename][$i]); + } + + else if ($files[$filename][$i] == -2) { + $add = FALSE; + } + } else { + $add = FALSE; + } + + $methodCount = max($methodCount, $count); + + if ($add) { + $lines[$i] = array( + 'count' => $count, + 'type' => 'stmt' + ); + } + } + + if ($methodCount > 0) { + $classStatistics['coveredMethods']++; + } + + $lines[$method['startLine']] = array( + 'count' => $methodCount, + 'crap' => PHP_CodeCoverage_Util::crap( + $method['ccn'], + PHP_CodeCoverage_Util::percent( + $methodLinesCovered, + $methodLines + ) + ), + 'type' => 'method', + 'name' => $methodName + ); + } + + $package = PHP_CodeCoverage_Util::getPackageInformation( + $className, $_class['docblock'] + ); + + if (!empty($package['namespace'])) { + $namespace = $package['namespace']; + } + + $class = $document->createElement('class'); + $class->setAttribute('name', $className); + $class->setAttribute('namespace', $namespace); + + if (!empty($package['fullPackage'])) { + $class->setAttribute( + 'fullPackage', $package['fullPackage'] + ); + } + + if (!empty($package['category'])) { + $class->setAttribute( + 'category', $package['category'] + ); + } + + if (!empty($package['package'])) { + $class->setAttribute( + 'package', $package['package'] + ); + } + + if (!empty($package['subpackage'])) { + $class->setAttribute( + 'subpackage', $package['subpackage'] + ); + } + + $file->appendChild($class); + + $metrics = $document->createElement('metrics'); + + $metrics->setAttribute( + 'methods', $classStatistics['methods'] + ); + + $metrics->setAttribute( + 'coveredmethods', $classStatistics['coveredMethods'] + ); + + $metrics->setAttribute( + 'conditionals', $classStatistics['conditionals'] + ); + + $metrics->setAttribute( + 'coveredconditionals', + $classStatistics['coveredConditionals'] + ); + + $metrics->setAttribute( + 'statements', $classStatistics['statements'] + ); + + $metrics->setAttribute( + 'coveredstatements', + $classStatistics['coveredStatements'] + ); + + $metrics->setAttribute( + 'elements', + $classStatistics['conditionals'] + + $classStatistics['statements'] + + $classStatistics['methods'] + ); + + $metrics->setAttribute( + 'coveredelements', + $classStatistics['coveredConditionals'] + + $classStatistics['coveredStatements'] + + $classStatistics['coveredMethods'] + ); + + $class->appendChild($metrics); + + $fileStatistics['methods'] += $classStatistics['methods']; + $fileStatistics['coveredMethods'] += $classStatistics['coveredMethods']; + $fileStatistics['conditionals'] += $classStatistics['conditionals']; + $fileStatistics['coveredConditionals'] += $classStatistics['coveredConditionals']; + $fileStatistics['statements'] += $classStatistics['statements']; + $fileStatistics['coveredStatements'] += $classStatistics['coveredStatements']; + $fileStatistics['classes']++; + } + + foreach ($data as $_line => $_data) { + if (isset($lines[$_line]) || isset($ignoredLines[$_line])) { + continue; + } + + if ($_data != -2) { + $fileStatistics['statements']++; + + if (is_array($_data)) { + $count = count($_data); + $fileStatistics['coveredStatements']++; + } else { + $count = 0; + } + + $lines[$_line] = array( + 'count' => $count, + 'type' => 'stmt' + ); + } + } + + ksort($lines); + + foreach ($lines as $_line => $_data) { + if (isset($ignoredLines[$_line])) { + continue; + } + + $line = $document->createElement('line'); + $line->setAttribute('num', $_line); + $line->setAttribute('type', $_data['type']); + + if (isset($_data['name'])) { + $line->setAttribute('name', $_data['name']); + } + + if (isset($_data['crap'])) { + $line->setAttribute('crap', $_data['crap']); + } + + $line->setAttribute('count', $_data['count']); + + $file->appendChild($line); + } + + $metrics = $document->createElement('metrics'); + + $metrics->setAttribute('loc', $linesOfCode['loc']); + $metrics->setAttribute('ncloc', $linesOfCode['ncloc']); + $metrics->setAttribute('classes', $fileStatistics['classes']); + $metrics->setAttribute('methods', $fileStatistics['methods']); + + $metrics->setAttribute( + 'coveredmethods', $fileStatistics['coveredMethods'] + ); + + $metrics->setAttribute( + 'conditionals', $fileStatistics['conditionals'] + ); + + $metrics->setAttribute( + 'coveredconditionals', $fileStatistics['coveredConditionals'] + ); + + $metrics->setAttribute( + 'statements', $fileStatistics['statements'] + ); + + $metrics->setAttribute( + 'coveredstatements', $fileStatistics['coveredStatements'] + ); + + $metrics->setAttribute( + 'elements', + $fileStatistics['conditionals'] + + $fileStatistics['statements'] + + $fileStatistics['methods'] + ); + + $metrics->setAttribute( + 'coveredelements', + $fileStatistics['coveredConditionals'] + + $fileStatistics['coveredStatements'] + + $fileStatistics['coveredMethods'] + ); + + $file->appendChild($metrics); + + if ($namespace == 'global') { + $project->appendChild($file); + } else { + if (!isset($packages[$namespace])) { + $packages[$namespace] = $document->createElement( + 'package' + ); + + $packages[$namespace]->setAttribute('name', $namespace); + $project->appendChild($packages[$namespace]); + } + + $packages[$namespace]->appendChild($file); + } + + $projectStatistics['loc'] += $linesOfCode['loc']; + $projectStatistics['ncloc'] += $linesOfCode['ncloc']; + $projectStatistics['classes'] += $fileStatistics['classes']; + $projectStatistics['methods'] += $fileStatistics['methods']; + $projectStatistics['coveredMethods'] += $fileStatistics['coveredMethods']; + $projectStatistics['conditionals'] += $fileStatistics['conditionals']; + $projectStatistics['coveredConditionals'] += $fileStatistics['coveredConditionals']; + $projectStatistics['statements'] += $fileStatistics['statements']; + $projectStatistics['coveredStatements'] += $fileStatistics['coveredStatements']; + $projectStatistics['files']++; + } + } + + $metrics = $document->createElement('metrics'); + + $metrics->setAttribute('files', $projectStatistics['files']); + $metrics->setAttribute('loc', $projectStatistics['loc']); + $metrics->setAttribute('ncloc', $projectStatistics['ncloc']); + $metrics->setAttribute('classes', $projectStatistics['classes']); + $metrics->setAttribute('methods', $projectStatistics['methods']); + + $metrics->setAttribute( + 'coveredmethods', $projectStatistics['coveredMethods'] + ); + + $metrics->setAttribute( + 'conditionals', $projectStatistics['conditionals'] + ); + + $metrics->setAttribute( + 'coveredconditionals', $projectStatistics['coveredConditionals'] + ); + + $metrics->setAttribute( + 'statements', $projectStatistics['statements'] + ); + + $metrics->setAttribute( + 'coveredstatements', $projectStatistics['coveredStatements'] + ); + + $metrics->setAttribute( + 'elements', + $projectStatistics['conditionals'] + + $projectStatistics['statements'] + + $projectStatistics['methods'] + ); + + $metrics->setAttribute( + 'coveredelements', + $projectStatistics['coveredConditionals'] + + $projectStatistics['coveredStatements'] + + $projectStatistics['coveredMethods'] + ); + + $project->appendChild($metrics); + + if ($target !== NULL) { + if (!is_dir(dirname($target))) { + mkdir(dirname($target), 0777, TRUE); + } + + return $document->save($target); + } else { + return $document->saveXML(); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML.php b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML.php new file mode 100644 index 0000000..4313375 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML.php @@ -0,0 +1,419 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since File available since Release 1.0.0 + */ + +require_once 'PHP/CodeCoverage.php'; +require_once 'PHP/CodeCoverage/Report/HTML/Node.php'; +require_once 'Text/Template.php'; + +/** + * Generates an HTML report from an PHP_CodeCoverage object. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.4 + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since Class available since Release 1.0.0 + */ +class PHP_CodeCoverage_Report_HTML +{ + /** + * @var string + */ + public static $templatePath; + + /** + * @var array + */ + protected $options; + + /** + * Constructor. + * + * @param array $options + */ + public function __construct(array $options = array()) + { + if (!isset($options['title'])) { + $options['title'] = ''; + } + + if (!isset($options['charset'])) { + $options['charset'] = 'UTF-8'; + } + + if (!isset($options['yui'])) { + $options['yui'] = TRUE; + } + + if (!isset($options['highlight'])) { + $options['highlight'] = FALSE; + } + + if (!isset($options['lowUpperBound'])) { + $options['lowUpperBound'] = 35; + } + + if (!isset($options['highLowerBound'])) { + $options['highLowerBound'] = 70; + } + + if (!isset($options['generator'])) { + $options['generator'] = ''; + } + + $this->options = $options; + + self::$templatePath = sprintf( + '%s%sHTML%sTemplate%s', + + dirname(__FILE__), + DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR + ); + } + + /** + * @param PHP_CodeCoverage $coverage + * @param string $target + */ + public function process(PHP_CodeCoverage $coverage, $target) + { + $target = PHP_CodeCoverage_Util::getDirectory($target); + $files = $coverage->getSummary(); + $commonPath = PHP_CodeCoverage_Util::reducePaths($files); + $items = PHP_CodeCoverage_Util::buildDirectoryStructure($files); + $root = new PHP_CodeCoverage_Report_HTML_Node_Directory( + $commonPath, NULL + ); + + $this->addItems($root, $items); + + $this->renderDashboard( + $root, $target . 'index.dashboard.html', $this->options['title'] + ); + + foreach ($root as $node) { + if ($node instanceof PHP_CodeCoverage_Report_HTML_Node_Directory) { + $this->renderDashboard( + $node, + $target . PHP_CodeCoverage_Util::getSafeFilename( + $node->getId() + ) . '.dashboard.html', + $node->getName(TRUE) + ); + } + } + + $root->render( + $target, + $this->options['title'], + $this->options['charset'], + $this->options['lowUpperBound'], + $this->options['highLowerBound'], + $this->options['generator'] + ); + + $this->copyFiles($target); + } + + /** + * @param PHP_CodeCoverage_Report_HTML_Node_Directory $root + * @param string $file + * @param string $title + */ + protected function renderDashboard(PHP_CodeCoverage_Report_HTML_Node_Directory $root, $file, $title) + { + $classes = $this->classes($root); + $template = new Text_Template( + PHP_CodeCoverage_Report_HTML::$templatePath . 'dashboard.html' + ); + + $template->setVar( + array( + 'title' => $title, + 'charset' => $this->options['charset'], + 'date' => date( + 'D M j G:i:s T Y', + $_SERVER['REQUEST_TIME'] + ), + 'version' => '1.0.4', + 'php_version' => PHP_VERSION, + 'generator' => $this->options['generator'], + 'least_tested_methods' => $this->leastTestedMethods($classes), + 'top_project_risks' => $this->topProjectRisks($classes), + 'cc_values' => $this->classComplexity($classes), + 'ccd_values' => $this->classCoverageDistribution($classes), + 'backlink' => basename(str_replace('.dashboard', '', $file)) + ) + ); + + $template->renderTo($file); + } + + /** + * @param PHP_CodeCoverage_Report_HTML_Node_Directory $root + * @param array $items + */ + protected function addItems(PHP_CodeCoverage_Report_HTML_Node_Directory $root, array $items) + { + foreach ($items as $key => $value) { + if (substr($key, -2) == '/f') { + try { + $root->addFile( + substr($key, 0, -2), + $value, + $this->options['yui'], + $this->options['highlight'] + ); + } + + catch (RuntimeException $e) { + continue; + } + } else { + $child = $root->addDirectory($key); + $this->addItems($child, $value); + } + } + } + + /** + * Returns the classes. + * + * @param PHP_CodeCoverage_Report_HTML_Node_Directory $root + * @return array + */ + protected function classes(PHP_CodeCoverage_Report_HTML_Node_Directory $root) + { + $classes = array(); + + foreach ($root as $node) { + if ($node instanceof PHP_CodeCoverage_Report_HTML_Node_File) { + $classes = array_merge($classes, $node->getClasses()); + } + } + + if (isset($classes['*'])) { + unset($classes['*']); + } + + return $classes; + } + + /** + * Returns the data for the Class Complexity chart. + * + * @param array $classes + * @return string + */ + protected function classComplexity(array $classes) + { + $data = array(); + + foreach ($classes as $name => $class) { + $data[] = array($class['coverage'], $class['ccn'], 'blue', $name); + } + + return json_encode($data); + } + + /** + * Returns the data for the Class Coverage Distribution chart. + * + * @param array $classes + * @return string + */ + protected function classCoverageDistribution(array $classes) + { + $data = array( + '0%' => 0, + '0-10%' => 0, + '10-20%' => 0, + '20-30%' => 0, + '30-40%' => 0, + '40-50%' => 0, + '50-60%' => 0, + '60-70%' => 0, + '70-80%' => 0, + '80-90%' => 0, + '90-100%' => 0, + '100%' => 0 + ); + + foreach ($classes as $class) { + if ($class['coverage'] == 0) { + $data['0%']++; + } + + else if ($class['coverage'] == 100) { + $data['100%']++; + } + + else { + $key = floor($class['coverage']/10)*10; + $key = $key . '-' . ($key + 10) . '%'; + $data[$key]++; + } + } + + return json_encode(array_values($data)); + } + + /** + * @param string $target + */ + protected function copyFiles($target) + { + $files = array( + 'butter.png', + 'chameleon.png', + 'close12_1.gif', + 'container.css', + 'container-min.js', + 'directory.png', + 'excanvas.compressed.js', + 'file.png', + 'glass.png', + 'RGraph.bar.js', + 'RGraph.common.core.js', + 'RGraph.common.tooltips.js', + 'RGraph.scatter.js', + 'scarlet_red.png', + 'snow.png', + 'style.css', + 'yahoo-dom-event.js' + ); + + foreach ($files as $file) { + copy(self::$templatePath . $file, $target . $file); + } + } + + /** + * Returns the least tested methods. + * + * @param array $classes + * @param integer $max + * @return string + */ + protected function leastTestedMethods(array $classes, $max = 10) + { + $methods = array(); + + foreach ($classes as $className => $class) { + foreach ($class['methods'] as $methodName => $method) { + if ($method['coverage'] < 100) { + if ($className != '*') { + $key = $className . '::' . $methodName; + } else { + $key = $methodName; + } + + $methods[$key] = $method['coverage']; + } + } + } + + asort($methods); + + $methods = array_slice($methods, 0, min($max, count($methods))); + $buffer = ''; + + foreach ($methods as $name => $coverage) { + list($class, $method) = explode('::', $name); + + $buffer .= sprintf( + '
  • %s (%d%%)
  • ' . "\n", + $classes[$class]['methods'][$method]['file'], + $name, + $coverage + ); + } + + return $buffer; + } + + /** + * Returns the top project risks according to the CRAP index. + * + * @param array $classes + * @param integer $max + * @return string + */ + protected function topProjectRisks(array $classes, $max = 10) + { + $risks = array(); + + foreach ($classes as $className => $class) { + if ($class['coverage'] < 100 && + $class['ccn'] > count($class['methods'])) { + $risks[$className] = $class['crap']; + } + } + + asort($risks); + + $risks = array_reverse( + array_slice($risks, 0, min($max, count($risks))) + ); + + $buffer = ''; + + foreach ($risks as $name => $crap) { + $buffer .= sprintf( + '
  • %s (%d)
  • ' . "\n", + $classes[$name]['file'], + $name, + $crap + ); + } + + return $buffer; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node.php b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node.php new file mode 100644 index 0000000..d7d0e45 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node.php @@ -0,0 +1,512 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since File available since Release 1.0.0 + */ + +/** + * Base class for nodes in the code coverage information tree. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.4 + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since Class available since Release 1.0.0 + */ +abstract class PHP_CodeCoverage_Report_HTML_Node +{ + /** + * @var array + */ + protected $cache = array(); + + /** + * @var string + */ + protected $name; + + /** + * @var PHP_CodeCoverage_Report_HTML_Node + */ + protected $parent; + + /** + * Constructor. + * + * @param string $name + * @param PHP_CodeCoverage_Report_HTML_Node $parent + */ + public function __construct($name, PHP_CodeCoverage_Report_HTML_Node $parent = NULL) + { + $this->name = $name; + $this->parent = $parent; + } + + /** + * Returns the percentage of classes that has been tested. + * + * @return integer + */ + public function getTestedClassesPercent() + { + return PHP_CodeCoverage_Util::percent( + $this->getNumTestedClasses(), + $this->getNumClasses(), + TRUE + ); + } + + /** + * Returns the percentage of methods that has been tested. + * + * @return integer + */ + public function getTestedMethodsPercent() + { + return PHP_CodeCoverage_Util::percent( + $this->getNumTestedMethods(), + $this->getNumMethods(), + TRUE + ); + } + + /** + * Returns the percentage of executed lines. + * + * @return integer + */ + public function getLineExecutedPercent() + { + return PHP_CodeCoverage_Util::percent( + $this->getNumExecutedLines(), + $this->getNumExecutableLines(), + TRUE + ); + } + + /** + * Returns this node's ID. + * + * @return string + */ + public function getId() + { + if (!isset($this->cache['id'])) { + if ($this->parent === NULL) { + $this->cache['id'] = 'index'; + } else { + $parentId = $this->parent->getId(); + + if ($parentId == 'index') { + $this->cache['id'] = $this->getName(); + } else { + $this->cache['id'] = $parentId . '_' . $this->getName(); + } + } + } + + return $this->cache['id']; + } + + /** + * Returns this node's name. + * + * @param boolean $includeParent + * @return string + */ + public function getName($includeParent = FALSE, $includeCommonPath = FALSE) + { + if ($includeParent && $this->parent !== NULL) { + if (!isset($this->cache['nameIncludingParent'])) { + $parent = $this->parent->getName(TRUE); + + if (!empty($parent)) { + $this->cache['nameIncludingParent'] = $parent . '/' . + $this->name; + } else { + $this->cache['nameIncludingParent'] = $this->name; + } + } + + return $this->cache['nameIncludingParent']; + } else { + if ($this->parent !== NULL) { + return $this->name; + } else { + return $includeCommonPath ? $this->name : ''; + } + } + } + + /** + * Returns the link to this node. + * + * @param boolean $full + * @return string + */ + public function getLink($full) + { + if (substr($this->name, -1) == DIRECTORY_SEPARATOR) { + $name = substr($this->name, 0, -1); + } else { + $name = $this->name; + } + + $cleanId = PHP_CodeCoverage_Util::getSafeFilename($this->getId()); + + if ($full) { + if ($this->parent !== NULL) { + $parent = $this->parent->getLink(TRUE) . DIRECTORY_SEPARATOR; + } else { + $parent = ''; + } + + return sprintf( + '%s%s', + $parent, + $cleanId, + $name + ); + } else { + return sprintf( + '%s', + $cleanId, + $name + ); + } + } + + /** + * Returns this node's path. + * + * @return string + */ + public function getPath() + { + if (!isset($this->cache['path'])) { + if ($this->parent === NULL) { + $this->cache['path'] = $this->getName(FALSE, TRUE); + } else { + $parentPath = $this->parent->getPath(); + + if (substr($parentPath, -1) == DIRECTORY_SEPARATOR) { + $this->cache['path'] = $parentPath . + $this->getName(FALSE, TRUE); + } else { + $this->cache['path'] = $parentPath . + DIRECTORY_SEPARATOR . + $this->getName(FALSE, TRUE); + + if ($parentPath === '' && + realpath($this->cache['path']) === FALSE && + realpath($this->getName(FALSE, TRUE)) !== FALSE) { + $this->cache['path'] = $this->getName(FALSE, TRUE); + } + } + } + } + + return $this->cache['path']; + } + + protected function doRenderItemObject(PHP_CodeCoverage_Report_HTML_Node $item, $lowUpperBound, $highLowerBound, $link = NULL, $itemClass = 'coverItem') + { + return $this->doRenderItem( + array( + 'name' => $link != NULL ? $link : $item->getLink( + FALSE + ), + 'itemClass' => $itemClass, + 'numClasses' => $item->getNumClasses(), + 'numTestedClasses' => $item->getNumTestedClasses(), + 'testedClassesPercent' => $item->getTestedClassesPercent(), + 'numMethods' => $item->getNumMethods(), + 'numTestedMethods' => $item->getNumTestedMethods(), + 'testedMethodsPercent' => $item->getTestedMethodsPercent(), + 'numExecutableLines' => $item->getNumExecutableLines(), + 'numExecutedLines' => $item->getNumExecutedLines(), + 'executedLinesPercent' => $item->getLineExecutedPercent(), + 'crap' => $link == 'Total' ? 'CRAP' : '' + ), + $lowUpperBound, + $highLowerBound + ); + } + + protected function doRenderItem(array $data, $lowUpperBound, $highLowerBound, $template = NULL) + { + if ($template === NULL) { + if ($this instanceof PHP_CodeCoverage_Report_HTML_Node_Directory) { + $template = 'directory_item.html'; + } else { + $template = 'file_item.html'; + } + } + + $itemTemplate = new Text_Template( + PHP_CodeCoverage_Report_HTML::$templatePath . $template + ); + + if ($data['numClasses'] > 0) { + list($classesColor, $classesLevel) = $this->getColorLevel( + $data['testedClassesPercent'], $lowUpperBound, $highLowerBound + ); + + $classesNumber = $data['numTestedClasses'] . ' / ' . + $data['numClasses']; + } else { + $classesColor = 'snow'; + $classesLevel = 'None'; + $classesNumber = ' '; + } + + if ($data['numMethods'] > 0) { + list($methodsColor, $methodsLevel) = $this->getColorLevel( + $data['testedMethodsPercent'], $lowUpperBound, $highLowerBound + ); + + $methodsNumber = $data['numTestedMethods'] . ' / ' . + $data['numMethods']; + } else { + $methodsColor = 'snow'; + $methodsLevel = 'None'; + $methodsNumber = ' '; + } + + list($linesColor, $linesLevel) = $this->getColorLevel( + $data['executedLinesPercent'], $lowUpperBound, $highLowerBound + ); + + if ($data['name'] == '*') { + $functions = TRUE; + } else { + $functions = FALSE; + } + + $icon = ''; + + if (isset($data['itemClass'])) { + if ($data['itemClass'] == 'coverDirectory') { + $icon = 'directory '; + } + + else if ($data['itemClass'] == 'coverFile') { + $icon = 'file '; + } + } + + $itemTemplate->setVar( + array( + 'name' => $functions ? 'Functions' : $data['name'], + 'icon' => $icon, + 'itemClass' => isset($data['itemClass']) ? $data['itemClass'] : 'coverItem', + 'classes_color' => $classesColor, + 'classes_level' => $functions ? 'None' : $classesLevel, + 'classes_tested_width' => floor($data['testedClassesPercent']), + 'classes_tested_percent' => !$functions && $data['numClasses'] > 0 ? $data['testedClassesPercent'] . '%' : ' ', + 'classes_not_tested_width' => 100 - floor($data['testedClassesPercent']), + 'classes_number' => $functions ? ' ' : $classesNumber, + 'methods_color' => $methodsColor, + 'methods_level' => $methodsLevel, + 'methods_tested_width' => floor($data['testedMethodsPercent']), + 'methods_tested_percent' => $data['numMethods'] > 0 ? $data['testedMethodsPercent'] . '%' : ' ', + 'methods_not_tested_width' => 100 - floor($data['testedMethodsPercent']), + 'methods_number' => $methodsNumber, + 'lines_color' => $linesColor, + 'lines_level' => $linesLevel, + 'lines_executed_width' => floor($data['executedLinesPercent']), + 'lines_executed_percent' => $data['executedLinesPercent'] . '%', + 'lines_not_executed_width' => 100 - floor($data['executedLinesPercent']), + 'num_executable_lines' => $data['numExecutableLines'], + 'num_executed_lines' => $data['numExecutedLines'], + 'crap' => isset($data['crap']) ? $data['crap'] : '' + ) + ); + + return $itemTemplate->render(); + } + + protected function getColorLevel($percent, $lowUpperBound, $highLowerBound) + { + $floorPercent = floor($percent); + + if ($floorPercent < $lowUpperBound) { + $color = 'scarlet_red'; + $level = 'Lo'; + } + + else if ($floorPercent >= $lowUpperBound && + $floorPercent < $highLowerBound) { + $color = 'butter'; + $level = 'Med'; + } + + else { + $color = 'chameleon'; + $level = 'Hi'; + } + + return array($color, $level); + } + + protected function renderTotalItem($lowUpperBound, $highLowerBound, $directory = TRUE) + { + if ($directory && + empty($this->directories) && + count($this->files) == 1) { + return ''; + } + + return $this->doRenderItemObject( + $this, $lowUpperBound, $highLowerBound, 'Total' + ) . + " \n" . + '  ' . + "\n \n"; + } + + /** + * @param Text_Template $template + * @param string $title + * @param string $charset + * @param string $generator + */ + protected function setTemplateVars(Text_Template $template, $title, $charset, $generator) + { + $dashboard = ''; + + if ($this instanceof PHP_CodeCoverage_Report_HTML_Node_Directory) { + $dashboard = sprintf( + 'dashboard', + PHP_CodeCoverage_Util::getSafeFilename( + $this->getId() + ) . '.dashboard.html' + ); + } + + $template->setVar( + array( + 'title' => $title, + 'charset' => $charset, + 'link' => $this->getLink(TRUE), + 'dashboard_link' => $dashboard, + 'num_executable_lines' => $this->getNumExecutableLines(), + 'num_executed_lines' => $this->getNumExecutedLines(), + 'lines_executed_percent' => $this->getLineExecutedPercent(), + 'date' => date( + 'D M j G:i:s T Y', + $_SERVER['REQUEST_TIME'] + ), + 'version' => '1.0.4', + 'php_version' => PHP_VERSION, + 'generator' => $generator + ) + ); + } + + /** + * Returns the classes of this node. + * + * @return array + */ + abstract public function getClasses(); + + /** + * Returns the number of executable lines. + * + * @return integer + */ + abstract public function getNumExecutableLines(); + + /** + * Returns the number of executed lines. + * + * @return integer + */ + abstract public function getNumExecutedLines(); + + /** + * Returns the number of classes. + * + * @return integer + */ + abstract public function getNumClasses(); + + /** + * Returns the number of tested classes. + * + * @return integer + */ + abstract public function getNumTestedClasses(); + + /** + * Returns the number of methods. + * + * @return integer + */ + abstract public function getNumMethods(); + + /** + * Returns the number of tested methods. + * + * @return integer + */ + abstract public function getNumTestedMethods(); + + /** + * Renders this node. + * + * @param string $target + * @param string $title + * @param string $charset + * @param integer $lowUpperBound + * @param integer $highLowerBound + * @param string $generator + */ + abstract public function render($target, $title, $charset = 'UTF-8', $lowUpperBound = 35, $highLowerBound = 70, $generator = ''); +} + +require_once 'PHP/CodeCoverage/Report/HTML/Node/Directory.php'; +require_once 'PHP/CodeCoverage/Report/HTML/Node/File.php'; diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node/Directory.php b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node/Directory.php new file mode 100644 index 0000000..a9af0ff --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node/Directory.php @@ -0,0 +1,430 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since File available since Release 1.0.0 + */ + +require_once 'PHP/CodeCoverage/Report/HTML/Node/Iterator.php'; + +/** + * Represents a directory in the code coverage information tree. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.4 + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since Class available since Release 1.0.0 + */ +class PHP_CodeCoverage_Report_HTML_Node_Directory extends PHP_CodeCoverage_Report_HTML_Node implements IteratorAggregate +{ + /** + * @var PHP_CodeCoverage_Report_HTML_Node[] + */ + protected $children = array(); + + /** + * @var PHP_CodeCoverage_Report_HTML_Node_Directory[] + */ + protected $directories = array(); + + /** + * @var PHP_CodeCoverage_Report_HTML_Node_File[] + */ + protected $files = array(); + + /** + * @var array + */ + protected $classes; + + /** + * @var integer + */ + protected $numExecutableLines = -1; + + /** + * @var integer + */ + protected $numExecutedLines = -1; + + /** + * @var integer + */ + protected $numClasses = -1; + + /** + * @var integer + */ + protected $numTestedClasses = -1; + + /** + * @var integer + */ + protected $numMethods = -1; + + /** + * @var integer + */ + protected $numTestedMethods = -1; + + /** + * Returns an iterator for this node. + * + * @return RecursiveIteratorIterator + */ + public function getIterator() + { + return new RecursiveIteratorIterator( + new PHP_CodeCoverage_Report_HTML_Node_Iterator($this), + RecursiveIteratorIterator::SELF_FIRST + ); + } + + /** + * Adds a new directory. + * + * @return PHP_CodeCoverage_Report_HTML_Node_Directory + */ + public function addDirectory($name) + { + $directory = new PHP_CodeCoverage_Report_HTML_Node_Directory( + $name, $this + ); + + $this->children[] = $directory; + $this->directories[] = &$this->children[count($this->children) - 1]; + + return $directory; + } + + /** + * Adds a new file. + * + * @param string $name + * @param array $lines + * @param boolean $yui + * @param boolean $highlight + * @return PHP_CodeCoverage_Report_HTML_Node_File + * @throws RuntimeException + */ + public function addFile($name, array $lines, $yui, $highlight) + { + $file = new PHP_CodeCoverage_Report_HTML_Node_File( + $name, $this, $lines, $yui, $highlight + ); + + $this->children[] = $file; + $this->files[] = &$this->children[count($this->children) - 1]; + + $this->numExecutableLines = -1; + $this->numExecutedLines = -1; + + return $file; + } + + /** + * Returns the directories in this directory. + * + * @return array + */ + public function getDirectories() + { + return $this->directories; + } + + /** + * Returns the files in this directory. + * + * @return array + */ + public function getFiles() + { + return $this->files; + } + + /** + * Returns the child nodes of this node. + * + * @return array + */ + public function getChildNodes() + { + return $this->children; + } + + /** + * Returns the classes of this node. + * + * @return array + */ + public function getClasses() + { + if ($this->classes === NULL) { + $this->classes = array(); + + foreach ($this->children as $child) { + $this->classes = array_merge( + $this->classes, $child->getClasses() + ); + } + } + + return $this->classes; + } + + /** + * Returns the number of executable lines. + * + * @return integer + */ + public function getNumExecutableLines() + { + if ($this->numExecutableLines == -1) { + $this->numExecutableLines = 0; + + foreach ($this->children as $child) { + $this->numExecutableLines += $child->getNumExecutableLines(); + } + } + + return $this->numExecutableLines; + } + + /** + * Returns the number of executed lines. + * + * @return integer + */ + public function getNumExecutedLines() + { + if ($this->numExecutedLines == -1) { + $this->numExecutedLines = 0; + + foreach ($this->children as $child) { + $this->numExecutedLines += $child->getNumExecutedLines(); + } + } + + return $this->numExecutedLines; + } + + /** + * Returns the number of classes. + * + * @return integer + */ + public function getNumClasses() + { + if ($this->numClasses == -1) { + $this->numClasses = 0; + + foreach ($this->children as $child) { + $this->numClasses += $child->getNumClasses(); + } + } + + return $this->numClasses; + } + + /** + * Returns the number of tested classes. + * + * @return integer + */ + public function getNumTestedClasses() + { + if ($this->numTestedClasses == -1) { + $this->numTestedClasses = 0; + + foreach ($this->children as $child) { + $this->numTestedClasses += $child->getNumTestedClasses(); + } + } + + return $this->numTestedClasses; + } + + /** + * Returns the number of methods. + * + * @return integer + */ + public function getNumMethods() + { + if ($this->numMethods == -1) { + $this->numMethods = 0; + + foreach ($this->children as $child) { + $this->numMethods += $child->getNumMethods(); + } + } + + return $this->numMethods; + } + + /** + * Returns the number of tested methods. + * + * @return integer + */ + public function getNumTestedMethods() + { + if ($this->numTestedMethods == -1) { + $this->numTestedMethods = 0; + + foreach ($this->children as $child) { + $this->numTestedMethods += $child->getNumTestedMethods(); + } + } + + return $this->numTestedMethods; + } + + /** + * Renders this node. + * + * @param string $target + * @param string $title + * @param string $charset + * @param integer $lowUpperBound + * @param integer $highLowerBound + * @param string $generator + */ + public function render($target, $title, $charset = 'UTF-8', $lowUpperBound = 35, $highLowerBound = 70, $generator = '') + { + $this->doRender( + $target, $title, $charset, $lowUpperBound, $highLowerBound, $generator + ); + + foreach ($this->children as $child) { + $child->render( + $target, + $title, + $charset, + $lowUpperBound, + $highLowerBound, + $generator + ); + } + + $this->children = array(); + } + + /** + * @param string $target + * @param string $title + * @param string $charset + * @param integer $lowUpperBound + * @param integer $highLowerBound + * @param string $generator + */ + protected function doRender($target, $title, $charset, $lowUpperBound, $highLowerBound, $generator) + { + $cleanId = PHP_CodeCoverage_Util::getSafeFilename($this->getId()); + $file = $target . $cleanId . '.html'; + + $template = new Text_Template( + PHP_CodeCoverage_Report_HTML::$templatePath . 'directory.html' + ); + + $this->setTemplateVars($template, $title, $charset, $generator); + + $template->setVar( + array( + 'total_item' => $this->renderTotalItem( + $lowUpperBound, $highLowerBound + ), + 'items' => $this->renderItems( + $lowUpperBound, $highLowerBound + ), + 'low_upper_bound' => $lowUpperBound, + 'high_lower_bound' => $highLowerBound + ) + ); + + $template->renderTo($file); + + $this->directories = array(); + $this->files = array(); + } + + /** + * @param float $lowUpperBound + * @param float $highLowerBound + * @return string + */ + protected function renderItems($lowUpperBound, $highLowerBound) + { + $items = $this->doRenderItems( + $this->directories, $lowUpperBound, $highLowerBound, 'coverDirectory' + ); + + $items .= $this->doRenderItems( + $this->files, $lowUpperBound, $highLowerBound, 'coverFile' + ); + + return $items; + } + + /** + * @param array $items + * @param float $lowUpperBound + * @param float $highLowerBound + * @param string $itemClass + * @return string + */ + protected function doRenderItems(array $items, $lowUpperBound, $highLowerBound, $itemClass) + { + $result = ''; + + foreach ($items as $item) { + $result .= $this->doRenderItemObject( + $item, $lowUpperBound, $highLowerBound, NULL, $itemClass + ); + } + + return $result; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node/File.php b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node/File.php new file mode 100644 index 0000000..b1ea11d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node/File.php @@ -0,0 +1,916 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since File available since Release 1.0.0 + */ + +if (!defined('T_NAMESPACE')) { + define('T_NAMESPACE', 377); +} + +require_once 'PHP/Token/Stream/CachingFactory.php'; + +/** + * Represents a file in the code coverage information tree. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.4 + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since Class available since Release 1.0.0 + */ +class PHP_CodeCoverage_Report_HTML_Node_File extends PHP_CodeCoverage_Report_HTML_Node +{ + /** + * @var array + */ + protected $codeLines; + + /** + * @var array + */ + protected $codeLinesFillup = array(); + + /** + * @var array + */ + protected $executedLines; + + /** + * @var boolean + */ + protected $yui = TRUE; + + /** + * @var boolean + */ + protected $highlight = FALSE; + + /** + * @var integer + */ + protected $numExecutableLines = 0; + + /** + * @var integer + */ + protected $numExecutedLines = 0; + + /** + * @var array + */ + protected $classes = array(); + + /** + * @var integer + */ + protected $numTestedClasses = 0; + + /** + * @var integer + */ + protected $numClasses = NULL; + + /** + * @var integer + */ + protected $numMethods = NULL; + + /** + * @var integer + */ + protected $numTestedMethods = NULL; + + /** + * @var string + */ + protected $yuiPanelJS = ''; + + /** + * @var array + */ + protected $startLines = array(); + + /** + * @var array + */ + protected $endLines = array(); + + /** + * Constructor. + * + * @param string $name + * @param PHP_CodeCoverage_Report_HTML_Node $parent + * @param array $executedLines + * @param boolean $yui + * @param boolean $highlight + * @throws RuntimeException + */ + public function __construct($name, PHP_CodeCoverage_Report_HTML_Node $parent, array $executedLines, $yui = TRUE, $highlight = FALSE) + { + parent::__construct($name, $parent); + + $path = $this->getPath(); + + if (!file_exists($path)) { + throw new RuntimeException( + sprintf('Path "%s" does not exist.', $path) + ); + } + + $this->executedLines = $executedLines; + $this->highlight = $highlight; + $this->yui = $yui; + $this->codeLines = $this->loadFile($path); + $this->ignoredLines = PHP_CodeCoverage_Util::getLinesToBeIgnored( + $path + ); + + $this->calculateStatistics(); + } + + /** + * Returns the classes of this node. + * + * @return array + */ + public function getClasses() + { + return $this->classes; + } + + /** + * Returns the number of executable lines. + * + * @return integer + */ + public function getNumExecutableLines() + { + return $this->numExecutableLines; + } + + /** + * Returns the number of executed lines. + * + * @return integer + */ + public function getNumExecutedLines() + { + return $this->numExecutedLines; + } + + /** + * Returns the number of classes. + * + * @return integer + */ + public function getNumClasses() + { + if ($this->numClasses === NULL) { + $this->numClasses = count($this->classes); + + if (isset($this->classes['*'])) { + $this->numClasses--; + } + } + + return $this->numClasses; + } + + /** + * Returns the number of tested classes. + * + * @return integer + */ + public function getNumTestedClasses() + { + return $this->numTestedClasses; + } + + /** + * Returns the number of methods. + * + * @return integer + */ + public function getNumMethods() + { + if ($this->numMethods === NULL) { + $this->numMethods = 0; + + foreach ($this->classes as $class) { + foreach ($class['methods'] as $method) { + if ($method['executableLines'] > 0) { + $this->numMethods++; + } + } + } + } + + return $this->numMethods; + } + + /** + * Returns the number of tested methods. + * + * @return integer + */ + public function getNumTestedMethods() + { + if ($this->numTestedMethods === NULL) { + $this->numTestedMethods = 0; + + foreach ($this->classes as $class) { + foreach ($class['methods'] as $method) { + if ($method['executableLines'] > 0 && + $method['coverage'] == 100) { + $this->numTestedMethods++; + } + } + } + } + + return $this->numTestedMethods; + } + + /** + * Renders this node. + * + * @param string $target + * @param string $title + * @param string $charset + * @param integer $lowUpperBound + * @param integer $highLowerBound + * @param string $generator + */ + public function render($target, $title, $charset = 'UTF-8', $lowUpperBound = 35, $highLowerBound = 70, $generator = '') + { + if ($this->yui) { + $template = new Text_Template( + PHP_CodeCoverage_Report_HTML::$templatePath . 'file.html' + ); + + $yuiTemplate = new Text_Template( + PHP_CodeCoverage_Report_HTML::$templatePath . 'yui_item.js' + ); + } else { + $template = new Text_Template( + PHP_CodeCoverage_Report_HTML::$templatePath . 'file_no_yui.html' + ); + } + + $i = 1; + $lines = ''; + + foreach ($this->codeLines as $line) { + $css = ''; + + if (!isset($this->ignoredLines[$i]) && + isset($this->executedLines[$i])) { + $count = ''; + + // Array: Line is executable and was executed. + // count(Array) = Number of tests that hit this line. + if (is_array($this->executedLines[$i])) { + $color = 'lineCov'; + $numTests = count($this->executedLines[$i]); + $count = sprintf('%8d', $numTests); + + if ($this->yui) { + $buffer = ''; + $testCSS = ''; + + foreach ($this->executedLines[$i] as $test) { + switch ($test['status']) { + case 0: { + $testCSS = ' class=\"testPassed\"'; + } + break; + + case 1: + case 2: { + $testCSS = ' class=\"testIncomplete\"'; + } + break; + + case 3: { + $testCSS = ' class=\"testFailure\"'; + } + break; + + case 4: { + $testCSS = ' class=\"testError\"'; + } + break; + + default: { + $testCSS = ''; + } + } + + $buffer .= sprintf( + '%s', + + $testCSS, + addslashes(htmlspecialchars($test['id'])) + ); + } + + if ($numTests > 1) { + $header = $numTests . ' tests cover'; + } else { + $header = '1 test covers'; + } + + $header .= ' line ' . $i; + + $yuiTemplate->setVar( + array( + 'line' => $i, + 'header' => $header, + 'tests' => $buffer + ), + FALSE + ); + + $this->yuiPanelJS .= $yuiTemplate->render(); + } + } + + // -1: Line is executable and was not executed. + else if ($this->executedLines[$i] == -1) { + $color = 'lineNoCov'; + $count = sprintf('%8d', 0); + } + + // -2: Line is dead code. + else { + $color = 'lineDeadCode'; + $count = ' '; + } + + $css = sprintf( + ' %s : ', + + $color, + $count + ); + } + + $fillup = array_shift($this->codeLinesFillup); + + if ($fillup > 0) { + $line .= str_repeat(' ', $fillup); + } + + $lines .= sprintf( + ''. + '%8d %s%s%s' . "\n", + + $i, + $i, + $i, + $i, + $i, + !empty($css) ? $css : ' : ', + !$this->highlight ? htmlspecialchars($line) : $line, + !empty($css) ? '' : '' + ); + + $i++; + } + + $items = ''; + + foreach ($this->classes as $className => $classData) { + if ($classData['executedLines'] == $classData['executableLines']) { + $numTestedClasses = 1; + $testedClassesPercent = 100; + } else { + $numTestedClasses = 0; + $testedClassesPercent = 0; + } + + $numMethods = 0; + $numTestedMethods = 0; + + foreach ($classData['methods'] as $method) { + if ($method['executableLines'] > 0) { + $numMethods++; + + if ($method['executedLines'] == $method['executableLines']) { + $numTestedMethods++; + } + } + } + + $items .= $this->doRenderItem( + array( + 'name' => sprintf( + '%s', + + $classData['startLine'], + $className + ), + 'numClasses' => 1, + 'numTestedClasses' => $numTestedClasses, + 'testedClassesPercent' => sprintf( + '%01.2f', $testedClassesPercent + ), + 'numMethods' => $numMethods, + 'numTestedMethods' => $numTestedMethods, + 'testedMethodsPercent' => PHP_CodeCoverage_Util::percent( + $numTestedMethods, $numMethods, TRUE + ), + 'numExecutableLines' => $classData['executableLines'], + 'numExecutedLines' => $classData['executedLines'], + 'executedLinesPercent' => PHP_CodeCoverage_Util::percent( + $classData['executedLines'], + $classData['executableLines'], + TRUE + ) + ), + $lowUpperBound, + $highLowerBound + ); + + foreach ($classData['methods'] as $methodData) { + if ($methodData['executableLines'] > 0) { + if ($methodData['executedLines'] == $methodData['executableLines']) { + $numTestedMethods = 1; + $testedMethodsPercent = 100; + } else { + $numTestedMethods = 0; + $testedMethodsPercent = 0; + } + + $items .= $this->doRenderItem( + array( + 'name' => sprintf( + ' %s', + + $methodData['startLine'], + htmlspecialchars($methodData['signature']) + ), + 'numClasses' => '', + 'numTestedClasses' => '', + 'testedClassesPercent' => '', + 'numMethods' => 1, + 'numTestedMethods' => $numTestedMethods, + 'testedMethodsPercent' => sprintf( + '%01.2f', $testedMethodsPercent + ), + 'numExecutableLines' => $methodData['executableLines'], + 'numExecutedLines' => $methodData['executedLines'], + 'executedLinesPercent' => PHP_CodeCoverage_Util::percent( + $methodData['executedLines'], + $methodData['executableLines'], + TRUE + ), + 'crap' => PHP_CodeCoverage_Util::crap( + $methodData['ccn'], + PHP_CodeCoverage_Util::percent( + $methodData['executedLines'], + $methodData['executableLines'] + ) + ) + ), + $lowUpperBound, + $highLowerBound, + 'method_item.html' + ); + } + } + } + + $this->setTemplateVars($template, $title, $charset, $generator); + + $template->setVar( + array( + 'lines' => $lines, + 'total_item' => $this->renderTotalItem( + $lowUpperBound, $highLowerBound, FALSE + ), + 'items' => $items, + 'yuiPanelJS' => $this->yuiPanelJS + ) + ); + + $cleanId = PHP_CodeCoverage_Util::getSafeFilename($this->getId()); + $template->renderTo($target . $cleanId . '.html'); + + $this->yuiPanelJS = ''; + $this->executedLines = array(); + } + + /** + * Calculates coverage statistics for the file. + * + */ + protected function calculateStatistics() + { + $this->processClasses(); + $this->processFunctions(); + + $max = count($this->codeLines); + + for ($lineNumber = 1; $lineNumber <= $max; $lineNumber++) { + if (isset($this->startLines[$lineNumber])) { + // Start line of a class. + if (isset($this->startLines[$lineNumber]['methods'])) { + $currentClass = &$this->startLines[$lineNumber]; + } + + // Start line of a method. + else { + $currentMethod = &$this->startLines[$lineNumber]; + } + } + + if (isset($this->executedLines[$lineNumber])) { + // Array: Line is executable and was executed. + if (is_array($this->executedLines[$lineNumber])) { + if (isset($currentClass)) { + $currentClass['executableLines']++; + $currentClass['executedLines']++; + } + + if (isset($currentMethod)) { + $currentMethod['executableLines']++; + $currentMethod['executedLines']++; + } + + $this->numExecutableLines++; + $this->numExecutedLines++; + } + + // -1: Line is executable and was not executed. + else if ($this->executedLines[$lineNumber] == -1) { + if (isset($currentClass)) { + $currentClass['executableLines']++; + } + + if (isset($currentMethod)) { + $currentMethod['executableLines']++; + } + + $this->numExecutableLines++; + + if (isset($this->ignoredLines[$lineNumber])) { + if (isset($currentClass)) { + $currentClass['executedLines']++; + } + + if (isset($currentMethod)) { + $currentMethod['executedLines']++; + } + + $this->numExecutedLines++; + } + } + } + + if (isset($this->endLines[$lineNumber])) { + // End line of a class. + if (isset($this->endLines[$lineNumber]['methods'])) { + unset($currentClass); + } + + // End line of a method. + else { + unset($currentMethod); + } + } + } + + foreach ($this->classes as $className => &$class) { + foreach ($class['methods'] as &$method) { + if ($method['executableLines'] > 0) { + $method['coverage'] = ($method['executedLines'] / + $method['executableLines']) * 100; + } else { + $method['coverage'] = 100; + } + + $method['crap'] = PHP_CodeCoverage_Util::crap( + $method['ccn'], $method['coverage'] + ); + + $class['ccn'] += $method['ccn']; + } + + if ($className != '*') { + if ($class['executableLines'] > 0) { + $class['coverage'] = ($class['executedLines'] / + $class['executableLines']) * 100; + } else { + $class['coverage'] = 100; + } + + if ($class['coverage'] == 100) { + $this->numTestedClasses++; + } + + $class['crap'] = PHP_CodeCoverage_Util::crap( + $class['ccn'], $class['coverage'] + ); + } + } + } + + /** + * @param string $file + * @return array + * @author Aidan Lister + */ + protected function loadFile($file) + { + $buffer = file_get_contents($file); + $lines = explode("\n", str_replace("\t", ' ', $buffer)); + $result = array(); + + if (count($lines) == 0) { + return $result; + } + + $lines = array_map('rtrim', $lines); + $linesLength = array_map('strlen', $lines); + $width = max($linesLength); + + foreach ($linesLength as $line => $length) { + $this->codeLinesFillup[$line] = $width - $length; + } + + if (!$this->highlight) { + unset($lines[count($lines)-1]); + return $lines; + } + + $tokens = token_get_all($buffer); + $stringFlag = FALSE; + $i = 0; + $result[$i] = ''; + + foreach ($tokens as $j => $token) { + if (is_string($token)) { + if ($token === '"' && $tokens[$j - 1] !== '\\') { + $result[$i] .= sprintf( + '%s', + + htmlspecialchars($token) + ); + + $stringFlag = !$stringFlag; + } else { + $result[$i] .= sprintf( + '%s', + + htmlspecialchars($token) + ); + } + + continue; + } + + list ($token, $value) = $token; + + $value = str_replace( + array("\t", ' '), + array('    ', ' '), + htmlspecialchars($value) + ); + + if ($value === "\n") { + $result[++$i] = ''; + } else { + $lines = explode("\n", $value); + + foreach ($lines as $jj => $line) { + $line = trim($line); + + if ($line !== '') { + if ($stringFlag) { + $colour = 'string'; + } else { + switch ($token) { + case T_INLINE_HTML: { + $colour = 'html'; + } + break; + + case T_COMMENT: + case T_DOC_COMMENT: { + $colour = 'comment'; + } + break; + + case T_ABSTRACT: + case T_ARRAY: + case T_ARRAY_CAST: + case T_AS: + case T_BOOLEAN_AND: + case T_BOOLEAN_OR: + case T_BOOL_CAST: + case T_BREAK: + case T_CASE: + case T_CATCH: + case T_CLASS: + case T_CLONE: + case T_CONCAT_EQUAL: + case T_CONTINUE: + case T_DEFAULT: + case T_DOUBLE_ARROW: + case T_DOUBLE_CAST: + case T_ECHO: + case T_ELSE: + case T_ELSEIF: + case T_EMPTY: + case T_ENDDECLARE: + case T_ENDFOR: + case T_ENDFOREACH: + case T_ENDIF: + case T_ENDSWITCH: + case T_ENDWHILE: + case T_END_HEREDOC: + case T_EXIT: + case T_EXTENDS: + case T_FINAL: + case T_FOREACH: + case T_FUNCTION: + case T_GLOBAL: + case T_IF: + case T_INC: + case T_INCLUDE: + case T_INCLUDE_ONCE: + case T_INSTANCEOF: + case T_INT_CAST: + case T_ISSET: + case T_IS_EQUAL: + case T_IS_IDENTICAL: + case T_IS_NOT_IDENTICAL: + case T_IS_SMALLER_OR_EQUAL: + case T_NAMESPACE: + case T_NEW: + case T_OBJECT_CAST: + case T_OBJECT_OPERATOR: + case T_PAAMAYIM_NEKUDOTAYIM: + case T_PRIVATE: + case T_PROTECTED: + case T_PUBLIC: + case T_REQUIRE: + case T_REQUIRE_ONCE: + case T_RETURN: + case T_SL: + case T_SL_EQUAL: + case T_SR: + case T_SR_EQUAL: + case T_START_HEREDOC: + case T_STATIC: + case T_STRING_CAST: + case T_THROW: + case T_TRY: + case T_UNSET_CAST: + case T_USE: + case T_VAR: + case T_WHILE: { + $colour = 'keyword'; + } + break; + + default: { + $colour = 'default'; + } + } + } + + $result[$i] .= sprintf( + '%s', + + $colour, + $line + ); + } + + if (isset($lines[$jj + 1])) { + $result[++$i] = ''; + } + } + } + } + + unset($result[count($result)-1]); + + return $result; + } + + protected function processClasses() + { + $file = $this->getId() . '.html#'; + $tokens = PHP_Token_Stream_CachingFactory::get($this->getPath()); + $classes = $tokens->getClasses(); + unset($tokens); + + foreach ($classes as $className => $class) { + $this->classes[$className] = array( + 'methods' => array(), + 'startLine' => $class['startLine'], + 'executableLines' => 0, + 'executedLines' => 0, + 'ccn' => 0, + 'coverage' => 0, + 'crap' => 0, + 'file' => $file . $class['startLine'] + ); + + $this->startLines[$class['startLine']] = &$this->classes[$className]; + $this->endLines[$class['endLine']] = &$this->classes[$className]; + + foreach ($class['methods'] as $methodName => $method) { + $this->classes[$className]['methods'][$methodName] = array( + 'signature' => $method['signature'], + 'startLine' => $method['startLine'], + 'executableLines' => 0, + 'executedLines' => 0, + 'ccn' => $method['ccn'], + 'coverage' => 0, + 'crap' => 0, + 'file' => $file . $method['startLine'] + ); + + $this->startLines[$method['startLine']] = &$this->classes[$className]['methods'][$methodName]; + $this->endLines[$method['endLine']] = &$this->classes[$className]['methods'][$methodName]; + } + } + } + + protected function processFunctions() + { + $tokens = PHP_Token_Stream_CachingFactory::get($this->getPath()); + $functions = $tokens->getFunctions(); + unset($tokens); + + if (count($functions) > 0 && !isset($this->classes['*'])) { + $this->classes['*'] = array( + 'methods' => array(), + 'startLine' => 0, + 'executableLines' => 0, + 'executedLines' => 0, + 'ccn' => 0 + ); + } + + foreach ($functions as $functionName => $function) { + $this->classes['*']['methods'][$functionName] = array( + 'signature' => $function['signature'], + 'startLine' => $function['startLine'], + 'executableLines' => 0, + 'executedLines' => 0, + 'ccn' => $function['ccn'] + ); + + $this->startLines[$function['startLine']] = &$this->classes['*']['methods'][$functionName]; + $this->endLines[$function['endLine']] = &$this->classes['*']['methods'][$functionName]; + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node/Iterator.php b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node/Iterator.php new file mode 100644 index 0000000..e49caa3 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Node/Iterator.php @@ -0,0 +1,149 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since File available since Release 1.0.0 + */ + +/** + * Recursive iterator for PHP_CodeCoverage_Report_HTML_Node object graphs. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.4 + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since Class available since Release 1.0.0 + */ +class PHP_CodeCoverage_Report_HTML_Node_Iterator implements RecursiveIterator +{ + /** + * @var integer + */ + protected $position; + + /** + * @var PHP_CodeCoverage_Report_HTML_Node[] + */ + protected $nodes; + + /** + * Constructor. + * + * @param PHP_CodeCoverage_Report_HTML_Node_Directory $node + */ + public function __construct(PHP_CodeCoverage_Report_HTML_Node_Directory $node) + { + $this->nodes = $node->getChildNodes(); + } + + /** + * Rewinds the Iterator to the first element. + * + */ + public function rewind() + { + $this->position = 0; + } + + /** + * Checks if there is a current element after calls to rewind() or next(). + * + * @return boolean + */ + public function valid() + { + return $this->position < count($this->nodes); + } + + /** + * Returns the key of the current element. + * + * @return integer + */ + public function key() + { + return $this->position; + } + + /** + * Returns the current element. + * + * @return PHPUnit_Framework_Test + */ + public function current() + { + return $this->valid() ? $this->nodes[$this->position] : NULL; + } + + /** + * Moves forward to next element. + * + */ + public function next() + { + $this->position++; + } + + /** + * Returns the sub iterator for the current element. + * + * @return PHP_CodeCoverage_Report_HTML_Node_Iterator + */ + public function getChildren() + { + return new PHP_CodeCoverage_Report_HTML_Node_Iterator( + $this->nodes[$this->position] + ); + } + + /** + * Checks whether the current element has children. + * + * @return boolean + */ + public function hasChildren() + { + return $this->nodes[$this->position] instanceof PHP_CodeCoverage_Report_HTML_Node_Directory; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.bar.js b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.bar.js new file mode 100644 index 0000000..777ec2e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.bar.js @@ -0,0 +1,1653 @@ + /** + * o------------------------------------------------------------------------------o + * | This file is part of the RGraph package - you can learn more at: | + * | | + * | http://www.rgraph.net | + * | | + * | This package is licensed under the RGraph license. For all kinds of business | + * | purposes there is a small one-time licensing fee to pay and for non | + * | commercial purposes it is free to use. You can read the full license here: | + * | | + * | http://www.rgraph.net/LICENSE.txt | + * o------------------------------------------------------------------------------o + */ + + if (typeof(RGraph) == 'undefined') RGraph = {}; + + /** + * The bar chart constructor + * + * @param object canvas The canvas object + * @param array data The chart data + */ + RGraph.Bar = function (id, data) + { + // Get the canvas and context objects + this.id = id; + this.canvas = document.getElementById(id); + this.context = this.canvas.getContext ? this.canvas.getContext("2d") : null; + this.canvas.__object__ = this; + this.type = 'bar'; + this.max = 0; + this.stackedOrGrouped = false; + this.isRGraph = true; + + /** + * Compatibility with older browsers + */ + RGraph.OldBrowserCompat(this.context); + + + // Various config type stuff + this.properties = { + 'chart.background.barcolor1': 'rgba(0,0,0,0)', + 'chart.background.barcolor2': 'rgba(0,0,0,0)', + 'chart.background.grid': true, + 'chart.background.grid.color': '#ddd', + 'chart.background.grid.width': 1, + 'chart.background.grid.hsize': 20, + 'chart.background.grid.vsize': 20, + 'chart.background.grid.vlines': true, + 'chart.background.grid.hlines': true, + 'chart.background.grid.border': true, + 'chart.background.grid.autofit':false, + 'chart.background.grid.autofit.numhlines': 7, + 'chart.background.grid.autofit.numvlines': 20, + 'chart.ytickgap': 20, + 'chart.smallyticks': 3, + 'chart.largeyticks': 5, + 'chart.numyticks': 10, + 'chart.hmargin': 5, + 'chart.strokecolor': '#666', + 'chart.axis.color': 'black', + 'chart.gutter': 25, + 'chart.labels': null, + 'chart.labels.ingraph': null, + 'chart.labels.above': false, + 'chart.labels.above.decimals': 0, + 'chart.labels.above.size': null, + 'chart.ylabels': true, + 'chart.ylabels.count': 5, + 'chart.ylabels.inside': false, + 'chart.xlabels.offset': 0, + 'chart.xaxispos': 'bottom', + 'chart.yaxispos': 'left', + 'chart.text.color': 'black', + 'chart.text.size': 10, + 'chart.text.angle': 0, + 'chart.text.font': 'Verdana', + 'chart.ymax': null, + 'chart.title': '', + 'chart.title.background': null, + 'chart.title.hpos': null, + 'chart.title.vpos': null, + 'chart.title.xaxis': '', + 'chart.title.yaxis': '', + 'chart.title.xaxis.pos': 0.25, + 'chart.title.yaxis.pos': 0.25, + 'chart.colors': ['rgb(0,0,255)', '#0f0', '#00f', '#ff0', '#0ff', '#0f0'], + 'chart.grouping': 'grouped', + 'chart.variant': 'bar', + 'chart.shadow': false, + 'chart.shadow.color': '#666', + 'chart.shadow.offsetx': 3, + 'chart.shadow.offsety': 3, + 'chart.shadow.blur': 3, + 'chart.tooltips': null, + 'chart.tooltips.effect': 'fade', + 'chart.tooltips.css.class': 'RGraph_tooltip', + 'chart.tooltips.event': 'onclick', + 'chart.tooltips.coords.adjust': [0,0], + 'chart.tooltips.highlight': true, + 'chart.background.hbars': null, + + 'chart.key': [], + 'chart.key.background': 'white', + 'chart.key.position': 'graph', + 'chart.key.shadow': false, + 'chart.key.shadow.color': '#666', + 'chart.key.shadow.blur': 3, + 'chart.key.shadow.offsetx': 2, + 'chart.key.shadow.offsety': 2, + 'chart.key.position.gutter.boxed': true, + 'chart.key.position.x': null, + 'chart.key.position.y': null, + 'chart.key.color.shape': 'square', + 'chart.key.rounded': true, + 'chart.key.text.size': 10, + + 'chart.contextmenu': null, + 'chart.line': null, + 'chart.units.pre': '', + 'chart.units.post': '', + 'chart.scale.decimals': 0, + 'chart.scale.point': '.', + 'chart.scale.thousand': ',', + 'chart.crosshairs': false, + 'chart.crosshairs.color': '#333', + 'chart.linewidth': 1, + 'chart.annotatable': false, + 'chart.annotate.color': 'black', + 'chart.zoom.factor': 1.5, + 'chart.zoom.fade.in': true, + 'chart.zoom.fade.out': true, + 'chart.zoom.hdir': 'right', + 'chart.zoom.vdir': 'down', + 'chart.zoom.frames': 10, + 'chart.zoom.delay': 50, + 'chart.zoom.shadow': true, + 'chart.zoom.mode': 'canvas', + 'chart.zoom.thumbnail.width': 75, + 'chart.zoom.thumbnail.height': 75, + 'chart.zoom.background': true, + 'chart.resizable': false, + 'chart.adjustable': false + } + + // Check for support + if (!this.canvas) { + alert('[BAR] No canvas support'); + return; + } + + // Check the common library has been included + if (typeof(RGraph) == 'undefined') { + alert('[BAR] Fatal error: The common library does not appear to have been included'); + } + + /** + * Determine whether the chart will contain stacked or grouped bars + */ + for (i=0; i 0) { + + alert('[BAR] (' + this.id + ') Sorry, tooltips are not supported with dot or pyramid charts'); + } + + /** + * Stop the coords array from growing uncontrollably + */ + this.coords = []; + + /** + * Work out a few things. They need to be here because they depend on things you can change before you + * call Draw() but after you instantiate the object + */ + this.max = 0; + this.grapharea = this.canvas.height - ( (2 * this.gutter)); + this.halfgrapharea = this.grapharea / 2; + this.halfTextHeight = this.Get('chart.text.size') / 2; + + // Progressively Draw the chart + RGraph.background.Draw(this); + + + //If it's a sketch chart variant, draw the axes first + if (this.Get('chart.variant') == 'sketch') { + this.DrawAxes(); + this.Drawbars(); + } else { + this.Drawbars(); + this.DrawAxes(); + } + + this.DrawLabels(); + + + // Draw the key if necessary + if (this.Get('chart.key').length) { + RGraph.DrawKey(this, this.Get('chart.key'), this.Get('chart.colors')); + } + + + /** + * Setup the context menu if required + */ + if (this.Get('chart.contextmenu')) { + RGraph.ShowContext(this); + } + + + /** + * Is a line is defined, draw it + */ + var line = this.Get('chart.line'); + + if (line) { + + // Check the length of the data(s) + if (line.original_data[0].length != this.data.length) { + alert("[BAR] You're adding a line with a differing amount of data points to the bar chart - this is not permitted"); + } + + // Check the X axis positions + if (this.Get('chart.xaxispos') != line.Get('chart.xaxispos')) { + alert("[BAR] Using different X axis positions when combining the Bar and Line is not advised"); + } + + line.Set('chart.gutter', this.Get('chart.gutter')); + line.Set('chart.noaxes', true); + line.Set('chart.background.barcolor1', 'rgba(0,0,0,0)'); + line.Set('chart.background.barcolor2', 'rgba(0,0,0,0)'); + line.Set('chart.background.grid', false); + line.Set('chart.ylabels', false); + line.Set('chart.hmargin', (this.canvas.width - (2 * this.gutter)) / (line.original_data[0].length * 2)); + + // If a custom yMax is set, use that + if (this.Get('chart.ymax')) { + line.Set('chart.ymax', this.Get('chart.ymax')); + } + + line.Draw(); + } + + + /** + * Draw "in graph" labels + */ + if (this.Get('chart.labels.ingraph')) { + RGraph.DrawInGraphLabels(this); + } + + /** + * Draw crosschairs + */ + if (this.Get('chart.crosshairs')) { + RGraph.DrawCrosshairs(this); + } + + /** + * If the canvas is annotatable, do install the event handlers + */ + if (this.Get('chart.annotatable')) { + RGraph.Annotate(this); + } + + /** + * This bit shows the mini zoom window if requested + */ + if (this.Get('chart.zoom.mode') == 'thumbnail' || this.Get('chart.zoom.mode') == 'area') { + RGraph.ShowZoomWindow(this); + } + + + /** + * This function enables resizing + */ + if (this.Get('chart.resizable')) { + RGraph.AllowResizing(this); + } + + + /** + * This function enables adjusting + */ + if (this.Get('chart.adjustable')) { + RGraph.AllowAdjusting(this); + } + + /** + * Fire the RGraph ondraw event + */ + RGraph.FireCustomEvent(this, 'ondraw'); + } + + + /** + * Draws the charts axes + */ + RGraph.Bar.prototype.DrawAxes = function () + { + var gutter = this.gutter; + var xaxispos = this.Get('chart.xaxispos'); + var yaxispos = this.Get('chart.yaxispos'); + + this.context.beginPath(); + this.context.strokeStyle = this.Get('chart.axis.color'); + this.context.lineWidth = 1; + + // Draw the Y axis + if (yaxispos == 'right') { + this.context.moveTo(this.canvas.width - gutter, gutter); + this.context.lineTo(this.canvas.width - gutter, this.canvas.height - gutter); + } else { + this.context.moveTo(gutter, gutter); + this.context.lineTo(gutter, this.canvas.height - gutter); + } + + // Draw the X axis + this.context.moveTo(gutter, (xaxispos == 'center' ? this.canvas.height / 2 : this.canvas.height - gutter)); + this.context.lineTo(this.canvas.width - gutter, xaxispos == 'center' ? this.canvas.height / 2 : this.canvas.height - gutter); + + var numYTicks = this.Get('chart.numyticks'); + + // Draw the Y tickmarks + var yTickGap = (this.canvas.height - (2 * gutter)) / numYTicks; + var xpos = yaxispos == 'left' ? gutter : this.canvas.width - gutter; + + for (y=gutter; + xaxispos == 'center' ? y <= (this.canvas.height - gutter) : y < (this.canvas.height - gutter); + y += yTickGap) { + + if (xaxispos == 'center' && y == (this.canvas.height / 2)) continue; + + this.context.moveTo(xpos, y); + this.context.lineTo(xpos + (yaxispos == 'left' ? -3 : 3), y); + } + + // Draw the X tickmarks + xTickGap = (this.canvas.width - (2 * gutter) ) / this.data.length; + yStart = this.canvas.height - gutter; + yEnd = (this.canvas.height - gutter) + 3; + + //////////////// X TICKS //////////////// + + // Now move the Y start end positions down if the axis is set to center + if (xaxispos == 'center') { + yStart = (this.canvas.height / 2) + 3; + yEnd = (this.canvas.height / 2) - 3; + } + + for (x=gutter + (yaxispos == 'left' ? xTickGap : 0); x 0) { + RGraph.DrawBars(this); + } + + var variant = this.Get('chart.variant'); + + /** + * Draw the 3D axes is necessary + */ + if (variant == '3d') { + RGraph.Draw3DAxes(this); + } + + /** + * Get the variant once, and draw the bars, be they regular, stacked or grouped + */ + + // Get these variables outside of the loop + var xaxispos = this.Get('chart.xaxispos'); + var width = (this.canvas.width - (2 * gutter) ) / this.data.length; + var orig_height = height; + var hmargin = this.Get('chart.hmargin'); + var shadow = this.Get('chart.shadow'); + var shadowColor = this.Get('chart.shadow.color'); + var shadowBlur = this.Get('chart.shadow.blur'); + var shadowOffsetX = this.Get('chart.shadow.offsetx'); + var shadowOffsetY = this.Get('chart.shadow.offsety'); + var strokeStyle = this.Get('chart.strokecolor'); + var colors = this.Get('chart.colors'); + + for (i=0; i 0.4 ? -1 : 3) - (r * width),y - 1); + this.context.lineTo(x + hmargin + width - (r > 0.4 ? 1 : -1) - (r * width), y + height + (r == 0.2 ? 1 : -2)); + } + + this.context.stroke(); + + // Regular bar + } else if (variant == 'bar' || variant == '3d' || variant == 'glass') { + + if (document.all && shadow) { + this.DrawIEShadow([x + hmargin, y, barWidth, height]); + } + + if (variant == 'glass') { + RGraph.filledCurvyRect(this.context, x + hmargin, y, barWidth, height, 3, this.data[i] > 0, this.data[i] > 0, this.data[i] < 0, this.data[i] < 0); + RGraph.strokedCurvyRect(this.context, x + hmargin, y, barWidth, height, 3, this.data[i] > 0, this.data[i] > 0, this.data[i] < 0, this.data[i] < 0); + } else { + this.context.strokeRect(x + hmargin, y, barWidth, height); + this.context.fillRect(x + hmargin, y, barWidth, height); + } + + + // This bit draws the text labels that appear above the bars if requested + if (this.Get('chart.labels.above')) { + + // Turn off any shadow + if (shadow) { + RGraph.NoShadow(this); + } + + var yPos = y - 3; + + // Account for negative bars + if (this.data[i] < 0) { + yPos += height + 6 + (this.Get('chart.text.size') - 4); + } + + this.context.fillStyle = this.Get('chart.text.color'); + RGraph.Text(this.context, this.Get('chart.text.font'), typeof(this.Get('chart.labels.above.size')) == 'number' ? this.Get('chart.labels.above.size') : this.Get('chart.text.size') - 3, x + hmargin + (barWidth / 2), yPos, RGraph.number_format(this, Number(this.data[i]).toFixed(this.Get('chart.labels.above.decimals')),this.Get('chart.units.pre'), this.Get('chart.units.post')), null, 'center'); + } + + // 3D effect + if (variant == '3d') { + + var prevStrokeStyle = this.context.strokeStyle; + var prevFillStyle = this.context.fillStyle; + + // Draw the top + this.context.beginPath(); + this.context.moveTo(x + hmargin, y); + this.context.lineTo(x + hmargin + 10, y - 5); + this.context.lineTo(x + hmargin + 10 + barWidth, y - 5); + this.context.lineTo(x + hmargin + barWidth, y); + this.context.closePath(); + + this.context.stroke(); + this.context.fill(); + + // Draw the right hand side + this.context.beginPath(); + this.context.moveTo(x + hmargin + barWidth, y); + this.context.lineTo(x + hmargin + barWidth + 10, y - 5); + this.context.lineTo(x + hmargin + barWidth + 10, y + height - 5); + this.context.lineTo(x + hmargin + barWidth, y + height); + this.context.closePath(); + + this.context.stroke(); + this.context.fill(); + + // Draw the darker top section + this.context.beginPath(); + this.context.fillStyle = 'rgba(255,255,255,0.3)'; + this.context.moveTo(x + hmargin, y); + this.context.lineTo(x + hmargin + 10, y - 5); + this.context.lineTo(x + hmargin + 10 + barWidth, y - 5); + this.context.lineTo(x + hmargin + barWidth, y); + this.context.lineTo(x + hmargin, y); + this.context.closePath(); + + this.context.stroke(); + this.context.fill(); + + // Draw the darker right side section + this.context.beginPath(); + this.context.fillStyle = 'rgba(0,0,0,0.4)'; + this.context.moveTo(x + hmargin + barWidth, y); + this.context.lineTo(x + hmargin + barWidth + 10, y - 5); + this.context.lineTo(x + hmargin + barWidth + 10, y - 5 + height); + this.context.lineTo(x + hmargin + barWidth, y + height); + this.context.lineTo(x + hmargin + barWidth, y); + this.context.closePath(); + + this.context.stroke(); + this.context.fill(); + + this.context.strokeStyle = prevStrokeStyle; + this.context.fillStyle = prevFillStyle; + + // Glass variant + } else if (variant == 'glass') { + + var grad = this.context.createLinearGradient( + x + hmargin, + y, + x + hmargin + (barWidth / 2), + y + ); + grad.addColorStop(0, 'rgba(255,255,255,0.9)'); + grad.addColorStop(1, 'rgba(255,255,255,0.5)'); + + this.context.beginPath(); + this.context.fillStyle = grad; + this.context.fillRect(x + hmargin + 2,y + (this.data[i] > 0 ? 2 : 0),(barWidth / 2) - 2,height - 2); + this.context.fill(); + } + + // Dot chart + } else if (variant == 'dot') { + + this.context.beginPath(); + this.context.moveTo(x + (width / 2), y); + this.context.lineTo(x + (width / 2), y + height); + this.context.stroke(); + + this.context.beginPath(); + this.context.fillStyle = this.Get('chart.colors')[i]; + this.context.arc(x + (width / 2), y + (this.data[i] > 0 ? 0 : height), 2, 0, 6.28, 0); + + // Set the colour for the dots + this.context.fillStyle = this.Get('chart.colors')[0]; + + this.context.stroke(); + this.context.fill(); + + // Pyramid chart + } else if (variant == 'pyramid') { + + this.context.beginPath(); + var startY = (this.Get('chart.xaxispos') == 'center' ? (this.canvas.height / 2) : (this.canvas.height - this.Get('chart.gutter'))); + + this.context.moveTo(x + hmargin, startY); + this.context.lineTo( + x + hmargin + (barWidth / 2), + y + (this.Get('chart.xaxispos') == 'center' && (this.data[i] < 0) ? height : 0) + ); + this.context.lineTo(x + hmargin + barWidth, startY); + + this.context.closePath(); + + this.context.stroke(); + this.context.fill(); + + // Arrow chart + } else if (variant == 'arrow') { + var startY = (this.Get('chart.xaxispos') == 'center' ? (this.canvas.height / 2) : (this.canvas.height - this.gutter)); + + this.context.lineWidth = this.Get('chart.linewidth') ? this.Get('chart.linewidth') : 1; + this.context.lineCap = 'round'; + + this.context.beginPath(); + + this.context.moveTo(x + hmargin + (barWidth / 2), startY); + this.context.lineTo(x + hmargin + (barWidth / 2), y + (this.Get('chart.xaxispos') == 'center' && (this.data[i] < 0) ? height : 0)); + this.context.arc(x + hmargin + (barWidth / 2), + y + (this.Get('chart.xaxispos') == 'center' && (this.data[i] < 0) ? height : 0), + 5, + this.data[i] > 0 ? 0.78 : 5.6, + this.data[i] > 0 ? 0.79 : 5.48, + this.data[i] < 0); + + this.context.moveTo(x + hmargin + (barWidth / 2), y + (this.Get('chart.xaxispos') == 'center' && (this.data[i] < 0) ? height : 0)); + this.context.arc(x + hmargin + (barWidth / 2), + y + (this.Get('chart.xaxispos') == 'center' && (this.data[i] < 0) ? height : 0), + 5, + this.data[i] > 0 ? 2.355 : 4, + this.data[i] > 0 ? 2.4 : 3.925, + this.data[i] < 0); + + this.context.stroke(); + + this.context.lineWidth = 1; + + // Unknown variant type + } else { + alert('[BAR] Warning! Unknown chart.variant: ' + variant); + } + + this.coords.push([x + hmargin, y, width - (2 * hmargin), height]); + + + /** + * Stacked bar + */ + } else if (typeof(this.data[i]) == 'object' && this.Get('chart.grouping') == 'stacked') { + + var barWidth = width - (2 * hmargin); + var redrawCoords = [];// Necessary to draw if the shadow is enabled + var startY = 0; + + for (j=0; j 0) { + + /** + * Get the tooltip text + */ + if (typeof(obj.Get('chart.tooltips')) == 'function') { + var text = String(obj.Get('chart.tooltips')(barCoords[5])); + + } else if (typeof(obj.Get('chart.tooltips')) == 'object' && typeof(obj.Get('chart.tooltips')[barCoords[5]]) == 'function') { + var text = String(obj.Get('chart.tooltips')[barCoords[5]](barCoords[5])); + + } else if (typeof(obj.Get('chart.tooltips')) == 'object' && (typeof(obj.Get('chart.tooltips')[barCoords[5]]) == 'string' || typeof(obj.Get('chart.tooltips')[barCoords[5]]) == 'number')) { + var text = String(obj.Get('chart.tooltips')[barCoords[5]]); + + } else { + var text = null; + } + + if (text) { + canvas.style.cursor = 'pointer'; + } else { + canvas.style.cursor = 'default'; + } + + /** + * Hide the currently displayed tooltip if the index is the same + */ + if ( RGraph.Registry.Get('chart.tooltip') + && RGraph.Registry.Get('chart.tooltip').__canvas__.id != obj.id + && obj.Get('chart.tooltips.event') == 'onmousemove') { + + RGraph.Redraw(); + RGraph.HideTooltip(); + } + + /** + * This facilitates the tooltips using the onmousemove event + */ + + if ( obj.Get('chart.tooltips.event') == 'onmousemove' + && ( + (RGraph.Registry.Get('chart.tooltip') && RGraph.Registry.Get('chart.tooltip').__index__ != barCoords[5]) + || !RGraph.Registry.Get('chart.tooltip') + ) + && text) { + /** + * Show a tooltip if it's defined + */ + RGraph.Redraw(obj); + + obj.context.beginPath(); + obj.context.strokeStyle = 'black'; + obj.context.fillStyle = 'rgba(255,255,255,0.5)'; + obj.context.strokeRect(barCoords[1], barCoords[2], barCoords[3], barCoords[4]); + obj.context.fillRect(barCoords[1], barCoords[2], barCoords[3], barCoords[4]); + + obj.context.stroke(); + obj.context.fill(); + + RGraph.Tooltip(canvas, text, e.pageX, e.pageY, barCoords[5]); + } + } else { + canvas.style.cursor = 'default'; + } + } + RGraph.AddEventListener(this.id, 'mousemove', canvas_onmousemove); + this.canvas.addEventListener('mousemove', canvas_onmousemove, false); + + + /** + * Install the onclick event handler for the tooltips + */ + if (this.Get('chart.tooltips.event') == 'onclick') { + + canvas_onclick = function (e) + { + var e = RGraph.FixEventObject(e); + + // If the button pressed isn't the left, we're not interested + if (e.button != 0) return; + + e = RGraph.FixEventObject(e); + + var canvas = document.getElementById(this.id); + var obj = canvas.__object__; + var barCoords = obj.getBar(e); + + /** + * Redraw the graph first, in effect resetting the graph to as it was when it was first drawn + * This "deselects" any already selected bar + */ + RGraph.Redraw(); + + /** + * Loop through the bars determining if the mouse is over a bar + */ + if (barCoords) { + + /** + * Get the tooltip text + */ + if (typeof(obj.Get('chart.tooltips')) == 'function') { + var text = String(obj.Get('chart.tooltips')(barCoords[5])); + + } else if (typeof(obj.Get('chart.tooltips')) == 'object' && typeof(obj.Get('chart.tooltips')[barCoords[5]]) == 'function') { + var text = String(obj.Get('chart.tooltips')[barCoords[5]](barCoords[5])); + + } else if (typeof(obj.Get('chart.tooltips')) == 'object') { + var text = String(obj.Get('chart.tooltips')[barCoords[5]]); + + } else { + var text = null; + } + + /** + * Show a tooltip if it's defined + */ + if (text && text != 'undefined') { + + // [TODO] Allow customisation of the highlight colors + obj.context.beginPath(); + obj.context.strokeStyle = 'black'; + obj.context.fillStyle = 'rgba(255,255,255,0.5)'; + obj.context.strokeRect(barCoords[1], barCoords[2], barCoords[3], barCoords[4]); + obj.context.fillRect(barCoords[1], barCoords[2], barCoords[3], barCoords[4]); + + obj.context.stroke(); + obj.context.fill(); + + RGraph.Tooltip(canvas, text, e.pageX, e.pageY, barCoords[5]); + } + } + + /** + * Stop the event bubbling + */ + e.stopPropagation(); + } + RGraph.AddEventListener(this.id, 'click', canvas_onclick); + this.canvas.addEventListener('click', canvas_onclick, false); + } + + + // This resets the bar graph + // 8th August 2010 : Is this redundant + //if (typeof(obj) != 'undefined' && obj == RGraph.Registry.Get('chart.tooltip')) { + // obj.style.display = 'none'; + // RGraph.Registry.Set('chart.tooltip', null) + //} + } + } + + /** + * Draws the labels for the graph + */ + RGraph.Bar.prototype.DrawLabels = function () + { + var context = this.context; + var gutter = this.gutter; + var text_angle = this.Get('chart.text.angle'); + var text_size = this.Get('chart.text.size'); + var labels = this.Get('chart.labels'); + + + // Draw the Y axis labels: + if (this.Get('chart.ylabels')) { + this.Drawlabels_center(); + this.Drawlabels_bottom(); + } + + /** + * The X axis labels + */ + if (typeof(labels) == 'object' && labels) { + + var yOffset = 13 + Number(this.Get('chart.xlabels.offset')); + + /** + * Text angle + */ + var angle = 0; + var halign = 'center'; + + if (text_angle > 0) { + angle = -1 * text_angle; + halign = 'right'; + yOffset -= 5; + } + + // Draw the X axis labels + context.fillStyle = this.Get('chart.text.color'); + + // How wide is each bar + var barWidth = (this.canvas.width - (2 * gutter) ) / labels.length; + + // Reset the xTickGap + xTickGap = (this.canvas.width - (2 * gutter)) / labels.length + + // Draw the X tickmarks + var i=0; + var font = this.Get('chart.text.font'); + + for (x=gutter + (xTickGap / 2); x<=this.canvas.width - gutter; x+=xTickGap) { + RGraph.Text(context, font, + text_size, + x + (this.Get('chart.text.angle') == 90 ? 0: 0), + (this.canvas.height - gutter) + yOffset, + String(labels[i++]), + (this.Get('chart.text.angle') == 90 ? 'center' : null), + halign, + null, + angle); + } + } + } + + /** + * Draws the X axis in the middle + */ + RGraph.Bar.prototype.Drawlabels_center = function () + { + var font = this.Get('chart.text.font'); + var numYLabels = this.Get('chart.ylabels.count'); + + this.context.fillStyle = this.Get('chart.text.color'); + + if (this.Get('chart.xaxispos') == 'center') { + + /** + * Draw the top labels + */ + var interval = (this.grapharea * (1/10) ); + var text_size = this.Get('chart.text.size'); + var gutter = this.gutter; + var units_pre = this.Get('chart.units.pre'); + var units_post = this.Get('chart.units.post'); + var context = this.context; + var align = ''; + var xpos = 0; + var boxed = false; + + this.context.fillStyle = this.Get('chart.text.color'); + this.context.strokeStyle = 'black'; + + if (this.Get('chart.ylabels.inside') == true) { + var xpos = this.Get('chart.yaxispos') == 'left' ? gutter + 5 : this.canvas.width - gutter - 5; + var align = this.Get('chart.yaxispos') == 'left' ? 'left' : 'right'; + var boxed = true; + } else { + var xpos = this.Get('chart.yaxispos') == 'left' ? gutter - 5 : this.canvas.width - gutter + 5; + var align = this.Get('chart.yaxispos') == 'left' ? 'right' : 'left'; + var boxed = false; + } + + + + + + + + + + + + + /** + * Draw specific Y labels here so that the local variables can be reused + */ + if (typeof(this.Get('chart.ylabels.specific')) == 'object') { + + var labels = this.Get('chart.ylabels.specific'); + var grapharea = this.canvas.height - (2 * gutter); + + // Draw the top halves labels + for (var i=0; i=0; --i) { + var y = gutter + (grapharea * ( (i+1) / (labels.length * 2) )) + (grapharea / 2); + + RGraph.Text(context, font, text_size, xpos, y, labels[labels.length - i - 1], 'center', align, boxed); + } + + return; + } + + + + + + + + + + + + + if (numYLabels == 3 || numYLabels == 5) { + RGraph.Text(context, font, text_size, xpos, gutter + this.halfTextHeight, RGraph.number_format(this, this.scale[4], units_pre, units_post), null, align, boxed); + + if (numYLabels == 5) { + RGraph.Text(context, font, text_size, xpos, (1*interval) + gutter + this.halfTextHeight, RGraph.number_format(this, this.scale[3], units_pre, units_post), null, align, boxed); + RGraph.Text(context, font, text_size, xpos, (3*interval) + gutter + this.halfTextHeight, RGraph.number_format(this, this.scale[1], units_pre, units_post), null, align, boxed); + } + + if (numYLabels == 3 || numYLabels == 5) { + RGraph.Text(context, font, text_size, xpos, (4*interval) + gutter + this.halfTextHeight, RGraph.number_format(this, this.scale[0], units_pre, units_post), null, align, boxed); + RGraph.Text(context, font, text_size, xpos, (2*interval) + gutter + this.halfTextHeight, RGraph.number_format(this, this.scale[2], units_pre, units_post), null, align, boxed); + } + } else if (numYLabels == 10) { + // 10Y labels + interval = (this.grapharea / numYLabels) / 2; + + for (var i=0; i= (left + obj.Get('chart.tooltips.coords.adjust')[0]) + && mouseX <= (left + width+ obj.Get('chart.tooltips.coords.adjust')[0]) + && mouseY >= (top + obj.Get('chart.tooltips.coords.adjust')[1]) + && mouseY <= (top + height + obj.Get('chart.tooltips.coords.adjust')[1]) ) { + + return [obj, left, top, width, height, i]; + } + } + + return null; + } diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.common.core.js b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.common.core.js new file mode 100644 index 0000000..b3b26b7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.common.core.js @@ -0,0 +1,2454 @@ + /** + * o------------------------------------------------------------------------------o + * | This file is part of the RGraph package - you can learn more at: | + * | | + * | http://www.rgraph.net | + * | | + * | This package is licensed under the RGraph license. For all kinds of business | + * | purposes there is a small one-time licensing fee to pay and for non | + * | commercial purposes it is free to use. You can read the full license here: | + * | | + * | http://www.rgraph.net/LICENSE.txt | + * o------------------------------------------------------------------------------o + */ + + /** + * Initialise the various objects + */ + if (typeof(RGraph) == 'undefined') RGraph = {isRGraph:true,type:'common'}; + + + RGraph.Registry = {}; + RGraph.Registry.store = []; + RGraph.Registry.store['chart.event.handlers'] = []; + RGraph.background = {}; + RGraph.objects = []; + RGraph.Resizing = {}; + RGraph.events = []; + + + + /** + * Returns five values which are used as a nice scale + * + * @param max int The maximum value of the graph + * @param obj object The graph object + * @return array An appropriate scale + */ + RGraph.getScale = function (max, obj) + { + /** + * Special case for 0 + */ + if (max == 0) { + return ['0.2', '0.4', '0.6', '0.8', '1.0']; + } + + var original_max = max; + + /** + * Manually do decimals + */ + if (max <= 1) { + if (max > 0.5) { + return [0.2,0.4,0.6,0.8, Number(1).toFixed(1)]; + + } else if (max >= 0.1) { + return obj.Get('chart.scale.round') ? [0.2,0.4,0.6,0.8,1] : [0.1,0.2,0.3,0.4,0.5]; + + } else { + + var tmp = max; + var exp = 0; + + while (tmp < 1.01) { + exp += 1; + tmp *= 10; + } + + var ret = ['2e-' + exp, '4e-' + exp, '6e-' + exp, '8e-' + exp, '10e-' + exp]; + + + if (max <= ('5e-' + exp)) { + ret = ['1e-' + exp, '2e-' + exp, '3e-' + exp, '4e-' + exp, '5e-' + exp]; + } + + return ret; + } + } + + // Take off any decimals + if (String(max).indexOf('.') > 0) { + max = String(max).replace(/\.\d+$/, ''); + } + + var interval = Math.pow(10, Number(String(Number(max)).length - 1)); + var topValue = interval; + + while (topValue < max) { + topValue += (interval / 2); + } + + // Handles cases where the max is (for example) 50.5 + if (Number(original_max) > Number(topValue)) { + topValue += (interval / 2); + } + + // Custom if the max is greater than 5 and less than 10 + if (max < 10) { + topValue = (Number(original_max) <= 5 ? 5 : 10); + } + + /** + * Added 02/11/2010 to create "nicer" scales + */ + if (obj && typeof(obj.Get('chart.scale.round')) == 'boolean' && obj.Get('chart.scale.round')) { + topValue = 10 * interval; + } + + return [topValue * 0.2, topValue * 0.4, topValue * 0.6, topValue * 0.8, topValue]; + } + + + /** + * Returns the maximum value which is in an array + * + * @param array arr The array + * @param int Whether to ignore signs (ie negative/positive) + * @return int The maximum value in the array + */ + RGraph.array_max = function (arr) + { + var max = null; + + for (var i=0; i ' + RGraph.pr(obj[i], true, indent + ' ') + '\n'; + } + + var str = str + indent + ')'; + break; + + case 'function': + str += obj; + break; + + case 'boolean': + str += 'Boolean: ' + (obj ? 'true' : 'false'); + break; + } + + /** + * Finished, now either return if we're in a recursed call, or alert() + * if we're not. + */ + if (arguments[1]) { + return str; + } else { + alert(str); + } + } + + + /** + * The RGraph registry Set() function + * + * @param string name The name of the key + * @param mixed value The value to set + * @return mixed Returns the same value as you pass it + */ + RGraph.Registry.Set = function (name, value) + { + // Store the setting + RGraph.Registry.store[name] = value; + + // Don't really need to do this, but ho-hum + return value; + } + + + /** + * The RGraph registry Get() function + * + * @param string name The name of the particular setting to fetch + * @return mixed The value if exists, null otherwise + */ + RGraph.Registry.Get = function (name) + { + //return RGraph.Registry.store[name] == null ? null : RGraph.Registry.store[name]; + return RGraph.Registry.store[name]; + } + + + /** + * This function draws the background for the bar chart, line chart and scatter chart. + * + * @param object obj The graph object + */ + RGraph.background.Draw = function (obj) + { + var canvas = obj.canvas; + var context = obj.context; + var height = 0; + var gutter = obj.Get('chart.gutter'); + var variant = obj.Get('chart.variant'); + + context.fillStyle = obj.Get('chart.text.color'); + + // If it's a bar and 3D variant, translate + if (variant == '3d') { + context.save(); + context.translate(10, -5); + } + + // X axis title + if (typeof(obj.Get('chart.title.xaxis')) == 'string' && obj.Get('chart.title.xaxis').length) { + + var size = obj.Get('chart.text.size'); + var font = obj.Get('chart.text.font'); + + context.beginPath(); + RGraph.Text(context, font, size + 2, obj.canvas.width / 2, canvas.height - (gutter * obj.Get('chart.title.xaxis.pos')), obj.Get('chart.title.xaxis'), 'center', 'center', false, false, false, true); + context.fill(); + } + + // Y axis title + if (typeof(obj.Get('chart.title.yaxis')) == 'string' && obj.Get('chart.title.yaxis').length) { + + var size = obj.Get('chart.text.size'); + var font = obj.Get('chart.text.font'); + + context.beginPath(); + RGraph.Text(context, font, size + 2, gutter * obj.Get('chart.title.yaxis.pos'), canvas.height / 2, obj.Get('chart.title.yaxis'), 'center', 'center', false, 270, false, true); + context.fill(); + } + + obj.context.beginPath(); + + // Draw the horizontal bars + context.fillStyle = obj.Get('chart.background.barcolor1'); + height = (obj.canvas.height - obj.Get('chart.gutter')); + + for (var i=gutter; i < height ; i+=80) { + obj.context.fillRect(gutter, i, obj.canvas.width - (gutter * 2), Math.min(40, obj.canvas.height - gutter - i) ); + } + + context.fillStyle = obj.Get('chart.background.barcolor2'); + height = (obj.canvas.height - gutter); + + for (var i= (40 + gutter); i < height; i+=80) { + obj.context.fillRect(gutter, i, obj.canvas.width - (gutter * 2), i + 40 > (obj.canvas.height - gutter) ? obj.canvas.height - (gutter + i) : 40); + } + + context.stroke(); + + + // Draw the background grid + if (obj.Get('chart.background.grid')) { + + // If autofit is specified, use the .numhlines and .numvlines along with the width to work + // out the hsize and vsize + if (obj.Get('chart.background.grid.autofit')) { + var vsize = (canvas.width - (2 * obj.Get('chart.gutter')) - (obj.type == 'gantt' ? 2 * obj.Get('chart.gutter') : 0)) / obj.Get('chart.background.grid.autofit.numvlines'); + var hsize = (canvas.height - (2 * obj.Get('chart.gutter'))) / obj.Get('chart.background.grid.autofit.numhlines'); + + obj.Set('chart.background.grid.vsize', vsize); + obj.Set('chart.background.grid.hsize', hsize); + } + + context.beginPath(); + context.lineWidth = obj.Get('chart.background.grid.width') ? obj.Get('chart.background.grid.width') : 1; + context.strokeStyle = obj.Get('chart.background.grid.color'); + + // Draw the horizontal lines + if (obj.Get('chart.background.grid.hlines')) { + height = (canvas.height - gutter) + for (y=gutter; y < height; y+=obj.Get('chart.background.grid.hsize')) { + context.moveTo(gutter, y); + context.lineTo(canvas.width - gutter, y); + } + } + + if (obj.Get('chart.background.grid.vlines')) { + // Draw the vertical lines + var width = (canvas.width - gutter) + for (x=gutter + (obj.type == 'gantt' ? (2 * gutter) : 0); x<=width; x+=obj.Get('chart.background.grid.vsize')) { + context.moveTo(x, gutter); + context.lineTo(x, obj.canvas.height - gutter); + } + } + + if (obj.Get('chart.background.grid.border')) { + // Make sure a rectangle, the same colour as the grid goes around the graph + context.strokeStyle = obj.Get('chart.background.grid.color'); + context.strokeRect(gutter, gutter, canvas.width - (2 * gutter), canvas.height - (2 * gutter)); + } + } + + context.stroke(); + + // If it's a bar and 3D variant, translate + if (variant == '3d') { + context.restore(); + } + + // Draw the title if one is set + if ( typeof(obj.Get('chart.title')) == 'string') { + + if (obj.type == 'gantt') { + gutter /= 2; + } + + RGraph.DrawTitle(canvas, obj.Get('chart.title'), gutter, null, obj.Get('chart.text.size') + 2); + } + + context.stroke(); + } + + + /** + * Returns the day number for a particular date. Eg 1st February would be 32 + * + * @param object obj A date object + * @return int The day number of the given date + */ + RGraph.GetDays = function (obj) + { + var year = obj.getFullYear(); + var days = obj.getDate(); + var month = obj.getMonth(); + + if (month == 0) return days; + if (month >= 1) days += 31; + if (month >= 2) days += 28; + + // Leap years. Crude, but if this code is still being used + // when it stops working, then you have my permission to shoot + // me. Oh, you won't be able to - I'll be dead... + if (year >= 2008 && year % 4 == 0) days += 1; + + if (month >= 3) days += 31; + if (month >= 4) days += 30; + if (month >= 5) days += 31; + if (month >= 6) days += 30; + if (month >= 7) days += 31; + if (month >= 8) days += 31; + if (month >= 9) days += 30; + if (month >= 10) days += 31; + if (month >= 11) days += 30; + + return days; + } + + + + + + + + + + + + + + + + /** + * Draws the graph key (used by various graphs) + * + * @param object obj The graph object + * @param array key An array of the texts to be listed in the key + * @param colors An array of the colors to be used + */ + RGraph.DrawKey = function (obj, key, colors) + { + var canvas = obj.canvas; + var context = obj.context; + context.lineWidth = 1; + + context.beginPath(); + + /** + * Key positioned in the gutter + */ + var keypos = obj.Get('chart.key.position'); + var textsize = obj.Get('chart.text.size'); + var gutter = obj.Get('chart.gutter'); + + /** + * Change the older chart.key.vpos to chart.key.position.y + */ + if (typeof(obj.Get('chart.key.vpos')) == 'number') { + obj.Set('chart.key.position.y', obj.Get('chart.key.vpos') * gutter); + } + + if (keypos && keypos == 'gutter') { + + RGraph.DrawKey_gutter(obj, key, colors); + + + /** + * In-graph style key + */ + } else if (keypos && keypos == 'graph') { + + RGraph.DrawKey_graph(obj, key, colors); + + } else { + alert('[COMMON] (' + obj.id + ') Unknown key position: ' + keypos); + } + } + + + + + + /** + * This does the actual drawing of the key when it's in the graph + * + * @param object obj The graph object + * @param array key The key items to draw + * @param array colors An aray of colors that the key will use + */ + RGraph.DrawKey_graph = function (obj, key, colors) + { + var canvas = obj.canvas; + var context = obj.context; + var text_size = typeof(obj.Get('chart.key.text.size')) == 'number' ? obj.Get('chart.key.text.size') : obj.Get('chart.text.size'); + var text_font = obj.Get('chart.text.font'); + var gutter = obj.Get('chart.gutter'); + var hpos = obj.Get('chart.yaxispos') == 'right' ? gutter + 10 : canvas.width - gutter - 10; + var vpos = gutter + 10; + var title = obj.Get('chart.title'); + var blob_size = text_size; // The blob of color + var hmargin = 8; // This is the size of the gaps between the blob of color and the text + var vmargin = 4; // This is the vertical margin of the key + var fillstyle = obj.Get('chart.key.background'); + var strokestyle = 'black'; + var height = 0; + var width = 0; + + + // Need to set this so that measuring the text works out OK + context.font = text_size + 'pt ' + obj.Get('chart.text.font'); + + // Work out the longest bit of text + for (i=0; i=0; i--) { + var j = Number(i) + 1; + + // Draw the blob of color + if (obj.Get('chart.key.color.shape') == 'circle') { + context.beginPath(); + context.strokeStyle = 'rgba(0,0,0,0)'; + context.fillStyle = colors[i]; + context.arc(hpos + 5 + (blob_size / 2), vpos + (5 * j) + (text_size * j) - text_size + (blob_size / 2), blob_size / 2, 0, 6.26, 0); + context.fill(); + + } else if (obj.Get('chart.key.color.shape') == 'line') { + context.beginPath(); + context.strokeStyle = colors[i]; + context.moveTo(hpos + 5, vpos + (5 * j) + (text_size * j) - text_size + (blob_size / 2)); + context.lineTo(hpos + blob_size + 5, vpos + (5 * j) + (text_size * j) - text_size + (blob_size / 2)); + context.stroke(); + + } else { + context.fillStyle = colors[i]; + context.fillRect(hpos + 5, vpos + (5 * j) + (text_size * j) - text_size, text_size, text_size + 1); + } + + context.beginPath(); + + context.fillStyle = 'black'; + + RGraph.Text(context, + text_font, + text_size, + hpos + blob_size + 5 + 5, + vpos + (5 * j) + (text_size * j), + key[i]); + } + context.fill(); + } + + + + + + + /** + * This does the actual drawing of the key when it's in the gutter + * + * @param object obj The graph object + * @param array key The key items to draw + * @param array colors An aray of colors that the key will use + */ + RGraph.DrawKey_gutter = function (obj, key, colors) + { + var canvas = obj.canvas; + var context = obj.context; + var text_size = typeof(obj.Get('chart.key.text.size')) == 'number' ? obj.Get('chart.key.text.size') : obj.Get('chart.text.size'); + var text_font = obj.Get('chart.text.font'); + var gutter = obj.Get('chart.gutter'); + var hpos = canvas.width / 2; + var vpos = (gutter / 2) - 5; + var title = obj.Get('chart.title'); + var blob_size = text_size; // The blob of color + var hmargin = 8; // This is the size of the gaps between the blob of color and the text + var vmargin = 4; // This is the vertical margin of the key + var fillstyle = obj.Get('chart.key.background'); + var strokestyle = 'black'; + var length = 0; + + + + // Need to work out the length of the key first + context.font = text_size + 'pt ' + text_font; + for (i=0; i=0; i--) { + newarr.push(arr[i]); + } + + return newarr; + } + + + /** + * Formats a number with thousand seperators so it's easier to read + * + * @param integer num The number to format + * @param string The (optional) string to prepend to the string + * @param string The (optional) string to ap + * pend to the string + * @return string The formatted number + */ + RGraph.number_format = function (obj, num) + { + var i; + var prepend = arguments[2] ? String(arguments[2]) : ''; + var append = arguments[3] ? String(arguments[3]) : ''; + var output = ''; + var decimal = ''; + var decimal_seperator = obj.Get('chart.scale.point') ? obj.Get('chart.scale.point') : '.'; + var thousand_seperator = obj.Get('chart.scale.thousand') ? obj.Get('chart.scale.thousand') : ','; + RegExp.$1 = ''; + var i,j; + + // Ignore the preformatted version of "1e-2" + if (String(num).indexOf('e') > 0) { + return String(prepend + String(num) + append); + } + + // We need then number as a string + num = String(num); + + // Take off the decimal part - we re-append it later + if (num.indexOf('.') > 0) { + num = num.replace(/\.(.*)/, ''); + decimal = RegExp.$1; + } + + // Thousand seperator + //var seperator = arguments[1] ? String(arguments[1]) : ','; + var seperator = thousand_seperator; + + /** + * Work backwards adding the thousand seperators + */ + var foundPoint; + for (i=(num.length - 1),j=0; i>=0; j++,i--) { + var character = num.charAt(i); + + if ( j % 3 == 0 && j != 0) { + output += seperator; + } + + /** + * Build the output + */ + output += character; + } + + /** + * Now need to reverse the string + */ + var rev = output; + output = ''; + for (i=(rev.length - 1); i>=0; i--) { + output += rev.charAt(i); + } + + // Tidy up + output = output.replace(/^-,/, '-'); + + // Reappend the decimal + if (decimal.length) { + output = output + decimal_seperator + decimal; + decimal = ''; + RegExp.$1 = ''; + } + + // Minor bugette + if (output.charAt(0) == '-') { + output *= -1; + prepend = '-' + prepend; + } + + return prepend + output + append; + } + + + /** + * Draws horizontal coloured bars on something like the bar, line or scatter + */ + RGraph.DrawBars = function (obj) + { + var hbars = obj.Get('chart.background.hbars'); + + /** + * Draws a horizontal bar + */ + obj.context.beginPath(); + + for (i=0; i obj.max) { + hbars[i][1] = obj.max - hbars[i][0]; + } + + + // If height is negative, and the abs() value is greater than .max, use a negative max instead + if (Math.abs(hbars[i][1]) > obj.max) { + hbars[i][1] = -1 * obj.max; + } + + + // If start point is greater than max, change it to max + if (Math.abs(hbars[i][0]) > obj.max) { + hbars[i][0] = obj.max; + } + + // If start point plus height is less than negative max, use the negative max plus the start point + if (hbars[i][0] + hbars[i][1] < (-1 * obj.max) ) { + hbars[i][1] = -1 * (obj.max + hbars[i][0]); + } + + // If the X axis is at the bottom, and a negative max is given, warn the user + if (obj.Get('chart.xaxispos') == 'bottom' && (hbars[i][0] < 0 || (hbars[i][1] + hbars[i][1] < 0)) ) { + alert('[' + obj.type.toUpperCase() + ' (ID: ' + obj.id + ') BACKGROUND HBARS] You have a negative value in one of your background hbars values, whilst the X axis is in the center'); + } + + var ystart = (obj.grapharea - ((hbars[i][0] / obj.max) * obj.grapharea)); + var height = (Math.min(hbars[i][1], obj.max - hbars[i][0]) / obj.max) * obj.grapharea; + + // Account for the X axis being in the center + if (obj.Get('chart.xaxispos') == 'center') { + ystart /= 2; + height /= 2; + } + + ystart += obj.Get('chart.gutter') + + var x = obj.Get('chart.gutter'); + var y = ystart - height; + var w = obj.canvas.width - (2 * obj.Get('chart.gutter')); + var h = height; + + // Accommodate Opera :-/ + if (navigator.userAgent.indexOf('Opera') != -1 && obj.Get('chart.xaxispos') == 'center' && h < 0) { + h *= -1; + y = y - h; + } + + obj.context.fillStyle = hbars[i][2]; + obj.context.fillRect(x, y, w, h); + } + + obj.context.fill(); + } + + + /** + * Draws in-graph labels. + * + * @param object obj The graph object + */ + RGraph.DrawInGraphLabels = function (obj) + { + var canvas = obj.canvas; + var context = obj.context; + var labels = obj.Get('chart.labels.ingraph'); + var labels_processed = []; + + // Defaults + var fgcolor = 'black'; + var bgcolor = 'white'; + var direction = 1; + + if (!labels) { + return; + } + + /** + * Preprocess the labels array. Numbers are expanded + */ + for (var i=0; i 0) { + + for (var i=0; i 0) { + var x = (obj.type == 'bar' ? coords[0] + (coords[2] / 2) : coords[0]); + var y = (obj.type == 'bar' ? coords[1] + (coords[3] / 2) : coords[1]); + var length = typeof(labels_processed[i][4]) == 'number' ? labels_processed[i][4] : 25; + + context.beginPath(); + context.fillStyle = 'black'; + context.strokeStyle = 'black'; + + + if (obj.type == 'bar') { + + if (obj.Get('chart.variant') == 'dot') { + context.moveTo(x, obj.coords[i][1] - 5); + context.lineTo(x, obj.coords[i][1] - 5 - length); + + var text_x = x; + var text_y = obj.coords[i][1] - 5 - length; + + } else if (obj.Get('chart.variant') == 'arrow') { + context.moveTo(x, obj.coords[i][1] - 5); + context.lineTo(x, obj.coords[i][1] - 5 - length); + + var text_x = x; + var text_y = obj.coords[i][1] - 5 - length; + + } else { + + context.arc(x, y, 2.5, 0, 6.28, 0); + context.moveTo(x, y); + context.lineTo(x, y - length); + + var text_x = x; + var text_y = y - length; + } + + context.stroke(); + context.fill(); + + + } else if (obj.type == 'line') { + + if ( + typeof(labels_processed[i]) == 'object' && + typeof(labels_processed[i][3]) == 'number' && + labels_processed[i][3] == -1 + ) { + + context.moveTo(x, y + 5); + context.lineTo(x, y + 5 + length); + + context.stroke(); + context.beginPath(); + + // This draws the arrow + context.moveTo(x, y + 5); + context.lineTo(x - 3, y + 10); + context.lineTo(x + 3, y + 10); + context.closePath(); + + var text_x = x; + var text_y = y + 5 + length; + + } else { + + var text_x = x; + var text_y = y - 5 - length; + + context.moveTo(x, y - 5); + context.lineTo(x, y - 5 - length); + + context.stroke(); + context.beginPath(); + + // This draws the arrow + context.moveTo(x, y - 5); + context.lineTo(x - 3, y - 10); + context.lineTo(x + 3, y - 10); + context.closePath(); + } + + context.fill(); + } + + + // Taken out on the 10th Nov 2010 - unnecessary + //var width = context.measureText(labels[i]).width; + + context.beginPath(); + + // Fore ground color + context.fillStyle = (typeof(labels_processed[i]) == 'object' && typeof(labels_processed[i][1]) == 'string') ? labels_processed[i][1] : 'black'; + + RGraph.Text(context, + obj.Get('chart.text.font'), + obj.Get('chart.text.size'), + text_x, + text_y, + (typeof(labels_processed[i]) == 'object' && typeof(labels_processed[i][0]) == 'string') ? labels_processed[i][0] : labels_processed[i], + 'bottom', + 'center', + true, + null, + (typeof(labels_processed[i]) == 'object' && typeof(labels_processed[i][2]) == 'string') ? labels_processed[i][2] : 'white'); + context.fill(); + } + } + } + } + } + + + /** + * This function "fills in" key missing properties that various implementations lack + * + * @param object e The event object + */ + RGraph.FixEventObject = function (e) + { + if (RGraph.isIE8()) { + + var e = event; + + e.pageX = (event.clientX + document.body.scrollLeft); + e.pageY = (event.clientY + document.body.scrollTop); + e.target = event.srcElement; + + if (!document.body.scrollTop && document.documentElement.scrollTop) { + e.pageX += parseInt(document.documentElement.scrollLeft); + e.pageY += parseInt(document.documentElement.scrollTop); + } + } + + // This is mainly for FF which doesn't provide offsetX + if (typeof(e.offsetX) == 'undefined' && typeof(e.offsetY) == 'undefined') { + var coords = RGraph.getMouseXY(e); + e.offsetX = coords[0]; + e.offsetY = coords[1]; + } + + // Any browser that doesn't implement stopPropagation() (MSIE) + if (!e.stopPropagation) { + e.stopPropagation = function () {window.event.cancelBubble = true;} + } + + return e; + } + + + /** + * Draw crosshairs if enabled + * + * @param object obj The graph object (from which we can get the context and canvas as required) + */ + RGraph.DrawCrosshairs = function (obj) + { + if (obj.Get('chart.crosshairs')) { + var canvas = obj.canvas; + var context = obj.context; + + // 5th November 2010 - removed now that tooltips are DOM2 based. + //if (obj.Get('chart.tooltips') && obj.Get('chart.tooltips').length > 0) { + //alert('[' + obj.type.toUpperCase() + '] Sorry - you cannot have crosshairs enabled with tooltips! Turning off crosshairs...'); + //obj.Set('chart.crosshairs', false); + //return; + //} + + canvas.onmousemove = function (e) + { + var e = RGraph.FixEventObject(e); + var canvas = obj.canvas; + var context = obj.context; + var gutter = obj.Get('chart.gutter'); + var width = canvas.width; + var height = canvas.height; + var adjustments = obj.Get('chart.tooltips.coords.adjust'); + + var mouseCoords = RGraph.getMouseXY(e); + var x = mouseCoords[0]; + var y = mouseCoords[1]; + + if (typeof(adjustments) == 'object' && adjustments[0] && adjustments[1]) { + x = x - adjustments[0]; + y = y - adjustments[1]; + } + + RGraph.Clear(canvas); + obj.Draw(); + + if ( x >= gutter + && y >= gutter + && x <= (width - gutter) + && y <= (height - gutter) + ) { + + var linewidth = obj.Get('chart.crosshairs.linewidth'); + context.lineWidth = linewidth ? linewidth : 1; + + context.beginPath(); + context.strokeStyle = obj.Get('chart.crosshairs.color'); + + // Draw a top vertical line + context.moveTo(x, gutter); + context.lineTo(x, height - gutter); + + // Draw a horizontal line + context.moveTo(gutter, y); + context.lineTo(width - gutter, y); + + context.stroke(); + + /** + * Need to show the coords? + */ + if (obj.Get('chart.crosshairs.coords')) { + if (obj.type == 'scatter') { + + var xCoord = (((x - obj.Get('chart.gutter')) / (obj.canvas.width - (2 * obj.Get('chart.gutter')))) * (obj.Get('chart.xmax') - obj.Get('chart.xmin'))) + obj.Get('chart.xmin'); + xCoord = xCoord.toFixed(obj.Get('chart.scale.decimals')); + var yCoord = obj.max - (((y - obj.Get('chart.gutter')) / (obj.canvas.height - (2 * obj.Get('chart.gutter')))) * obj.max); + + if (obj.type == 'scatter' && obj.Get('chart.xaxispos') == 'center') { + yCoord = (yCoord - (obj.max / 2)) * 2; + } + + yCoord = yCoord.toFixed(obj.Get('chart.scale.decimals')); + var div = RGraph.Registry.Get('chart.coordinates.coords.div'); + var mouseCoords = RGraph.getMouseXY(e); + var canvasXY = RGraph.getCanvasXY(canvas); + + if (!div) { + + div = document.createElement('DIV'); + div.__object__ = obj; + div.style.position = 'absolute'; + div.style.backgroundColor = 'white'; + div.style.border = '1px solid black'; + div.style.fontFamily = 'Arial, Verdana, sans-serif'; + div.style.fontSize = '10pt' + div.style.padding = '2px'; + div.style.opacity = 1; + div.style.WebkitBorderRadius = '3px'; + div.style.borderRadius = '3px'; + div.style.MozBorderRadius = '3px'; + document.body.appendChild(div); + + RGraph.Registry.Set('chart.coordinates.coords.div', div); + } + + // Convert the X/Y pixel coords to correspond to the scale + + div.style.opacity = 1; + div.style.display = 'inline'; + + if (!obj.Get('chart.crosshairs.coords.fixed')) { + div.style.left = Math.max(2, (e.pageX - div.offsetWidth - 3)) + 'px'; + div.style.top = Math.max(2, (e.pageY - div.offsetHeight - 3)) + 'px'; + } else { + div.style.left = canvasXY[0] + obj.Get('chart.gutter') + 3 + 'px'; + div.style.top = canvasXY[1] + obj.Get('chart.gutter') + 3 + 'px'; + } + + div.innerHTML = '' + obj.Get('chart.crosshairs.coords.labels.x') + ': ' + xCoord + '
    ' + obj.Get('chart.crosshairs.coords.labels.y') + ': ' + yCoord; + + canvas.addEventListener('mouseout', RGraph.HideCrosshairCoords, false); + + } else { + alert('[RGRAPH] Showing crosshair coordinates is only supported on the Scatter chart'); + } + } + } else { + RGraph.HideCrosshairCoords(); + } + } + } + } + + /** + * Thisz function hides the crosshairs coordinates + */ + RGraph.HideCrosshairCoords = function () + { + var div = RGraph.Registry.Get('chart.coordinates.coords.div'); + + if ( div + && div.style.opacity == 1 + && div.__object__.Get('chart.crosshairs.coords.fadeout') + ) { + setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.9;}, 50); + setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.8;}, 100); + setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.7;}, 150); + setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.6;}, 200); + setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.5;}, 250); + setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.4;}, 300); + setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.3;}, 350); + setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.2;}, 400); + setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0.1;}, 450); + setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.opacity = 0;}, 500); + setTimeout(function() {RGraph.Registry.Get('chart.coordinates.coords.div').style.display = 'none';}, 550); + } + } + + + /** + * Trims the right hand side of a string. Removes SPACE, TAB + * CR and LF. + * + * @param string str The string to trim + */ + RGraph.rtrim = function (str) + { + return str.replace(/( |\n|\r|\t)+$/, ''); + } + + + /** + * Draws the3D axes/background + */ + RGraph.Draw3DAxes = function (obj) + { + var gutter = obj.Get('chart.gutter'); + var context = obj.context; + var canvas = obj.canvas; + + context.strokeStyle = '#aaa'; + context.fillStyle = '#ddd'; + + // Draw the vertical left side + context.beginPath(); + context.moveTo(gutter, gutter); + context.lineTo(gutter + 10, gutter - 5); + context.lineTo(gutter + 10, canvas.height - gutter - 5); + context.lineTo(gutter, canvas.height - gutter); + context.closePath(); + + context.stroke(); + context.fill(); + + // Draw the bottom floor + context.beginPath(); + context.moveTo(gutter, canvas.height - gutter); + context.lineTo(gutter + 10, canvas.height - gutter - 5); + context.lineTo(canvas.width - gutter + 10, canvas.height - gutter - 5); + context.lineTo(canvas.width - gutter, canvas.height - gutter); + context.closePath(); + + context.stroke(); + context.fill(); + } + + /** + * Turns off any shadow + * + * @param object obj The graph object + */ + RGraph.NoShadow = function (obj) + { + obj.context.shadowColor = 'rgba(0,0,0,0)'; + obj.context.shadowBlur = 0; + obj.context.shadowOffsetX = 0; + obj.context.shadowOffsetY = 0; + } + + + /** + * Sets the four shadow properties - a shortcut function + * + * @param object obj Your graph object + * @param string color The shadow color + * @param number offsetx The shadows X offset + * @param number offsety The shadows Y offset + * @param number blur The blurring effect applied to the shadow + */ + RGraph.SetShadow = function (obj, color, offsetx, offsety, blur) + { + obj.context.shadowColor = color; + obj.context.shadowOffsetX = offsetx; + obj.context.shadowOffsetY = offsety; + obj.context.shadowBlur = blur; + } + + + /** + * This function attempts to "fill in" missing functions from the canvas + * context object. Only two at the moment - measureText() nd fillText(). + * + * @param object context The canvas 2D context + */ + RGraph.OldBrowserCompat = function (context) + { + if (!context.measureText) { + + // This emulates the measureText() function + context.measureText = function (text) + { + var textObj = document.createElement('DIV'); + textObj.innerHTML = text; + textObj.style.backgroundColor = 'white'; + textObj.style.position = 'absolute'; + textObj.style.top = -100 + textObj.style.left = 0; + document.body.appendChild(textObj); + + var width = {width: textObj.offsetWidth}; + + textObj.style.display = 'none'; + + return width; + } + } + + if (!context.fillText) { + // This emulates the fillText() method + context.fillText = function (text, targetX, targetY) + { + return false; + } + } + + // If IE8, add addEventListener() + if (!context.canvas.addEventListener) { + window.addEventListener = function (ev, func, bubble) + { + return this.attachEvent('on' + ev, func); + } + + context.canvas.addEventListener = function (ev, func, bubble) + { + return this.attachEvent('on' + ev, func); + } + } + } + + + /** + * This function is for use with circular graph types, eg the Pie or Radar. Pass it your event object + * and it will pass you back the corresponding segment details as an array: + * + * [x, y, r, startAngle, endAngle] + * + * Angles are measured in degrees, and are measured from the "east" axis (just like the canvas). + * + * @param object e Your event object + */ + RGraph.getSegment = function (e) + { + RGraph.FixEventObject(e); + + // The optional arg provides a way of allowing some accuracy (pixels) + var accuracy = arguments[1] ? arguments[1] : 0; + + var obj = e.target.__object__; + var canvas = obj.canvas; + var context = obj.context; + var mouseCoords = RGraph.getMouseXY(e); + var x = mouseCoords[0] - obj.centerx; + var y = mouseCoords[1] - obj.centery; + var r = obj.radius; + var theta = Math.atan(y / x); // RADIANS + var hyp = y / Math.sin(theta); + var angles = obj.angles; + var ret = []; + var hyp = (hyp < 0) ? hyp + accuracy : hyp - accuracy; + + + // Put theta in DEGREES + theta *= 57.3 + + // hyp should not be greater than radius if it's a Rose chart + if (obj.type == 'rose') { + if ( (isNaN(hyp) && Math.abs(mouseCoords[0]) < (obj.centerx - r) ) + || (isNaN(hyp) && Math.abs(mouseCoords[0]) > (obj.centerx + r)) + || (!isNaN(hyp) && Math.abs(hyp) > r)) { + return; + } + } + + /** + * Account for the correct quadrant + */ + if (x < 0 && y >= 0) { + theta += 180; + } else if (x < 0 && y < 0) { + theta += 180; + } else if (x > 0 && y < 0) { + theta += 360; + } + + /** + * Account for the rose chart + */ + if (obj.type == 'rose') { + theta += 90; + } + + if (theta > 360) { + theta -= 360; + } + + for (var i=0; i= angles[i][0] && theta < angles[i][1]) { + + hyp = Math.abs(hyp); + + if (obj.type == 'rose' && hyp > angles[i][2]) { + return null; + } + + if (!hyp || (obj.type == 'pie' && obj.radius && hyp > obj.radius) ) { + return null; + } + + if (obj.type == 'pie' && obj.Get('chart.variant') == 'donut' && (hyp > obj.radius || hyp < (obj.radius / 2) ) ) { + return null; + } + + ret[0] = obj.centerx; + ret[1] = obj.centery; + ret[2] = (obj.type == 'rose') ? angles[i][2] : obj.radius; + ret[3] = angles[i][0]; + ret[4] = angles[i][1]; + ret[5] = i; + + if (obj.type == 'rose') { + + ret[3] -= 90; + ret[4] -= 90; + + if (x > 0 && y < 0) { + ret[3] += 360; + ret[4] += 360; + } + } + + if (ret[3] < 0) ret[3] += 360; + if (ret[4] > 360) ret[4] -= 360; + + return ret; + } + } + + return null; + } + + + /** + * This is a function that can be used to run code asynchronously, which can + * be used to speed up the loading of you pages. + * + * @param string func This is the code to run. It can also be a function pointer. + * The front page graphs show this function in action. Basically + * each graphs code is made in a function, and that function is + * passed to this function to run asychronously. + */ + RGraph.Async = function (func) + { + return setTimeout(func, arguments[1] ? arguments[1] : 1); + } + + + /** + * A custom random number function + * + * @param number min The minimum that the number should be + * @param number max The maximum that the number should be + * @param number How many decimal places there should be. Default for this is 0 + */ + RGraph.random = function (min, max) + { + var dp = arguments[2] ? arguments[2] : 0; + var r = Math.random(); + + return Number((((max - min) * r) + min).toFixed(dp)); + } + + + /** + * Draws a rectangle with curvy corners + * + * @param context object The context + * @param x number The X coordinate (top left of the square) + * @param y number The Y coordinate (top left of the square) + * @param w number The width of the rectangle + * @param h number The height of the rectangle + * @param number The radius of the curved corners + * @param boolean Whether the top left corner is curvy + * @param boolean Whether the top right corner is curvy + * @param boolean Whether the bottom right corner is curvy + * @param boolean Whether the bottom left corner is curvy + */ + RGraph.strokedCurvyRect = function (context, x, y, w, h) + { + // The corner radius + var r = arguments[5] ? arguments[5] : 3; + + // The corners + var corner_tl = (arguments[6] || arguments[6] == null) ? true : false; + var corner_tr = (arguments[7] || arguments[7] == null) ? true : false; + var corner_br = (arguments[8] || arguments[8] == null) ? true : false; + var corner_bl = (arguments[9] || arguments[9] == null) ? true : false; + + context.beginPath(); + + // Top left side + context.moveTo(x + (corner_tl ? r : 0), y); + context.lineTo(x + w - (corner_tr ? r : 0), y); + + // Top right corner + if (corner_tr) { + context.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2, false); + } + + // Top right side + context.lineTo(x + w, y + h - (corner_br ? r : 0) ); + + // Bottom right corner + if (corner_br) { + context.arc(x + w - r, y - r + h, r, Math.PI * 2, Math.PI * 0.5, false); + } + + // Bottom right side + context.lineTo(x + (corner_bl ? r : 0), y + h); + + // Bottom left corner + if (corner_bl) { + context.arc(x + r, y - r + h, r, Math.PI * 0.5, Math.PI, false); + } + + // Bottom left side + context.lineTo(x, y + (corner_tl ? r : 0) ); + + // Top left corner + if (corner_tl) { + context.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5, false); + } + + context.stroke(); + } + + + /** + * Draws a filled rectangle with curvy corners + * + * @param context object The context + * @param x number The X coordinate (top left of the square) + * @param y number The Y coordinate (top left of the square) + * @param w number The width of the rectangle + * @param h number The height of the rectangle + * @param number The radius of the curved corners + * @param boolean Whether the top left corner is curvy + * @param boolean Whether the top right corner is curvy + * @param boolean Whether the bottom right corner is curvy + * @param boolean Whether the bottom left corner is curvy + */ + RGraph.filledCurvyRect = function (context, x, y, w, h) + { + // The corner radius + var r = arguments[5] ? arguments[5] : 3; + + // The corners + var corner_tl = (arguments[6] || arguments[6] == null) ? true : false; + var corner_tr = (arguments[7] || arguments[7] == null) ? true : false; + var corner_br = (arguments[8] || arguments[8] == null) ? true : false; + var corner_bl = (arguments[9] || arguments[9] == null) ? true : false; + + context.beginPath(); + + // First draw the corners + + // Top left corner + if (corner_tl) { + context.moveTo(x + r, y + r); + context.arc(x + r, y + r, r, Math.PI, 1.5 * Math.PI, false); + } else { + context.fillRect(x, y, r, r); + } + + // Top right corner + if (corner_tr) { + context.moveTo(x + w - r, y + r); + context.arc(x + w - r, y + r, r, 1.5 * Math.PI, 0, false); + } else { + context.moveTo(x + w - r, y); + context.fillRect(x + w - r, y, r, r); + } + + + // Bottom right corner + if (corner_br) { + context.moveTo(x + w - r, y + h - r); + context.arc(x + w - r, y - r + h, r, 0, Math.PI / 2, false); + } else { + context.moveTo(x + w - r, y + h - r); + context.fillRect(x + w - r, y + h - r, r, r); + } + + // Bottom left corner + if (corner_bl) { + context.moveTo(x + r, y + h - r); + context.arc(x + r, y - r + h, r, Math.PI / 2, Math.PI, false); + } else { + context.moveTo(x, y + h - r); + context.fillRect(x, y + h - r, r, r); + } + + // Now fill it in + context.fillRect(x + r, y, w - r - r, h); + context.fillRect(x, y + r, r + 1, h - r - r); + context.fillRect(x + w - r - 1, y + r, r + 1, h - r - r); + + context.fill(); + } + + + /** + * A crude timing function + * + * @param string label The label to use for the time + */ + RGraph.Timer = function (label) + { + var d = new Date(); + + // This uses the Firebug console + console.log(label + ': ' + d.getSeconds() + '.' + d.getMilliseconds()); + } + + + /** + * Hides the palette if it's visible + */ + RGraph.HidePalette = function () + { + var div = RGraph.Registry.Get('palette'); + + if (typeof(div) == 'object' && div) { + div.style.visibility = 'hidden'; + div.style.display = 'none'; + RGraph.Registry.Set('palette', null); + } + } + + + /** + * Hides the zoomed canvas + */ + RGraph.HideZoomedCanvas = function () + { + if (typeof(__zoomedimage__) == 'object') { + obj = __zoomedimage__.obj; + } else { + return; + } + + if (obj.Get('chart.zoom.fade.out')) { + for (var i=10,j=1; i>=0; --i, ++j) { + if (typeof(__zoomedimage__) == 'object') { + setTimeout("__zoomedimage__.style.opacity = " + String(i / 10), j * 30); + } + } + + if (typeof(__zoomedbackground__) == 'object') { + setTimeout("__zoomedbackground__.style.opacity = " + String(i / 10), j * 30); + } + } + + if (typeof(__zoomedimage__) == 'object') { + setTimeout("__zoomedimage__.style.display = 'none'", obj.Get('chart.zoom.fade.out') ? 310 : 0); + } + + if (typeof(__zoomedbackground__) == 'object') { + setTimeout("__zoomedbackground__.style.display = 'none'", obj.Get('chart.zoom.fade.out') ? 310 : 0); + } + } + + + /** + * Adds an event handler + * + * @param object obj The graph object + * @param string event The name of the event, eg ontooltip + * @param object func The callback function + */ + RGraph.AddCustomEventListener = function (obj, name, func) + { + if (typeof(RGraph.events[obj.id]) == 'undefined') { + RGraph.events[obj.id] = []; + } + + RGraph.events[obj.id].push([obj, name, func]); + } + + + /** + * Used to fire one of the RGraph custom events + * + * @param object obj The graph object that fires the event + * @param string event The name of the event to fire + */ + RGraph.FireCustomEvent = function (obj, name) + { + for (i in RGraph.events) { + if (typeof(i) == 'string' && i == obj.id && RGraph.events[i].length > 0) { + for(var j=0; j 0; + } + + + /** + * Checks the browser for traces of MSIE9 + */ + RGraph.isIE9 = function () + { + return navigator.userAgent.indexOf('MSIE 9') > 0; + } + + + /** + * Checks the browser for traces of MSIE9 + */ + RGraph.isIE9up = function () + { + navigator.userAgent.match(/MSIE (\d+)/); + + return Number(RegExp.$1) >= 9; + } + + + /** + * This clears a canvases event handlers. + * + * @param string id The ID of the canvas whose event handlers will be cleared + */ + RGraph.ClearEventListeners = function (id) + { + for (var i=0; i str.length ? obj.Get('chart.labels')[i] : str); + } + } + + obj.context.font = obj.Get('chart.text.size') + 'pt ' + obj.Get('chart.text.font'); + + len = obj.context.measureText(str).width + 5; + + return (obj.type == 'hbar' ? len / 3 : len); + } + + + /** + * A basic Array shift gunction + * + * @param object The numerical array to work on + * @return The new array + */ + RGraph.array_shift = function (arr) + { + var ret = []; + + for (var i=1; i document.body.offsetWidth ? RGraph.Registry.Get('chart.tooltip').offsetWidth : 0); + var diffy = y - currenty - RGraph.Registry.Get('chart.tooltip').offsetHeight; + + // Position the tooltip + setTimeout('RGraph.Registry.Get("chart.tooltip").style.left = "' + (currentx + (diffx * 0.2)) + 'px"', 25); + setTimeout('RGraph.Registry.Get("chart.tooltip").style.left = "' + (currentx + (diffx * 0.4)) + 'px"', 50); + setTimeout('RGraph.Registry.Get("chart.tooltip").style.left = "' + (currentx + (diffx * 0.6)) + 'px"', 75); + setTimeout('RGraph.Registry.Get("chart.tooltip").style.left = "' + (currentx + (diffx * 0.8)) + 'px"', 100); + setTimeout('RGraph.Registry.Get("chart.tooltip").style.left = "' + (currentx + (diffx * 1.0)) + 'px"', 125); + + setTimeout('RGraph.Registry.Get("chart.tooltip").style.top = "' + (currenty + (diffy * 0.2)) + 'px"', 25); + setTimeout('RGraph.Registry.Get("chart.tooltip").style.top = "' + (currenty + (diffy * 0.4)) + 'px"', 50); + setTimeout('RGraph.Registry.Get("chart.tooltip").style.top = "' + (currenty + (diffy * 0.6)) + 'px"', 75); + setTimeout('RGraph.Registry.Get("chart.tooltip").style.top = "' + (currenty + (diffy * 0.8)) + 'px"', 100); + setTimeout('RGraph.Registry.Get("chart.tooltip").style.top = "' + (currenty + (diffy * 1.0)) + 'px"', 125); + + } else { + + alert('[TOOLTIPS] The "snap" effect is only supported on the Line, Rscatter, Scatter and Tradar charts'); + } + + /** + * Fire the tooltip event + */ + RGraph.FireCustomEvent(canvas.__object__, 'ontooltip'); + + return; + } + + /** + * Hide any currently shown tooltip + */ + RGraph.HideTooltip(); + + + /** + * Show a tool tip + */ + var tooltipObj = document.createElement('DIV'); + tooltipObj.className = canvas.__object__.Get('chart.tooltips.css.class'); + tooltipObj.style.display = 'none'; + tooltipObj.style.position = 'absolute'; + tooltipObj.style.left = 0; + tooltipObj.style.top = 0; + tooltipObj.style.backgroundColor = '#ffe'; + tooltipObj.style.color = 'black'; + if (!document.all) tooltipObj.style.border = '1px solid rgba(0,0,0,0)'; + tooltipObj.style.visibility = 'visible'; + tooltipObj.style.paddingLeft = RGraph.tooltips.padding; + tooltipObj.style.paddingRight = RGraph.tooltips.padding; + tooltipObj.style.fontFamily = RGraph.tooltips.font_face; + tooltipObj.style.fontSize = RGraph.tooltips.font_size; + tooltipObj.style.zIndex = 3; + tooltipObj.style.borderRadius = '5px'; + tooltipObj.style.MozBorderRadius = '5px'; + tooltipObj.style.WebkitBorderRadius = '5px'; + tooltipObj.style.WebkitBoxShadow = 'rgba(96,96,96,0.5) 3px 3px 3px'; + tooltipObj.style.MozBoxShadow = 'rgba(96,96,96,0.5) 3px 3px 3px'; + tooltipObj.style.boxShadow = 'rgba(96,96,96,0.5) 3px 3px 3px'; + tooltipObj.style.filter = 'progid:DXImageTransform.Microsoft.Shadow(color=#666666,direction=135)'; + tooltipObj.style.opacity = 0; + tooltipObj.style.overflow = 'hidden'; + tooltipObj.innerHTML = text; + tooltipObj.__text__ = text; // This is set because the innerHTML can change when it's set + tooltipObj.__canvas__ = canvas; + tooltipObj.style.display = 'inline'; + + if (typeof(idx) == 'number') { + tooltipObj.__index__ = idx; + } + + document.body.appendChild(tooltipObj); + + var width = tooltipObj.offsetWidth; + var height = tooltipObj.offsetHeight - (RGraph.isIE9up() ? 7 : 0); + + if ((y - height - 2) > 0) { + y = y - height - 2; + } else { + y = y + 2; + } + + /** + * Set the width on the tooltip so it doesn't resize if the window is resized + */ + tooltipObj.style.width = width + 'px'; + //tooltipObj.style.height = 0; // Initially set the tooltip height to nothing + + /** + * If the mouse is towards the right of the browser window and the tooltip would go outside of the window, + * move it left + */ + if ( (x + width) > document.body.offsetWidth ) { + x = x - width - 7; + var placementLeft = true; + + if (canvas.__object__.Get('chart.tooltips.effect') == 'none') { + x = x - 3; + } + + tooltipObj.style.left = x + 'px'; + tooltipObj.style.top = y + 'px'; + + } else { + x += 5; + + tooltipObj.style.left = x + 'px'; + tooltipObj.style.top = y + 'px'; + } + + + if (effect == 'expand') { + + tooltipObj.style.left = (x + (width / 2)) + 'px'; + tooltipObj.style.top = (y + (height / 2)) + 'px'; + leftDelta = (width / 2) / 10; + topDelta = (height / 2) / 10; + + tooltipObj.style.width = 0; + tooltipObj.style.height = 0; + tooltipObj.style.boxShadow = ''; + tooltipObj.style.MozBoxShadow = ''; + tooltipObj.style.WebkitBoxShadow = ''; + tooltipObj.style.borderRadius = 0; + tooltipObj.style.MozBorderRadius = 0; + tooltipObj.style.WebkitBorderRadius = 0; + tooltipObj.style.opacity = 1; + + // Progressively move the tooltip to where it should be (the x position) + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) - leftDelta) + 'px' }", 25)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) - leftDelta) + 'px' }", 50)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) - leftDelta) + 'px' }", 75)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) - leftDelta) + 'px' }", 100)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) - leftDelta) + 'px' }", 125)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) - leftDelta) + 'px' }", 150)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) - leftDelta) + 'px' }", 175)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) - leftDelta) + 'px' }", 200)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) - leftDelta) + 'px' }", 225)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) - leftDelta) + 'px' }", 250)); + + // Progressively move the tooltip to where it should be (the Y position) + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) - topDelta) + 'px' }", 25)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) - topDelta) + 'px' }", 50)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) - topDelta) + 'px' }", 75)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) - topDelta) + 'px' }", 100)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) - topDelta) + 'px' }", 125)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) - topDelta) + 'px' }", 150)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) - topDelta) + 'px' }", 175)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) - topDelta) + 'px' }", 200)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) - topDelta) + 'px' }", 225)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) - topDelta) + 'px' }", 250)); + + // Progressively grow the tooltip width + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 0.1) + "px'; }", 25)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 0.2) + "px'; }", 50)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 0.3) + "px'; }", 75)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 0.4) + "px'; }", 100)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 0.5) + "px'; }", 125)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 0.6) + "px'; }", 150)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 0.7) + "px'; }", 175)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 0.8) + "px'; }", 200)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 0.9) + "px'; }", 225)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + width + "px'; }", 250)); + + // Progressively grow the tooltip height + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 0.1) + "px'; }", 25)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 0.2) + "px'; }", 50)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 0.3) + "px'; }", 75)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 0.4) + "px'; }", 100)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 0.5) + "px'; }", 125)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 0.6) + "px'; }", 150)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 0.7) + "px'; }", 175)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 0.8) + "px'; }", 200)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 0.9) + "px'; }", 225)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + height + "px'; }", 250)); + + // When the animation is finished, set the tooltip HTML + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').innerHTML = RGraph.Registry.Get('chart.tooltip').__text__; }", 250)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.boxShadow = 'rgba(96,96,96,0.5) 3px 3px 3px'; }", 250)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.MozBoxShadow = 'rgba(96,96,96,0.5) 3px 3px 3px'; }", 250)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.WebkitBoxShadow = 'rgba(96,96,96,0.5) 3px 3px 3px'; }", 250)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.borderRadius = '5px'; }", 250)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.MozBorderRadius = '5px'; }", 250)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.WebkitBorderRadius = '5px'; }", 250)); + + } else if (effect == 'contract') { + + tooltipObj.style.left = (x - width) + 'px'; + tooltipObj.style.top = (y - (height * 2)) + 'px'; + tooltipObj.style.cursor = 'pointer'; + + leftDelta = width / 10; + topDelta = height / 10; + + tooltipObj.style.width = (width * 5) + 'px'; + tooltipObj.style.height = (height * 5) + 'px'; + + tooltipObj.style.opacity = 0.2; + + // Progressively move the tooltip to where it should be (the x position) + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) + leftDelta) + 'px' }", 25)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) + leftDelta) + 'px' }", 50)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) + leftDelta) + 'px' }", 75)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) + leftDelta) + 'px' }", 100)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) + leftDelta) + 'px' }", 125)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) + leftDelta) + 'px' }", 150)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) + leftDelta) + 'px' }", 175)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) + leftDelta) + 'px' }", 200)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) + leftDelta) + 'px' }", 225)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.left = (parseInt(RGraph.Registry.Get('chart.tooltip').style.left) + leftDelta) + 'px' }", 250)); + + // Progressively move the tooltip to where it should be (the Y position) + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) + (topDelta*2)) + 'px' }", 25)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) + (topDelta*2)) + 'px' }", 50)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) + (topDelta*2)) + 'px' }", 75)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) + (topDelta*2)) + 'px' }", 100)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) + (topDelta*2)) + 'px' }", 125)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) + (topDelta*2)) + 'px' }", 150)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) + (topDelta*2)) + 'px' }", 175)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) + (topDelta*2)) + 'px' }", 200)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) + (topDelta*2)) + 'px' }", 225)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.top = (parseInt(RGraph.Registry.Get('chart.tooltip').style.top) + (topDelta*2)) + 'px' }", 250)); + + // Progressively shrink the tooltip width + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 5.5) + "px'; }", 25)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 5.0) + "px'; }", 50)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 4.5) + "px'; }", 75)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 4.0) + "px'; }", 100)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 3.5) + "px'; }", 125)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 3.0) + "px'; }", 150)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 2.5) + "px'; }", 175)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 2.0) + "px'; }", 200)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + (width * 1.5) + "px'; }", 225)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.width = '" + width + "px'; }", 250)); + + // Progressively shrink the tooltip height + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 5.5) + "px'; }", 25)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 5.0) + "px'; }", 50)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 4.5) + "px'; }", 75)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 4.0) + "px'; }", 100)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 3.5) + "px'; }", 125)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 3.0) + "px'; }", 150)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 2.5) + "px'; }", 175)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 2.0) + "px'; }", 200)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + (height * 1.5) + "px'; }", 225)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.height = '" + height + "px'; }", 250)); + + // When the animation is finished, set the tooltip HTML + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').innerHTML = RGraph.Registry.Get('chart.tooltip').__text__; }", 250)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.boxShadow = 'rgba(96,96,96,0.5) 3px 3px 3px'; }", 250)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.MozBoxShadow = 'rgba(96,96,96,0.5) 3px 3px 3px'; }", 250)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.WebkitBoxShadow = 'rgba(96,96,96,0.5) 3px 3px 3px'; }", 250)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.borderRadius = '5px'; }", 250)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.MozBorderRadius = '5px'; }", 250)); + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.WebkitBorderRadius = '5px'; }", 250)); + + /** + * This resets the pointer + */ + RGraph.Registry.Get('chart.tooltip.timers').push(setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.cursor = 'default'; }", 275)); + + + + } else if (effect != 'fade' && effect != 'expand' && effect != 'none' && effect != 'snap' && effect != 'contract') { + alert('[COMMON] Unknown tooltip effect: ' + effect); + } + + if (effect != 'none') { + setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.opacity = 0.1; RGraph.Registry.Get('chart.tooltip').style.border = '1px solid rgba(96,96,96,0.2)'; }", 25); + setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.opacity = 0.2; RGraph.Registry.Get('chart.tooltip').style.border = '1px solid rgba(96,96,96,0.2)'; }", 50); + setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.opacity = 0.3; RGraph.Registry.Get('chart.tooltip').style.border = '1px solid rgba(96,96,96,0.2)'; }", 75); + setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.opacity = 0.4; RGraph.Registry.Get('chart.tooltip').style.border = '1px solid rgba(96,96,96,0.2)'; }", 100); + setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.opacity = 0.5; RGraph.Registry.Get('chart.tooltip').style.border = '1px solid rgba(96,96,96,0.2)'; }", 125); + setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.opacity = 0.6; RGraph.Registry.Get('chart.tooltip').style.border = '1px solid rgba(96,96,96,0.2)'; }", 150); + setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.opacity = 0.7; RGraph.Registry.Get('chart.tooltip').style.border = '1px solid rgba(96,96,96,0.4)'; }", 175); + setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.opacity = 0.8; RGraph.Registry.Get('chart.tooltip').style.border = '1px solid rgba(96,96,96,0.6)'; }", 200); + setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.opacity = 0.9; RGraph.Registry.Get('chart.tooltip').style.border = '1px solid rgba(96,96,96,0.8)'; }", 225); + } + + setTimeout("if (RGraph.Registry.Get('chart.tooltip')) { RGraph.Registry.Get('chart.tooltip').style.opacity = 1;RGraph.Registry.Get('chart.tooltip').style.border = '1px solid rgb(96,96,96)';}", effect == 'none' ? 50 : 250); + + /** + * If the tooltip it self is clicked, cancel it + */ + tooltipObj.onmousedown = function (e) + { + e = RGraph.FixEventObject(e) + e.stopPropagation(); + } + + tooltipObj.onclick = function (e) + { + if (e.button == 0) { + e = RGraph.FixEventObject(e); + e.stopPropagation(); + } + } + + /** + * Install the function for hiding the tooltip. + */ + document.body.onmousedown = function (event) + { + var tooltip = RGraph.Registry.Get('chart.tooltip'); + + if (tooltip) { + RGraph.HideTooltip(); + + // Redraw if highlighting is enabled + if (tooltip.__canvas__.__object__.Get('chart.tooltips.highlight')) { + RGraph.Redraw(); + } + } + } + + /** + * If the window is resized, hide the tooltip + */ + window.onresize = function () + { + var tooltip = RGraph.Registry.Get('chart.tooltip'); + + if (tooltip) { + tooltip.parentNode.removeChild(tooltip); + tooltip.style.display = 'none'; + tooltip.style.visibility = 'hidden'; + RGraph.Registry.Set('chart.tooltip', null); + + // Redraw the graph if necessary + if (canvas.__object__.Get('chart.tooltips.highlight')) { + RGraph.Clear(canvas); + canvas.__object__.Draw(); + } + } + } + + /** + * Keep a reference to the tooltip + */ + RGraph.Registry.Set('chart.tooltip', tooltipObj); + + /** + * Fire the tooltip event + */ + RGraph.FireCustomEvent(canvas.__object__, 'ontooltip'); + } + + + /** + * + */ + RGraph.getTooltipText = function (text) + { + var result = /^id:(.*)/.exec(text); + + if (result) { + text = document.getElementById(result[1]).innerHTML; + } + + return text; + } + + + /** + * + */ + RGraph.getTooltipWidth = function (text, obj) + { + var div = document.createElement('DIV'); + div.className = obj.Get('chart.tooltips.css.class'); + div.style.paddingLeft = RGraph.tooltips.padding; + div.style.paddingRight = RGraph.tooltips.padding; + div.style.fontFamily = RGraph.tooltips.font_face; + div.style.fontSize = RGraph.tooltips.font_size; + div.style.visibility = 'hidden'; + div.style.position = 'absolute'; + div.style.top = '300px'; + div.style.left = 0; + div.style.display = 'inline'; + div.innerHTML = RGraph.getTooltipText(text); + document.body.appendChild(div); + + return div.offsetWidth; + } + + + /** + * Hides the currently shown tooltip + */ + RGraph.HideTooltip = function () + { + var tooltip = RGraph.Registry.Get('chart.tooltip'); + + if (tooltip) { + tooltip.parentNode.removeChild(tooltip); + tooltip.style.display = 'none'; + tooltip.style.visibility = 'hidden'; + RGraph.Registry.Set('chart.tooltip', null); + } + } \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.scatter.js b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.scatter.js new file mode 100644 index 0000000..e87202c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.scatter.js @@ -0,0 +1,1168 @@ + /** + * o------------------------------------------------------------------------------o + * | This file is part of the RGraph package - you can learn more at: | + * | | + * | http://www.rgraph.net | + * | | + * | This package is licensed under the RGraph license. For all kinds of business | + * | purposes there is a small one-time licensing fee to pay and for non | + * | commercial purposes it is free to use. You can read the full license here: | + * | | + * | http://www.rgraph.net/LICENSE.txt | + * o------------------------------------------------------------------------------o + */ + + if (typeof(RGraph) == 'undefined') RGraph = {}; + + /** + * The scatter graph constructor + * + * @param object canvas The cxanvas object + * @param array data The chart data + */ + RGraph.Scatter = function (id, data) + { + // Get the canvas and context objects + this.id = id; + this.canvas = document.getElementById(id); + this.canvas.__object__ = this; + this.context = this.canvas.getContext ? this.canvas.getContext("2d") : null; + this.max = 0; + this.coords = []; + this.data = []; + this.type = 'scatter'; + this.isRGraph = true; + + + /** + * Compatibility with older browsers + */ + RGraph.OldBrowserCompat(this.context); + + + // Various config properties + this.properties = { + 'chart.background.barcolor1': 'white', + 'chart.background.barcolor2': 'white', + 'chart.background.grid': true, + 'chart.background.grid.width': 1, + 'chart.background.grid.color': '#ddd', + 'chart.background.grid.hsize': 20, + 'chart.background.grid.vsize': 20, + 'chart.background.hbars': null, + 'chart.background.vbars': null, + 'chart.background.grid.vlines': true, + 'chart.background.grid.hlines': true, + 'chart.background.grid.border': true, + 'chart.background.grid.autofit':false, + 'chart.background.grid.autofit.numhlines': 7, + 'chart.background.grid.autofit.numvlines': 20, + 'chart.text.size': 10, + 'chart.text.angle': 0, + 'chart.text.color': 'black', + 'chart.text.font': 'Verdana', + 'chart.tooltips.effect': 'fade', + 'chart.tooltips.hotspot': 3, + 'chart.tooltips.css.class': 'RGraph_tooltip', + 'chart.tooltips.highlight': true, + 'chart.tooltips.coords.adjust': [0,0], + 'chart.units.pre': '', + 'chart.units.post': '', + 'chart.tickmarks': 'cross', + 'chart.ticksize': 5, + 'chart.xticks': true, + 'chart.xaxis': true, + 'chart.gutter': 25, + 'chart.xmax': 0, + 'chart.ymax': null, + 'chart.ymin': null, + 'chart.scale.decimals': null, + 'chart.scale.point': '.', + 'chart.scale.thousand': ',', + 'chart.title': '', + 'chart.title.background': null, + 'chart.title.hpos': null, + 'chart.title.vpos': null, + 'chart.title.xaxis': '', + 'chart.title.yaxis': '', + 'chart.title.xaxis.pos': 0.25, + 'chart.title.yaxis.pos': 0.25, + 'chart.labels': [], + 'chart.ylabels': true, + 'chart.ylabels.count': 5, + 'chart.contextmenu': null, + 'chart.defaultcolor': 'black', + 'chart.xaxispos': 'bottom', + 'chart.yaxispos': 'left', + 'chart.noendxtick': false, + 'chart.crosshairs': false, + 'chart.crosshairs.color': '#333', + 'chart.crosshairs.linewidth': 1, + 'chart.crosshairs.coords': false, + 'chart.crosshairs.coords.fixed':true, + 'chart.crosshairs.coords.fadeout':false, + 'chart.crosshairs.coords.labels.x': 'X', + 'chart.crosshairs.coords.labels.y': 'Y', + 'chart.annotatable': false, + 'chart.annotate.color': 'black', + 'chart.line': false, + 'chart.line.linewidth': 1, + 'chart.line.colors': ['green', 'red'], + 'chart.line.shadow.color': 'rgba(0,0,0,0)', + 'chart.line.shadow.blur': 2, + 'chart.line.shadow.offsetx': 3, + 'chart.line.shadow.offsety': 3, + 'chart.line.stepped': false, + 'chart.noaxes': false, + 'chart.key': [], + 'chart.key.background': 'white', + 'chart.key.position': 'graph', + 'chart.key.shadow': false, + 'chart.key.shadow.color': '#666', + 'chart.key.shadow.blur': 3, + 'chart.key.shadow.offsetx': 2, + 'chart.key.shadow.offsety': 2, + 'chart.key.position.gutter.boxed': true, + 'chart.key.position.x': null, + 'chart.key.position.y': null, + 'chart.key.color.shape': 'square', + 'chart.key.rounded': true, + 'chart.axis.color': 'black', + 'chart.zoom.factor': 1.5, + 'chart.zoom.fade.in': true, + 'chart.zoom.fade.out': true, + 'chart.zoom.hdir': 'right', + 'chart.zoom.vdir': 'down', + 'chart.zoom.frames': 10, + 'chart.zoom.delay': 50, + 'chart.zoom.shadow': true, + 'chart.zoom.mode': 'canvas', + 'chart.zoom.thumbnail.width': 75, + 'chart.zoom.thumbnail.height': 75, + 'chart.zoom.background': true, + 'chart.zoom.action': 'zoom', + 'chart.boxplot.width': 8, + 'chart.resizable': false, + 'chart.xmin': 0 + } + + // Handle multiple datasets being given as one argument + if (arguments[1][0] && arguments[1][0][0] && typeof(arguments[1][0][0][0]) == 'number') { + // Store the data set(s) + for (var i=0; i 0) { + + this.scale = []; + this.max = this.Get('chart.ymax'); + this.min = this.Get('chart.ymin') ? this.Get('chart.ymin') : 0; + + this.scale[0] = ((this.max - this.min) * (1/5)) + this.min; + this.scale[1] = ((this.max - this.min) * (2/5)) + this.min; + this.scale[2] = ((this.max - this.min) * (3/5)) + this.min; + this.scale[3] = ((this.max - this.min) * (4/5)) + this.min; + this.scale[4] = ((this.max - this.min) * (5/5)) + this.min; + + var decimals = this.Get('chart.scale.decimals'); + + this.scale = [ + Number(this.scale[0]).toFixed(decimals), + Number(this.scale[1]).toFixed(decimals), + Number(this.scale[2]).toFixed(decimals), + Number(this.scale[3]).toFixed(decimals), + Number(this.scale[4]).toFixed(decimals) + ]; + + } else { + + var i = 0; + var j = 0; + + for (i=0; i= (xCoord - offset) && + mouseCoords[1] <= (yCoord + offset) && + mouseCoords[1] >= (yCoord - offset) && + tooltip && + tooltip.length > 0) { + + overHotspot = true; + canvas.style.cursor = 'pointer'; + + if ( + !RGraph.Registry.Get('chart.tooltip') || + RGraph.Registry.Get('chart.tooltip').__text__ != tooltip || + RGraph.Registry.Get('chart.tooltip').__index__ != i || + RGraph.Registry.Get('chart.tooltip').__dataset__ != set + ) { + + if (obj.Get('chart.tooltips.highlight')) { + RGraph.Redraw(); + } + + /** + * Get the tooltip text + */ + if (typeof(tooltip) == 'function') { + var text = String(tooltip(i)); + + } else { + var text = String(tooltip); + } + + RGraph.Tooltip(canvas, text, e.pageX, e.pageY, i); + RGraph.Registry.Get('chart.tooltip').__dataset__ = set; + + /** + * Draw a circle around the mark + */ + if (obj.Get('chart.tooltips.highlight')) { + context.beginPath(); + context.fillStyle = 'rgba(255,255,255,0.5)'; + context.arc(xCoord, yCoord, 3, 0, 6.28, 0); + context.fill(); + } + } + } + } + } + + /** + * Reset the pointer + */ + if (!overHotspot) { + canvas.style.cursor = 'default'; + } + } + this.canvas.addEventListener('mousemove', canvas_onmousemove_func, false); + RGraph.AddEventListener(this.id, 'mousemove', canvas_onmousemove_func); + } + + + /** + * Draw the key if necessary + */ + if (this.Get('chart.key') && this.Get('chart.key').length) { + RGraph.DrawKey(this, this.Get('chart.key'), this.Get('chart.line.colors')); + } + + + /** + * Draw crosschairs + */ + RGraph.DrawCrosshairs(this); + + /** + * If the canvas is annotatable, do install the event handlers + */ + if (this.Get('chart.annotatable')) { + RGraph.Annotate(this); + } + + /** + * This bit shows the mini zoom window if requested + */ + if (this.Get('chart.zoom.mode') == 'thumbnail' || this.Get('chart.zoom.mode') == 'area') { + RGraph.ShowZoomWindow(this); + } + + + /** + * This function enables resizing + */ + if (this.Get('chart.resizable')) { + RGraph.AllowResizing(this); + } + + /** + * Fire the RGraph ondraw event + */ + RGraph.FireCustomEvent(this, 'ondraw'); + } + + + /** + * Draws the axes of the scatter graph + */ + RGraph.Scatter.prototype.DrawAxes = function () + { + var canvas = this.canvas; + var context = this.context; + var graphHeight = this.canvas.height - (this.Get('chart.gutter') * 2); + var gutter = this.Get('chart.gutter'); + + context.beginPath(); + context.strokeStyle = this.Get('chart.axis.color'); + context.lineWidth = 1; + + // Draw the Y axis + if (this.Get('chart.yaxispos') == 'left') { + context.moveTo(gutter, gutter); + context.lineTo(gutter, this.canvas.height - gutter); + } else { + context.moveTo(canvas.width - gutter, gutter); + context.lineTo(canvas.width - gutter, canvas.height - gutter); + } + + + // Draw the X axis + if (this.Get('chart.xaxis')) { + if (this.Get('chart.xaxispos') == 'center') { + context.moveTo(gutter, canvas.height / 2); + context.lineTo(canvas.width - gutter, canvas.height / 2); + } else { + context.moveTo(gutter, canvas.height - gutter); + context.lineTo(canvas.width - gutter, canvas.height - gutter); + } + } + + /** + * Draw the Y tickmarks + */ + for (y=gutter; y < canvas.height - gutter + (this.Get('chart.xaxispos') == 'center' ? 1 : 0) ; y+=(graphHeight / 5) / 2) { + + // This is here to accomodate the X axis being at the center + if (y == (canvas.height / 2) ) continue; + + if (this.Get('chart.yaxispos') == 'left') { + context.moveTo(gutter, y); + context.lineTo(gutter - 3, y); + } else { + context.moveTo(canvas.width - gutter +3, y); + context.lineTo(canvas.width - gutter, y); + } + } + + + /** + * Draw the X tickmarks + */ + if (this.Get('chart.xticks') && this.Get('chart.xaxis')) { + + var x = 0; + var y = (this.Get('chart.xaxispos') == 'center') ? (this.canvas.height / 2) : (this.canvas.height - gutter); + this.xTickGap = (this.canvas.width - (2 * gutter) ) / this.Get('chart.labels').length; + + for (x = (gutter + (this.Get('chart.yaxispos') == 'left' ? this.xTickGap / 2 : 0) ); x<=(canvas.width - gutter - (this.Get('chart.yaxispos') == 'left' ? 0 : 1)); x += this.xTickGap / 2) { + + if (this.Get('chart.yaxispos') == 'left' && this.Get('chart.noendxtick') == true && x == (canvas.width - gutter) ) { + continue; + + } else if (this.Get('chart.yaxispos') == 'right' && this.Get('chart.noendxtick') == true && x == gutter) { + continue; + } + + context.moveTo(x, y - (this.Get('chart.xaxispos') == 'center' ? 3 : 0)); + context.lineTo(x, y + 3); + } + } + + context.stroke(); + } + + + /** + * Draws the labels on the scatter graph + */ + RGraph.Scatter.prototype.DrawLabels = function () + { + this.context.fillStyle = this.Get('chart.text.color'); + var font = this.Get('chart.text.font'); + var xMin = this.Get('chart.xmin'); + var xMax = this.Get('chart.xmax'); + var yMax = this.scale[4]; + var gutter = this.Get('chart.gutter'); + var text_size = this.Get('chart.text.size'); + var units_pre = this.Get('chart.units.pre'); + var units_post = this.Get('chart.units.post'); + var numYLabels = this.Get('chart.ylabels.count'); + var context = this.context; + var canvas = this.canvas; + + this.halfTextHeight = text_size / 2; + + + this.halfGraphHeight = (this.canvas.height - (2 * this.Get('chart.gutter'))) / 2; + + /** + * Draw the Y yaxis labels, be it at the top or center + */ + if (this.Get('chart.ylabels')) { + + var xPos = this.Get('chart.yaxispos') == 'left' ? gutter - 5 : canvas.width - gutter + 5; + var align = this.Get('chart.yaxispos') == 'right' ? 'left' : 'right'; + + if (this.Get('chart.xaxispos') == 'center') { + + + /** + * Specific Y labels + */ + if (typeof(this.Get('chart.ylabels.specific')) == 'object') { + + var labels = this.Get('chart.ylabels.specific'); + + for (var i=0; i= 5) { + RGraph.Text(context, font, text_size, xPos, gutter + ((canvas.height - (2 * gutter)) * (1/10) ), RGraph.number_format(this, this.scale[3], units_pre, units_post), 'center', align); + RGraph.Text(context, font, text_size, xPos, gutter + ((canvas.height - (2 * gutter)) * (3/10) ), RGraph.number_format(this, this.scale[1], units_pre, units_post), 'center', align); + } + + if (numYLabels >= 3) { + RGraph.Text(context, font, text_size, xPos, gutter + ((canvas.height - (2 * gutter)) * (2/10) ), RGraph.number_format(this, this.scale[2], units_pre, units_post), 'center', align); + RGraph.Text(context, font, text_size, xPos, gutter + ((canvas.height - (2 * gutter)) * (4/10) ), RGraph.number_format(this, this.scale[0], units_pre, units_post), 'center', align); + } + + // Draw the bottom halves labels + if (numYLabels >= 3) { + RGraph.Text(context, font, text_size, xPos, gutter + ((canvas.height - (2 * gutter)) * (1/10) ) + this.halfGraphHeight, '-' + RGraph.number_format(this, this.scale[0], units_pre, units_post), 'center', align); + RGraph.Text(context, font, text_size, xPos, gutter + ((canvas.height - (2 * gutter)) * (3/10) ) + this.halfGraphHeight, '-' + RGraph.number_format(this, this.scale[2], units_pre, units_post), 'center', align); + } + + if (numYLabels == 5) { + RGraph.Text(context, font, text_size, xPos, gutter + ((canvas.height - (2 * gutter)) * (2/10) ) + this.halfGraphHeight, '-' + RGraph.number_format(this, this.scale[1], units_pre, units_post), 'center', align); + RGraph.Text(context, font, text_size, xPos, gutter + ((canvas.height - (2 * gutter)) * (4/10) ) + this.halfGraphHeight, '-' + RGraph.number_format(this, this.scale[3], units_pre, units_post), 'center', align); + } + + RGraph.Text(context, font, text_size, xPos, gutter + ((canvas.height - (2 * gutter)) * (5/10) ) + this.halfGraphHeight, '-' + RGraph.number_format(this, this.scale[4], units_pre, units_post), 'center', align); + + } else if (numYLabels == 10) { + // 10 Y labels + var interval = (this.grapharea / numYLabels) / 2; + + for (var i=0; i= 5) { + RGraph.Text(context, font, text_size, xPos, gutter + ((canvas.height - (2 * gutter)) * (1/5) ), RGraph.number_format(this, this.scale[3], units_pre, units_post), 'center', align); + RGraph.Text(context, font, text_size, xPos, gutter + ((canvas.height - (2 * gutter)) * (3/5) ), RGraph.number_format(this, this.scale[1], units_pre, units_post), 'center', align); + } + + if (numYLabels >= 3) { + RGraph.Text(context, font, text_size, xPos, gutter + ((canvas.height - (2 * gutter)) * (2/5) ), RGraph.number_format(this, this.scale[2], units_pre, units_post), 'center', align); + RGraph.Text(context, font, text_size, xPos, gutter + ((canvas.height - (2 * gutter)) * (4/5) ), RGraph.number_format(this, this.scale[0], units_pre, units_post), 'center', align); + } + } else if (numYLabels == 10) { + + // 10 Y labels + var interval = (this.grapharea / numYLabels) / 2; + + for (var i=0; i 0) { + angle = -1 * this.Get('chart.text.angle'); + valign = 'center'; + halign = 'right'; + yPos -= 10; + } + + for (i=0; i= 2) { + + this.context.lineCap = 'round'; + this.context.lineJoin = 'round'; + this.context.lineWidth = this.GetLineWidth(i);// i is the index of the set of coordinates + this.context.strokeStyle = this.Get('chart.line.colors')[i]; + this.context.beginPath(); + + var len = this.coords[i].length; + + for (var j=0; j{XE z)7O>#8Y?HeiPce~l`DWkvL&t&CC>S|xv6<249-QVi6yBi3gww4844j8sS56%z5(x3 pRP%rec|2VlLpZJ{|M+}Ko`F@8$+T(TnfpL-22WQ%mvv4FO#nkKCNls4 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/chameleon.png b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/chameleon.png new file mode 100644 index 0000000000000000000000000000000000000000..68046070133a2c309839b9d340ced4c521fa9d3b GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1SBVv2j2ryoCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#8Y?HesrbxqN9F*9WJ_ElN}Tg^b5rw57@Uhz6H8K46v{J8G895GQWe}ieFNU7 psOA9`@_4#9hHzX@eo>Xe#K1g@abe4bR%xI(gQu&X%Q~loCID3dC3gS- literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/close12_1.gif b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/close12_1.gif new file mode 100644 index 0000000000000000000000000000000000000000..e2f67d72efc158da4e069822cbe338915761e396 GIT binary patch literal 85 zcmZ?wbhEHbz lf$Gy9znh?Y?^x%Bps9Cfw!UsJn!aoAS>7kV)`>G%0|4uCA&me4 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/container-min.js b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/container-min.js new file mode 100644 index 0000000..eadb7f2 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/container-min.js @@ -0,0 +1,19 @@ +/* +Copyright (c) 2010, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.com/yui/license.html +version: 2.8.2r1 +*/ +(function(){YAHOO.util.Config=function(D){if(D){this.init(D);}};var B=YAHOO.lang,C=YAHOO.util.CustomEvent,A=YAHOO.util.Config;A.CONFIG_CHANGED_EVENT="configChanged";A.BOOLEAN_TYPE="boolean";A.prototype={owner:null,queueInProgress:false,config:null,initialConfig:null,eventQueue:null,configChangedEvent:null,init:function(D){this.owner=D;this.configChangedEvent=this.createEvent(A.CONFIG_CHANGED_EVENT);this.configChangedEvent.signature=C.LIST;this.queueInProgress=false;this.config={};this.initialConfig={};this.eventQueue=[];},checkBoolean:function(D){return(typeof D==A.BOOLEAN_TYPE);},checkNumber:function(D){return(!isNaN(D));},fireEvent:function(D,F){var E=this.config[D];if(E&&E.event){E.event.fire(F);}},addProperty:function(E,D){E=E.toLowerCase();this.config[E]=D;D.event=this.createEvent(E,{scope:this.owner});D.event.signature=C.LIST;D.key=E;if(D.handler){D.event.subscribe(D.handler,this.owner);}this.setProperty(E,D.value,true);if(!D.suppressEvent){this.queueProperty(E,D.value);}},getConfig:function(){var D={},F=this.config,G,E;for(G in F){if(B.hasOwnProperty(F,G)){E=F[G];if(E&&E.event){D[G]=E.value;}}}return D;},getProperty:function(D){var E=this.config[D.toLowerCase()];if(E&&E.event){return E.value;}else{return undefined;}},resetProperty:function(D){D=D.toLowerCase();var E=this.config[D];if(E&&E.event){if(this.initialConfig[D]&&!B.isUndefined(this.initialConfig[D])){this.setProperty(D,this.initialConfig[D]);return true;}}else{return false;}},setProperty:function(E,G,D){var F;E=E.toLowerCase();if(this.queueInProgress&&!D){this.queueProperty(E,G);return true;}else{F=this.config[E];if(F&&F.event){if(F.validator&&!F.validator(G)){return false;}else{F.value=G;if(!D){this.fireEvent(E,G);this.configChangedEvent.fire([E,G]);}return true;}}else{return false;}}},queueProperty:function(S,P){S=S.toLowerCase();var R=this.config[S],K=false,J,G,H,I,O,Q,F,M,N,D,L,T,E;if(R&&R.event){if(!B.isUndefined(P)&&R.validator&&!R.validator(P)){return false;}else{if(!B.isUndefined(P)){R.value=P;}else{P=R.value;}K=false;J=this.eventQueue.length;for(L=0;L0){G=F-1;do{D=E.subscribers[G];if(D&&D.obj==I&&D.fn==H){return true;}}while(G--);}return false;};YAHOO.lang.augmentProto(A,YAHOO.util.EventProvider);}());(function(){YAHOO.widget.Module=function(R,Q){if(R){this.init(R,Q);}else{}};var F=YAHOO.util.Dom,D=YAHOO.util.Config,N=YAHOO.util.Event,M=YAHOO.util.CustomEvent,G=YAHOO.widget.Module,I=YAHOO.env.ua,H,P,O,E,A={"BEFORE_INIT":"beforeInit","INIT":"init","APPEND":"append","BEFORE_RENDER":"beforeRender","RENDER":"render","CHANGE_HEADER":"changeHeader","CHANGE_BODY":"changeBody","CHANGE_FOOTER":"changeFooter","CHANGE_CONTENT":"changeContent","DESTROY":"destroy","BEFORE_SHOW":"beforeShow","SHOW":"show","BEFORE_HIDE":"beforeHide","HIDE":"hide"},J={"VISIBLE":{key:"visible",value:true,validator:YAHOO.lang.isBoolean},"EFFECT":{key:"effect",suppressEvent:true,supercedes:["visible"]},"MONITOR_RESIZE":{key:"monitorresize",value:true},"APPEND_TO_DOCUMENT_BODY":{key:"appendtodocumentbody",value:false}};G.IMG_ROOT=null;G.IMG_ROOT_SSL=null;G.CSS_MODULE="yui-module";G.CSS_HEADER="hd";G.CSS_BODY="bd";G.CSS_FOOTER="ft";G.RESIZE_MONITOR_SECURE_URL="javascript:false;";G.RESIZE_MONITOR_BUFFER=1;G.textResizeEvent=new M("textResize");G.forceDocumentRedraw=function(){var Q=document.documentElement;if(Q){Q.className+=" ";Q.className=YAHOO.lang.trim(Q.className);}};function L(){if(!H){H=document.createElement("div");H.innerHTML=('
    '+'
    ');P=H.firstChild;O=P.nextSibling;E=O.nextSibling;}return H;}function K(){if(!P){L();}return(P.cloneNode(false));}function B(){if(!O){L();}return(O.cloneNode(false));}function C(){if(!E){L();}return(E.cloneNode(false));}G.prototype={constructor:G,element:null,header:null,body:null,footer:null,id:null,imageRoot:G.IMG_ROOT,initEvents:function(){var Q=M.LIST; +this.beforeInitEvent=this.createEvent(A.BEFORE_INIT);this.beforeInitEvent.signature=Q;this.initEvent=this.createEvent(A.INIT);this.initEvent.signature=Q;this.appendEvent=this.createEvent(A.APPEND);this.appendEvent.signature=Q;this.beforeRenderEvent=this.createEvent(A.BEFORE_RENDER);this.beforeRenderEvent.signature=Q;this.renderEvent=this.createEvent(A.RENDER);this.renderEvent.signature=Q;this.changeHeaderEvent=this.createEvent(A.CHANGE_HEADER);this.changeHeaderEvent.signature=Q;this.changeBodyEvent=this.createEvent(A.CHANGE_BODY);this.changeBodyEvent.signature=Q;this.changeFooterEvent=this.createEvent(A.CHANGE_FOOTER);this.changeFooterEvent.signature=Q;this.changeContentEvent=this.createEvent(A.CHANGE_CONTENT);this.changeContentEvent.signature=Q;this.destroyEvent=this.createEvent(A.DESTROY);this.destroyEvent.signature=Q;this.beforeShowEvent=this.createEvent(A.BEFORE_SHOW);this.beforeShowEvent.signature=Q;this.showEvent=this.createEvent(A.SHOW);this.showEvent.signature=Q;this.beforeHideEvent=this.createEvent(A.BEFORE_HIDE);this.beforeHideEvent.signature=Q;this.hideEvent=this.createEvent(A.HIDE);this.hideEvent.signature=Q;},platform:function(){var Q=navigator.userAgent.toLowerCase();if(Q.indexOf("windows")!=-1||Q.indexOf("win32")!=-1){return"windows";}else{if(Q.indexOf("macintosh")!=-1){return"mac";}else{return false;}}}(),browser:function(){var Q=navigator.userAgent.toLowerCase();if(Q.indexOf("opera")!=-1){return"opera";}else{if(Q.indexOf("msie 7")!=-1){return"ie7";}else{if(Q.indexOf("msie")!=-1){return"ie";}else{if(Q.indexOf("safari")!=-1){return"safari";}else{if(Q.indexOf("gecko")!=-1){return"gecko";}else{return false;}}}}}}(),isSecure:function(){if(window.location.href.toLowerCase().indexOf("https")===0){return true;}else{return false;}}(),initDefaultConfig:function(){this.cfg.addProperty(J.VISIBLE.key,{handler:this.configVisible,value:J.VISIBLE.value,validator:J.VISIBLE.validator});this.cfg.addProperty(J.EFFECT.key,{suppressEvent:J.EFFECT.suppressEvent,supercedes:J.EFFECT.supercedes});this.cfg.addProperty(J.MONITOR_RESIZE.key,{handler:this.configMonitorResize,value:J.MONITOR_RESIZE.value});this.cfg.addProperty(J.APPEND_TO_DOCUMENT_BODY.key,{value:J.APPEND_TO_DOCUMENT_BODY.value});},init:function(V,U){var S,W;this.initEvents();this.beforeInitEvent.fire(G);this.cfg=new D(this);if(this.isSecure){this.imageRoot=G.IMG_ROOT_SSL;}if(typeof V=="string"){S=V;V=document.getElementById(V);if(!V){V=(L()).cloneNode(false);V.id=S;}}this.id=F.generateId(V);this.element=V;W=this.element.firstChild;if(W){var R=false,Q=false,T=false;do{if(1==W.nodeType){if(!R&&F.hasClass(W,G.CSS_HEADER)){this.header=W;R=true;}else{if(!Q&&F.hasClass(W,G.CSS_BODY)){this.body=W;Q=true;}else{if(!T&&F.hasClass(W,G.CSS_FOOTER)){this.footer=W;T=true;}}}}}while((W=W.nextSibling));}this.initDefaultConfig();F.addClass(this.element,G.CSS_MODULE);if(U){this.cfg.applyConfig(U,true);}if(!D.alreadySubscribed(this.renderEvent,this.cfg.fireQueue,this.cfg)){this.renderEvent.subscribe(this.cfg.fireQueue,this.cfg,true);}this.initEvent.fire(G);},initResizeMonitor:function(){var R=(I.gecko&&this.platform=="windows");if(R){var Q=this;setTimeout(function(){Q._initResizeMonitor();},0);}else{this._initResizeMonitor();}},_initResizeMonitor:function(){var Q,S,U;function W(){G.textResizeEvent.fire();}if(!I.opera){S=F.get("_yuiResizeMonitor");var V=this._supportsCWResize();if(!S){S=document.createElement("iframe");if(this.isSecure&&G.RESIZE_MONITOR_SECURE_URL&&I.ie){S.src=G.RESIZE_MONITOR_SECURE_URL;}if(!V){U=[" + + + + + + + + + + +
    {title}
    + +
    + +
    + + + + + + + + + + + +
    +

    Class Coverage Distribution

    + + +
    +

    Class Complexity

    + + +
    +

    Top Project Risks

    +
      +{top_project_risks} +
    +
    +

    Least Tested Methods

    +
      +{least_tested_methods} +
    +
    +
    + +
    + + + + +
    Generated by PHP_CodeCoverage {version} using PHP {php_version}{generator} at {date}.
    + +
    + + diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/directory.html.dist b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/directory.html.dist new file mode 100644 index 0000000..fda0ed1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/directory.html.dist @@ -0,0 +1,71 @@ + + + + + + {title} + + + + + + + + + + + + + + +
    {title}
    + + + + + + + + + +
    Current directory:{link} ({dashboard_link})
    Legend: + + Low: 0% to {low_upper_bound}% + + + Medium: {low_upper_bound}% to {high_lower_bound}% + + + High: {high_lower_bound}% to 100% + +
    +
    + +
    + +
    + + + + + + + + + + + +{total_item}{items} +
     Coverage
     LinesFunctions / MethodsClasses
    +
    + +
    + + + + +
    Generated by PHP_CodeCoverage {version} using PHP {php_version}{generator} at {date}.
    + +
    + + diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/directory.png b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/directory.png new file mode 100644 index 0000000000000000000000000000000000000000..65bd0bbdcb9005cb8929f06e25d9cb15a926366a GIT binary patch literal 581 zcmV-L0=oT)P)2|yPkE-3> z-8b(3_?ov1cYiV%432IDm|3sa>)kUm%nWx2;PmwLe!t&8>~uQMm(4k6LI`Cz9Dc0p zx&Tx;XIE7wlL@7i6(oef_V#uMc)NrGOsCVTl=7;s>w_zRjH+U0Ymj!k-P+vTq}6H> zV^0g%)=c>R8-N-3GD0!|F@>GqJ z%4)bdf_Rm4wwyD#6GYg!0ieZcvQf+lK>!v2)x`$$R0x3iqPe(Z=9oKK7jS;E^w*b55oWe`mg~7=)i^mlj0C%nT8s$wuo= zb!&(s!bMVmQn@?FCx!@o{yMsKc&XWJj=)i68(aN%$9JEC^W*#Yp8+C_MZ$~UM;0NT T9Al?300000NkvXXu0mjfM@0T3 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/directory_item.html.dist b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/directory_item.html.dist new file mode 100644 index 0000000..a0065f9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/directory_item.html.dist @@ -0,0 +1,31 @@ + + {icon}{name} + + + + + +
    {lines_executed_percent}{lines_executed_percent}
    + + {lines_executed_percent} + {num_executed_lines} / {num_executable_lines} + + + + + +
    {methods_tested_percent}{methods_tested_percent}
    + + {methods_tested_percent} + {methods_number} + + + + + +
    {classes_tested_percent}{classes_tested_percent}
    + + {classes_tested_percent} + {classes_number} + + diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/excanvas.compressed.js b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/excanvas.compressed.js new file mode 100644 index 0000000000000000000000000000000000000000..fc3d35c73606b2cdcea1cfb77aa125f90251d04d GIT binary patch literal 8660 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 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/file.html.dist b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/file.html.dist new file mode 100644 index 0000000..a1a5766 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/file.html.dist @@ -0,0 +1,120 @@ + + + + + + {title} + + + + + + + + + + + + + + + + + + +
    {title}
    + + + + + + + + + +
    Current file:{link}
    Legend: + executed + not executed + dead code +
    +
    + +
    + +
    + + + + + + + + + + + +{total_item}{items} +
     Coverage
     ClassesFunctions / MethodsLines
    +
    + +
    + + + + + + + + +

    +
    +{lines}
    +
    +
    + + + + +
    Generated by PHP_CodeCoverage {version} using PHP {php_version}{generator} at {date}.
    + +
    + + + + diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/file.png b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/file.png new file mode 100644 index 0000000000000000000000000000000000000000..2d7f2d6017d823bf9f1209d9933faf612dffe9f8 GIT binary patch literal 333 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP$ic-+2*wv2(<2J_t+h+ zs5rlI{^p#SO2-|aiODDi-jZP}W|aE1)~BmOR3$EA(Vi@w>U%ZDa$9qM8}c0HKK>=@ z`d4d)YqwsmShMx=n<-}wTJ%-CXPi)?Z+d)E$Kx3$zTq0>%B>G-<`ESK<06 zKLv;!Rde(>`RU=L2g~Ovo%n1M@bQ?*+>S*Vvl$k=|9v$za@qmb9gNTaiaD`NnxMxo zp5*#q&TW}{<`>WDw{ULpSLj^#x@qe3m+d`GEQ*uw+Md|dvtPsTSdE!)vF)Ukp32Aj azp#b`#_#;I)BX+6mkge+elF{r5}E*#afeO- literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/file_item.html.dist b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/file_item.html.dist new file mode 100644 index 0000000..938db30 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/file_item.html.dist @@ -0,0 +1,32 @@ + + {name} + + + + + +
    {classes_tested_percent}{classes_tested_percent}
    + + {classes_tested_percent} + {classes_number} + + + + + +
    {methods_tested_percent}{methods_tested_percent}
    + + {methods_tested_percent} + {methods_number} + {crap} + + + + + +
    {lines_executed_percent}{lines_executed_percent}
    + + {lines_executed_percent} + {num_executed_lines} / {num_executable_lines} + + diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/file_no_yui.html.dist b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/file_no_yui.html.dist new file mode 100644 index 0000000..9bdb84f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/file_no_yui.html.dist @@ -0,0 +1,79 @@ + + + + + + {title} + + + + + + + + + + + + + + + +
    {title}
    + + + + + + + + + +
    Current file:{link}
    Legend: + executed + not executed + dead code +
    +
    + +
    + +
    + + + + + + + + + + + +{total_item}{items} +
     Coverage
     ClassesFunctions / MethodsLines
    +
    + +
    + + + + + + + + +

    +
    +{lines}
    +
    +
    + + + + +
    Generated by PHP_CodeCoverage {version} using PHP {php_version}{generator} at {date}.
    + +
    + + diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/glass.png b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/glass.png new file mode 100644 index 0000000000000000000000000000000000000000..e1abc00680a3093c49fdb775ae6bdb6764c95af2 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)gaEa{HEjtmSN`?>!lvI6;R0X`wF z|Ns97GD8ntt^-nxB|(0{3=Yq3q=7g|-tI089jvk*Kn`btM`SSr1Gf+eGhVt|_XjA* zUgGKN%6^Gmn4d%Ph(nkFP>9RZ#WAE}PI3Z}&BVayv3^M*kj3EX>gTe~DWM4f=_Dpv literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/method_item.html.dist b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/method_item.html.dist new file mode 100644 index 0000000..1efeeb1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/method_item.html.dist @@ -0,0 +1,23 @@ + + {name} + + + + + +
    {methods_tested_percent}{methods_tested_percent}
    + + {methods_tested_percent} + {methods_number} + {crap} + + + + + +
    {lines_executed_percent}{lines_executed_percent}
    + + {lines_executed_percent} + {num_executed_lines} / {num_executable_lines} + + diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/scarlet_red.png b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/scarlet_red.png new file mode 100644 index 0000000000000000000000000000000000000000..a879424d5a211cb33221e66174277791f59013eb GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1SBVv2j2ryoCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#8Y?HesoB-}R}KM%WJ_ElN}Tg^b5rw57@Uhz6H8K46v{J8G895GQWe}ieFNU7 psOA9`@_4#9hHzX@u2{d4lY!ZX(W(5B_f()bgQu&X%Q~loCIDbBC29Zw literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/snow.png b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/snow.png new file mode 100644 index 0000000000000000000000000000000000000000..2cdae107fceec6e7f02ac7acb4a34a82a540caa5 GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^MM!lvI6;R0X`wF|Ns97GD8ntt^-nBo-U3d c6}OTTfNUlP#;5A{K>8RwUHx3vIVCg!071?oo&W#< literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/style.css b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/style.css new file mode 100644 index 0000000..8c58ddc --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/style.css @@ -0,0 +1,459 @@ +/* All views: initial background and text color */ +body +{ + background-color: #fff; + color: #2e3436; + font-family: arial, helvetica, sans-serif; + font-size: 12px; + margin: 0 auto; + width: 100%; +} + +/* All views: standard link format*/ +a:link +{ + color: #2e3436; + text-decoration: underline; +} + +/* All views: standard link - visited format */ +a:visited +{ + color: #2e3436; + text-decoration: underline; +} + +/* All views: standard link - activated format */ +a:active +{ + color: #2e3436; + text-decoration: underline; +} + +/* All views: main title format */ +td.title +{ + text-align: center; + padding: 10px; + font-family: sans-serif; + font-style: italic; + font-weight: bold; + font-size: 1.6em; +} + +/* All views: header item format */ +td.headerItem +{ + text-align: right; + padding-right: 6px; + font-family: sans-serif; + font-weight: bold; +} + +/* All views: header item value format */ +td.headerValue +{ + text-align: left; + font-family: sans-serif; + font-weight: bold; +} + +/* All views: header legend item format */ +td.legendItem +{ + text-align: right; + padding-right: 6px; + padding-top: 10px; + padding-bottom: 2px; + font-family: sans-serif; + font-weight: bold; +} + +/* All views: header legend item value format */ +td.legendValue +{ + text-align: left; + padding-top: 10px; + padding-bottom: 2px; + color: #2e3436; + font-family: sans-serif; + font-weight: bold; +} + +/* All views: color of horizontal ruler */ +td.ruler +{ + background-color: #d3d7cf; +} + +/* All views: version string format */ +td.versionInfo +{ + text-align: center; + padding-top: 2px; + font-family: sans-serif; + font-style: italic; +} + +/* Directory view/File view (all)/Test case descriptions: +table headline format */ +td.tableHead +{ + text-align: center; + color: #ffffff; + background-color: #555753; + font-family: sans-serif; + font-weight: bold; +} + +/* Directory view/File view (all): filename entry format */ +td.coverItem, td.coverDirectory, td.coverFile +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + background-color: #d3d7cf; + font-family: monospace; +} + +td.coverDirectory +{ + font-weight: bold; +} + +/* Directory view/File view (all): bar-graph entry format*/ +td.coverBar +{ + padding-left: 10px; + padding-right: 10px; + background-color: #d3d7cf; +} + +/* Directory view/File view (all): bar-graph outline color */ +td.coverBarOutline +{ + background-color: #2e3436; +} + +/* Directory view/File view (all): percentage entry for files with +no coverage rate */ +td.coverPerNone +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #d3d7cf; + font-weight: bold; +} + +/* Directory view/File view (all): line count entry for files with +no coverage rate */ +td.coverNumNone +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #d3d7cf; + white-space: nowrap; +} + +/* Directory view/File view (all): percentage entry for files with +high coverage rate */ +td.coverPerHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #8ae234; + font-weight: bold; +} + +/* Directory view/File view (all): line count entry for files with +high coverage rate */ +td.coverNumHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #8ae234; + white-space: nowrap; +} + +/* Directory view/File view (all): legend entry for high coverage +rate */ +span.coverLegendHi +{ + text-align: center; + padding-left: 10px; + padding-right: 10px; + background-color: #8ae234; +} + +/* Directory view/File view (all): percentage entry for files with +medium coverage rate */ +td.coverPerMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #fce94f; + font-weight: bold; +} + +/* Directory view/File view (all): line count entry for files with +medium coverage rate */ +td.coverNumMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #fce94f; + white-space: nowrap; +} + +/* Directory view/File view (all): legend entry for medium coverage +rate */ +span.coverLegendMed +{ + text-align: center; + padding-left: 10px; + padding-right: 10px; + margin-top: 5px; + margin-bottom: 5px; + margin-right: 2px; + background-color: #fce94f; +} + +/* Directory view/File view (all): percentage entry for files with +low coverage rate */ +td.coverPerLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #f57900; + font-weight: bold; +} + +/* Directory view/File view (all): line count entry for files with +low coverage rate */ +td.coverNumLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #f57900; + white-space: nowrap; +} + +/* Directory view/File view (all): legend entry for low coverage +rate */ +span.coverLegendLo +{ + text-align: center; + padding-left: 10px; + padding-right: 10px; + margin-right: 2px; + background-color: #f57900; +} + +/* File view (all): "show/hide details" link format */ +a.detail:link +{ + color: #ffffff; +} + +/* File view (all): "show/hide details" link - visited format */ +a.detail:visited +{ + color: #ffffff; +} + +/* File view (all): "show/hide details" link - activated format */ +a.detail:active +{ + color: #ffffff; +} + +/* File view (detail): test name table headline format */ +td.testNameHead +{ + text-align: left; + padding-left: 10px; + background-color: #729fcf; + font-family: sans-serif; + font-weight: bold; +} + +/* File view (detail): test lines table headline format */ +td.testLinesHead +{ + text-align: center; + background-color: #729fcf; + font-family: sans-serif; + font-weight: bold; +} + +/* File view (detail): test name entry */ +td.testName +{ + text-align: left; + padding-left: 10px; + background-color: #729fcf; +} + +/* File view (detail): test percentage entry */ +td.testPer +{ + text-align: right; + vertical-align: top; + padding-left: 10px; + padding-right: 10px; + background-color: #729fcf; +} + +/* File view (detail): test lines count entry */ +td.testNum +{ + text-align: right; + vertical-align: top; + padding-left: 10px; + padding-right: 10px; + background-color: #729fcf; + white-space: nowrap; +} + +/* Test case descriptions: test name format*/ +dt +{ + font-family: sans-serif; + font-weight: bold; +} + +/* Test case descriptions: description table body */ +td.testDescription +{ + padding-top: 10px; + padding-left: 30px; + padding-bottom: 10px; + padding-right: 30px; + background-color: #729fcf; +} + +/* Source code view: source code format */ +pre.source +{ + font-family: monospace; + white-space: pre; +} + +/* Source code view: line number format */ +span.lineNum +{ + background-color: #d3d7cf; +} + +span.lineNum a { + text-decoration: none; +} + +/* Source code view: format for lines which were executed */ +span.lineCov +{ + background-color: #8ae234; +} + +/* Source code view: format for Cov legend */ +span.LegendCov +{ + text-align: center; + padding-left: 10px; + padding-right: 10px; + margin-right: 2px; + background-color: #8ae234; +} + +/* Source code view: format for lines which were not executed */ +span.lineNoCov +{ + background-color: #f57900; +} + +/* Source code view: format for NoCov legend */ +span.LegendNoCov +{ + text-align: center; + padding-left: 10px; + padding-right: 10px; + margin-right: 2px; + background-color: #f57900; +} + +/* Source code view: format for lines which are dead code */ +span.lineDeadCode +{ + background-color: #d3d7cf; +} + +/* Source code view: format for NoCov legend */ +span.LegendDeadCode +{ + text-align: center; + padding-left: 10px; + padding-right: 10px; + margin-right: 2px; + background-color: #d3d7cf; +} + +/* Test view: format for tests which have passed */ +li.testPassed +{ +} + +/* Test view: format for tests which failed */ +li.testFailure +{ + background-color: #f57900; +} + +/* Test view: format for tests which failed with an error */ +li.testError +{ + background-color: #f57900; +} + +/* Test view: format for incomplete and skipped tests */ +li.testIncomplete +{ + background-color: #fcaf3e; +} + +/* CRAP */ +td.crap +{ + text-align: right; + padding-left: 10px; + padding-right: 20px; + background-color: #d3d7cf; +} + +pre span.comment { + color: #888a85; +} + +pre span.default { + color: #2e3436; +} + +pre span.html { + color: #888a85; +} + +pre span.keyword { + color: #2e3436; + font-weight: bold; +} + +pre span.string { + color: #2e3436; +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/yahoo-dom-event.js b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/yahoo-dom-event.js new file mode 100644 index 0000000..8ab7c86 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Report/HTML/Template/yahoo-dom-event.js @@ -0,0 +1,14 @@ +/* +Copyright (c) 2010, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.com/yui/license.html +version: 2.8.2r1 +*/ +if(typeof YAHOO=="undefined"||!YAHOO){var YAHOO={};}YAHOO.namespace=function(){var A=arguments,E=null,C,B,D;for(C=0;C0)?B.dump(I[K],N-1):Q);}else{P.push(I[K]);}P.push(O);}if(P.length>1){P.pop();}P.push("]");}else{P.push("{");for(K in I){if(B.hasOwnProperty(I,K)){P.push(K+L);if(B.isObject(I[K])){P.push((N>0)?B.dump(I[K],N-1):Q);}else{P.push(I[K]);}P.push(O);}}if(P.length>1){P.pop();}P.push("}");}return P.join("");},substitute:function(Y,J,R){var N,M,L,U,V,X,T=[],K,O="dump",S=" ",I="{",W="}",Q,P;for(;;){N=Y.lastIndexOf(I);if(N<0){break;}M=Y.indexOf(W,N);if(N+1>=M){break;}K=Y.substring(N+1,M);U=K;X=null;L=U.indexOf(S);if(L>-1){X=U.substring(L+1);U=U.substring(0,L);}V=J[U];if(R){V=R(U,V,X);}if(B.isObject(V)){if(B.isArray(V)){V=B.dump(V,parseInt(X,10));}else{X=X||"";Q=X.indexOf(O);if(Q>-1){X=X.substring(4);}P=V.toString();if(P===G||Q>-1){V=B.dump(V,parseInt(X,10));}else{V=P;}}}else{if(!B.isString(V)&&!B.isNumber(V)){V="~-"+T.length+"-~";T[T.length]=K;}}Y=Y.substring(0,N)+V+Y.substring(M+1);}for(N=T.length-1;N>=0;N=N-1){Y=Y.replace(new RegExp("~-"+N+"-~"),"{"+T[N]+"}","g");}return Y;},trim:function(I){try{return I.replace(/^\s+|\s+$/g,"");}catch(J){return I;}},merge:function(){var L={},J=arguments,I=J.length,K;for(K=0;K519)?true:false);while((G=G[u])){z[0]+=G[b];z[1]+=G[P];if(AC){z=E.Dom._calcBorders(G,z);}}if(E.Dom._getStyle(y,p)!==f){G=y;while((G=G[Z])&&G[C]){AA=G[i];AB=G[O];if(H&&(E.Dom._getStyle(G,"overflow")!=="visible")){z=E.Dom._calcBorders(G,z);}if(AA||AB){z[0]-=AB;z[1]-=AA;}}z[0]+=x;z[1]+=Y;}else{if(D){z[0]-=x;z[1]-=Y;}else{if(I||H){z[0]+=x;z[1]+=Y;}}}z[0]=Math.floor(z[0]);z[1]=Math.floor(z[1]);}else{}return z;};}}(),getX:function(G){var Y=function(x){return E.Dom.getXY(x)[0];};return E.Dom.batch(G,Y,E.Dom,true);},getY:function(G){var Y=function(x){return E.Dom.getXY(x)[1];};return E.Dom.batch(G,Y,E.Dom,true);},setXY:function(G,x,Y){E.Dom.batch(G,E.Dom._setXY,{pos:x,noRetry:Y});},_setXY:function(G,z){var AA=E.Dom._getStyle(G,p),y=E.Dom.setStyle,AD=z.pos,Y=z.noRetry,AB=[parseInt(E.Dom.getComputedStyle(G,j),10),parseInt(E.Dom.getComputedStyle(G,o),10)],AC,x;if(AA=="static"){AA=V;y(G,p,AA);}AC=E.Dom._getXY(G);if(!AD||AC===false){return false;}if(isNaN(AB[0])){AB[0]=(AA==V)?0:G[b];}if(isNaN(AB[1])){AB[1]=(AA==V)?0:G[P];}if(AD[0]!==null){y(G,j,AD[0]-AC[0]+AB[0]+"px");}if(AD[1]!==null){y(G,o,AD[1]-AC[1]+AB[1]+"px");}if(!Y){x=E.Dom._getXY(G);if((AD[0]!==null&&x[0]!=AD[0])||(AD[1]!==null&&x[1]!=AD[1])){E.Dom._setXY(G,{pos:AD,noRetry:true});}}},setX:function(Y,G){E.Dom.setXY(Y,[G,null]);},setY:function(G,Y){E.Dom.setXY(G,[null,Y]);},getRegion:function(G){var Y=function(x){var y=false;if(E.Dom._canPosition(x)){y=E.Region.getRegion(x);}else{}return y;};return E.Dom.batch(G,Y,E.Dom,true);},getClientWidth:function(){return E.Dom.getViewportWidth();},getClientHeight:function(){return E.Dom.getViewportHeight();},getElementsByClassName:function(AB,AF,AC,AE,x,AD){AF=AF||"*";AC=(AC)?E.Dom.get(AC):null||K;if(!AC){return[];}var Y=[],G=AC.getElementsByTagName(AF),z=E.Dom.hasClass;for(var y=0,AA=G.length;y-1;}}else{}return G;},addClass:function(Y,G){return E.Dom.batch(Y,E.Dom._addClass,G);},_addClass:function(x,Y){var G=false,y;if(x&&Y){y=E.Dom._getAttribute(x,F)||J;if(!E.Dom._hasClass(x,Y)){E.Dom.setAttribute(x,F,A(y+B+Y));G=true;}}else{}return G;},removeClass:function(Y,G){return E.Dom.batch(Y,E.Dom._removeClass,G);},_removeClass:function(y,x){var Y=false,AA,z,G;if(y&&x){AA=E.Dom._getAttribute(y,F)||J;E.Dom.setAttribute(y,F,AA.replace(E.Dom._getClassRegex(x),J));z=E.Dom._getAttribute(y,F);if(AA!==z){E.Dom.setAttribute(y,F,A(z));Y=true;if(E.Dom._getAttribute(y,F)===""){G=(y.hasAttribute&&y.hasAttribute(g))?g:F; +y.removeAttribute(G);}}}else{}return Y;},replaceClass:function(x,Y,G){return E.Dom.batch(x,E.Dom._replaceClass,{from:Y,to:G});},_replaceClass:function(y,x){var Y,AB,AA,G=false,z;if(y&&x){AB=x.from;AA=x.to;if(!AA){G=false;}else{if(!AB){G=E.Dom._addClass(y,x.to);}else{if(AB!==AA){z=E.Dom._getAttribute(y,F)||J;Y=(B+z.replace(E.Dom._getClassRegex(AB),B+AA)).split(E.Dom._getClassRegex(AA));Y.splice(1,0,B+AA);E.Dom.setAttribute(y,F,A(Y.join(J)));G=true;}}}}else{}return G;},generateId:function(G,x){x=x||"yui-gen";var Y=function(y){if(y&&y.id){return y.id;}var z=x+YAHOO.env._id_counter++;if(y){if(y[e]&&y[e].getElementById(z)){return E.Dom.generateId(y,z+x);}y.id=z;}return z;};return E.Dom.batch(G,Y,E.Dom,true)||Y.apply(E.Dom,arguments);},isAncestor:function(Y,x){Y=E.Dom.get(Y);x=E.Dom.get(x);var G=false;if((Y&&x)&&(Y[l]&&x[l])){if(Y.contains&&Y!==x){G=Y.contains(x);}else{if(Y.compareDocumentPosition){G=!!(Y.compareDocumentPosition(x)&16);}}}else{}return G;},inDocument:function(G,Y){return E.Dom._inDoc(E.Dom.get(G),Y);},_inDoc:function(Y,x){var G=false;if(Y&&Y[C]){x=x||Y[e];G=E.Dom.isAncestor(x[v],Y);}else{}return G;},getElementsBy:function(Y,AF,AB,AD,y,AC,AE){AF=AF||"*";AB=(AB)?E.Dom.get(AB):null||K;if(!AB){return[];}var x=[],G=AB.getElementsByTagName(AF);for(var z=0,AA=G.length;z=8&&K.documentElement.hasAttribute){E.Dom.DOT_ATTRIBUTES.type=true;}})();YAHOO.util.Region=function(C,D,A,B){this.top=C;this.y=C;this[1]=C;this.right=D;this.bottom=A;this.left=B;this.x=B;this[0]=B; +this.width=this.right-this.left;this.height=this.bottom-this.top;};YAHOO.util.Region.prototype.contains=function(A){return(A.left>=this.left&&A.right<=this.right&&A.top>=this.top&&A.bottom<=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(E){var C=Math.max(this.top,E.top),D=Math.min(this.right,E.right),A=Math.min(this.bottom,E.bottom),B=Math.max(this.left,E.left);if(A>=C&&D>=B){return new YAHOO.util.Region(C,D,A,B);}else{return null;}};YAHOO.util.Region.prototype.union=function(E){var C=Math.min(this.top,E.top),D=Math.max(this.right,E.right),A=Math.max(this.bottom,E.bottom),B=Math.min(this.left,E.left);return new YAHOO.util.Region(C,D,A,B);};YAHOO.util.Region.prototype.toString=function(){return("Region {"+"top: "+this.top+", right: "+this.right+", bottom: "+this.bottom+", left: "+this.left+", height: "+this.height+", width: "+this.width+"}");};YAHOO.util.Region.getRegion=function(D){var F=YAHOO.util.Dom.getXY(D),C=F[1],E=F[0]+D.offsetWidth,A=F[1]+D.offsetHeight,B=F[0];return new YAHOO.util.Region(C,E,A,B);};YAHOO.util.Point=function(A,B){if(YAHOO.lang.isArray(A)){B=A[1];A=A[0];}YAHOO.util.Point.superclass.constructor.call(this,B,A,B,A);};YAHOO.extend(YAHOO.util.Point,YAHOO.util.Region);(function(){var B=YAHOO.util,A="clientTop",F="clientLeft",J="parentNode",K="right",W="hasLayout",I="px",U="opacity",L="auto",D="borderLeftWidth",G="borderTopWidth",P="borderRightWidth",V="borderBottomWidth",S="visible",Q="transparent",N="height",E="width",H="style",T="currentStyle",R=/^width|height$/,O=/^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,M={get:function(X,Z){var Y="",a=X[T][Z];if(Z===U){Y=B.Dom.getStyle(X,U);}else{if(!a||(a.indexOf&&a.indexOf(I)>-1)){Y=a;}else{if(B.Dom.IE_COMPUTED[Z]){Y=B.Dom.IE_COMPUTED[Z](X,Z);}else{if(O.test(a)){Y=B.Dom.IE.ComputedStyle.getPixel(X,Z);}else{Y=a;}}}}return Y;},getOffset:function(Z,e){var b=Z[T][e],X=e.charAt(0).toUpperCase()+e.substr(1),c="offset"+X,Y="pixel"+X,a="",d;if(b==L){d=Z[c];if(d===undefined){a=0;}a=d;if(R.test(e)){Z[H][e]=d;if(Z[c]>d){a=d-(Z[c]-d);}Z[H][e]=L;}}else{if(!Z[H][Y]&&!Z[H][e]){Z[H][e]=b;}a=Z[H][Y];}return a+I;},getBorderWidth:function(X,Z){var Y=null;if(!X[T][W]){X[H].zoom=1;}switch(Z){case G:Y=X[A];break;case V:Y=X.offsetHeight-X.clientHeight-X[A];break;case D:Y=X[F];break;case P:Y=X.offsetWidth-X.clientWidth-X[F];break;}return Y+I;},getPixel:function(Y,X){var a=null,b=Y[T][K],Z=Y[T][X];Y[H][K]=Z;a=Y[H].pixelRight;Y[H][K]=b;return a+I;},getMargin:function(Y,X){var Z;if(Y[T][X]==L){Z=0+I;}else{Z=B.Dom.IE.ComputedStyle.getPixel(Y,X);}return Z;},getVisibility:function(Y,X){var Z;while((Z=Y[T])&&Z[X]=="inherit"){Y=Y[J];}return(Z)?Z[X]:S;},getColor:function(Y,X){return B.Dom.Color.toRGB(Y[T][X])||Q;},getBorderColor:function(Y,X){var Z=Y[T],a=Z[X]||Z.color;return B.Dom.Color.toRGB(B.Dom.Color.toHex(a));}},C={};C.top=C.right=C.bottom=C.left=C[E]=C[N]=M.getOffset;C.color=M.getColor;C[G]=C[P]=C[V]=C[D]=M.getBorderWidth;C.marginTop=C.marginRight=C.marginBottom=C.marginLeft=M.getMargin;C.visibility=M.getVisibility;C.borderColor=C.borderTopColor=C.borderRightColor=C.borderBottomColor=C.borderLeftColor=M.getBorderColor;B.Dom.IE_COMPUTED=C;B.Dom.IE_ComputedStyle=M;})();(function(){var C="toString",A=parseInt,B=RegExp,D=YAHOO.util;D.Dom.Color={KEYWORDS:{black:"000",silver:"c0c0c0",gray:"808080",white:"fff",maroon:"800000",red:"f00",purple:"800080",fuchsia:"f0f",green:"008000",lime:"0f0",olive:"808000",yellow:"ff0",navy:"000080",blue:"00f",teal:"008080",aqua:"0ff"},re_RGB:/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,re_hex:/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,re_hex3:/([0-9A-F])/gi,toRGB:function(E){if(!D.Dom.Color.re_RGB.test(E)){E=D.Dom.Color.toHex(E);}if(D.Dom.Color.re_hex.exec(E)){E="rgb("+[A(B.$1,16),A(B.$2,16),A(B.$3,16)].join(", ")+")";}return E;},toHex:function(H){H=D.Dom.Color.KEYWORDS[H]||H;if(D.Dom.Color.re_RGB.exec(H)){var G=(B.$1.length===1)?"0"+B.$1:Number(B.$1),F=(B.$2.length===1)?"0"+B.$2:Number(B.$2),E=(B.$3.length===1)?"0"+B.$3:Number(B.$3);H=[G[C](16),F[C](16),E[C](16)].join("");}if(H.length<6){H=H.replace(D.Dom.Color.re_hex3,"$1$1");}if(H!=="transparent"&&H.indexOf("#")<0){H="#"+H;}return H.toLowerCase();}};}());YAHOO.register("dom",YAHOO.util.Dom,{version:"2.8.2r1",build:"7"});YAHOO.util.CustomEvent=function(D,C,B,A,E){this.type=D;this.scope=C||window;this.silent=B;this.fireOnce=E;this.fired=false;this.firedWith=null;this.signature=A||YAHOO.util.CustomEvent.LIST;this.subscribers=[];if(!this.silent){}var F="_YUICEOnSubscribe";if(D!==F){this.subscribeEvent=new YAHOO.util.CustomEvent(F,this,true);}this.lastError=null;};YAHOO.util.CustomEvent.LIST=0;YAHOO.util.CustomEvent.FLAT=1;YAHOO.util.CustomEvent.prototype={subscribe:function(B,C,D){if(!B){throw new Error("Invalid callback for subscriber to '"+this.type+"'");}if(this.subscribeEvent){this.subscribeEvent.fire(B,C,D);}var A=new YAHOO.util.Subscriber(B,C,D);if(this.fireOnce&&this.fired){this.notify(A,this.firedWith);}else{this.subscribers.push(A);}},unsubscribe:function(D,F){if(!D){return this.unsubscribeAll();}var E=false;for(var B=0,A=this.subscribers.length;B0){H=C[0];}try{B=F.fn.call(E,H,F.obj);}catch(G){this.lastError=G;if(A){throw G;}}}else{try{B=F.fn.call(E,this.type,C,F.obj);}catch(D){this.lastError=D;if(A){throw D;}}}return B;},unsubscribeAll:function(){var A=this.subscribers.length,B;for(B=A-1;B>-1;B--){this._delete(B);}this.subscribers=[];return A;},_delete:function(A){var B=this.subscribers[A];if(B){delete B.fn;delete B.obj;}this.subscribers.splice(A,1);},toString:function(){return"CustomEvent: "+"'"+this.type+"', "+"context: "+this.scope;}};YAHOO.util.Subscriber=function(A,B,C){this.fn=A;this.obj=YAHOO.lang.isUndefined(B)?null:B;this.overrideContext=C;};YAHOO.util.Subscriber.prototype.getScope=function(A){if(this.overrideContext){if(this.overrideContext===true){return this.obj;}else{return this.overrideContext;}}return A;};YAHOO.util.Subscriber.prototype.contains=function(A,B){if(B){return(this.fn==A&&this.obj==B);}else{return(this.fn==A);}};YAHOO.util.Subscriber.prototype.toString=function(){return"Subscriber { obj: "+this.obj+", overrideContext: "+(this.overrideContext||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var G=false,H=[],J=[],A=0,E=[],B=0,C={63232:38,63233:40,63234:37,63235:39,63276:33,63277:34,25:9},D=YAHOO.env.ua.ie,F="focusin",I="focusout";return{POLL_RETRYS:500,POLL_INTERVAL:40,EL:0,TYPE:1,FN:2,WFN:3,UNLOAD_OBJ:3,ADJ_SCOPE:4,OBJ:5,OVERRIDE:6,CAPTURE:7,lastError:null,isSafari:YAHOO.env.ua.webkit,webkit:YAHOO.env.ua.webkit,isIE:D,_interval:null,_dri:null,_specialTypes:{focusin:(D?"focusin":"focus"),focusout:(D?"focusout":"blur")},DOMReady:false,throwErrors:false,startInterval:function(){if(!this._interval){this._interval=YAHOO.lang.later(this.POLL_INTERVAL,this,this._tryPreloadAttach,null,true);}},onAvailable:function(Q,M,O,P,N){var K=(YAHOO.lang.isString(Q))?[Q]:Q;for(var L=0;L-1;M--){S=(this.removeListener(L[M],K,R)&&S);}return S;}}if(!R||!R.call){return this.purgeElement(L,false,K);}if("unload"==K){for(M=J.length-1;M>-1;M--){U=J[M];if(U&&U[0]==L&&U[1]==K&&U[2]==R){J.splice(M,1);return true;}}return false;}var N=null;var O=arguments[3];if("undefined"===typeof O){O=this._getCacheIndex(H,L,K,R);}if(O>=0){N=H[O];}if(!L||!N){return false;}var T=N[this.CAPTURE]===true?true:false;try{this._simpleRemove(L,K,N[this.WFN],T);}catch(Q){this.lastError=Q;return false;}delete H[O][this.WFN];delete H[O][this.FN];H.splice(O,1);return true;},getTarget:function(M,L){var K=M.target||M.srcElement;return this.resolveTextNode(K);},resolveTextNode:function(L){try{if(L&&3==L.nodeType){return L.parentNode;}}catch(K){}return L;},getPageX:function(L){var K=L.pageX;if(!K&&0!==K){K=L.clientX||0;if(this.isIE){K+=this._getScrollLeft();}}return K;},getPageY:function(K){var L=K.pageY;if(!L&&0!==L){L=K.clientY||0;if(this.isIE){L+=this._getScrollTop();}}return L;},getXY:function(K){return[this.getPageX(K),this.getPageY(K)];},getRelatedTarget:function(L){var K=L.relatedTarget;if(!K){if(L.type=="mouseout"){K=L.toElement; +}else{if(L.type=="mouseover"){K=L.fromElement;}}}return this.resolveTextNode(K);},getTime:function(M){if(!M.time){var L=new Date().getTime();try{M.time=L;}catch(K){this.lastError=K;return L;}}return M.time;},stopEvent:function(K){this.stopPropagation(K);this.preventDefault(K);},stopPropagation:function(K){if(K.stopPropagation){K.stopPropagation();}else{K.cancelBubble=true;}},preventDefault:function(K){if(K.preventDefault){K.preventDefault();}else{K.returnValue=false;}},getEvent:function(M,K){var L=M||window.event;if(!L){var N=this.getEvent.caller;while(N){L=N.arguments[0];if(L&&Event==L.constructor){break;}N=N.caller;}}return L;},getCharCode:function(L){var K=L.keyCode||L.charCode||0;if(YAHOO.env.ua.webkit&&(K in C)){K=C[K];}return K;},_getCacheIndex:function(M,P,Q,O){for(var N=0,L=M.length;N0&&E.length>0);}var P=[];var R=function(T,U){var S=T;if(U.overrideContext){if(U.overrideContext===true){S=U.obj;}else{S=U.overrideContext;}}U.fn.call(S,U.obj);};var L,K,O,N,M=[];for(L=0,K=E.length;L-1;L--){O=E[L];if(!O||!O.id){E.splice(L,1);}}this.startInterval();}else{if(this._interval){this._interval.cancel();this._interval=null;}}this.locked=false;},purgeElement:function(O,P,R){var M=(YAHOO.lang.isString(O))?this.getEl(O):O;var Q=this.getListeners(M,R),N,K;if(Q){for(N=Q.length-1;N>-1;N--){var L=Q[N];this.removeListener(M,L.type,L.fn);}}if(P&&M&&M.childNodes){for(N=0,K=M.childNodes.length;N-1;N--){M=H[N];if(M){L.removeListener(M[L.EL],M[L.TYPE],M[L.FN],N);}}M=null;}L._simpleRemove(window,"unload",L._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var K=document.documentElement,L=document.body;if(K&&(K.scrollTop||K.scrollLeft)){return[K.scrollTop,K.scrollLeft];}else{if(L){return[L.scrollTop,L.scrollLeft];}else{return[0,0];}}},regCE:function(){},_simpleAdd:function(){if(window.addEventListener){return function(M,N,L,K){M.addEventListener(N,L,(K));};}else{if(window.attachEvent){return function(M,N,L,K){M.attachEvent("on"+N,L);};}else{return function(){};}}}(),_simpleRemove:function(){if(window.removeEventListener){return function(M,N,L,K){M.removeEventListener(N,L,(K));};}else{if(window.detachEvent){return function(L,M,K){L.detachEvent("on"+M,K);};}else{return function(){};}}}()};}();(function(){var EU=YAHOO.util.Event;EU.on=EU.addListener;EU.onFocus=EU.addFocusListener;EU.onBlur=EU.addBlurListener; +/* DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */ +if(EU.isIE){if(self!==self.top){document.onreadystatechange=function(){if(document.readyState=="complete"){document.onreadystatechange=null;EU._ready();}};}else{YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event,true);var n=document.createElement("p");EU._dri=setInterval(function(){try{n.doScroll("left");clearInterval(EU._dri);EU._dri=null;EU._ready();n=null;}catch(ex){}},EU.POLL_INTERVAL);}}else{if(EU.webkit&&EU.webkit<525){EU._dri=setInterval(function(){var rs=document.readyState;if("loaded"==rs||"complete"==rs){clearInterval(EU._dri);EU._dri=null;EU._ready();}},EU.POLL_INTERVAL);}else{EU._simpleAdd(document,"DOMContentLoaded",EU._ready);}}EU._simpleAdd(window,"load",EU._load);EU._simpleAdd(window,"unload",EU._unload);EU._tryPreloadAttach();})();}YAHOO.util.EventProvider=function(){};YAHOO.util.EventProvider.prototype={__yui_events:null,__yui_subscribers:null,subscribe:function(A,C,F,E){this.__yui_events=this.__yui_events||{};var D=this.__yui_events[A];if(D){D.subscribe(C,F,E);}else{this.__yui_subscribers=this.__yui_subscribers||{};var B=this.__yui_subscribers;if(!B[A]){B[A]=[];}B[A].push({fn:C,obj:F,overrideContext:E});}},unsubscribe:function(C,E,G){this.__yui_events=this.__yui_events||{};var A=this.__yui_events;if(C){var F=A[C];if(F){return F.unsubscribe(E,G);}}else{var B=true;for(var D in A){if(YAHOO.lang.hasOwnProperty(A,D)){B=B&&A[D].unsubscribe(E,G);}}return B;}return false;},unsubscribeAll:function(A){return this.unsubscribe(A); +},createEvent:function(B,G){this.__yui_events=this.__yui_events||{};var E=G||{},D=this.__yui_events,F;if(D[B]){}else{F=new YAHOO.util.CustomEvent(B,E.scope||this,E.silent,YAHOO.util.CustomEvent.FLAT,E.fireOnce);D[B]=F;if(E.onSubscribeCallback){F.subscribeEvent.subscribe(E.onSubscribeCallback);}this.__yui_subscribers=this.__yui_subscribers||{};var A=this.__yui_subscribers[B];if(A){for(var C=0;C{tests}", + "footer": "" + }, diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/TextUI/Command.php b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/TextUI/Command.php new file mode 100644 index 0000000..9f667f1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/TextUI/Command.php @@ -0,0 +1,268 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since File available since Release 1.0.0 + */ + +require_once 'PHP/CodeCoverage.php'; + +require_once 'ezc/Base/base.php'; +spl_autoload_register(array('ezcBase', 'autoload')); + +/** + * TextUI frontend for PHP_CodeCoverage. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.4 + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since Class available since Release 1.0.0 + */ +class PHP_CodeCoverage_TextUI_Command +{ + /** + * Main method. + */ + public static function main() + { + $input = new ezcConsoleInput; + + $input->registerOption( + new ezcConsoleOption( + '', + 'clover', + ezcConsoleInput::TYPE_STRING + ) + ); + + $input->registerOption( + new ezcConsoleOption( + '', + 'html', + ezcConsoleInput::TYPE_STRING + ) + ); + + $input->registerOption( + new ezcConsoleOption( + '', + 'blacklist', + ezcConsoleInput::TYPE_STRING, + array(), + TRUE + ) + ); + + $input->registerOption( + new ezcConsoleOption( + '', + 'whitelist', + ezcConsoleInput::TYPE_STRING, + array(), + TRUE + ) + ); + + $input->registerOption( + new ezcConsoleOption( + 'h', + 'help', + ezcConsoleInput::TYPE_NONE, + NULL, + FALSE, + '', + '', + array(), + array(), + FALSE, + FALSE, + TRUE + ) + ); + + $input->registerOption( + new ezcConsoleOption( + 'v', + 'version', + ezcConsoleInput::TYPE_NONE, + NULL, + FALSE, + '', + '', + array(), + array(), + FALSE, + FALSE, + TRUE + ) + ); + + try { + $input->process(); + } + + catch (ezcConsoleOptionException $e) { + print $e->getMessage() . "\n"; + exit(1); + } + + if ($input->getOption('help')->value) { + self::showHelp(); + exit(0); + } + + else if ($input->getOption('version')->value) { + self::printVersionString(); + exit(0); + } + + $arguments = $input->getArguments(); + $clover = $input->getOption('clover')->value; + $html = $input->getOption('html')->value; + $blacklist = $input->getOption('blacklist')->value; + $whitelist = $input->getOption('whitelist')->value; + + if (count($arguments) == 1) { + self::printVersionString(); + + $coverage = new PHP_CodeCoverage; + $filter = $coverage->filter(); + + if (empty($whitelist)) { + $c = new ReflectionClass('ezcBase'); + $filter->addDirectoryToBlacklist(dirname($c->getFileName())); + $c = new ReflectionClass('ezcConsoleInput'); + $filter->addDirectoryToBlacklist(dirname($c->getFileName())); + + foreach ($blacklist as $item) { + if (is_dir($item)) { + $filter->addDirectoryToBlacklist($item); + } + + else if (is_file($item)) { + $filter->addFileToBlacklist($item); + } + } + } else { + foreach ($whitelist as $item) { + if (is_dir($item)) { + $filter->addDirectoryToWhitelist($item); + } + + else if (is_file($item)) { + $filter->addFileToWhitelist($item); + } + } + } + + $coverage->start('phpcov'); + + require $arguments[0]; + + $coverage->stop(); + + if ($clover) { + require 'PHP/CodeCoverage/Report/Clover.php'; + + $writer = new PHP_CodeCoverage_Report_Clover; + $writer->process($coverage, $clover); + } + + if ($html) { + require 'PHP/CodeCoverage/Report/HTML.php'; + + $writer = new PHP_CodeCoverage_Report_HTML; + $writer->process($coverage, $html); + } + } else { + self::showHelp(); + exit(1); + } + } + + /** + * Shows an error. + * + * @param string $message + */ + protected static function showError($message) + { + self::printVersionString(); + + print $message; + + exit(1); + } + + /** + * Shows the help. + */ + protected static function showHelp() + { + self::printVersionString(); + + print << + + --clover Write code coverage data in Clover XML format. + --html Generate code coverage report in HTML format. + + --blacklist Adds to the blacklist. + --whitelist Adds to the whitelist. + + --help Prints this usage information. + --version Prints the version and exits. + +EOT; + } + + /** + * Prints the version string. + */ + protected static function printVersionString() + { + print "phpcov 1.0.4 by Sebastian Bergmann.\n\n"; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Util.php b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Util.php new file mode 100644 index 0000000..80d7192 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/CodeCoverage/Util.php @@ -0,0 +1,643 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since File available since Release 1.0.0 + */ + +if (!defined('T_NAMESPACE')) { + define('T_NAMESPACE', 377); +} + +require_once 'PHP/Token/Stream/CachingFactory.php'; + +/** + * Utility methods. + * + * @category PHP + * @package CodeCoverage + * @author Sebastian Bergmann + * @copyright 2009-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.4 + * @link http://github.com/sebastianbergmann/php-code-coverage + * @since Class available since Release 1.0.0 + */ +class PHP_CodeCoverage_Util +{ + /** + * @var string + */ + const REGEX = '(@covers\s+(?P.*?)\s*$)m'; + + /** + * @var array + */ + protected static $ignoredLines = array(); + + /** + * @var array + */ + protected static $templateMethods = array( + 'setUp', 'assertPreConditions', 'assertPostConditions', 'tearDown' + ); + + /** + * Builds an array representation of the directory structure. + * + * For instance, + * + * + * Array + * ( + * [Money.php] => Array + * ( + * ... + * ) + * + * [MoneyBag.php] => Array + * ( + * ... + * ) + * ) + * + * + * is transformed into + * + * + * Array + * ( + * [.] => Array + * ( + * [Money.php] => Array + * ( + * ... + * ) + * + * [MoneyBag.php] => Array + * ( + * ... + * ) + * ) + * ) + * + * + * @param array $files + * @return array + */ + public static function buildDirectoryStructure($files) + { + $result = array(); + + foreach ($files as $path => $file) { + $path = explode('/', $path); + $pointer = &$result; + $max = count($path); + + for ($i = 0; $i < $max; $i++) { + if ($i == ($max - 1)) { + $type = '/f'; + } else { + $type = ''; + } + + $pointer = &$pointer[$path[$i] . $type]; + } + + $pointer = $file; + } + + return $result; + } + + /** + * Calculates the Change Risk Anti-Patterns (CRAP) index for a unit of code + * based on its cyclomatic complexity and percentage of code coverage. + * + * @param integer $ccn + * @param float $coverage + * @return string + */ + public static function crap($ccn, $coverage) + { + if ($coverage == 0) { + return (string)pow($ccn, 2) + $ccn; + } + + if ($coverage >= 95) { + return (string)$ccn; + } + + return sprintf( + '%01.2F', pow($ccn, 2) * pow(1 - $coverage/100, 3) + $ccn + ); + } + + /** + * @param string $directory + * @return string + * @throws RuntimeException + */ + public static function getDirectory($directory) + { + if (substr($directory, -1, 1) != DIRECTORY_SEPARATOR) { + $directory .= DIRECTORY_SEPARATOR; + } + + if (is_dir($directory)) { + return $directory; + } + + if (mkdir($directory, 0777, TRUE)) { + return $directory; + } + + throw new RuntimeException( + sprintf( + 'Directory "%s" does not exist.', + $directory + ) + ); + } + + /** + * Returns the files and lines a test method wants to cover. + * + * @param string $className + * @param string $methodName + * @return array + */ + public static function getLinesToBeCovered($className, $methodName) + { + $codeToCoverList = array(); + $result = array(); + // @codeCoverageIgnoreStart + if (($pos = strpos($methodName, ' ')) !== FALSE) { + $methodName = substr($methodName, 0, $pos); + } + // @codeCoverageIgnoreEnd + $class = new ReflectionClass($className); + $method = new ReflectionMethod($className, $methodName); + $docComment = $class->getDocComment() . $method->getDocComment(); + + foreach (self::$templateMethods as $templateMethod) { + if ($class->hasMethod($templateMethod)) { + $reflector = $class->getMethod($templateMethod); + $docComment .= $reflector->getDocComment(); + unset($reflector); + } + } + + if (preg_match_all(self::REGEX, $docComment, $matches)) { + foreach ($matches['coveredElement'] as $coveredElement) { + $codeToCoverList = array_merge( + $codeToCoverList, + self::resolveCoversToReflectionObjects($coveredElement) + ); + } + + foreach ($codeToCoverList as $codeToCover) { + $fileName = $codeToCover->getFileName(); + + if (!isset($result[$fileName])) { + $result[$fileName] = array(); + } + + $result[$fileName] = array_unique( + array_merge( + $result[$fileName], + range( + $codeToCover->getStartLine(), $codeToCover->getEndLine() + ) + ) + ); + } + } + + return $result; + } + + /** + * Returns the lines of a source file that should be ignored. + * + * @param string $filename + * @return array + */ + public static function getLinesToBeIgnored($filename) + { + if (!isset(self::$ignoredLines[$filename])) { + self::$ignoredLines[$filename] = array(); + + $ignore = FALSE; + $stop = FALSE; + $tokens = PHP_Token_Stream_CachingFactory::get($filename)->tokens(); + + foreach ($tokens as $token) { + switch (get_class($token)) { + case 'PHP_Token_CLASS': + case 'PHP_Token_FUNCTION': { + $docblock = $token->getDocblock(); + $endLine = $token->getEndLine(); + + if (strpos($docblock, '@codeCoverageIgnore')) { + for ($i = $token->getLine(); $i <= $endLine; $i++) { + self::$ignoredLines[$filename][$i] = TRUE; + } + } + } + break; + + case 'PHP_Token_COMMENT': { + $_token = trim($token); + + if ($_token == '// @codeCoverageIgnoreStart' || + $_token == '//@codeCoverageIgnoreStart') { + $ignore = TRUE; + } + + else if ($_token == '// @codeCoverageIgnoreEnd' || + $_token == '//@codeCoverageIgnoreEnd') { + $stop = TRUE; + } + } + break; + } + + if ($ignore) { + self::$ignoredLines[$filename][$token->getLine()] = TRUE; + + if ($stop) { + $ignore = FALSE; + $stop = FALSE; + } + } + } + } + + return self::$ignoredLines[$filename]; + } + + /** + * Returns the package information of a user-defined class. + * + * @param string $className + * @param string $docComment + * @return array + */ + public static function getPackageInformation($className, $docComment) + { + $result = array( + 'namespace' => '', + 'fullPackage' => '', + 'category' => '', + 'package' => '', + 'subpackage' => '' + ); + + if (strpos($className, '\\') !== FALSE) { + $result['namespace'] = self::arrayToName( + explode('\\', $className) + ); + } + + if (preg_match('/@category[\s]+([\.\w]+)/', $docComment, $matches)) { + $result['category'] = $matches[1]; + } + + if (preg_match('/@package[\s]+([\.\w]+)/', $docComment, $matches)) { + $result['package'] = $matches[1]; + $result['fullPackage'] = $matches[1]; + } + + if (preg_match('/@subpackage[\s]+([\.\w]+)/', $docComment, $matches)) { + $result['subpackage'] = $matches[1]; + $result['fullPackage'] .= '.' . $matches[1]; + } + + if (empty($result['fullPackage'])) { + $result['fullPackage'] = self::arrayToName( + explode('_', str_replace('\\', '_', $className)), '.' + ); + } + + return $result; + } + + /** + * Returns a filesystem safe version of the passed filename. + * This function does not operate on full paths, just filenames. + * + * @param string $filename + * @return string + * @author Michael Lively Jr. + */ + public static function getSafeFilename($filename) + { + /* characters allowed: A-Z, a-z, 0-9, _ and . */ + return preg_replace('#[^\w.]#', '_', $filename); + } + + /** + * @param float $a + * @param float $b + * @return float ($a / $b) * 100 + */ + public static function percent($a, $b, $asString = FALSE) + { + if ($b > 0) { + $percent = ($a / $b) * 100; + } else { + $percent = 100; + } + + if ($asString) { + return sprintf('%01.2F', $percent); + } else { + return $percent; + } + } + + /** + * Reduces the paths by cutting the longest common start path. + * + * For instance, + * + * + * Array + * ( + * [/home/sb/Money/Money.php] => Array + * ( + * ... + * ) + * + * [/home/sb/Money/MoneyBag.php] => Array + * ( + * ... + * ) + * ) + * + * + * is reduced to + * + * + * Array + * ( + * [Money.php] => Array + * ( + * ... + * ) + * + * [MoneyBag.php] => Array + * ( + * ... + * ) + * ) + * + * + * @param array $files + * @return string + */ + public static function reducePaths(&$files) + { + if (empty($files)) { + return '.'; + } + + $commonPath = ''; + $paths = array_keys($files); + + if (count($files) == 1) { + $commonPath = dirname($paths[0]) . '/'; + $files[basename($paths[0])] = $files[$paths[0]]; + + unset($files[$paths[0]]); + + return $commonPath; + } + + $max = count($paths); + + for ($i = 0; $i < $max; $i++) { + $paths[$i] = explode(DIRECTORY_SEPARATOR, $paths[$i]); + + if (empty($paths[$i][0])) { + $paths[$i][0] = DIRECTORY_SEPARATOR; + } + } + + $done = FALSE; + $max = count($paths); + + while (!$done) { + for ($i = 0; $i < $max - 1; $i++) { + if (!isset($paths[$i][0]) || + !isset($paths[$i+1][0]) || + $paths[$i][0] != $paths[$i+1][0]) { + $done = TRUE; + break; + } + } + + if (!$done) { + $commonPath .= $paths[0][0]; + + if ($paths[0][0] != DIRECTORY_SEPARATOR) { + $commonPath .= DIRECTORY_SEPARATOR; + } + + for ($i = 0; $i < $max; $i++) { + array_shift($paths[$i]); + } + } + } + + $original = array_keys($files); + $max = count($original); + + for ($i = 0; $i < $max; $i++) { + $files[join('/', $paths[$i])] = $files[$original[$i]]; + unset($files[$original[$i]]); + } + + ksort($files); + + return $commonPath; + } + + /** + * Returns the package information of a user-defined class. + * + * @param array $parts + * @param string $join + * @return string + */ + protected static function arrayToName(array $parts, $join = '\\') + { + $result = ''; + + if (count($parts) > 1) { + array_pop($parts); + + $result = join($join, $parts); + } + + return $result; + } + + /** + * @param string $coveredElement + * @return array + */ + protected static function resolveCoversToReflectionObjects($coveredElement) + { + $codeToCoverList = array(); + + if (strpos($coveredElement, '::') !== FALSE) { + list($className, $methodName) = explode('::', $coveredElement); + + if ($methodName[0] == '<') { + $classes = array($className); + + foreach ($classes as $className) { + if (!class_exists($className) && + !interface_exists($className)) { + throw new RuntimeException( + sprintf( + 'Trying to @cover not existing class or ' . + 'interface "%s".', + $className + ) + ); + } + + $class = new ReflectionClass($className); + $methods = $class->getMethods(); + $inverse = isset($methodName[1]) && $methodName[1] == '!'; + + if (strpos($methodName, 'protected')) { + $visibility = 'isProtected'; + } + + else if (strpos($methodName, 'private')) { + $visibility = 'isPrivate'; + } + + else if (strpos($methodName, 'public')) { + $visibility = 'isPublic'; + } + + foreach ($methods as $method) { + if ($inverse && !$method->$visibility()) { + $codeToCoverList[] = $method; + } + + else if (!$inverse && $method->$visibility()) { + $codeToCoverList[] = $method; + } + } + } + } else { + $classes = array($className); + + foreach ($classes as $className) { + if ($className == '' && function_exists($methodName)) { + $codeToCoverList[] = new ReflectionFunction( + $methodName + ); + } else { + if (!((class_exists($className) || + interface_exists($className)) && + method_exists($className, $methodName))) { + throw new RuntimeException( + sprintf( + 'Trying to @cover not existing method "%s::%s".', + $className, + $methodName + ) + ); + } + + $codeToCoverList[] = new ReflectionMethod( + $className, $methodName + ); + } + } + } + } else { + $extended = FALSE; + + if (strpos($coveredElement, '') !== FALSE) { + $coveredElement = str_replace( + '', '', $coveredElement + ); + + $extended = TRUE; + } + + $classes = array($coveredElement); + + if ($extended) { + $classes = array_merge( + $classes, + class_implements($coveredElement), + class_parents($coveredElement) + ); + } + + foreach ($classes as $className) { + if (!class_exists($className) && + !interface_exists($className)) { + throw new RuntimeException( + sprintf( + 'Trying to @cover not existing class or ' . + 'interface "%s".', + $className + ) + ); + } + + $codeToCoverList[] = new ReflectionClass($className); + } + } + + return $codeToCoverList; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/Timer.php b/typo3conf/ext/phpunit/PEAR/PHP/Timer.php new file mode 100644 index 0000000..afecddf --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/Timer.php @@ -0,0 +1,139 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHP + * @subpackage Timer + * @author Sebastian Bergmann + * @copyright 2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/php-timer + * @since File available since Release 1.0.0 + */ + +/** + * Utility class for timing. + * + * @package PHP + * @subpackage Timer + * @author Sebastian Bergmann + * @copyright 2002-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.0 + * @link http://github.com/sebastianbergmann/php-timer + * @since Class available since Release 1.0.0 + */ +class PHP_Timer +{ + protected static $startTimes = array(); + + /** + * Starts the timer. + */ + public static function start() + { + array_push(self::$startTimes, microtime(TRUE)); + } + + /** + * Stops the timer and returns the elapsed time. + * + * @return float + */ + public static function stop() + { + return microtime(TRUE) - array_pop(self::$startTimes); + } + + /** + * Formats the elapsed time as a string. + * + * @param float $time + * @return string + */ + public static function secondsToTimeString($time) + { + $buffer = ''; + + $hours = sprintf('%02d', ($time >= 3600) ? floor($time / 3600) : 0); + $minutes = sprintf( + '%02d', + ($time >= 60) ? floor($time / 60) - 60 * $hours : 0 + ); + $seconds = sprintf('%02d', $time - 60 * 60 * $hours - 60 * $minutes); + + if ($hours == 0 && $minutes == 0) { + $seconds = sprintf('%1d', $seconds); + + $buffer .= $seconds . ' second'; + + if ($seconds != '1') { + $buffer .= 's'; + } + } else { + if ($hours > 0) { + $buffer = $hours . ':'; + } + + $buffer .= $minutes . ':' . $seconds; + } + + return $buffer; + } + + /** + * Formats the elapsed time since the start of the request as a string. + * + * @return string + */ + public static function timeSinceStartOfRequest() + { + return self::secondsToTimeString(time() - $_SERVER['REQUEST_TIME']); + } + + /** + * Returns the resources (time, memory) of the request as a string. + * + * @return string + */ + public static function resourceUsage() + { + return sprintf( + 'Time: %s, Memory: %4.2fMb', + self::timeSinceStartOfRequest(), + memory_get_peak_usage(TRUE) / 1048576 + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/Token.php b/typo3conf/ext/phpunit/PEAR/PHP/Token.php new file mode 100644 index 0000000..1581e0e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/Token.php @@ -0,0 +1,475 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHP_TokenStream + * @author Sebastian Bergmann + * @copyright 2009-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @since File available since Release 1.0.0 + */ + +require_once 'PHP/Token/Exception.php'; + +/** + * A PHP token. + * + * @author Sebastian Bergmann + * @copyright 2009-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.1 + * @link http://github.com/sebastianbergmann/php-token-stream/tree + * @since Class available since Release 1.0.0 + */ +abstract class PHP_Token +{ + /** + * @var string + */ + protected $text; + + /** + * @var integer + */ + protected $line; + + /** + * @var PHP_Token_Stream + */ + protected $tokenStream; + + /** + * @var integer + */ + protected $id; + + /** + * Constructor. + * + * @param string $text + * @param integer $line + * @param PHP_Token_Stream $tokenStream + * @param integer $id + */ + public function __construct($text, $line, PHP_Token_Stream $tokenStream, $id) + { + $this->text = $text; + $this->line = $line; + $this->tokenStream = $tokenStream; + $this->id = $id; + } + + /** + * @return string + */ + public function __toString() + { + return $this->text; + } + + /** + * @return integer + */ + public function getLine() + { + return $this->line; + } +} + +abstract class PHP_TokenWithScope extends PHP_Token +{ + protected $endTokenId; + + public function getDocblock() + { + $tokens = $this->tokenStream->tokens(); + + for ($i = $this->id - 2; $i > $this->id - 6; $i -= 2) { + if (isset($tokens[$i]) && + $tokens[$i] instanceof PHP_Token_DOC_COMMENT) { + return (string)$tokens[$i]; + } + } + } + + public function getEndTokenId() + { + $block = 0; + $i = $this->id; + $tokens = $this->tokenStream->tokens(); + + while ($this->endTokenId === NULL && isset($tokens[$i])) { + if ($tokens[$i] instanceof PHP_Token_OPEN_CURLY) { + $block++; + } + + else if ($tokens[$i] instanceof PHP_Token_CLOSE_CURLY) { + $block--; + + if ($block === 0) { + $this->endTokenId = $i; + } + } + + $i++; + } + + if ($this->endTokenId === NULL) { + $this->endTokenId = $this->id; + } + + return $this->endTokenId; + } + + public function getEndLine() + { + return $this->tokenStream[$this->getEndTokenId()]->getLine(); + } +} + +class PHP_Token_REQUIRE_ONCE extends PHP_Token {} +class PHP_Token_REQUIRE extends PHP_Token {} +class PHP_Token_EVAL extends PHP_Token {} +class PHP_Token_INCLUDE_ONCE extends PHP_Token {} +class PHP_Token_INCLUDE extends PHP_Token {} +class PHP_Token_LOGICAL_OR extends PHP_Token {} +class PHP_Token_LOGICAL_XOR extends PHP_Token {} +class PHP_Token_LOGICAL_AND extends PHP_Token {} +class PHP_Token_PRINT extends PHP_Token {} +class PHP_Token_SR_EQUAL extends PHP_Token {} +class PHP_Token_SL_EQUAL extends PHP_Token {} +class PHP_Token_XOR_EQUAL extends PHP_Token {} +class PHP_Token_OR_EQUAL extends PHP_Token {} +class PHP_Token_AND_EQUAL extends PHP_Token {} +class PHP_Token_MOD_EQUAL extends PHP_Token {} +class PHP_Token_CONCAT_EQUAL extends PHP_Token {} +class PHP_Token_DIV_EQUAL extends PHP_Token {} +class PHP_Token_MUL_EQUAL extends PHP_Token {} +class PHP_Token_MINUS_EQUAL extends PHP_Token {} +class PHP_Token_PLUS_EQUAL extends PHP_Token {} +class PHP_Token_BOOLEAN_OR extends PHP_Token {} +class PHP_Token_BOOLEAN_AND extends PHP_Token {} +class PHP_Token_IS_NOT_IDENTICAL extends PHP_Token {} +class PHP_Token_IS_IDENTICAL extends PHP_Token {} +class PHP_Token_IS_NOT_EQUAL extends PHP_Token {} +class PHP_Token_IS_EQUAL extends PHP_Token {} +class PHP_Token_IS_GREATER_OR_EQUAL extends PHP_Token {} +class PHP_Token_IS_SMALLER_OR_EQUAL extends PHP_Token {} +class PHP_Token_SR extends PHP_Token {} +class PHP_Token_SL extends PHP_Token {} +class PHP_Token_INSTANCEOF extends PHP_Token {} +class PHP_Token_UNSET_CAST extends PHP_Token {} +class PHP_Token_BOOL_CAST extends PHP_Token {} +class PHP_Token_OBJECT_CAST extends PHP_Token {} +class PHP_Token_ARRAY_CAST extends PHP_Token {} +class PHP_Token_STRING_CAST extends PHP_Token {} +class PHP_Token_DOUBLE_CAST extends PHP_Token {} +class PHP_Token_INT_CAST extends PHP_Token {} +class PHP_Token_DEC extends PHP_Token {} +class PHP_Token_INC extends PHP_Token {} +class PHP_Token_CLONE extends PHP_Token {} +class PHP_Token_NEW extends PHP_Token {} +class PHP_Token_EXIT extends PHP_Token {} +class PHP_Token_IF extends PHP_Token {} +class PHP_Token_ELSEIF extends PHP_Token {} +class PHP_Token_ELSE extends PHP_Token {} +class PHP_Token_ENDIF extends PHP_Token {} +class PHP_Token_LNUMBER extends PHP_Token {} +class PHP_Token_DNUMBER extends PHP_Token {} +class PHP_Token_STRING extends PHP_Token {} +class PHP_Token_STRING_VARNAME extends PHP_Token {} +class PHP_Token_VARIABLE extends PHP_Token {} +class PHP_Token_NUM_STRING extends PHP_Token {} +class PHP_Token_INLINE_HTML extends PHP_Token {} +class PHP_Token_CHARACTER extends PHP_Token {} +class PHP_Token_BAD_CHARACTER extends PHP_Token {} +class PHP_Token_ENCAPSED_AND_WHITESPACE extends PHP_Token {} +class PHP_Token_CONSTANT_ENCAPSED_STRING extends PHP_Token {} +class PHP_Token_ECHO extends PHP_Token {} +class PHP_Token_DO extends PHP_Token {} +class PHP_Token_WHILE extends PHP_Token {} +class PHP_Token_ENDWHILE extends PHP_Token {} +class PHP_Token_FOR extends PHP_Token {} +class PHP_Token_ENDFOR extends PHP_Token {} +class PHP_Token_FOREACH extends PHP_Token {} +class PHP_Token_ENDFOREACH extends PHP_Token {} +class PHP_Token_DECLARE extends PHP_Token {} +class PHP_Token_ENDDECLARE extends PHP_Token {} +class PHP_Token_AS extends PHP_Token {} +class PHP_Token_SWITCH extends PHP_Token {} +class PHP_Token_ENDSWITCH extends PHP_Token {} +class PHP_Token_CASE extends PHP_Token {} +class PHP_Token_DEFAULT extends PHP_Token {} +class PHP_Token_BREAK extends PHP_Token {} +class PHP_Token_CONTINUE extends PHP_Token {} +class PHP_Token_GOTO extends PHP_Token {} + +class PHP_Token_FUNCTION extends PHP_TokenWithScope +{ + protected $arguments; + protected $ccn; + protected $name; + protected $signature; + + public function getArguments() + { + if ($this->arguments !== NULL) { + return $this->arguments; + } + + $this->arguments = array(); + $i = $this->id + 3; + $tokens = $this->tokenStream->tokens(); + $typeHint = NULL; + + while (!$tokens[$i] instanceof PHP_Token_CLOSE_BRACKET) { + if ($tokens[$i] instanceof PHP_Token_STRING) { + $typeHint = (string)$tokens[$i]; + } + + else if ($tokens[$i] instanceof PHP_Token_VARIABLE) { + $this->arguments[(string)$tokens[$i]] = $typeHint; + $typeHint = NULL; + } + + $i++; + } + + return $this->arguments; + } + + public function getName() + { + if ($this->name !== NULL) { + return $this->name; + } + + $tokens = $this->tokenStream->tokens(); + + if ($tokens[$this->id+2] instanceof PHP_Token_STRING) { + $this->name = (string)$tokens[$this->id+2]; + } + + else if ($tokens[$this->id+2] instanceof PHP_Token_AMPERSAND && + $tokens[$this->id+3] instanceof PHP_Token_STRING) { + $this->name = (string)$tokens[$this->id+3]; + } + + else { + $this->name = 'anonymous function'; + } + + return $this->name; + } + + public function getCCN() + { + if ($this->ccn !== NULL) { + return $this->ccn; + } + + $this->ccn = 1; + $end = $this->getEndTokenId(); + $tokens = $this->tokenStream->tokens(); + + for ($i = $this->id; $i <= $end; $i++) { + switch (get_class($tokens[$i])) { + case 'PHP_Token_IF': + case 'PHP_Token_ELSEIF': + case 'PHP_Token_FOR': + case 'PHP_Token_FOREACH': + case 'PHP_Token_WHILE': + case 'PHP_Token_CASE': + case 'PHP_Token_CATCH': + case 'PHP_Token_BOOLEAN_AND': + case 'PHP_Token_LOGICAL_AND': + case 'PHP_Token_BOOLEAN_OR': + case 'PHP_Token_LOGICAL_OR': + case 'PHP_Token_QUESTION_MARK': { + $this->ccn++; + } + break; + } + } + + return $this->ccn; + } + + public function getSignature() + { + if ($this->signature !== NULL) { + return $this->signature; + } + + $this->signature = ''; + + $i = $this->id + 2; + $tokens = $this->tokenStream->tokens(); + + while (!$tokens[$i] instanceof PHP_Token_CLOSE_BRACKET) { + $this->signature .= $tokens[$i++]; + } + + $this->signature .= ')'; + + return $this->signature; + } +} + +class PHP_Token_CONST extends PHP_Token {} +class PHP_Token_RETURN extends PHP_Token {} +class PHP_Token_TRY extends PHP_Token {} +class PHP_Token_CATCH extends PHP_Token {} +class PHP_Token_THROW extends PHP_Token {} +class PHP_Token_USE extends PHP_Token {} +class PHP_Token_GLOBAL extends PHP_Token {} +class PHP_Token_PUBLIC extends PHP_Token {} +class PHP_Token_PROTECTED extends PHP_Token {} +class PHP_Token_PRIVATE extends PHP_Token {} +class PHP_Token_FINAL extends PHP_Token {} +class PHP_Token_ABSTRACT extends PHP_Token {} +class PHP_Token_STATIC extends PHP_Token {} +class PHP_Token_VAR extends PHP_Token {} +class PHP_Token_UNSET extends PHP_Token {} +class PHP_Token_ISSET extends PHP_Token {} +class PHP_Token_EMPTY extends PHP_Token {} +class PHP_Token_HALT_COMPILER extends PHP_Token {} + +class PHP_Token_INTERFACE extends PHP_TokenWithScope +{ + public function getName() + { + return (string)$this->tokenStream[$this->id + 2]; + } + + public function hasParent() + { + return $this->tokenStream[$this->id + 4] instanceof PHP_Token_EXTENDS; + } + + public function getParent() + { + if (!$this->hasParent()) { + return FALSE; + } + + $i = $this->id + 6; + $tokens = $this->tokenStream->tokens(); + $className = (string)$tokens[$i]; + + while (!$tokens[$i+1] instanceof PHP_Token_WHITESPACE) { + $className .= (string)$tokens[++$i]; + } + + return $className; + } +} + +class PHP_Token_CLASS extends PHP_Token_INTERFACE {} +class PHP_Token_EXTENDS extends PHP_Token {} +class PHP_Token_IMPLEMENTS extends PHP_Token {} +class PHP_Token_OBJECT_OPERATOR extends PHP_Token {} +class PHP_Token_DOUBLE_ARROW extends PHP_Token {} +class PHP_Token_LIST extends PHP_Token {} +class PHP_Token_ARRAY extends PHP_Token {} +class PHP_Token_CLASS_C extends PHP_Token {} +class PHP_Token_METHOD_C extends PHP_Token {} +class PHP_Token_FUNC_C extends PHP_Token {} +class PHP_Token_LINE extends PHP_Token {} +class PHP_Token_FILE extends PHP_Token {} +class PHP_Token_COMMENT extends PHP_Token {} +class PHP_Token_DOC_COMMENT extends PHP_Token {} +class PHP_Token_OPEN_TAG extends PHP_Token {} +class PHP_Token_OPEN_TAG_WITH_ECHO extends PHP_Token {} +class PHP_Token_CLOSE_TAG extends PHP_Token {} +class PHP_Token_WHITESPACE extends PHP_Token {} +class PHP_Token_START_HEREDOC extends PHP_Token {} +class PHP_Token_END_HEREDOC extends PHP_Token {} +class PHP_Token_DOLLAR_OPEN_CURLY_BRACES extends PHP_Token {} +class PHP_Token_CURLY_OPEN extends PHP_Token {} +class PHP_Token_PAAMAYIM_NEKUDOTAYIM extends PHP_Token {} + +class PHP_Token_NAMESPACE extends PHP_Token +{ + public function getName() + { + $tokens = $this->tokenStream->tokens(); + $namespace = (string)$tokens[$this->id+2]; + + for ($i = $this->id + 3; ; $i += 2) { + if (isset($tokens[$i]) && + $tokens[$i] instanceof PHP_Token_NS_SEPARATOR) { + $namespace .= '\\' . $tokens[$i+1]; + } else { + break; + } + } + + return $namespace; + } +} + +class PHP_Token_NS_C extends PHP_Token {} +class PHP_Token_DIR extends PHP_Token {} +class PHP_Token_NS_SEPARATOR extends PHP_Token {} +class PHP_Token_DOUBLE_COLON extends PHP_Token {} +class PHP_Token_OPEN_BRACKET extends PHP_Token {} +class PHP_Token_CLOSE_BRACKET extends PHP_Token {} +class PHP_Token_OPEN_SQUARE extends PHP_Token {} +class PHP_Token_CLOSE_SQUARE extends PHP_Token {} +class PHP_Token_OPEN_CURLY extends PHP_Token {} +class PHP_Token_CLOSE_CURLY extends PHP_Token {} +class PHP_Token_SEMICOLON extends PHP_Token {} +class PHP_Token_DOT extends PHP_Token {} +class PHP_Token_COMMA extends PHP_Token {} +class PHP_Token_EQUAL extends PHP_Token {} +class PHP_Token_LT extends PHP_Token {} +class PHP_Token_GT extends PHP_Token {} +class PHP_Token_PLUS extends PHP_Token {} +class PHP_Token_MINUS extends PHP_Token {} +class PHP_Token_MULT extends PHP_Token {} +class PHP_Token_DIV extends PHP_Token {} +class PHP_Token_QUESTION_MARK extends PHP_Token {} +class PHP_Token_EXCLAMATION_MARK extends PHP_Token {} +class PHP_Token_COLON extends PHP_Token {} +class PHP_Token_DOUBLE_QUOTES extends PHP_Token {} +class PHP_Token_AT extends PHP_Token {} +class PHP_Token_AMPERSAND extends PHP_Token {} +class PHP_Token_PERCENT extends PHP_Token {} +class PHP_Token_PIPE extends PHP_Token {} +class PHP_Token_DOLLAR extends PHP_Token {} +class PHP_Token_CARET extends PHP_Token {} +class PHP_Token_TILDE extends PHP_Token {} +class PHP_Token_BACKTICK extends PHP_Token {} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/Token/Exception.php b/typo3conf/ext/phpunit/PEAR/PHP/Token/Exception.php new file mode 100644 index 0000000..3791aa3 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/Token/Exception.php @@ -0,0 +1,56 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHP_TokenStream + * @author Sebastian Bergmann + * @copyright 2009-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @since File available since Release 1.0.0 + */ + +/** + * Exception class. + * + * @author Sebastian Bergmann + * @copyright 2009-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.1 + * @link http://github.com/sebastianbergmann/php-token-stream/tree + * @since Class available since Release 1.0.0 + */ +class PHP_Token_Exception extends RuntimeException +{ +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/Token/Stream.php b/typo3conf/ext/phpunit/PEAR/PHP/Token/Stream.php new file mode 100644 index 0000000..60aba66 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/Token/Stream.php @@ -0,0 +1,378 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHP_TokenStream + * @author Sebastian Bergmann + * @copyright 2009-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @since File available since Release 1.0.0 + */ + +require_once 'PHP/Token.php'; + +/** + * A stream of PHP tokens. + * + * @author Sebastian Bergmann + * @copyright 2009-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.1 + * @link http://github.com/sebastianbergmann/php-token-stream/tree + * @since Class available since Release 1.0.0 + */ +class PHP_Token_Stream implements ArrayAccess, Countable, SeekableIterator +{ + /** + * @var array + */ + protected static $customTokens = array( + '(' => 'PHP_Token_OPEN_BRACKET', + ')' => 'PHP_Token_CLOSE_BRACKET', + '[' => 'PHP_Token_OPEN_SQUARE', + ']' => 'PHP_Token_CLOSE_SQUARE', + '{' => 'PHP_Token_OPEN_CURLY', + '}' => 'PHP_Token_CLOSE_CURLY', + ';' => 'PHP_Token_SEMICOLON', + '.' => 'PHP_Token_DOT', + ',' => 'PHP_Token_COMMA', + '=' => 'PHP_Token_EQUAL', + '<' => 'PHP_Token_LT', + '>' => 'PHP_Token_GT', + '+' => 'PHP_Token_PLUS', + '-' => 'PHP_Token_MINUS', + '*' => 'PHP_Token_MULT', + '/' => 'PHP_Token_DIV', + '?' => 'PHP_Token_QUESTION_MARK', + '!' => 'PHP_Token_EXCLAMATION_MARK', + ':' => 'PHP_Token_COLON', + '"' => 'PHP_Token_DOUBLE_QUOTES', + '@' => 'PHP_Token_AT', + '&' => 'PHP_Token_AMPERSAND', + '%' => 'PHP_Token_PERCENT', + '|' => 'PHP_Token_PIPE', + '$' => 'PHP_Token_DOLLAR', + '^' => 'PHP_Token_CARET', + '~' => 'PHP_Token_TILDE', + '`' => 'PHP_Token_BACKTICK' + ); + + /** + * @var array + */ + protected $tokens = array(); + + /** + * @var integer + */ + protected $position = 0; + + /** + * @var array + */ + protected $linesOfCode = array('loc' => 0, 'cloc' => 0, 'ncloc' => 0); + + /** + * @var array + */ + protected $classes; + + /** + * @var array + */ + protected $functions; + + /** + * Constructor. + * + * @param string $sourceCode + */ + public function __construct($sourceCode) + { + if (is_file($sourceCode)) { + $sourceCode = file_get_contents($sourceCode); + } + + $this->scan($sourceCode); + } + + /** + * Scans the source for sequences of characters and converts them into a + * stream of tokens. + * + * @param string $sourceCode + */ + protected function scan($sourceCode) + { + $line = 1; + $tokens = token_get_all($sourceCode); + $numTokens = count($tokens); + + for ($i = 0; $i < $numTokens; ++$i) { + $token = $tokens[$i]; + unset($tokens[$i]); + + if (is_array($token)) { + $text = $token[1]; + $tokenClass = 'PHP_Token_' . substr(token_name($token[0]), 2); + } else { + $text = $token; + $tokenClass = self::$customTokens[$token]; + } + + $this->tokens[] = new $tokenClass($text, $line, $this, $i); + $lines = substr_count($text, "\n"); + $line += $lines; + + if ($tokenClass == 'PHP_Token_HALT_COMPILER') { + break; + } + + else if ($tokenClass == 'PHP_Token_COMMENT' || + $tokenClass == 'PHP_Token_DOC_COMMENT') { + $this->linesOfCode['cloc'] += $lines + 1; + } + } + + $this->linesOfCode['loc'] = substr_count($sourceCode, "\n"); + $this->linesOfCode['ncloc'] = $this->linesOfCode['loc'] - + $this->linesOfCode['cloc']; + } + + /** + * @return string + */ + public function __toString() + { + $buffer = ''; + + foreach ($this as $token) { + $buffer .= $token; + } + + return $buffer; + } + + /** + * @return integer + */ + public function count() + { + return count($this->tokens); + } + + /** + * @return PHP_Token[] + */ + public function tokens() + { + return $this->tokens; + } + + /** + * @return array + */ + public function getClasses() + { + if ($this->classes !== NULL) { + return $this->classes; + } + + $this->parseClassesFunctions(); + + return $this->classes; + } + + /** + * @return array + */ + public function getFunctions() + { + if ($this->functions !== NULL) { + return $this->functions; + } + + $this->parseClassesFunctions(); + + return $this->functions; + } + + protected function parseClassesFunctions() + { + $this->classes = array(); + $this->functions = array(); + $class = FALSE; + $classEndLine = FALSE; + + foreach ($this->tokens as $token) { + switch (get_class($token)) { + case 'PHP_Token_CLASS': { + $class = $token->getName(); + $classEndLine = $token->getEndLine(); + + $this->classes[$class] = array( + 'methods' => array(), + 'docblock' => $token->getDocblock(), + 'startLine' => $token->getLine(), + 'endLine' => $classEndLine + ); + } + break; + + case 'PHP_Token_FUNCTION': { + $name = $token->getName(); + $tmp = array( + 'docblock' => $token->getDocblock(), + 'signature' => $token->getSignature(), + 'startLine' => $token->getLine(), + 'endLine' => $token->getEndLine(), + 'ccn' => $token->getCCN() + ); + + if ($class === FALSE) { + $this->functions[$name] = $tmp; + } else { + $this->classes[$class]['methods'][$name] = $tmp; + } + } + break; + + case 'PHP_Token_CLOSE_CURLY': { + if ($classEndLine !== FALSE && + $classEndLine == $token->getLine()) { + $class = FALSE; + $classEndLine = FALSE; + } + } + break; + } + } + } + + /** + * @return array + */ + public function getLinesOfCode() + { + return $this->linesOfCode; + } + + /** + */ + public function rewind() + { + $this->position = 0; + } + + /** + * @return boolean + */ + public function valid() + { + return isset($this->tokens[$this->position]); + } + + /** + * @return integer + */ + public function key() + { + return $this->position; + } + + /** + * @return PHP_Token + */ + public function current() + { + return $this->tokens[$this->position]; + } + + /** + */ + public function next() + { + $this->position++; + } + + /** + * @param mixed $offset + */ + public function offsetExists($offset) + { + return isset($this->tokens[$offset]); + } + + /** + * @param mixed $offset + * @return mixed + */ + public function offsetGet($offset) + { + return $this->tokens[$offset]; + } + + /** + * @param mixed $offset + * @param mixed $value + */ + public function offsetSet($offset, $value) + { + $this->tokens[$offset] = $value; + } + + /** + * @param mixed $offset + */ + public function offsetUnset($offset) + { + unset($this->tokens[$offset]); + } + + /** + * Seek to an absolute position. + * + * @param integer $position + * @throws OutOfBoundsException + */ + public function seek($position) + { + $this->position = $position; + + if (!$this->valid()) { + throw new OutOfBoundsException('Invalid seek position'); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/Token/Stream/CachingFactory.php b/typo3conf/ext/phpunit/PEAR/PHP/Token/Stream/CachingFactory.php new file mode 100644 index 0000000..e1a43b9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/Token/Stream/CachingFactory.php @@ -0,0 +1,75 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHP_TokenStream + * @author Sebastian Bergmann + * @copyright 2009-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @since File available since Release 1.0.0 + */ + +require_once 'PHP/Token/Stream.php'; + +/** + * A caching factory for token stream objects. + * + * @author Sebastian Bergmann + * @copyright 2009-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.1 + * @link http://github.com/sebastianbergmann/php-token-stream/tree + * @since Class available since Release 1.0.0 + */ +class PHP_Token_Stream_CachingFactory +{ + /** + * @var array + */ + protected static $cache = array(); + + /** + * @param string $filename + * @return PHP_Token_Stream + */ + public static function get($filename) + { + if (!isset(self::$cache[$filename])) { + self::$cache[$filename] = new PHP_Token_Stream($filename); + } + + return self::$cache[$filename]; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHP/Token/Stream/TextUI/Command.php b/typo3conf/ext/phpunit/PEAR/PHP/Token/Stream/TextUI/Command.php new file mode 100644 index 0000000..8bcc4a8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHP/Token/Stream/TextUI/Command.php @@ -0,0 +1,181 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHP_TokenStream + * @author Sebastian Bergmann + * @copyright 2009-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @since File available since Release 1.0.0 + */ + +require_once 'PHP/Token/Stream.php'; +require_once 'ezc/Base/base.php'; + +function __autoload($className) +{ + ezcBase::autoload($className); +} + +/** + * TextUI frontend for PHP_TokenStream. + * + * @author Sebastian Bergmann + * @copyright 2009-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.1 + * @link http://github.com/sebastianbergmann/php-token-stream/tree + * @since Class available since Release 1.0.0 + */ +class PHP_Token_Stream_TextUI_Command +{ + /** + * Main method. + */ + public static function main() + { + $input = new ezcConsoleInput; + + $input->registerOption( + new ezcConsoleOption( + 'h', + 'help', + ezcConsoleInput::TYPE_NONE, + NULL, + FALSE, + '', + '', + array(), + array(), + FALSE, + FALSE, + TRUE + ) + ); + + $input->registerOption( + new ezcConsoleOption( + 'v', + 'version', + ezcConsoleInput::TYPE_NONE, + NULL, + FALSE, + '', + '', + array(), + array(), + FALSE, + FALSE, + TRUE + ) + ); + + try { + $input->process(); + } + + catch (ezcConsoleOptionException $e) { + print $e->getMessage() . "\n"; + exit(1); + } + + if ($input->getOption('help')->value) { + self::showHelp(); + exit(0); + } + + else if ($input->getOption('version')->value) { + self::printVersionString(); + exit(0); + } + + $arguments = $input->getArguments(); + + if (empty($arguments)) { + self::showHelp(); + exit(1); + } + + self::printVersionString(); + + print "Line Token Text\n" . + str_repeat('-', 79) . "\n"; + + foreach (new PHP_Token_Stream($arguments[0]) as $token) { + if ($token instanceof PHP_Token_WHITESPACE) { + $text = ''; + } else { + $text = str_replace(array("\r", "\n"), '', (string)$token); + + if (strlen($text) > 40) { + $text = explode("\n", wordwrap($text, 40)); + $text = $text[0]; + } + } + + printf( + "%5d %-30s %s\n", + $token->getLine(), + str_replace('PHP_Token_', '', get_class($token)), + $text + ); + } + } + + /** + * Shows the help. + */ + protected static function showHelp() + { + self::printVersionString(); + + print << + + --help Prints this usage information. + --version Prints the version and exits. + +EOT; + } + + /** + * Prints the version string. + */ + protected static function printVersionString() + { + print "phptok 1.0.1 by Sebastian Bergmann.\n\n"; + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Autoload.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Autoload.php new file mode 100644 index 0000000..19ea365 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Autoload.php @@ -0,0 +1,89 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.5.0 + */ + +require_once 'PHPUnit/Util/Filesystem.php'; +require_once 'PHP/CodeCoverage/Filter.php'; + +if (!function_exists('phpunit_autoload')) { + function phpunit_autoload($class) + { + if (strpos($class, 'PHPUnit_') === 0) { + $file = str_replace('_', '/', $class) . '.php'; + $file = PHPUnit_Util_Filesystem::fileExistsInIncludePath($file); + + if ($file) { + require_once $file; + } + } + } + + spl_autoload_register('phpunit_autoload'); + + $dir = dirname(__FILE__); + $filter = PHP_CodeCoverage_Filter::getInstance(); + + $filter->addDirectoryToBlacklist( + $dir . '/Extensions', '.php', '', 'PHPUNIT', FALSE + ); + + $filter->addDirectoryToBlacklist( + $dir . '/Framework', '.php', '', 'PHPUNIT', FALSE + ); + + $filter->addDirectoryToBlacklist( + $dir . '/Runner', '.php', '', 'PHPUNIT', FALSE + ); + + $filter->addDirectoryToBlacklist( + $dir . '/TextUI', '.php', '', 'PHPUNIT', FALSE + ); + + $filter->addDirectoryToBlacklist( + $dir . '/Util', '.php', '', 'PHPUNIT', FALSE + ); + + $filter->addFileToBlacklist(__FILE__, 'PHPUNIT', FALSE); + + unset($dir, $filter); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/AbstractTester.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/AbstractTester.php new file mode 100644 index 0000000..1f5614a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/AbstractTester.php @@ -0,0 +1,195 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Can be used as a foundation for new DatabaseTesters. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +abstract class PHPUnit_Extensions_Database_AbstractTester implements PHPUnit_Extensions_Database_ITester +{ + + /** + * @var PHPUnit_Extensions_Database_Operation_IDatabaseOperation + */ + protected $setUpOperation; + + /** + * @var PHPUnit_Extensions_Database_Operation_IDatabaseOperation + */ + protected $tearDownOperation; + + /** + * @var PHPUnit_Extensions_Database_DataSet_IDataSet + */ + protected $dataSet; + + /** + * @var string + */ + protected $schema; + + /** + * Creates a new database tester. + * + * @param PHPUnit_Extensions_Database_DB_IDatabaseConnection $databaseConnection + */ + public function __construct() + { + $this->setUpOperation = PHPUnit_Extensions_Database_Operation_Factory::CLEAN_INSERT(); + $this->tearDownOperation = PHPUnit_Extensions_Database_Operation_Factory::NONE(); + } + + /** + * Closes the specified connection. + * + * @param PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection + */ + public function closeConnection(PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection) + { + $connection->close(); + } + + /** + * Returns the test dataset. + * + * @return PHPUnit_Extensions_Database_DataSet_IDataSet + */ + public function getDataSet() + { + return $this->dataSet; + } + + /** + * TestCases must call this method inside setUp(). + */ + public function onSetUp() + { + $this->getSetUpOperation()->execute($this->getConnection(), $this->getDataSet()); + } + + /** + * TestCases must call this method inside tearDown(). + */ + public function onTearDown() + { + $this->getTearDownOperation()->execute($this->getConnection(), $this->getDataSet()); + } + + /** + * Sets the test dataset to use. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet + */ + public function setDataSet(PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet) + { + $this->dataSet = $dataSet; + } + + /** + * Sets the schema value. + * + * @param string $schema + */ + public function setSchema($schema) + { + $this->schema = $schema; + } + + /** + * Sets the DatabaseOperation to call when starting the test. + * + * @param PHPUnit_Extensions_Database_Operation_DatabaseOperation $setUpOperation + */ + public function setSetUpOperation(PHPUnit_Extensions_Database_Operation_IDatabaseOperation $setUpOperation) + { + $this->setUpOperation = $setUpOperation; + } + + /** + * Sets the DatabaseOperation to call when ending the test. + * + * @param PHPUnit_Extensions_Database_Operation_DatabaseOperation $tearDownOperation + */ + public function setTearDownOperation(PHPUnit_Extensions_Database_Operation_IDatabaseOperation $tearDownOperation) + { + $this->tearDownOperation = $tearDownOperation; + } + + /** + * Returns the schema value + * + * @return string + */ + protected function getSchema() + { + return $this->schema; + } + + /** + * Returns the database operation that will be called when starting the test. + * + * @return PHPUnit_Extensions_Database_Operation_DatabaseOperation + */ + protected function getSetUpOperation() + { + return $this->setUpOperation; + } + + /** + * Returns the database operation that will be called when ending the test. + * + * @return PHPUnit_Extensions_Database_Operation_DatabaseOperation + */ + protected function getTearDownOperation() + { + return $this->tearDownOperation; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Constraint/DataSetIsEqual.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Constraint/DataSetIsEqual.php new file mode 100644 index 0000000..16dcce4 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Constraint/DataSetIsEqual.php @@ -0,0 +1,122 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Asserts whether or not two dbunit datasets are equal. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_Constraint_DataSetIsEqual extends PHPUnit_Framework_Constraint +{ + + /** + * @var PHPUnit_Extensions_Database_DataSet_IDataSet + */ + protected $value; + + /** + * @var string + */ + protected $failure_reason; + + /** + * Creates a new constraint. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $value + */ + public function __construct(PHPUnit_Extensions_Database_DataSet_IDataSet $value) + { + $this->value = $value; + } + + /** + * Determines whether or not the given dataset matches the dataset used to + * create this constraint. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $other + * @return bool + */ + public function evaluate($other) + { + if ($other instanceof PHPUnit_Extensions_Database_DataSet_IDataSet) { + try { + $this->value->assertEquals($other); + return TRUE; + } catch (Exception $e) { + $this->failure_reason = $e->getMessage(); + return FALSE; + } + } else { + throw new InvalidArgumentException("PHPUnit_Extensions_Database_DataSet_IDataSet expected"); + } + } + + protected function customFailureDescription($other, $description, $not) + { + return sprintf( + 'Failed asserting that actual %s %s Reason: %s', + + $other->__toString(), + $this->toString(), + $this->failure_reason + ); + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return sprintf('is equal to expected %s', + $this->value->__toString()); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Constraint/TableIsEqual.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Constraint/TableIsEqual.php new file mode 100644 index 0000000..6afb43c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Constraint/TableIsEqual.php @@ -0,0 +1,123 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Asserts whether or not two dbunit tables are equal. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_Constraint_TableIsEqual extends PHPUnit_Framework_Constraint +{ + + /** + * @var PHPUnit_Extensions_Database_DataSet_ITable + */ + protected $value; + + /** + * @var string + */ + protected $failure_reason; + + /** + * Creates a new constraint. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $value + */ + public function __construct(PHPUnit_Extensions_Database_DataSet_ITable $value) + { + $this->value = $value; + } + + /** + * Determines whether or not the given table matches the table used to + * create this constraint. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $other + * @return bool + */ + public function evaluate($other) + { + if ($other instanceof PHPUnit_Extensions_Database_DataSet_ITable) { + try { + $this->value->assertEquals($other); + return TRUE; + } catch (Exception $e) { + $this->failure_reason = $e->getMessage(); + return FALSE; + } + } else { + throw new InvalidArgumentException("PHPUnit_Extensions_Database_DataSet_ITable expected"); + } + } + + protected function customFailureDescription($other, $description, $not) + { + return sprintf( + 'Failed asserting that actual %s %s Reason: %s', + + $other->__toString(), + $this->toString(), + $this->failure_reason + ); + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return sprintf('is equal to expected %s', + + PHPUnit_Util_Type::toString($this->value)); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/DataSet.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/DataSet.php new file mode 100644 index 0000000..3dcbf84 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/DataSet.php @@ -0,0 +1,173 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides access to a database instance as a data set. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DB_DataSet extends PHPUnit_Extensions_Database_DataSet_AbstractDataSet +{ + + /** + * An array of ITable objects. + * + * @var array + */ + protected $tables = array(); + + /** + * The database connection this dataset is using. + * + * @var PHPUnit_Extensions_Database_DB_IDatabaseConnection + */ + protected $databaseConnection; + + /** + * Creates a new dataset using the given database connection. + * + * @param PHPUnit_Extensions_Database_DB_IDatabaseConnection $databaseConnection + */ + public function __construct(PHPUnit_Extensions_Database_DB_IDatabaseConnection $databaseConnection) + { + $this->databaseConnection = $databaseConnection; + } + + /** + * Creates the query necessary to pull all of the data from a table. + * + * @param PHPUnit_Extensions_Database_DataSet_ITableMetaData $tableMetaData + * @return unknown + */ + public static function buildTableSelect(PHPUnit_Extensions_Database_DataSet_ITableMetaData $tableMetaData, PHPUnit_Extensions_Database_DB_IDatabaseConnection $databaseConnection = NULL) + { + if ($tableMetaData->getTableName() == '') { + $e = new Exception("Empty Table Name"); + echo $e->getTraceAsString(); + throw $e; + } + + $columns = $tableMetaData->getColumns(); + if ($databaseConnection) { + $columns = array_map(array($databaseConnection, 'quoteSchemaObject'), $columns); + } + $columnList = implode(', ', $columns); + + if ($databaseConnection) { + $tableName = $databaseConnection->quoteSchemaObject($tableMetaData->getTableName()); + } else { + $tableName = $tableMetaData->getTableName(); + } + + $primaryKeys = $tableMetaData->getPrimaryKeys(); + if ($databaseConnection) { + $primaryKeys = array_map(array($databaseConnection, 'quoteSchemaObject'), $primaryKeys); + } + if (count($primaryKeys)) { + $orderBy = 'ORDER BY ' . implode(' ASC, ', $primaryKeys) . ' ASC'; + } else { + $orderBy = ''; + } + + return "SELECT {$columnList} FROM {$tableName} {$orderBy}"; + } + + /** + * Creates an iterator over the tables in the data set. If $reverse is + * true a reverse iterator will be returned. + * + * @param bool $reverse + * @return PHPUnit_Extensions_Database_DB_TableIterator + */ + protected function createIterator($reverse = FALSE) + { + return new PHPUnit_Extensions_Database_DB_TableIterator($this->getTableNames(), $this, $reverse); + } + + /** + * Returns a table object for the given table. + * + * @param string $tableName + * @return PHPUnit_Extensions_Database_DB_Table + */ + public function getTable($tableName) + { + if (!in_array($tableName, $this->getTableNames())) { + throw new InvalidArgumentException("$tableName is not a table in the current database."); + } + + if (empty($this->tables[$tableName])) { + $this->tables[$tableName] = new PHPUnit_Extensions_Database_DB_Table($this->getTableMetaData($tableName), $this->databaseConnection); + } + + return $this->tables[$tableName]; + } + + /** + * Returns a table meta data object for the given table. + * + * @param string $tableName + * @return PHPUnit_Extensions_Database_DataSet_DefaultTableMetaData + */ + public function getTableMetaData($tableName) + { + return new PHPUnit_Extensions_Database_DataSet_DefaultTableMetaData($tableName, $this->databaseConnection->getMetaData()->getTableColumns($tableName), $this->databaseConnection->getMetaData()->getTablePrimaryKeys($tableName)); + } + + /** + * Returns a list of table names for the database + * + * @return Array + */ + public function getTableNames() + { + return $this->databaseConnection->getMetaData()->getTableNames(); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/DefaultDatabaseConnection.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/DefaultDatabaseConnection.php new file mode 100644 index 0000000..fa84a8e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/DefaultDatabaseConnection.php @@ -0,0 +1,210 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides a basic interface for communicating with a database. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection implements PHPUnit_Extensions_Database_DB_IDatabaseConnection +{ + /** + * @var PDO + */ + protected $connection; + + /** + * The metadata object used to retrieve table meta data from the database. + * + * @var PHPUnit_Extensions_Database_DB_IMetaData + */ + protected $metaData; + + /** + * Creates a new database connection + * + * @param PDO $connection + * @param string $schema - The name of the database schema you will be testing against. + */ + public function __construct(PDO $connection, $schema = '') + { + $this->connection = $connection; + $this->metaData = PHPUnit_Extensions_Database_DB_MetaData::createMetaData($connection, $schema); + $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + } + + /** + * Close this connection. + */ + public function close() + { + unset($this->connection); + } + + /** + * Returns a database metadata object that can be used to retrieve table + * meta data from the database. + * + * @return PHPUnit_Extensions_Database_DB_IMetaData + */ + public function getMetaData() + { + return $this->metaData; + } + + /** + * Returns the schema for the connection. + * + * @return string + */ + public function getSchema() + { + return $this->getMetaData()->getSchema(); + } + + /** + * Creates a dataset containing the specified table names. If no table + * names are specified then it will created a dataset over the entire + * database. + * + * @param array $tableNames + * @return PHPUnit_Extensions_Database_DataSet_IDataSet + * @todo Implement the filtered data set. + */ + public function createDataSet(array $tableNames = NULL) + { + if (empty($tableNames)) { + return new PHPUnit_Extensions_Database_DB_DataSet($this); + } else { + return new PHPUnit_Extensions_Database_DB_FilteredDataSet($this, $tableNames); + } + } + + /** + * Creates a table with the result of the specified SQL statement. + * + * @param string $resultName + * @param string $sql + * @return PHPUnit_Extensions_Database_DB_Table + */ + public function createQueryTable($resultName, $sql) + { + return new PHPUnit_Extensions_Database_DataSet_QueryTable($resultName, $sql, $this); + } + + /** + * Returns this connection database configuration + * + * @return PHPUnit_Extensions_Database_Database_DatabaseConfig + */ + public function getConfig() + { + } + + /** + * Returns a PDO Connection + * + * @return PDO + */ + public function getConnection() + { + return $this->connection; + } + + /** + * Returns the number of rows in the given table. You can specify an + * optional where clause to return a subset of the table. + * + * @param string $tableName + * @param string $whereClause + * @param int + */ + public function getRowCount($tableName, $whereClause = NULL) + { + $query = "SELECT COUNT(*) FROM ".$this->quoteSchemaObject($tableName); + + if (isset($whereClause)) { + $query .= " WHERE {$whereClause}"; + } + + return (int) $this->connection->query($query)->fetchColumn(); + } + + /** + * Returns a quoted schema object. (table name, column name, etc) + * + * @param string $object + * @return string + */ + public function quoteSchemaObject($object) + { + return $this->getMetaData()->quoteSchemaObject($object); + } + + /** + * Returns the command used to truncate a table. + * + * @return string + */ + public function getTruncateCommand() + { + return $this->getMetaData()->getTruncateCommand(); + } + + /** + * Returns true if the connection allows cascading + * + * @return bool + */ + public function allowsCascading() + { + return $this->getMetaData()->allowsCascading(); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/FilteredDataSet.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/FilteredDataSet.php new file mode 100644 index 0000000..3323441 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/FilteredDataSet.php @@ -0,0 +1,84 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides access to a database instance as a data set. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DB_FilteredDataSet extends PHPUnit_Extensions_Database_DB_DataSet +{ + + /** + * @var Array + */ + protected $tableNames; + + /** + * Creates a new dataset using the given database connection. + * + * @param PHPUnit_Extensions_Database_DB_IDatabaseConnection $databaseConnection + */ + public function __construct(PHPUnit_Extensions_Database_DB_IDatabaseConnection $databaseConnection, Array $tableNames) + { + parent::__construct($databaseConnection); + $this->tableNames = $tableNames; + } + + /** + * Returns a list of table names for the database + * + * @return Array + */ + public function getTableNames() + { + return $this->tableNames; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/IDatabaseConnection.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/IDatabaseConnection.php new file mode 100644 index 0000000..605bb17 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/IDatabaseConnection.php @@ -0,0 +1,136 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides a basic interface for communicating with a database. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_DB_IDatabaseConnection +{ + + /** + * Close this connection. + */ + public function close(); + + /** + * Creates a dataset containing the specified table names. If no table + * names are specified then it will created a dataset over the entire + * database. + * + * @param array $tableNames + * @return PHPUnit_Extensions_Database_DataSet_IDataSet + */ + public function createDataSet(Array $tableNames = NULL); + + /** + * Creates a table with the result of the specified SQL statement. + * + * @param string $resultName + * @param string $sql + * @return PHPUnit_Extensions_Database_DataSet_ITable + */ + public function createQueryTable($resultName, $sql); + + /** + * Returns a PDO Connection + * + * @return PDO + */ + public function getConnection(); + + /** + * Returns a database metadata object that can be used to retrieve table + * meta data from the database. + * + * @return PHPUnit_Extensions_Database_DB_IMetaData + */ + public function getMetaData(); + + /** + * Returns the number of rows in the given table. You can specify an + * optional where clause to return a subset of the table. + * + * @param string $tableName + * @param string $whereClause + * @param int + */ + public function getRowCount($tableName, $whereClause = NULL); + + /** + * Returns the schema for the connection. + * + * @return string + */ + public function getSchema(); + + /** + * Returns a quoted schema object. (table name, column name, etc) + * + * @param string $object + * @return string + */ + public function quoteSchemaObject($object); + + /** + * Returns the command used to truncate a table. + * + * @return string + */ + public function getTruncateCommand(); + + /** + * Returns true if the connection allows cascading + * + * @return bool + */ + public function allowsCascading(); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/IMetaData.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/IMetaData.php new file mode 100644 index 0000000..e5cc025 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/IMetaData.php @@ -0,0 +1,105 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides a basic interface for retreiving metadata from a database. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_DB_IMetaData +{ + + /** + * Returns an array containing the names of all the tables in the database. + * + * @return array + */ + public function getTableNames(); + + /** + * Returns an array containing the names of all the columns in the + * $tableName table, + * + * @param string $tableName + * @return array + */ + public function getTableColumns($tableName); + + /** + * Returns an array containing the names of all the primary key columns in + * the $tableName table. + * + * @param string $tableName + * @return array + */ + public function getTablePrimaryKeys($tableName); + + /** + * Returns the name of the default schema. + * + * @return string + */ + public function getSchema(); + + /** + * Returns a quoted schema object. (table name, column name, etc) + * + * @param string $object + * @return string + */ + public function quoteSchemaObject($object); + + /** + * Returns true if the rdbms allows cascading + * + * @return bool + */ + public function allowsCascading(); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData.php new file mode 100644 index 0000000..692e838 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData.php @@ -0,0 +1,226 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides a basic constructor for all meta data classes and a factory for + * generating the appropriate meta data class. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +abstract class PHPUnit_Extensions_Database_DB_MetaData implements PHPUnit_Extensions_Database_DB_IMetaData +{ + protected static $metaDataClassMap = array( + 'pgsql' => 'PHPUnit_Extensions_Database_DB_MetaData_PgSQL', + 'mysql' => 'PHPUnit_Extensions_Database_DB_MetaData_MySQL', + 'oci' => 'PHPUnit_Extensions_Database_DB_MetaData_Oci', + 'sqlite' => 'PHPUnit_Extensions_Database_DB_MetaData_Sqlite', + 'sqlite2'=> 'PHPUnit_Extensions_Database_DB_MetaData_Sqlite' + ); + + /** + * The PDO connection used to retreive database meta data + * + * @var PDO + */ + protected $pdo; + + /** + * The default schema name for the meta data object. + * + * @var string + */ + protected $schema; + + /** + * The character used to quote schema objects. + */ + protected $schemaObjectQuoteChar = '"'; + + /** + * The command used to perform a TRUNCATE operation. + */ + protected $truncateCommand = 'TRUNCATE'; + + /** + * Creates a new database meta data object using the given pdo connection + * and schema name. + * + * @param PDO $pdo + * @param string $schema + */ + public final function __construct(PDO $pdo, $schema = '') + { + $this->pdo = $pdo; + $this->schema = $schema; + } + + /** + * Creates a meta data object based on the driver of given $pdo object and + * $schema name. + * + * @param PDO $pdo + * @param string $schema + * @return PHPUnit_Extensions_Database_DB_MetaData + */ + public static function createMetaData(PDO $pdo, $schema = '') + { + $driverName = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME); + if (isset(self::$metaDataClassMap[$driverName])) { + $className = self::$metaDataClassMap[$driverName]; + + if ($className instanceof ReflectionClass) { + return $className->newInstance($pdo, $schema); + } else { + return self::registerClassWithDriver($className, $driverName)->newInstance($pdo, $schema); + } + } else { + throw new Exception("Could not find a meta data driver for {$driverName} pdo driver."); + } + } + + /** + * Validates and registers the given $className with the given $pdoDriver. + * It should be noted that this function will not attempt to include / + * require the file. The $pdoDriver can be determined by the value of the + * PDO::ATTR_DRIVER_NAME attribute for a pdo object. + * + * A reflection of the $className is returned. + * + * @param string $className + * @param string $pdoDriver + * @return ReflectionClass + */ + public static function registerClassWithDriver($className, $pdoDriver) + { + if (!class_exists($className)) { + throw new Exception("Specified class for {$pdoDriver} driver ({$className}) does not exist."); + } + + $reflection = new ReflectionClass($className); + if ($reflection->isSubclassOf('PHPUnit_Extensions_Database_DB_MetaData')) { + return self::$metaDataClassMap[$pdoDriver] = $reflection; + } else { + throw new Exception("Specified class for {$pdoDriver} driver ({$className}) does not extend PHPUnit_Extensions_Database_DB_MetaData."); + } + } + + /** + * Returns the schema for the connection. + * + * @return string + */ + public function getSchema() + { + return $this->schema; + } + + /** + * Returns a quoted schema object. (table name, column name, etc) + * + * @param string $object + * @return string + */ + public function quoteSchemaObject($object) + { + $parts = explode('.', $object); + $quotedParts = array(); + + foreach ($parts as $part) { + $quotedParts[] = $this->schemaObjectQuoteChar . + str_replace($this->schemaObjectQuoteChar, $this->schemaObjectQuoteChar.$this->schemaObjectQuoteChar, $part). + $this->schemaObjectQuoteChar; + } + + return implode('.', $quotedParts); + } + + /** + * Seperates the schema and the table from a fully qualified table name. + * + * Returns an associative array containing the 'schema' and the 'table'. + * + * @param string $fullTableName + * @return array + */ + public function splitTableName($fullTableName) + { + if (($dot = strpos($fullTableName, '.')) !== FALSE) { + return array( + 'schema' => substr($fullTableName, 0, $dot), + 'table' => substr($fullTableName, $dot + 1) + ); + } else { + return array( + 'schema' => NULL, + 'table' => $fullTableName + ); + } + } + + /** + * Returns the command for the database to truncate a table. + * + * @return string + */ + public function getTruncateCommand() + { + return $this->truncateCommand; + } + + /** + * Returns true if the rdbms allows cascading + * + * @return bool + */ + public function allowsCascading() + { + return FALSE; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/InformationSchema.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/InformationSchema.php new file mode 100644 index 0000000..b6642f3 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/InformationSchema.php @@ -0,0 +1,174 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides functionality to retrieve meta data from a database with information_schema support. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DB_MetaData_InformationSchema extends PHPUnit_Extensions_Database_DB_MetaData +{ + + protected $columns = array(); + + protected $keys = array(); + + /** + * Returns an array containing the names of all the tables in the database. + * + * @return array + */ + public function getTableNames() + { + $query = " + SELECT DISTINCT + TABLE_NAME + FROM INFORMATION_SCHEMA.TABLES + WHERE + TABLE_TYPE='BASE TABLE' AND + TABLE_SCHEMA = ? + ORDER BY TABLE_NAME + "; + + $statement = $this->pdo->prepare($query); + $statement->execute(array($this->getSchema())); + + $tableNames = array(); + while ($tableName = $statement->fetchColumn(0)) { + $tableNames[] = $tableName; + } + + return $tableNames; + } + + /** + * Returns an array containing the names of all the columns in the + * $tableName table, + * + * @param string $tableName + * @return array + */ + public function getTableColumns($tableName) + { + if (!isset($this->columns[$tableName])) { + $this->loadColumnInfo($tableName); + } + + return $this->columns[$tableName]; + } + + /** + * Returns an array containing the names of all the primary key columns in + * the $tableName table. + * + * @param string $tableName + * @return array + */ + public function getTablePrimaryKeys($tableName) + { + if (!isset($this->keys[$tableName])) { + $this->loadColumnInfo($tableName); + } + + return $this->keys[$tableName]; + } + + /** + * Loads column info from a sqlite database. + * + * @param string $tableName + */ + protected function loadColumnInfo($tableName) + { + $this->columns[$tableName] = array(); + $this->keys[$tableName] = array(); + + $columnQuery = " + SELECT DISTINCT + COLUMN_NAME + FROM INFORMATION_SCHEMA.COLUMNS + WHERE + TABLE_NAME = ? AND + TABLE_SCHEMA = ? + ORDER BY ORDINAL_POSITION + "; + + $columnStatement = $this->pdo->prepare($columnQuery); + $columnStatement->execute(array($tableName, $this->getSchema())); + + while ($columName = $columnStatement->fetchColumn(0)) { + $this->columns[$tableName][] = $columName; + } + + $keyQuery = " + SELECT + KCU.COLUMN_NAME + FROM + INFORMATION_SCHEMA.TABLE_CONSTRAINTS as TC, + INFORMATION_SCHEMA.KEY_COLUMN_USAGE as KCU + WHERE + TC.CONSTRAINT_NAME = KCU.CONSTRAINT_NAME AND + TC.TABLE_NAME = KCU.TABLE_NAME AND + TC.TABLE_SCHEMA = KCU.TABLE_SCHEMA AND + TC.CONSTRAINT_TYPE = 'PRIMARY KEY' AND + TC.TABLE_NAME = ? AND + TC.TABLE_SCHEMA = ? + ORDER BY + KCU.ORDINAL_POSITION ASC + "; + + $keyStatement = $this->pdo->prepare($keyQuery); + $keyStatement->execute(array($tableName, $this->getSchema())); + + while ($columName = $keyStatement->fetchColumn(0)) { + $this->keys[$tableName][] = $columName; + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/MySQL.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/MySQL.php new file mode 100644 index 0000000..38850d9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/MySQL.php @@ -0,0 +1,123 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides functionality to retrieve meta data from a MySQL database. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DB_MetaData_MySQL extends PHPUnit_Extensions_Database_DB_MetaData +{ + protected $schemaObjectQuoteChar = '`'; + + /** + * Returns an array containing the names of all the tables in the database. + * + * @return array + */ + public function getTableNames() + { + $query = 'SHOW TABLES'; + $statement = $this->pdo->prepare($query); + $statement->execute(); + + $tableNames = array(); + while (($tableName = $statement->fetchColumn(0))) { + $tableNames[] = $tableName; + } + + return $tableNames; + } + + /** + * Returns an array containing the names of all the columns in the + * $tableName table, + * + * @param string $tableName + * @return array + */ + public function getTableColumns($tableName) + { + $query = 'SHOW COLUMNS FROM ' . $this->quoteSchemaObject($tableName); + $statement = $this->pdo->prepare($query); + $statement->execute(); + + $columnNames = array(); + while (($columnName = $statement->fetchColumn(0))) { + $columnNames[] = $columnName; + } + + return $columnNames; + } + + /** + * Returns an array containing the names of all the primary key columns in + * the $tableName table. + * + * @param string $tableName + * @return array + */ + public function getTablePrimaryKeys($tableName) + { + $query = 'SHOW INDEX FROM ' . $this->quoteSchemaObject($tableName); + $statement = $this->pdo->prepare($query); + $statement->execute(); + $statement->setFetchMode(PDO::FETCH_ASSOC); + + $columnNames = array(); + while (($column = $statement->fetch())) { + if ($column['Key_name'] == 'PRIMARY') { + $columnNames[] = $column['Column_name']; + } + } + + return $columnNames; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/Oci.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/Oci.php new file mode 100644 index 0000000..43b0438 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/Oci.php @@ -0,0 +1,180 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Trond Hansen + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.2.3 + */ + +/** + * Provides functionality to retrieve meta data from an Oracle database. + * + * @package DbUnit + * @author Trond Hansen + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.2.3 + */ +class PHPUnit_Extensions_Database_DB_MetaData_Oci extends PHPUnit_Extensions_Database_DB_MetaData +{ + /** + * No character used to quote schema objects. + * @var string + */ + protected $schemaObjectQuoteChar = ''; + + /** + * The command used to perform a TRUNCATE operation. + * @var string + */ + protected $truncateCommand = 'TRUNCATE TABLE'; + + /** + * @var array + */ + protected $columns = array(); + + /** + * @var array + */ + protected $keys = array(); + + /** + * Returns an array containing the names of all the tables in the database. + * + * @return array + */ + public function getTableNames() + { + $tableNames = array(); + + $query = "SELECT table_name + FROM cat + WHERE table_type='TABLE' + ORDER BY table_name"; + + $result = $this->pdo->query($query); + + while ($tableName = $result->fetchColumn(0)) { + $tableNames[] = $tableName; + } + + return $tableNames; + } + + /** + * Returns an array containing the names of all the columns in the + * $tableName table, + * + * @param string $tableName + * @return array + */ + public function getTableColumns($tableName) + { + if (!isset($this->columns[$tableName])) { + $this->loadColumnInfo($tableName); + } + + return $this->columns[$tableName]; + } + + /** + * Returns an array containing the names of all the primary key columns in + * the $tableName table. + * + * @param string $tableName + * @return array + */ + public function getTablePrimaryKeys($tableName) + { + if (!isset($this->keys[$tableName])) { + $this->loadColumnInfo($tableName); + } + + return $this->keys[$tableName]; + } + + /** + * Loads column info from a oracle database. + * + * @param string $tableName + */ + protected function loadColumnInfo($tableName) + { + $ownerQuery = ''; + $conOwnerQuery = ''; + $tableParts = $this->splitTableName($tableName); + + $this->columns[$tableName] = array(); + $this->keys[$tableName] = array(); + + if (!empty($tableParts['schema'])) + { + $ownerQuery = " AND OWNER = '{$tableParts['schema']}'"; + $conOwnerQuery = " AND a.owner = '{$tableParts['schema']}'"; + } + + $query = "SELECT DISTINCT COLUMN_NAME + FROM USER_TAB_COLUMNS + WHERE TABLE_NAME='".$tableParts['table']."' + $ownerQuery + ORDER BY COLUMN_NAME"; + + $result = $this->pdo->query($query); + + while ($columnName = $result->fetchColumn(0)) { + $this->columns[$tableName][] = $columnName; + } + + $keyQuery = "SELECT b.column_name + FROM user_constraints a, user_cons_columns b + WHERE a.constraint_type='P' + AND a.constraint_name=b.constraint_name + $conOwnerQuery + AND a.table_name = '".$tableParts['table']."' "; + + $result = $this->pdo->query($keyQuery); + + while ($columnName = $result->fetchColumn(0)) { + $this->keys[$tableName][] = $columnName; + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/PgSQL.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/PgSQL.php new file mode 100644 index 0000000..cdbe5b8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/PgSQL.php @@ -0,0 +1,193 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides functionality to retrieve meta data from a PostgreSQL database. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DB_MetaData_PgSQL extends PHPUnit_Extensions_Database_DB_MetaData +{ + + /** + * Returns an array containing the names of all the tables in the database. + * + * @return array + */ + public function getTableNames() + { + $query = " + SELECT DISTINCT + TABLE_NAME + FROM INFORMATION_SCHEMA.TABLES + WHERE + TABLE_TYPE='BASE TABLE' AND + TABLE_SCHEMA = ? + ORDER BY TABLE_NAME + "; + + $statement = $this->pdo->prepare($query); + $statement->execute(array($this->getSchema())); + + $tableNames = array(); + while ($tableName = $statement->fetchColumn(0)) { + $tableNames[] = $tableName; + } + + return $tableNames; + } + + /** + * Returns an array containing the names of all the columns in the + * $tableName table, + * + * @param string $tableName + * @return array + */ + public function getTableColumns($tableName) + { + if (!isset($this->columns[$tableName])) { + $this->loadColumnInfo($tableName); + } + + return $this->columns[$tableName]; + } + + /** + * Returns an array containing the names of all the primary key columns in + * the $tableName table. + * + * @param string $tableName + * @return array + */ + public function getTablePrimaryKeys($tableName) + { + if (!isset($this->keys[$tableName])) { + $this->loadColumnInfo($tableName); + } + + return $this->keys[$tableName]; + } + + /** + * Loads column info from a database table. + * + * @param string $tableName + */ + protected function loadColumnInfo($tableName) + { + $this->columns[$tableName] = array(); + $this->keys[$tableName] = array(); + + $columnQuery = " + SELECT DISTINCT + COLUMN_NAME, ORDINAL_POSITION + FROM INFORMATION_SCHEMA.COLUMNS + WHERE + TABLE_NAME = ? AND + TABLE_SCHEMA = ? + ORDER BY ORDINAL_POSITION + "; + + $columnStatement = $this->pdo->prepare($columnQuery); + $columnStatement->execute(array($tableName, $this->getSchema())); + + while ($columName = $columnStatement->fetchColumn(0)) { + $this->columns[$tableName][] = $columName; + } + + $keyQuery = " + SELECT + KCU.COLUMN_NAME, + KCU.ORDINAL_POSITION + FROM + INFORMATION_SCHEMA.KEY_COLUMN_USAGE as KCU + LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS as TC + ON TC.TABLE_NAME = KCU.TABLE_NAME + WHERE + TC.CONSTRAINT_TYPE = 'PRIMARY KEY' AND + TC.TABLE_NAME = ? AND + TC.TABLE_SCHEMA = ? + ORDER BY + KCU.ORDINAL_POSITION ASC + "; + + $keyStatement = $this->pdo->prepare($keyQuery); + $keyStatement->execute(array($tableName, $this->getSchema())); + + while ($columName = $keyStatement->fetchColumn(0)) { + $this->keys[$tableName][] = $columName; + } + } + + /** + * Returns the schema for the connection. + * + * @return string + */ + public function getSchema() + { + if (empty($this->schema)) { + return 'public'; + } else { + return $this->schema; + } + } + + /** + * Returns true if the rdbms allows cascading + * + * @return bool + */ + public function allowsCascading() + { + return TRUE; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/Sqlite.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/Sqlite.php new file mode 100644 index 0000000..9a2c66d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/MetaData/Sqlite.php @@ -0,0 +1,143 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides functionality to retrieve meta data from an Sqlite database. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DB_MetaData_Sqlite extends PHPUnit_Extensions_Database_DB_MetaData +{ + + protected $columns = array(); + + protected $keys = array(); + + protected $truncateCommand = 'DELETE FROM'; + /** + * Returns an array containing the names of all the tables in the database. + * + * @return array + */ + public function getTableNames() + { + $query = " + SELECT name + FROM sqlite_master + WHERE + type='table' AND + name <> 'sqlite_sequence' + ORDER BY name + "; + + $result = $this->pdo->query($query); + + while ($tableName = $result->fetchColumn(0)) { + $tableNames[] = $tableName; + } + + return $tableNames; + } + + /** + * Returns an array containing the names of all the columns in the + * $tableName table, + * + * @param string $tableName + * @return array + */ + public function getTableColumns($tableName) + { + if (!isset($this->columns[$tableName])) { + $this->loadColumnInfo($tableName); + } + + return $this->columns[$tableName]; + } + + /** + * Returns an array containing the names of all the primary key columns in + * the $tableName table. + * + * @param string $tableName + * @return array + */ + public function getTablePrimaryKeys($tableName) + { + if (!isset($this->keys[$tableName])) { + $this->loadColumnInfo($tableName); + } + + return $this->keys[$tableName]; + } + + /** + * Loads column info from a sqlite database. + * + * @param string $tableName + */ + protected function loadColumnInfo($tableName) + { + $query = "PRAGMA table_info('{$tableName}')"; + $statement = $this->pdo->query($query); + + /* @var $statement PDOStatement */ + $this->columns[$tableName] = array(); + $this->keys[$tableName] = array(); + + while ($columnData = $statement->fetch(PDO::FETCH_NUM)) { + $this->columns[$tableName][] = $columnData[1]; + + if ($columnData[5] == 1) { + $this->keys[$tableName][] = $columnData[1]; + } + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/ResultSetTable.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/ResultSetTable.php new file mode 100644 index 0000000..e8a5f30 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/ResultSetTable.php @@ -0,0 +1,81 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides the functionality to represent a database result set as a DBUnit + * table. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @deprecated The PHPUnit_Extension_Database_DataSet_QueryTable should be used instead + * @see PHPUnit_Extension_Database_DataSet_QueryTable + * @see PHPUnit_Extension_Database_DataSet_QueryDataSet + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DB_ResultSetTable extends PHPUnit_Extensions_Database_DataSet_AbstractTable +{ + + /** + * Creates a new result set table. + * + * @param string $tableName + * @param PDOStatement $pdoStatement + */ + public function __construct($tableName, PDOStatement $pdoStatement) + { + $this->data = $pdoStatement->fetchAll(PDO::FETCH_ASSOC); + + if (count($this->data)) { + $columns = array_keys($this->data[0]); + } else { + $columns = array(); + } + + $this->setTableMetaData(new PHPUnit_Extensions_Database_DataSet_DefaultTableMetaData($tableName, $columns)); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/Table.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/Table.php new file mode 100644 index 0000000..02a4ed2 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/Table.php @@ -0,0 +1,73 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides the functionality to represent a database table. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DB_Table extends PHPUnit_Extensions_Database_DataSet_AbstractTable +{ + + /** + * Creates a new database table object. + * + * @param PHPUnit_Extensions_Database_DataSet_ITableMetaData $tableMetaData + * @param PHPUnit_Extensions_Database_DB_IDatabaseConnection $databaseConnection + */ + public function __construct(PHPUnit_Extensions_Database_DataSet_ITableMetaData $tableMetaData, PHPUnit_Extensions_Database_DB_IDatabaseConnection $databaseConnection) + { + $this->setTableMetaData($tableMetaData); + + $pdoStatement = $databaseConnection->getConnection()->prepare(PHPUnit_Extensions_Database_DB_DataSet::buildTableSelect($tableMetaData, $databaseConnection)); + $pdoStatement->execute(); + $this->data = $pdoStatement->fetchAll(PDO::FETCH_ASSOC); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/TableIterator.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/TableIterator.php new file mode 100644 index 0000000..b6beb7f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/TableIterator.php @@ -0,0 +1,165 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides iterative access to tables from a database instance. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DB_TableIterator implements PHPUnit_Extensions_Database_DataSet_ITableIterator +{ + + /** + * An array of tablenames. + * + * @var Array + */ + protected $tableNames; + + /** + * If this property is true then the tables will be iterated in reverse + * order. + * + * @var bool + */ + protected $reverse; + + /** + * The database dataset that this iterator iterates over. + * + * @var PHPUnit_Extensions_Database_DB_DataSet + */ + protected $dataSet; + + public function __construct($tableNames, PHPUnit_Extensions_Database_DB_DataSet $dataSet, $reverse = FALSE) + { + $this->tableNames = $tableNames; + $this->dataSet = $dataSet; + $this->reverse = $reverse; + + $this->rewind(); + } + + /** + * Returns the current table. + * + * @return PHPUnit_Extensions_Database_DataSet_ITable + */ + public function getTable() + { + return $this->current(); + } + + /** + * Returns the current table's meta data. + * + * @return PHPUnit_Extensions_Database_DataSet_ITableMetaData + */ + public function getTableMetaData() + { + return $this->current()->getTableMetaData(); + } + + /** + * Returns the current table. + * + * @return PHPUnit_Extensions_Database_DataSet_ITable + */ + public function current() + { + $tableName = current($this->tableNames); + return $this->dataSet->getTable($tableName); + } + + /** + * Returns the name of the current table. + * + * @return string + */ + public function key() + { + return $this->current()->getTableMetaData()->getTableName(); + } + + /** + * advances to the next element. + * + */ + public function next() + { + if ($this->reverse) { + prev($this->tableNames); + } else { + next($this->tableNames); + } + } + + /** + * Rewinds to the first element + */ + public function rewind() + { + if ($this->reverse) { + end($this->tableNames); + } else { + reset($this->tableNames); + } + } + + /** + * Returns true if the current index is valid + * + * @return bool + */ + public function valid() + { + return (current($this->tableNames) !== FALSE); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/TableMetaData.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/TableMetaData.php new file mode 100644 index 0000000..b49a6b1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DB/TableMetaData.php @@ -0,0 +1,65 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * This class loads a table metadata object with database metadata. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DB_TableMetaData extends PHPUnit_Extensions_Database_DataSet_DefaultTableMetaData +{ + + public function __construct($tableName, PHPUnit_Extensions_Database_DB_IMetaData $databaseMetaData) + { + $this->tableName = $tableName; + $this->columns = $databaseMetaData->getTableColumns($tableName); + $this->primaryKeys = $databaseMetaData->getTablePrimaryKeys($tableName); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractDataSet.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractDataSet.php new file mode 100644 index 0000000..01b3f03 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractDataSet.php @@ -0,0 +1,167 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Implements the basic functionality of data sets. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +abstract class PHPUnit_Extensions_Database_DataSet_AbstractDataSet implements PHPUnit_Extensions_Database_DataSet_IDataSet +{ + + /** + * Creates an iterator over the tables in the data set. If $reverse is + * true a reverse iterator will be returned. + * + * @param bool $reverse + * @return PHPUnit_Extensions_Database_DataSet_ITableIterator + */ + protected abstract function createIterator($reverse = FALSE); + + /** + * Returns an array of table names contained in the dataset. + * + * @return array + */ + public function getTableNames() + { + $tableNames = array(); + + foreach ($this->getIterator() as $table) { + /* @var $table PHPUnit_Extensions_Database_DataSet_ITable */ + $tableNames[] = $table->getTableMetaData()->getTableName(); + } + + return $tableNames; + } + + /** + * Returns a table meta data object for the given table. + * + * @param string $tableName + * @return PHPUnit_Extensions_Database_DataSet_ITableMetaData + */ + public function getTableMetaData($tableName) + { + return $this->getTable($tableName)->getTableMetaData(); + } + + /** + * Returns a table object for the given table. + * + * @param string $tableName + * @return PHPUnit_Extensions_Database_DataSet_ITable + */ + public function getTable($tableName) + { + foreach ($this->getIterator() as $table) { + /* @var $table PHPUnit_Extensions_Database_DataSet_ITable */ + if ($table->getTableMetaData()->getTableName() == $tableName) { + return $table; + } + } + } + + /** + * Returns an iterator for all table objects in the given dataset. + * + * @return PHPUnit_Extensions_Database_DataSet_ITableIterator + */ + public function getIterator() + { + return $this->createIterator(); + } + + /** + * Returns a reverse iterator for all table objects in the given dataset. + * + * @return PHPUnit_Extensions_Database_DataSet_ITableIterator + */ + public function getReverseIterator() + { + return $this->createIterator(TRUE); + } + + /** + * Asserts that the given data set matches this data set. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $other + */ + public function assertEquals(PHPUnit_Extensions_Database_DataSet_IDataSet $other) + { + $thisTableNames = $this->getTableNames(); + $otherTableNames = $other->getTableNames(); + + sort($thisTableNames); + sort($otherTableNames); + + if ($thisTableNames != $otherTableNames) { + throw new Exception("Expected following tables: " . implode(', ', $thisTableNames) . "; has columns: " . implode(', ', $otherTableNames)); + } + + foreach ($thisTableNames as $tableName) { + $this->getTable($tableName)->assertEquals($other->getTable($tableName)); + } + + return TRUE; + } + + public function __toString() + { + $iterator = $this->getIterator(); + + $dataSetString = ''; + foreach ($iterator as $table) { + $dataSetString .= $table->__toString(); + } + + return $dataSetString; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractTable.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractTable.php new file mode 100644 index 0000000..506afda --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractTable.php @@ -0,0 +1,212 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides a basic functionality for dbunit tables + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_AbstractTable implements PHPUnit_Extensions_Database_DataSet_ITable +{ + + /** + * @var PHPUnit_Extensions_Database_DataSet_ITableMetaData + */ + protected $tableMetaData; + + /** + * A 2-dimensional array containing the data for this table. + * + * @var array + */ + protected $data; + + /** + * Sets the metadata for this table. + * + * @param PHPUnit_Extensions_Database_DataSet_ITableMetaData $tableMetaData + * @deprecated + */ + protected function setTableMetaData(PHPUnit_Extensions_Database_DataSet_ITableMetaData $tableMetaData) + { + $this->tableMetaData = $tableMetaData; + } + + /** + * Returns the table's meta data. + * + * @return PHPUnit_Extensions_Database_DataSet_ITableMetaData + */ + public function getTableMetaData() + { + return $this->tableMetaData; + } + + /** + * Returns the number of rows in this table. + * + * @return int + */ + public function getRowCount() + { + return count($this->data); + } + + /** + * Returns the value for the given column on the given row. + * + * @param int $row + * @param int $column + * @todo reorganize this function to throw the exception first. + */ + public function getValue($row, $column) + { + if (isset($this->data[$row][$column])) { + return (string)$this->data[$row][$column]; + } else { + if (!in_array($column, $this->getTableMetaData()->getColumns()) || $this->getRowCount() <= $row) { + throw new InvalidArgumentException("The given row ({$row}) and column ({$column}) do not exist in table {$this->getTableMetaData()->getTableName()}"); + } else { + return NULL; + } + } + } + + /** + * Returns the an associative array keyed by columns for the given row. + * + * @param int $row + * @return array + */ + public function getRow($row) + { + if (isset($this->data[$row])) { + return $this->data[$row]; + } else { + if ($this->getRowCount() <= $row) { + throw new InvalidArgumentException("The given row ({$row}) does not exist in table {$this->getTableMetaData()->getTableName()}"); + } else { + return NULL; + } + } + } + + /** + * Asserts that the given table matches this table. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $other + */ + public function assertEquals(PHPUnit_Extensions_Database_DataSet_ITable $other) + { + $thisMetaData = $this->getTableMetaData(); + $otherMetaData = $other->getTableMetaData(); + + $thisMetaData->assertEquals($otherMetaData); + + if ($this->getRowCount() != $other->getRowCount()) { + throw new Exception("Expected row count of {$this->getRowCount()}, has a row count of {$other->getRowCount()}"); + } + + $columns = $thisMetaData->getColumns(); + $rowCount = $this->getRowCount(); + + for ($i = 0; $i < $rowCount; $i++) { + foreach ($columns as $columnName) { + if ($this->getValue($i, $columnName) != $other->getValue($i, $columnName)) { + throw new Exception("Expected value of {$this->getValue($i, $columnName)} for row {$i} column {$columnName}, has a value of {$other->getValue($i, $columnName)}"); + } + } + } + + return TRUE; + } + + public function __toString() + { + $columns = $this->getTableMetaData()->getColumns(); + $lineSeperator = str_repeat('+----------------------', count($columns)) . "+\n"; + $lineLength = strlen($lineSeperator) - 1; + + $tableString = $lineSeperator; + $tableString .= '| ' . str_pad($this->getTableMetaData()->getTableName(), $lineLength - 4, ' ', STR_PAD_RIGHT) . " |\n"; + $tableString .= $lineSeperator; + $tableString .= $this->rowToString($columns); + $tableString .= $lineSeperator; + + $rowCount = $this->getRowCount(); + + for ($i = 0; $i < $rowCount; $i++) { + $values = array(); + + foreach ($columns as $columnName) { + $values[] = $this->getValue($i, $columnName); + } + + $tableString .= $this->rowToString($values) . $lineSeperator; + } + + return "\n" . $tableString . "\n"; + } + + protected function rowToString(Array $row) + { + $rowString = ''; + + foreach ($row as $value) { + if (is_null($value)) { + $value = 'NULL'; + } + + $rowString .= '| ' . str_pad(substr($value, 0, 20), 20, ' ', STR_PAD_BOTH) . ' '; + } + + return $rowString . "|\n"; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractTableMetaData.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractTableMetaData.php new file mode 100644 index 0000000..0710946 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractTableMetaData.php @@ -0,0 +1,125 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides basic functionality for table meta data. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +abstract class PHPUnit_Extensions_Database_DataSet_AbstractTableMetaData implements PHPUnit_Extensions_Database_DataSet_ITableMetaData +{ + + /** + * The names of all columns in the table. + * + * @var Array + */ + protected $columns; + + /** + * The names of all the primary keys in the table. + * + * @var Array + */ + protected $primaryKeys; + + /** + * @var string + */ + protected $tableName; + + /** + * Returns the names of the columns in the table. + * + * @return array + */ + public function getColumns() + { + return $this->columns; + } + + /** + * Returns the names of the primary key columns in the table. + * + * @return array + */ + public function getPrimaryKeys() + { + return $this->primaryKeys; + } + + /** + * Returns the name of the table. + * + * @return string + */ + public function getTableName() + { + return $this->tableName; + } + + /** + * Asserts that the given tableMetaData matches this tableMetaData. + * + * @param PHPUnit_Extensions_Database_DataSet_ITableMetaData $other + */ + public function assertEquals(PHPUnit_Extensions_Database_DataSet_ITableMetaData $other) + { + if ($this->getTableName() != $other->getTableName()) { + throw new Exception("Expected table name of {$this->getTableName()}, has a name of {$other->getTableName()}"); + } + + if ($this->getColumns() != $other->getColumns()) { + throw new Exception("Expected following columns: " . implode(', ', $this->getColumns()) . "; has columns: " . implode(', ', $other->getColumns())); + } + + return TRUE; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractXmlDataSet.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractXmlDataSet.php new file mode 100644 index 0000000..c2c1b4f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/AbstractXmlDataSet.php @@ -0,0 +1,151 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * The default implementation of a data set. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +abstract class PHPUnit_Extensions_Database_DataSet_AbstractXmlDataSet extends PHPUnit_Extensions_Database_DataSet_AbstractDataSet +{ + + /** + * @var array + */ + protected $tables; + + /** + * @var SimpleXmlElement + */ + protected $xmlFileContents; + + /** + * Creates a new dataset using the given tables. + * + * @param array $tables + */ + public function __construct($xmlFile) + { + if (!is_file($xmlFile)) { + throw new InvalidArgumentException( + "Could not find xml file: {$xmlFile}" + ); + } + + $errorReporting = error_reporting(0); + $libxmlErrorReporting = libxml_use_internal_errors(TRUE); + $this->xmlFileContents = simplexml_load_file($xmlFile); + + if (!$this->xmlFileContents) { + $message = ''; + + foreach (libxml_get_errors() as $error) { + $message .= $error->message; + } + + throw new RuntimeException($message); + } + + libxml_clear_errors(); + libxml_use_internal_errors($libxmlErrorReporting); + error_reporting($errorReporting); + + $tableColumns = array(); + $tableValues = array(); + + $this->getTableInfo($tableColumns, $tableValues); + $this->createTables($tableColumns, $tableValues); + } + + /** + * Reads the simple xml object and creates the appropriate tables and meta + * data for this dataset. + */ + protected abstract function getTableInfo(Array &$tableColumns, Array &$tableValues); + + protected function createTables(Array &$tableColumns, Array &$tableValues) + { + foreach ($tableValues as $tableName => $values) { + $table = $this->getOrCreateTable($tableName, $tableColumns[$tableName]); + foreach ($values as $value) { + $table->addRow($value); + } + } + } + + /** + * Returns the table with the matching name. If the table does not exist + * an empty one is created. + * + * @param string $tableName + * @return PHPUnit_Extensions_Database_DataSet_ITable + */ + protected function getOrCreateTable($tableName, $tableColumns) + { + if (empty($this->tables[$tableName])) { + $tableMetaData = new PHPUnit_Extensions_Database_DataSet_DefaultTableMetaData($tableName, $tableColumns); + $this->tables[$tableName] = new PHPUnit_Extensions_Database_DataSet_DefaultTable($tableMetaData); + } + + return $this->tables[$tableName]; + } + + /** + * Creates an iterator over the tables in the data set. If $reverse is + * true a reverse iterator will be returned. + * + * @param bool $reverse + * @return PHPUnit_Extensions_Database_DataSet_ITableIterator + */ + protected function createIterator($reverse = FALSE) + { + return new PHPUnit_Extensions_Database_DataSet_DefaultTableIterator($this->tables, $reverse); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/CompositeDataSet.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/CompositeDataSet.php new file mode 100644 index 0000000..193e0b0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/CompositeDataSet.php @@ -0,0 +1,120 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Creates Composite Datasets + * + * Allows for creating datasets from multiple sources (csv, query, xml, etc.) + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_CompositeDataSet extends PHPUnit_Extensions_Database_DataSet_AbstractDataSet +{ + protected $dataSets = array(); + + /** + * Creates a new Composite dataset + * + * You can pass in any data set that implements PHPUnit_Extensions_Database_DataSet_IDataSet + * + * @param string $delimiter + * @param string $enclosure + * @param string $escape + */ + public function __construct(Array $dataSets) + { + foreach ($dataSets as $dataSet) + { + $this->addDataSet($dataSet); + } + } + + /** + * Adds a new data set to the composite. + * + * The dataset may not define tables that already exist in the composite. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet + */ + public function addDataSet(PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet) + { + foreach ($dataSet->getTableNames() as $tableName) + { + if (in_array($tableName, $this->getTableNames())) + { + throw new InvalidArgumentException("DataSet contains a table that already exists: {$tableName}"); + } + } + + $this->dataSets[] = $dataSet; + } + + /** + * Creates an iterator over the tables in the data set. If $reverse is + * true a reverse iterator will be returned. + * + * @param bool $reverse + * @return PHPUnit_Extensions_Database_DataSet_ITableIterator + */ + protected function createIterator($reverse = FALSE) + { + $iterator = new AppendIterator(); + + $dataSets = $reverse ? array_reverse($this->dataSets) : $this->dataSets; + + foreach ($dataSets as $dataSet) + { + /* @var $dataSet PHPUnit_Extensions_Database_DataSet_IDataSet */ + $dataSetIterator = $reverse ? $dataSet->getReverseIterator() : $dataSet->getIterator(); + $iterator->append($dataSetIterator); + } + return $iterator; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/CsvDataSet.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/CsvDataSet.php new file mode 100644 index 0000000..eb5ad7c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/CsvDataSet.php @@ -0,0 +1,160 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Creates CsvDataSets. + * + * You can incrementally add CSV files as tables to your datasets + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_CsvDataSet extends PHPUnit_Extensions_Database_DataSet_AbstractDataSet +{ + /** + * @var array + */ + protected $tables = array(); + + /** + * @var string + */ + protected $delimiter = ','; + + /** + * @var string + */ + protected $enclosure = '"'; + + /** + * @var string + */ + protected $escape = '"'; + + /** + * Creates a new CSV dataset + * + * You can pass in the parameters for how csv files will be read. + * + * @param string $delimiter + * @param string $enclosure + * @param string $escape + */ + public function __construct($delimiter = ',', $enclosure = '"', $escape = '"') + { + $this->delimiter = $delimiter; + $this->enclosure = $enclosure; + $this->escape = $escape; + } + + /** + * Adds a table to the dataset + * + * The table will be given the passed name. $csvFile should be a path to + * a valid csv file (based on the arguments passed to the constructor.) + * + * @param string $tableName + * @param string $csvFile + */ + public function addTable($tableName, $csvFile) + { + if (!is_file($csvFile)) { + throw new InvalidArgumentException("Could not find csv file: {$csvFile}"); + } + + if (!is_readable($csvFile)) { + throw new InvalidArgumentException("Could not read csv file: {$csvFile}"); + } + + $fh = fopen($csvFile, 'r'); + $columns = $this->getCsvRow($fh); + + if ($columns === FALSE) + { + throw new InvalidArgumentException("Could not determine the headers from the given file {$csvFile}"); + } + + $metaData = new PHPUnit_Extensions_Database_DataSet_DefaultTableMetaData($tableName, $columns); + $table = new PHPUnit_Extensions_Database_DataSet_DefaultTable($metaData); + + while (($row = $this->getCsvRow($fh)) !== FALSE) + { + $table->addRow(array_combine($columns, $row)); + } + + $this->tables[$tableName] = $table; + } + + /** + * Creates an iterator over the tables in the data set. If $reverse is + * true a reverse iterator will be returned. + * + * @param bool $reverse + * @return PHPUnit_Extensions_Database_DataSet_ITableIterator + */ + protected function createIterator($reverse = FALSE) + { + return new PHPUnit_Extensions_Database_DataSet_DefaultTableIterator($this->tables, $reverse); + } + + /** + * Returns a row from the csv file in an indexed array. + * + * @param resource $fh + * @return array + */ + protected function getCsvRow($fh) + { + if (version_compare(PHP_VERSION, '5.3.0', '>')) { + return fgetcsv($fh, NULL, $this->delimiter, $this->enclosure, $this->escape); + } else { + return fgetcsv($fh, NULL, $this->delimiter, $this->enclosure); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DataSetFilter.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DataSetFilter.php new file mode 100644 index 0000000..694c40b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DataSetFilter.php @@ -0,0 +1,196 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * A dataset decorator that allows filtering out tables and table columns from + * results. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_DataSetFilter extends PHPUnit_Extensions_Database_DataSet_AbstractDataSet +{ + + /** + * The dataset being decorated. + * @var PHPUnit_Extensions_Database_DataSet_IDataSet + */ + protected $originalDataSet; + + /** + * The tables to exclude from the data set. + * @var Array + */ + protected $excludeTables = array(); + + /** + * The tables to exclude from the data set. + * @var Array + */ + protected $includeTables = array(); + + /** + * The columns to exclude from the data set. + * @var Array + */ + protected $excludeColumns = array(); + + /** + * The columns to exclude from the data set. + * @var Array + */ + protected $includeColumns = array(); + + /** + * Creates a new filtered data set. + * + * The $exclude tables should be an associative array using table names as + * the key and an array of column names to exclude for the value. If you + * would like to exclude a full table set the value of the table's entry + * to the special string '*'. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $originalDataSet + * @param Array $excludeTables @deprecated use set* methods instead. + */ + public function __construct(PHPUnit_Extensions_Database_DataSet_IDataSet $originalDataSet, Array $excludeTables = array()) + { + $this->originalDataSet = $originalDataSet; + + $tables = array(); + foreach ($excludeTables as $tableName => $values) { + if (is_array($values)) { + $this->setExcludeColumnsForTable($tableName, $values); + } elseif ($values == '*') { + $tables[] = $tableName; + } else { + $this->setExcludeColumnsForTable($tableName, (array)$values); + } + } + + $this->addExcludeTables($tables); + } + + /** + * Creates an iterator over the tables in the data set. If $reverse is + * true a reverse iterator will be returned. + * + * @param bool $reverse + * @return PHPUnit_Extensions_Database_DataSet_ITableIterator + */ + protected function createIterator($reverse = FALSE) + { + $original_tables = $this->originalDataSet->getIterator($reverse); + $new_tables = array(); + + foreach ($original_tables as $table) { + /* @var $table PHPUnit_Extensions_Database_DataSet_ITable */ + $tableName = $table->getTableMetaData()->getTableName(); + + if ((!in_array($tableName, $this->includeTables) && !empty($this->includeTables)) || + in_array($tableName, $this->excludeTables) + ) { + continue; + } elseif (!empty($this->excludeColumns[$tableName]) || !empty($this->includeColumns[$tableName])) { + $new_table = new PHPUnit_Extensions_Database_DataSet_TableFilter($table); + + if (!empty($this->includeColumns[$tableName])) { + $new_table->addIncludeColumns($this->includeColumns[$tableName]); + } + + if (!empty($this->excludeColumns[$tableName])) { + $new_table->addExcludeColumns($this->excludeColumns[$tableName]); + } + + $new_tables[] = $new_table; + } else { + $new_tables[] = $table; + } + } + + return new PHPUnit_Extensions_Database_DataSet_DefaultTableIterator($new_tables); + } + + /** + * Adds tables to be included in the data set. + * @param array $tables + */ + public function addIncludeTables(Array $tables) + { + $this->includeTables = array_unique(array_merge($this->includeTables, $tables)); + } + + /** + * Adds tables to be included in the data set. + * @param array $tables + */ + public function addExcludeTables(Array $tables) + { + $this->excludeTables = array_unique(array_merge($this->excludeTables, $tables)); + } + + /** + * Adds columns to include in the data set for the given table. + * @param string $table + * @param Array $columns + */ + public function setIncludeColumnsForTable($table, Array $columns) + { + $this->includeColumns[$table] = $columns; + } + + /** + * Adds columns to include in the data set for the given table. + * @param string $table + * @param Array $columns + */ + public function setExcludeColumnsForTable($table, Array $columns) + { + $this->excludeColumns[$table] = $columns; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultDataSet.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultDataSet.php new file mode 100644 index 0000000..c9858af --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultDataSet.php @@ -0,0 +1,97 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * The default implementation of a data set. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_DefaultDataSet extends PHPUnit_Extensions_Database_DataSet_AbstractDataSet +{ + + /** + * An array of ITable objects. + * + * @var array + */ + protected $tables; + + /** + * Creates a new dataset using the given tables. + * + * @param array $tables + */ + public function __construct(Array $tables = array()) + { + $this->tables = $tables; + } + + /** + * Adds a table to the dataset. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + */ + public function addTable(PHPUnit_Extensions_Database_DataSet_ITable $table) + { + $this->tables[] = $table; + } + + /** + * Creates an iterator over the tables in the data set. If $reverse is + * true a reverse iterator will be returned. + * + * @param bool $reverse + * @return PHPUnit_Extensions_Database_DataSet_ITableIterator + */ + protected function createIterator($reverse = FALSE) + { + return new PHPUnit_Extensions_Database_DataSet_DefaultTableIterator($this->tables, $reverse); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultTable.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultTable.php new file mode 100644 index 0000000..1601a41 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultTable.php @@ -0,0 +1,117 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides default table functionality. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_DefaultTable extends PHPUnit_Extensions_Database_DataSet_AbstractTable +{ + + /** + * Creates a new table object using the given $tableMetaData + * + * @param PHPUnit_Extensions_Database_DataSet_ITableMetaData $tableMetaData + */ + public function __construct(PHPUnit_Extensions_Database_DataSet_ITableMetaData $tableMetaData) + { + $this->setTableMetaData($tableMetaData); + $this->data = array(); + } + + /** + * Adds a row to the table with optional values. + * + * @param array $values + */ + public function addRow($values = array()) + { + $this->data[] = array_merge( + array_fill_keys($this->getTableMetaData()->getColumns(), NULL), + $values + ); + } + + /** + * Adds the rows in the passed table to the current table. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + */ + public function addTableRows(PHPUnit_Extensions_Database_DataSet_ITable $table) + { + $tableColumns = $this->getTableMetaData()->getColumns(); + $rowCount = $table->getRowCount(); + + for ($i = 0; $i < $rowCount; $i++) { + $newRow = array(); + foreach ($tableColumns as $columnName) { + $newRow[$columnName] = $table->getValue($i, $columnName); + } + $this->addRow($newRow); + } + } + + /** + * Sets the specified column of the specied row to the specified value. + * + * @param int $row + * @param string $column + * @param mixed $value + */ + public function setValue($row, $column, $value) + { + if (isset($this->data[$row])) { + $this->data[$row][$column] = $value; + } else { + throw new InvalidArgumentException("The row given does not exist."); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultTableIterator.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultTableIterator.php new file mode 100644 index 0000000..af70ebf --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultTableIterator.php @@ -0,0 +1,161 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * The default table iterator + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_DefaultTableIterator implements PHPUnit_Extensions_Database_DataSet_ITableIterator +{ + /** + * An array of tables in the iterator. + * + * @var Array + */ + protected $tables; + + /** + * If this property is true then the tables will be iterated in reverse + * order. + * + * @var bool + */ + protected $reverse; + + /** + * Creates a new default table iterator object. + * + * @param array $tables + * @param bool $reverse + */ + public function __construct(Array $tables, $reverse = FALSE) + { + $this->tables = $tables; + $this->reverse = $reverse; + + $this->rewind(); + } + + /** + * Returns the current table. + * + * @return PHPUnit_Extensions_Database_DataSet_ITable + */ + public function getTable() + { + $this->current(); + } + + /** + * Returns the current table's meta data. + * + * @return PHPUnit_Extensions_Database_DataSet_ITableMetaData + */ + public function getTableMetaData() + { + $this->current()->getTableMetaData(); + } + + /** + * Returns the current table. + * + * @return PHPUnit_Extensions_Database_DataSet_ITable + */ + public function current() + { + return current($this->tables); + } + + /** + * Returns the name of the current table. + * + * @return string + */ + public function key() + { + return $this->current()->getTableMetaData()->getTableName(); + } + + /** + * advances to the next element. + * + */ + public function next() + { + if ($this->reverse) { + prev($this->tables); + } else { + next($this->tables); + } + } + + /** + * Rewinds to the first element + */ + public function rewind() + { + if ($this->reverse) { + end($this->tables); + } else { + reset($this->tables); + } + } + + /** + * Returns true if the current index is valid + * + * @return bool + */ + public function valid() + { + return ($this->current() !== FALSE); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultTableMetaData.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultTableMetaData.php new file mode 100644 index 0000000..4fd9e23 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/DefaultTableMetaData.php @@ -0,0 +1,80 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * The default implementation of table meta data + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_DefaultTableMetaData extends PHPUnit_Extensions_Database_DataSet_AbstractTableMetaData +{ + + /** + * Creates a new default table meta data object. + * + * @param string $tableName + * @param array $columns + * @param array $primaryKeys + */ + public function __construct($tableName, Array $columns, Array $primaryKeys = array()) + { + $this->tableName = $tableName; + $this->columns = $columns; + $this->primaryKeys = array(); + + foreach ($primaryKeys as $columnName) { + if (!in_array($columnName, $this->columns)) { + throw new InvalidArgumentException("Primary key column passed that is not in the column list."); + } else { + $this->primaryKeys[] = $columnName; + } + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/FlatXmlDataSet.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/FlatXmlDataSet.php new file mode 100644 index 0000000..2c051ea --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/FlatXmlDataSet.php @@ -0,0 +1,99 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * The default implementation of a data set. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_FlatXmlDataSet extends PHPUnit_Extensions_Database_DataSet_AbstractXmlDataSet +{ + + protected function getTableInfo(Array &$tableColumns, Array &$tableValues) + { + if ($this->xmlFileContents->getName() != 'dataset') { + throw new Exception("The root element of a flat xml data set file must be called "); + } + + foreach ($this->xmlFileContents->children() as $row) { + $tableName = $row->getName(); + + if (!isset($tableColumns[$tableName])) { + $tableColumns[$tableName] = array(); + $tableValues[$tableName] = array(); + } + + $values = array(); + foreach ($row->attributes() as $name => $value) { + if (!in_array($name, $tableColumns[$tableName])) { + $tableColumns[$tableName][] = $name; + } + + $values[$name] = $value; + } + + if (count($values)) { + $tableValues[$tableName][] = $values; + } + } + } + + public static function write(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset, $filename) + { + $pers = new PHPUnit_Extensions_Database_DataSet_Persistors_FlatXml(); + $pers->setFileName($filename); + + try { + $pers->write($dataset); + } catch (RuntimeException $e) { + throw new PHPUnit_Framework_Exception(__METHOD__ . ' called with an unwritable file.'); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/IDataSet.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/IDataSet.php new file mode 100644 index 0000000..2600638 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/IDataSet.php @@ -0,0 +1,95 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides a basic interface for creating and reading data from data sets. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_DataSet_IDataSet extends IteratorAggregate +{ + + /** + * Returns an array of table names contained in the dataset. + * + * @return array + */ + public function getTableNames(); + + /** + * Returns a table meta data object for the given table. + * + * @param string $tableName + * @return PHPUnit_Extensions_Database_DataSet_ITableMetaData + */ + public function getTableMetaData($tableName); + + /** + * Returns a table object for the given table. + * + * @param string $tableName + * @return PHPUnit_Extensions_Database_DataSet_ITable + */ + public function getTable($tableName); + + /** + * Returns a reverse iterator for all table objects in the given dataset. + * + * @return PHPUnit_Extensions_Database_DataSet_ITableIterator + */ + public function getReverseIterator(); + + /** + * Asserts that the given data set matches this data set. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $other + */ + public function assertEquals(PHPUnit_Extensions_Database_DataSet_IDataSet $other); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/IPersistable.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/IPersistable.php new file mode 100644 index 0000000..144a2c8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/IPersistable.php @@ -0,0 +1,66 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * An interface for persisting datasets + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_DataSet_IPersistable +{ + /** + * Writes the given dataset + * + * The previous dataset will be overwritten. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataset + */ + public function write(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ISpec.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ISpec.php new file mode 100644 index 0000000..a3163e4 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ISpec.php @@ -0,0 +1,65 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides an interface for creating data sets from data set spec strings. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_DataSet_ISpec +{ + /** + * Creates a data set from a data set spec string. + * + * @param string $dataSetSpec + * @return PHPUnit_Extensions_Database_DataSet_IDataSet + */ + public function getDataSet($dataSetSpec); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ITable.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ITable.php new file mode 100644 index 0000000..de65cc5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ITable.php @@ -0,0 +1,95 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides a basic interface for creating and reading data from data sets. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_DataSet_ITable +{ + + /** + * Returns the table's meta data. + * + * @return PHPUnit_Extensions_Database_DataSet_ITableMetaData + */ + public function getTableMetaData(); + + /** + * Returns the number of rows in this table. + * + * @return int + */ + public function getRowCount(); + + /** + * Returns the value for the given column on the given row. + * + * @param int $row + * @param int $column + */ + public function getValue($row, $column); + + /** + * Returns the an associative array keyed by columns for the given row. + * + * @param int $row + * @return array + */ + public function getRow($row); + + /** + * Asserts that the given table matches this table. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $other + */ + public function assertEquals(PHPUnit_Extensions_Database_DataSet_ITable $other); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ITableIterator.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ITableIterator.php new file mode 100644 index 0000000..e99b414 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ITableIterator.php @@ -0,0 +1,72 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides a basic interface for creating and reading data from data sets. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_DataSet_ITableIterator extends Iterator +{ + + /** + * Returns the current table. + * + * @return PHPUnit_Extensions_Database_DataSet_ITable + */ + public function getTable(); + + /** + * Returns the current table's meta data. + * + * @return PHPUnit_Extensions_Database_DataSet_ITableMetaData + */ + public function getTableMetaData(); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ITableMetaData.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ITableMetaData.php new file mode 100644 index 0000000..5a41ba4 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ITableMetaData.php @@ -0,0 +1,86 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides a basic interface for returning table meta data. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_DataSet_ITableMetaData +{ + + /** + * Returns the names of the columns in the table. + * + * @return array + */ + public function getColumns(); + + /** + * Returns the names of the primary key columns in the table. + * + * @return array + */ + public function getPrimaryKeys(); + + /** + * Returns the name of the table. + * + * @return string + */ + public function getTableName(); + + /** + * Asserts that the given tableMetaData matches this tableMetaData. + * + * @param PHPUnit_Extensions_Database_DataSet_ITableMetaData $other + */ + public function assertEquals(PHPUnit_Extensions_Database_DataSet_ITableMetaData $other); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/MysqlXmlDataSet.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/MysqlXmlDataSet.php new file mode 100644 index 0000000..1713c95 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/MysqlXmlDataSet.php @@ -0,0 +1,141 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Matthew Turland + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Data set implementation for the output of mysqldump --xml. + * + * @package DbUnit + * @author Matthew Turland + * @copyright 2010 Matthew Turland + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_MysqlXmlDataSet extends PHPUnit_Extensions_Database_DataSet_AbstractXmlDataSet +{ + protected function getTableInfo(array &$tableColumns, array &$tableValues) + { + if ($this->xmlFileContents->getName() != 'mysqldump') { + throw new Exception('The root element of a MySQL XML data set file must be called '); + } + + foreach ($this->xmlFileContents->xpath('./database/table_data') as $tableElement) { + if (empty($tableElement['name'])) { + throw new Exception(' elements must include a name attribute'); + } + + $tableName = (string)$tableElement['name']; + + if (!isset($tableColumns[$tableName])) { + $tableColumns[$tableName] = array(); + } + + if (!isset($tableValues[$tableName])) { + $tableValues[$tableName] = array(); + } + + foreach ($tableElement->xpath('./row') as $rowElement) { + $rowValues = array(); + + foreach ($rowElement->xpath('./field') as $columnElement) { + if (empty($columnElement['name'])) { + throw new Exception(' element name attributes cannot be empty'); + } + + $columnName = (string)$columnElement['name']; + + if (!in_array($columnName, $tableColumns[$tableName])) { + $tableColumns[$tableName][] = $columnName; + } + } + + foreach ($tableColumns[$tableName] as $columnName) { + $fields = $rowElement->xpath('./field[@name="' . $columnName . '"]'); + $column = $fields[0]; + $attr = $column->attributes('http://www.w3.org/2001/XMLSchema-instance'); + $null = isset($column['nil']) || isset($attr[0]); + $columnValue = $null ? NULL : (string)$column; + $rowValues[$columnName] = $columnValue; + } + + $tableValues[$tableName][] = $rowValues; + } + } + + foreach ($this->xmlFileContents->xpath('./database/table_structure') as $tableElement) { + if (empty($tableElement['name'])) { + throw new Exception(' elements must include a name attribute'); + } + + $tableName = (string) $tableElement['name']; + + foreach ($tableElement->xpath('./field') as $fieldElement) { + if (empty($fieldElement['Field'])) { + throw new Exception(' elements must include a Field attribute'); + } + + $columnName = (string) $fieldElement['Field']; + + if (!in_array($columnName, $tableColumns[$tableName])) { + $tableColumns[$tableName][] = $columnName; + } + } + } + } + + public static function write(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset, $filename) + { + $pers = new PHPUnit_Extensions_Database_DataSet_Persistors_MysqlXml; + $pers->setFileName($filename); + + try { + $pers->write($dataset); + } + + catch (RuntimeException $e) { + throw new PHPUnit_Framework_Exception(__METHOD__ . ' called with an unwritable file.'); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Abstract.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Abstract.php new file mode 100644 index 0000000..59847c2 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Abstract.php @@ -0,0 +1,127 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * An abstract implementation of a dataset persistor. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +abstract class PHPUnit_Extensions_Database_DataSet_Persistors_Abstract implements PHPUnit_Extensions_Database_DataSet_IPersistable +{ + public function write(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset) + { + $this->saveDataSet($dataset); + } + + /** + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataset + */ + protected function saveDataSet(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset) + { + $this->startDataSet($dataset); + + foreach ($dataset as $table) { + $this->saveTable($table); + } + + $this->endDataSet($dataset); + } + + /** + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + */ + protected function saveTable(PHPUnit_Extensions_Database_DataSet_ITable $table) + { + $rowCount = $table->getRowCount(); + $this->startTable($table); + + for ($i = 0; $i < $rowCount; $i++) { + $this->row($table->getRow($i), $table); + } + + $this->endTable($table); + } + + /** + * Override to save the start of a dataset. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataset + */ + abstract protected function startDataSet(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset); + + /** + * Override to save the end of a dataset. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataset + */ + abstract protected function endDataSet(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset); + + /** + * Override to save the start of a table. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + */ + abstract protected function startTable(PHPUnit_Extensions_Database_DataSet_ITable $table); + + /** + * Override to save the end of a table. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + */ + abstract protected function endTable(PHPUnit_Extensions_Database_DataSet_ITable $table); + + /** + * Override to save a table row. + * + * @param array $row + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + */ + abstract protected function row(Array $row, PHPUnit_Extensions_Database_DataSet_ITable $table); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Factory.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Factory.php new file mode 100644 index 0000000..aac0174 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Factory.php @@ -0,0 +1,87 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Creates the appropriate Persistor based on a given type and spec. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_Persistors_Factory +{ + /** + * Returns the persistor. + * + * @param string $type + * @param string $spec + * @return PHPUnit_Extensions_Database_DataSet_IPersistable + */ + public function getPersistorBySpec($type, $spec) + { + switch (strtolower($type)) { + case 'xml': + $xmlPersistor = new PHPUnit_Extensions_Database_DataSet_Persistors_Xml(); + $xmlPersistor->setFileName($spec); + return $xmlPersistor; + + case 'flatxml': + $flatXmlPersistor = new PHPUnit_Extensions_Database_DataSet_Persistors_FlatXml(); + $flatXmlPersistor->setFileName($spec); + return $flatXmlPersistor; + + case 'yaml': + $yamlPersistor = new PHPUnit_Extensions_Database_DataSet_Persistors_Yaml(); + $yamlPersistor->setFileName($spec); + return $yamlPersistor; + + default: + throw new Exception("I don't know what you want from me. PERSISTOR"); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/FlatXml.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/FlatXml.php new file mode 100644 index 0000000..771a153 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/FlatXml.php @@ -0,0 +1,147 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * A Flat XML dataset persistor. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_Persistors_FlatXml extends PHPUnit_Extensions_Database_DataSet_Persistors_Abstract +{ + /** + * @var string + */ + protected $filename; + + /** + * @var resource + */ + protected $fh; + + /** + * Sets the filename that this persistor will save to. + * + * @param string $filename + */ + public function setFileName($filename) + { + $this->filename = $filename; + } + + /** + * Override to save the start of a dataset. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataset + */ + protected function startDataSet(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset) + { + $this->fh = fopen($this->filename, 'w'); + + if ($this->fh === FALSE) { + throw new PHPUnit_Framework_Exception( + "Could not open {$this->filename} for writing see " . __CLASS__ . "::setFileName()" + ); + } + + fwrite($this->fh, "\n"); + fwrite($this->fh, "\n"); + } + + /** + * Override to save the end of a dataset. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataset + */ + protected function endDataSet(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset) + { + fwrite($this->fh, "\n"); + } + + /** + * Override to save the start of a table. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + */ + protected function startTable(PHPUnit_Extensions_Database_DataSet_ITable $table) + { + if ($table->getRowCount() == 0) { + fwrite($this->fh, "\t<{$table->getTableMetaData()->getTableName()} />\n"); + } + } + + /** + * Override to save the end of a table. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + */ + protected function endTable(PHPUnit_Extensions_Database_DataSet_ITable $table) + { + //do nothing + } + + /** + * Override to save a table row. + * + * @param array $row + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + */ + protected function row(Array $row, PHPUnit_Extensions_Database_DataSet_ITable $table) + { + fwrite($this->fh, "\t<{$table->getTableMetaData()->getTableName()}\n"); + + foreach ($table->getTableMetaData()->getColumns() as $columnName) { + if (isset($row[$columnName])) { + fwrite($this->fh, "\t\t{$columnName}=\"". htmlspecialchars($row[$columnName]) . "\"\n"); + } + } + + fwrite($this->fh, "\t/>\n"); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/MysqlXml.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/MysqlXml.php new file mode 100644 index 0000000..4979367 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/MysqlXml.php @@ -0,0 +1,165 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Matthew Turland + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * A MySQL XML dataset persistor. + * + * @package DbUnit + * @author Matthew Turland + * @copyright 2010 Matthew Turland + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_Persistors_MysqlXml extends PHPUnit_Extensions_Database_DataSet_Persistors_Abstract +{ + /** + * @var string + */ + protected $filename; + + /** + * @var string + */ + protected $database; + + /** + * @var resource + */ + protected $fh; + + /** + * Sets the filename that this persistor will save to. + * + * @param string $filename + */ + public function setFileName($filename) + { + $this->filename = $filename; + } + + /** + * Sets the name of the database. + * + * @param string $database + */ + public function setDatabase($database) + { + $this->database = $database; + } + + /** + * Override to save the start of a dataset. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataset + */ + protected function startDataSet(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset) + { + $this->fh = fopen($this->filename, 'w'); + + if ($this->fh === FALSE) { + throw new PHPUnit_Framework_Exception( + "Could not open {$this->filename} for writing see " . __CLASS__ . "::setFileName()" + ); + } + + fwrite($this->fh, '' . "\n"); + fwrite($this->fh, '' . "\n"); + fwrite($this->fh, '' . "\n"); + } + + /** + * Override to save the end of a dataset. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataset + */ + protected function endDataSet(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset) + { + fwrite($this->fh, '' . "\n"); + fwrite($this->fh, '' . "\n"); + } + + /** + * Override to save the start of a table. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + */ + protected function startTable(PHPUnit_Extensions_Database_DataSet_ITable $table) + { + fwrite($this->fh, "\t" . '' . "\n"); + } + + /** + * Override to save the end of a table. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + */ + protected function endTable(PHPUnit_Extensions_Database_DataSet_ITable $table) + { + fwrite($this->fh, "\t" . '' . "\n"); + } + + /** + * Override to save a table row. + * + * @param array $row + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + */ + protected function row(Array $row, PHPUnit_Extensions_Database_DataSet_ITable $table) + { + fwrite($this->fh, "\t" . '' . "\n"); + + foreach ($table->getTableMetaData()->getColumns() as $columnName) { + fwrite($this->fh, "\t\t" . 'fh, '>' . htmlspecialchars($row[$columnName]) . '' . "\n"); + } else { + fwrite($this->fh, ' xsi:nil="true" />' . "\n"); + } + } + + fwrite($this->fh, "\t" . '' . "\n"); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Xml.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Xml.php new file mode 100644 index 0000000..4165c8a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Xml.php @@ -0,0 +1,151 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * A XML dataset persistor. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_Persistors_Xml extends PHPUnit_Extensions_Database_DataSet_Persistors_Abstract +{ + /** + * @var string + */ + protected $filename; + + /** + * @var resource + */ + protected $fh; + + /** + * Sets the filename that this persistor will save to. + * + * @param string $filename + */ + public function setFileName($filename) + { + $this->filename = $filename; + } + + /** + * Override to save the start of a dataset. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataset + */ + protected function startDataSet(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset) + { + $this->fh = fopen($this->filename, 'w'); + + if ($this->fh === FALSE) { + throw new PHPUnit_Framework_Exception( + "Could not open {$this->filename} for writing see " . __CLASS__ . "::setFileName()" + ); + } + + fwrite($this->fh, "\n"); + fwrite($this->fh, "\n"); + } + + /** + * Override to save the end of a dataset. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataset + */ + protected function endDataSet(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset) + { + fwrite($this->fh, "\n"); + } + + /** + * Override to save the start of a table. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + */ + protected function startTable(PHPUnit_Extensions_Database_DataSet_ITable $table) + { + fwrite($this->fh, "\tgetTableMetaData()->getTableName()}\">\n"); + + foreach ($table->getTableMetaData()->getColumns() as $columnName) { + fwrite($this->fh, "\t\t{$columnName}\n"); + } + } + + /** + * Override to save the end of a table. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + */ + protected function endTable(PHPUnit_Extensions_Database_DataSet_ITable $table) + { + fwrite($this->fh, "\t
    \n"); + } + + /** + * Override to save a table row. + * + * @param array $row + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + */ + protected function row(Array $row, PHPUnit_Extensions_Database_DataSet_ITable $table) + { + fwrite($this->fh, "\t\t\n"); + + foreach ($table->getTableMetaData()->getColumns() as $columnName) { + if (isset($row[$columnName])) { + fwrite($this->fh, "\t\t\t" . htmlspecialchars($row[$columnName]) . "\n"); + } else { + fwrite($this->fh, "\t\t\t\n"); + } + } + + fwrite($this->fh, "\t\t\n"); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Yaml.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Yaml.php new file mode 100644 index 0000000..63389b8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Yaml.php @@ -0,0 +1,109 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * A yaml dataset persistor + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_Persistors_Yaml implements PHPUnit_Extensions_Database_DataSet_IPersistable +{ + /** + * @var string + */ + protected $filename; + + /** + * Sets the filename that this persistor will save to. + * + * @param string $filename + */ + public function setFileName($filename) + { + $this->filename = $filename; + } + + /** + * Writes the dataset to a yaml file + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataset + */ + public function write(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset) + { + $phpArr = array(); + $emptyTables = array(); + + foreach ($dataset as $table) { + $tableName = $table->getTableMetaData()->getTableName(); + $rowCount = $table->getRowCount(); + + if (!$rowCount) { + $emptyTables[] = $tableName; + continue; + } + + $phpArr[$tableName] = array(); + + for ($i = 0; $i < $rowCount; $i++) { + $phpArr[$tableName][] = $table->getRow($i); + } + } + + $emptyTablesAsString = ''; + + if (count($emptyTables)) { + $emptyTablesAsString = implode(":\n", $emptyTables) . ":\n\n"; + } + + file_put_contents( + $this->filename, sfYaml::dump($phpArr, 3) . $emptyTablesAsString + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/QueryDataSet.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/QueryDataSet.php new file mode 100644 index 0000000..d7d27ca --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/QueryDataSet.php @@ -0,0 +1,128 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides access to a database instance as a data set. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_QueryDataSet extends PHPUnit_Extensions_Database_DataSet_AbstractDataSet +{ + + /** + * An array of ITable objects. + * + * @var array + */ + protected $tables = array(); + + /** + * The database connection this dataset is using. + * + * @var PHPUnit_Extensions_Database_DB_IDatabaseConnection + */ + protected $databaseConnection; + + /** + * Creates a new dataset using the given database connection. + * + * @param PHPUnit_Extensions_Database_DB_IDatabaseConnection $databaseConnection + */ + public function __construct(PHPUnit_Extensions_Database_DB_IDatabaseConnection $databaseConnection) + { + $this->databaseConnection = $databaseConnection; + } + + public function addTable($tableName, $query = NULL) + { + if ($query === NULL) { + $query = 'SELECT * FROM ' . $tableName; + } + + $this->tables[$tableName] = new PHPUnit_Extensions_Database_DataSet_QueryTable($tableName, $query, $this->databaseConnection); + } + + /** + * Creates an iterator over the tables in the data set. If $reverse is + * true a reverse iterator will be returned. + * + * @param bool $reverse + * @return PHPUnit_Extensions_Database_DB_TableIterator + */ + protected function createIterator($reverse = FALSE) + { + return new PHPUnit_Extensions_Database_DataSet_DefaultTableIterator($this->tables, $reverse); + } + + /** + * Returns a table object for the given table. + * + * @param string $tableName + * @return PHPUnit_Extensions_Database_DB_Table + */ + public function getTable($tableName) + { + if (!isset($this->tables[$tableName])) { + throw new InvalidArgumentException("$tableName is not a table in the current database."); + } + + return $this->tables[$tableName]; + } + + /** + * Returns a list of table names for the database + * + * @return Array + */ + public function getTableNames() + { + return array_keys($this->tables); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/QueryTable.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/QueryTable.php new file mode 100644 index 0000000..01e8a8b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/QueryTable.php @@ -0,0 +1,160 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides the functionality to represent a database table. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_QueryTable extends PHPUnit_Extensions_Database_DataSet_AbstractTable +{ + /** + * @var string + */ + protected $query; + + /** + * @var PHPUnit_Extensions_Database_DB_IDatabaseConnection + */ + protected $databaseConnection; + + /** + * @var string + */ + protected $tableName; + + /** + * Creates a new database query table object. + * + * @param string $table_name + * @param string $query + * @param PHPUnit_Extensions_Database_DB_IDatabaseConnection $databaseConnection + */ + public function __construct($tableName, $query, PHPUnit_Extensions_Database_DB_IDatabaseConnection $databaseConnection) + { + $this->query = $query; + $this->databaseConnection = $databaseConnection; + $this->tableName = $tableName; + } + + /** + * Returns the table's meta data. + * + * @return PHPUnit_Extensions_Database_DataSet_ITableMetaData + */ + public function getTableMetaData() + { + $this->createTableMetaData(); + return parent::getTableMetaData(); + } + + /** + * Returns the number of rows in this table. + * + * @return int + */ + public function getRowCount() + { + $this->loadData(); + return parent::getRowCount(); + } + + /** + * Returns the value for the given column on the given row. + * + * @param int $row + * @param int $column + */ + public function getValue($row, $column) + { + $this->loadData(); + return parent::getValue($row, $column); + } + + /** + * Returns the an associative array keyed by columns for the given row. + * + * @param int $row + * @return array + */ + public function getRow($row) + { + $this->loadData(); + return parent::getRow($row); + } + + /** + * Asserts that the given table matches this table. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $other + */ + public function assertEquals(PHPUnit_Extensions_Database_DataSet_ITable $other) + { + $this->loadData(); + return parent::assertEquals($other); + } + + protected function loadData() + { + if ($this->data === NULL) { + $pdoStatement = $this->databaseConnection->getConnection()->query($this->query); + $this->data = $pdoStatement->fetchAll(PDO::FETCH_ASSOC); + } + } + + protected function createTableMetaData() + { + if ($this->tableMetaData === NULL) + { + $this->loadData(); + $this->tableMetaData = new PHPUnit_Extensions_Database_DataSet_DefaultTableMetaData($this->tableName, array_keys($this->data[0])); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ReplacementDataSet.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ReplacementDataSet.php new file mode 100644 index 0000000..27ec8bf --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ReplacementDataSet.php @@ -0,0 +1,129 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Allows for replacing arbitrary values or portions of values with new data. + * + * A usage for this is replacing all values == '[NULL'] with a true NULL value + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_ReplacementDataSet extends PHPUnit_Extensions_Database_DataSet_AbstractDataSet +{ + /** + * @var PHPUnit_Extensions_Database_DataSet_IDataSet + */ + protected $dataSet; + + /** + * @var array + */ + protected $fullReplacements; + + /** + * @var array + */ + protected $subStrReplacements; + + /** + * Creates a new replacement dataset + * + * You can pass in any data set that implements PHPUnit_Extensions_Database_DataSet_IDataSet + * + * @param string $delimiter + * @param string $enclosure + * @param string $escape + */ + public function __construct(PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet, Array $fullReplacements = array(), Array $subStrReplacements = array()) + { + $this->dataSet = $dataSet; + $this->fullReplacements = $fullReplacements; + $this->subStrReplacements = $subStrReplacements; + } + + /** + * Adds a new full replacement + * + * Full replacements will only replace values if the FULL value is a match + * + * @param string $value + * @param string $replacement + */ + public function addFullReplacement($value, $replacement) + { + $this->fullReplacements[$value] = $replacement; + } + + /** + * Adds a new substr replacement + * + * Substr replacements will replace all occurances of the substr in every column + * + * @param string $value + * @param string $replacement + */ + public function addSubStrReplacement($value, $replacement) + { + $this->subStrReplacements[$value] = $replacement; + } + + /** + * Creates an iterator over the tables in the data set. If $reverse is + * true a reverse iterator will be returned. + * + * @param bool $reverse + * @return PHPUnit_Extensions_Database_DataSet_ITableIterator + */ + protected function createIterator($reverse = FALSE) + { + $innerIterator = $reverse ? $this->dataSet->getReverseIterator() : $this->dataSet->getIterator(); + return new PHPUnit_Extensions_Database_DataSet_ReplacementTableIterator($innerIterator, $this->fullReplacements, $this->subStrReplacements); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ReplacementTable.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ReplacementTable.php new file mode 100644 index 0000000..1a85167 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ReplacementTable.php @@ -0,0 +1,246 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Allows for replacing arbitrary strings in your data sets with other values. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + * @todo When setTableMetaData() is taken out of the AbstractTable this class should extend AbstractTable. + */ +class PHPUnit_Extensions_Database_DataSet_ReplacementTable implements PHPUnit_Extensions_Database_DataSet_ITable +{ + /** + * @var PHPUnit_Extensions_Database_DataSet_ITable + */ + protected $table; + + /** + * @var array + */ + protected $fullReplacements; + + /** + * @var array + */ + protected $subStrReplacements; + + /** + * Creates a new replacement table + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $table + * @param array $fullReplacements + * @param array $subStrReplacements + */ + public function __construct(PHPUnit_Extensions_Database_DataSet_ITable $table, Array $fullReplacements = array(), Array $subStrReplacements = array()) + { + $this->table = $table; + $this->fullReplacements = $fullReplacements; + $this->subStrReplacements = $subStrReplacements; + } + + /** + * Adds a new full replacement + * + * Full replacements will only replace values if the FULL value is a match + * + * @param string $value + * @param string $replacement + */ + public function addFullReplacement($value, $replacement) + { + $this->fullReplacements[$value] = $replacement; + } + + /** + * Adds a new substr replacement + * + * Substr replacements will replace all occurances of the substr in every column + * + * @param string $value + * @param string $replacement + */ + public function addSubStrReplacement($value, $replacement) + { + $this->subStrReplacements[$value] = $replacement; + } + + /** + * Returns the table's meta data. + * + * @return PHPUnit_Extensions_Database_DataSet_ITableMetaData + */ + public function getTableMetaData() + { + return $this->table->getTableMetaData(); + } + + /** + * Returns the number of rows in this table. + * + * @return int + */ + public function getRowCount() + { + return $this->table->getRowCount(); + } + + /** + * Returns the value for the given column on the given row. + * + * @param int $row + * @param int $column + */ + public function getValue($row, $column) + { + return $this->getReplacedValue($this->table->getValue($row, $column)); + } + + /** + * Returns the an associative array keyed by columns for the given row. + * + * @param int $row + * @return array + */ + public function getRow($row) + { + $row = $this->table->getRow($row); + + return array_map(array($this, 'getReplacedValue'), $row); + } + + /** + * Asserts that the given table matches this table. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $other + */ + public function assertEquals(PHPUnit_Extensions_Database_DataSet_ITable $other) + { + $thisMetaData = $this->getTableMetaData(); + $otherMetaData = $other->getTableMetaData(); + + $thisMetaData->assertEquals($otherMetaData); + + if ($this->getRowCount() != $other->getRowCount()) { + throw new Exception("Expected row count of {$this->getRowCount()}, has a row count of {$other->getRowCount()}"); + } + + $columns = $thisMetaData->getColumns(); + $rowCount = $this->getRowCount(); + + for ($i = 0; $i < $rowCount; $i++) { + foreach ($columns as $columnName) { + if ($this->getValue($i, $columnName) != $other->getValue($i, $columnName)) { + throw new Exception("Expected value of {$this->getValue($i, $columnName)} for row {$i} column {$columnName}, has a value of {$other->getValue($i, $columnName)}"); + } + } + } + + return TRUE; + } + + public function __toString() + { + $columns = $this->getTableMetaData()->getColumns(); + + $lineSeperator = str_repeat('+----------------------', count($columns)) . "+\n"; + $lineLength = strlen($lineSeperator) - 1; + + $tableString = $lineSeperator; + $tableString .= '| ' . str_pad($this->getTableMetaData()->getTableName(), $lineLength - 4, ' ', STR_PAD_RIGHT) . " |\n"; + $tableString .= $lineSeperator; + $tableString .= $this->rowToString($columns); + $tableString .= $lineSeperator; + + $rowCount = $this->getRowCount(); + + for ($i = 0; $i < $rowCount; $i++) { + $values = array(); + + foreach ($columns as $columnName) { + $values[] = $this->getValue($i, $columnName); + } + + $tableString .= $this->rowToString($values); + $tableString .= $lineSeperator; + } + + return "\n" . $tableString . "\n"; + } + + protected function rowToString(Array $row) + { + $rowString = ''; + + foreach ($row as $value) { + if (is_null($value)) { + $value = 'NULL'; + } + + $rowString .= '| ' . str_pad(substr($value, 0, 20), 20, ' ', STR_PAD_BOTH) . ' '; + } + + return $rowString . "|\n"; + } + + protected function getReplacedValue($value) + { + if (is_scalar($value) && array_key_exists((string)$value, $this->fullReplacements)) { + return $this->fullReplacements[$value]; + } + + else if (count($this->subStrReplacements)) { + return str_replace(array_keys($this->subStrReplacements), array_values($this->subStrReplacements), $value); + } + + else { + return $value; + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ReplacementTableIterator.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ReplacementTableIterator.php new file mode 100644 index 0000000..d1d9bf3 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/ReplacementTableIterator.php @@ -0,0 +1,185 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * The default table iterator + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_ReplacementTableIterator implements OuterIterator, PHPUnit_Extensions_Database_DataSet_ITableIterator +{ + + /** + * @var PHPUnit_Extensions_Database_DataSet_ITableIterator + */ + protected $innerIterator; + + /** + * @var array + */ + protected $fullReplacements; + + /** + * @var array + */ + protected $subStrReplacements; + + /** + * Creates a new replacement table iterator object. + * + * @param PHPUnit_Extensions_Database_DataSet_ITableIterator $innerIterator + * @param array $fullReplacements + * @param array $subStrReplacements + */ + public function __construct(PHPUnit_Extensions_Database_DataSet_ITableIterator $innerIterator, Array $fullReplacements = array(), Array $subStrReplacements = array()) + { + $this->innerIterator = $innerIterator; + $this->fullReplacements = $fullReplacements; + $this->subStrReplacements = $subStrReplacements; + } + + /** + * Adds a new full replacement + * + * Full replacements will only replace values if the FULL value is a match + * + * @param string $value + * @param string $replacement + */ + public function addFullReplacement($value, $replacement) + { + $this->fullReplacements[$value] = $replacement; + } + + /** + * Adds a new substr replacement + * + * Substr replacements will replace all occurances of the substr in every column + * + * @param string $value + * @param string $replacement + */ + public function addSubStrReplacement($value, $replacement) + { + $this->subStrReplacements[$value] = $replacement; + } + + /** + * Returns the current table. + * + * @return PHPUnit_Extensions_Database_DataSet_ITable + */ + public function getTable() + { + return $this->current(); + } + + /** + * Returns the current table's meta data. + * + * @return PHPUnit_Extensions_Database_DataSet_ITableMetaData + */ + public function getTableMetaData() + { + $this->current()->getTableMetaData(); + } + + /** + * Returns the current table. + * + * @return PHPUnit_Extensions_Database_DataSet_ITable + */ + public function current() + { + return new PHPUnit_Extensions_Database_DataSet_ReplacementTable($this->innerIterator->current(), $this->fullReplacements, $this->subStrReplacements); + } + + /** + * Returns the name of the current table. + * + * @return string + */ + public function key() + { + return $this->current()->getTableMetaData()->getTableName(); + } + + /** + * advances to the next element. + * + */ + public function next() + { + $this->innerIterator->next(); + } + + /** + * Rewinds to the first element + */ + public function rewind() + { + $this->innerIterator->rewind(); + } + + /** + * Returns true if the current index is valid + * + * @return bool + */ + public function valid() + { + return $this->innerIterator->valid(); + } + + public function getInnerIterator() + { + return $this->innerIterator; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Csv.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Csv.php new file mode 100644 index 0000000..08de5e4 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Csv.php @@ -0,0 +1,125 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Creates CsvDataSets based off of a spec string. + * + * The format of the spec string is as follows: + * + * |table1:filename.csv,table2:filename2.csv + * + * The first portion of the spec including the pipe symbol '|' is optional. + * If the pipe option is included than it may be preceded by up to four + * characters specifying values for the following arguments in order: + * delimiter (defaults to ',',) enclosure (defaults to '"',) escape (defaults to '"',). + * + * Any additional characters in the csv options will be discarded. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_Specs_Csv implements PHPUnit_Extensions_Database_DataSet_ISpec +{ + /** + * Creates CSV Data Set from a data set spec. + * + * @param string $dataSetSpec + * @return PHPUnit_Extensions_Database_DataSet_CsvDataSet + */ + public function getDataSet($dataSetSpec) + { + $csvDataSetArgs = $this->getCsvOptions($dataSetSpec); + $csvDataSetRfl = new ReflectionClass('PHPUnit_Extensions_Database_DataSet_CsvDataSet'); + $csvDataSet = $csvDataSetRfl->newInstanceArgs($csvDataSetArgs); + + foreach ($this->getTableFileMap($dataSetSpec) as $tableName => $file) { + $csvDataSet->addTable($tableName, $file); + } + + return $csvDataSet; + } + + /** + * Returns CSV options. + * + * Returns an array containing the options that will be passed to the + * PHPUnit_Extensions_Database_DataSet_CsvDataSet constructor. The options + * are determined by the given $dataSetSpec. + * + * @param string $dataSetSpec + * @return array + */ + protected function getCsvOptions($dataSetSpec) + { + list($csvOptStr, ) = explode('|', $dataSetSpec, 2); + return str_split($csvOptStr); + } + + /** + * Returns map of tables to files. + * + * Returns an associative array containing a mapping of tables (the key) + * to files (the values.) The tables and files are determined by the given + * $dataSetSpec + * + * @param string $dataSetSpec + * @return array + */ + protected function getTableFileMap($dataSetSpec) + { + $tables = array(); + + foreach (explode(',', $dataSetSpec) as $csvfile) { + list($tableName, $file) = explode(':', $csvfile, 2); + $tables[$tableName] = $file; + } + + return $tables; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/DbQuery.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/DbQuery.php new file mode 100644 index 0000000..eb93c0c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/DbQuery.php @@ -0,0 +1,111 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Creates DefaultDataSets based off of a spec string. + * + * This spec class requires a list of databases to be set to the object before + * it can return a list of databases. + * + * The format of the spec string is as follows: + * + * ::: + * + * The db label should be equal to one of the keys in the array of databases + * passed to setDatabases(). + * + * The schema should be the primary schema you will be running the sql query + * against. + * + * The table name should be set to what you would like the table name in the + * dataset to be. + * + * The sql is the query you want to use to generate the table columns and data. + * The column names in the table will be identical to the column aliases in the + * query. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_Specs_DbQuery implements PHPUnit_Extensions_Database_DataSet_ISpec, PHPUnit_Extensions_Database_IDatabaseListConsumer +{ + /** + * @var array + */ + protected $databases = array(); + + /** + * Sets the database for the spec + * + * @param array $databases + */ + public function setDatabases(array $databases) + { + $this->databases = $databases; + } + + /** + * Creates a Default Data Set with a query table from a data set spec. + * + * @param string $dataSetSpec + * @return PHPUnit_Extensions_Database_DataSet_DefaultDataSet + */ + public function getDataSet($dataSetSpec) + { + list($dbLabel, $schema, $table, $sql) = explode(':', $dataSetSpec, 4); + $databaseInfo = $this->databases[$dbLabel]; + + $pdoRflc = new ReflectionClass('PDO'); + $pdo = $pdoRflc->newInstanceArgs(explode('|', $databaseInfo)); + $dbConnection = new PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection($pdo, $schema); + $table = $dbConnection->createQueryTable($table, $sql); + + return new PHPUnit_Extensions_Database_DataSet_DefaultDataSet(array($table)); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/DbTable.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/DbTable.php new file mode 100644 index 0000000..3337f65 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/DbTable.php @@ -0,0 +1,109 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Creates a database dataset based off of a spec string. + * + * This spec class requires a list of databases to be set to the object before + * it can return a list of databases. + * + * The format of the spec string is as follows: + * + * :: + * + * The db label should be equal to one of the keys in the array of databases + * passed to setDatabases(). + * + * The schema should be the primary schema you will be choosing tables from. + * + * The tables should be a comma delimited list of all tables you would like to + * pull data from. + * + * The sql is the query you want to use to generate the table columns and data. + * The column names in the table will be identical to the column aliases in the + * query. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_Specs_DbTable implements PHPUnit_Extensions_Database_DataSet_ISpec, PHPUnit_Extensions_Database_IDatabaseListConsumer +{ + /** + * @var array + */ + protected $databases = array(); + + /** + * Sets the database for the spec + * + * @param array $databases + */ + public function setDatabases(array $databases) + { + $this->databases = $databases; + } + + /** + * Creates a DB Data Set from a data set spec. + * + * @param string $dataSetSpec + * @return PHPUnit_Extensions_Database_DataSet_IDataSet + */ + public function getDataSet($dataSetSpec) + { + list($dbLabel, $schema, $tables) = explode(':', $dataSetSpec, 3); + $databaseInfo = $this->databases[$dbLabel]; + + $pdoRflc = new ReflectionClass('PDO'); + $pdo = $pdoRflc->newInstanceArgs(explode('|', $databaseInfo)); + $dbConnection = new PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection($pdo, $schema); + + return !empty($tables) ? $dbConnection->createDataSet(explode(',', $tables)) : $dbConnection->createDataSet(); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Factory.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Factory.php new file mode 100644 index 0000000..bed640b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Factory.php @@ -0,0 +1,89 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Creates the appropriate DataSet Spec based on a given type. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_Specs_Factory implements PHPUnit_Extensions_Database_DataSet_Specs_IFactory +{ + /** + * Returns the data set + * + * @param string $type + * @return PHPUnit_Extensions_Database_DataSet_ISpec + */ + public function getDataSetSpecByType($type) + { + switch ($type) { + case 'xml': + return new PHPUnit_Extensions_Database_DataSet_Specs_Xml(); + + case 'flatxml': + return new PHPUnit_Extensions_Database_DataSet_Specs_FlatXml(); + + case 'csv': + return new PHPUnit_Extensions_Database_DataSet_Specs_Csv(); + + case 'yaml': + return new PHPUnit_Extensions_Database_DataSet_Specs_Yaml(); + + case 'dbtable': + return new PHPUnit_Extensions_Database_DataSet_Specs_DbTable(); + + case 'dbquery': + return new PHPUnit_Extensions_Database_DataSet_Specs_DbQuery(); + + default: + throw new Exception("I don't know what you want from me."); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/FlatXml.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/FlatXml.php new file mode 100644 index 0000000..ad072ff --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/FlatXml.php @@ -0,0 +1,75 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0CSV + */ + +/** + * Creates a FlatXML dataset based off of a spec string. + * + * The format of the spec string is as follows: + * + * + * + * The filename should be the location of a flat xml file relative to the + * current working directory. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_Specs_FlatXml implements PHPUnit_Extensions_Database_DataSet_ISpec +{ + /** + * Creates Flat XML Data Set from a data set spec. + * + * @param string $dataSetSpec + * @return PHPUnit_Extensions_Database_DataSet_FlatXmlDataSet + */ + public function getDataSet($dataSetSpec) + { + return new PHPUnit_Extensions_Database_DataSet_FlatXmlDataSet($dataSetSpec); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/IFactory.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/IFactory.php new file mode 100644 index 0000000..64bc662 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/IFactory.php @@ -0,0 +1,65 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * An interface for data set spec factories. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_DataSet_Specs_IFactory +{ + /** + * Returns the data set + * + * @param string $type + * @return PHPUnit_Extensions_Database_DataSet_ISpec + */ + public function getDataSetSpecByType($type); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Xml.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Xml.php new file mode 100644 index 0000000..fec46d1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Xml.php @@ -0,0 +1,75 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0CSV + */ + +/** + * Creates a XML dataset based off of a spec string. + * + * The format of the spec string is as follows: + * + * + * + * The filename should be the location of a xml file relative to the + * current working directory. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_Specs_Xml implements PHPUnit_Extensions_Database_DataSet_ISpec +{ + /** + * Creates XML Data Set from a data set spec. + * + * @param string $dataSetSpec + * @return PHPUnit_Extensions_Database_DataSet_XmlDataSet + */ + public function getDataSet($dataSetSpec) + { + return new PHPUnit_Extensions_Database_DataSet_XmlDataSet($dataSetSpec); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Yaml.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Yaml.php new file mode 100644 index 0000000..3f8c3b7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Yaml.php @@ -0,0 +1,75 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0CSV + */ + +/** + * Creates a YAML dataset based off of a spec string. + * + * The format of the spec string is as follows: + * + * + * + * The filename should be the location of a yaml file relative to the + * current working directory. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_Specs_Yaml implements PHPUnit_Extensions_Database_DataSet_ISpec +{ + /** + * Creates YAML Data Set from a data set spec. + * + * @param string $dataSetSpec + * @return PHPUnit_Extensions_Database_DataSet_YamlDataSet + */ + public function getDataSet($dataSetSpec) + { + return new PHPUnit_Extensions_Database_DataSet_YamlDataSet($dataSetSpec); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/TableFilter.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/TableFilter.php new file mode 100644 index 0000000..8f07388 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/TableFilter.php @@ -0,0 +1,136 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * A table decorator that allows filtering out table columns from results. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_TableFilter extends PHPUnit_Extensions_Database_DataSet_AbstractTable +{ + + /** + * The table meta data being decorated. + * @var PHPUnit_Extensions_Database_DataSet_ITable + */ + protected $originalTable; + + /** + * Creates a new table filter using the original table + * + * @param $originalTable PHPUnit_Extensions_Database_DataSet_ITable + * @param $excludeColumns Array @deprecated, use the set* methods instead. + */ + public function __construct(PHPUnit_Extensions_Database_DataSet_ITable $originalTable, Array $excludeColumns = array()) + { + $this->originalTable = $originalTable; + $this->setTableMetaData(new PHPUnit_Extensions_Database_DataSet_TableMetaDataFilter($originalTable->getTableMetaData())); + $this->addExcludeColumns($excludeColumns); + } + + /** + * Returns the number of rows in this table. + * + * @return int + */ + public function getRowCount() + { + return $this->originalTable->getRowCount(); + } + + /** + * Returns the value for the given column on the given row. + * + * @param int $row + * @param int $column + */ + public function getValue($row, $column) + { + if (in_array($column, $this->getTableMetaData()->getColumns())) { + return $this->originalTable->getValue($row, $column); + } else { + throw new InvalidArgumentException("The given row ({$row}) and column ({$column}) do not exist in table {$this->getTableMetaData()->getTableName()}"); + } + } + + /** + * Sets the columns to include in the table. + * @param Array $includeColumns + */ + public function addIncludeColumns(Array $includeColumns) + { + $this->tableMetaData->addIncludeColumns($includeColumns); + } + + /** + * Clears the included columns. + */ + public function clearIncludeColumns() + { + $this->tableMetaData->clearIncludeColumns(); + } + + /** + * Sets the columns to exclude from the table. + * @param Array $excludeColumns + */ + public function addExcludeColumns(Array $excludeColumns) + { + $this->tableMetaData->addExcludeColumns($excludeColumns); + } + + /** + * Clears the included columns. + */ + public function clearExcludeColumns() + { + $this->tableMetaData->clearExcludeColumns(); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/TableMetaDataFilter.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/TableMetaDataFilter.php new file mode 100644 index 0000000..08ee7cf --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/TableMetaDataFilter.php @@ -0,0 +1,165 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * A TableMetaData decorator that allows filtering columns from another + * metaData object. + * + * The if a whitelist (include) filter is specified, then only those columns + * will be included. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_TableMetaDataFilter extends PHPUnit_Extensions_Database_DataSet_AbstractTableMetaData +{ + + /** + * The table meta data being decorated. + * @var PHPUnit_Extensions_Database_DataSet_ITableMetaData + */ + protected $originalMetaData; + + /** + * The columns to exclude from the meta data. + * @var Array + */ + protected $excludeColumns = array(); + + /** + * The columns to include from the meta data. + * @var Array + */ + protected $includeColumns = array(); + + /** + * Creates a new filtered table meta data object filtering out + * $excludeColumns. + * + * @param PHPUnit_Extensions_Database_DataSet_ITableMetaData $originalMetaData + * @param array $excludeColumns - Deprecated. Use the set* methods instead. + */ + public function __construct(PHPUnit_Extensions_Database_DataSet_ITableMetaData $originalMetaData, Array $excludeColumns = array()) + { + $this->originalMetaData = $originalMetaData; + $this->addExcludeColumns($excludeColumns); + } + + /** + * Returns the names of the columns in the table. + * + * @return array + */ + public function getColumns() + { + if (!empty($this->includeColumns)) { + return array_values(array_intersect($this->originalMetaData->getColumns(), $this->includeColumns)); + } + elseif (!empty($this->excludeColumns)) { + return array_values(array_diff($this->originalMetaData->getColumns(), $this->excludeColumns)); + } + else { + return $this->originalMetaData->getColumns(); + } + } + + /** + * Returns the names of the primary key columns in the table. + * + * @return array + */ + public function getPrimaryKeys() + { + return $this->originalMetaData->getPrimaryKeys(); + } + + /** + * Returns the name of the table. + * + * @return string + */ + public function getTableName() + { + return $this->originalMetaData->getTableName(); + } + + /** + * Sets the columns to include in the table. + * @param Array $includeColumns + */ + public function addIncludeColumns(Array $includeColumns) + { + $this->includeColumns = array_unique(array_merge($this->includeColumns, $includeColumns)); + } + + /** + * Clears the included columns. + */ + public function clearIncludeColumns() + { + $this->includeColumns = array(); + } + + /** + * Sets the columns to exclude from the table. + * @param Array $excludeColumns + */ + public function addExcludeColumns(Array $excludeColumns) + { + $this->excludeColumns = array_unique(array_merge($this->excludeColumns, $excludeColumns)); + } + + /** + * Clears the excluded columns. + */ + public function clearExcludeColumns() + { + $this->excludeColumns = array(); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/XmlDataSet.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/XmlDataSet.php new file mode 100644 index 0000000..7bc3834 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/XmlDataSet.php @@ -0,0 +1,132 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * The default implementation of a data set. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_XmlDataSet extends PHPUnit_Extensions_Database_DataSet_AbstractXmlDataSet +{ + + protected function getTableInfo(Array &$tableColumns, Array &$tableValues) + { + if ($this->xmlFileContents->getName() != 'dataset') { + throw new Exception("The root element of an xml data set file must be called "); + } + + foreach ($this->xmlFileContents->xpath('/dataset/table') as $tableElement) { + if (empty($tableElement['name'])) { + throw new Exception("Table elements must include a name attribute specifying the table name."); + } + + $tableName = (string)$tableElement['name']; + + if (!isset($tableColumns[$tableName])) { + $tableColumns[$tableName] = array(); + } + + if (!isset($tableValues[$tableName])) { + $tableValues[$tableName] = array(); + } + + $tableInstanceColumns = array(); + + foreach ($tableElement->xpath('./column') as $columnElement) { + $columnName = (string)$columnElement; + if (empty($columnName)) { + throw new Exception("column elements cannot be empty"); + } + + if (!in_array($columnName, $tableColumns[$tableName])) { + $tableColumns[$tableName][] = $columnName; + } + + $tableInstanceColumns[] = $columnName; + } + + foreach ($tableElement->xpath('./row') as $rowElement) { + $rowValues = array(); + $index = 0; + + foreach ($rowElement->children() as $columnValue) { + switch ($columnValue->getName()) { + case 'value': + $rowValues[$tableInstanceColumns[$index]] = (string)$columnValue; + $index++; + break; + case 'null': + $rowValues[$tableInstanceColumns[$index]] = NULL; + $index++; + break; + default: + throw new Exception("Unknown child in the a row element."); + } + } + + $tableValues[$tableName][] = $rowValues; + } + } + } + + public static function write(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset, $filename) + { + $pers = new PHPUnit_Extensions_Database_DataSet_Persistors_Xml(); + $pers->setFileName($filename); + + try { + $pers->write($dataset); + } + + catch (RuntimeException $e) { + throw new PHPUnit_Framework_Exception(__METHOD__ . ' called with an unwritable file.'); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/YamlDataSet.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/YamlDataSet.php new file mode 100644 index 0000000..45b2f14 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DataSet/YamlDataSet.php @@ -0,0 +1,168 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +require_once 'SymfonyComponents/YAML/sfYaml.php'; + +/** + * Creates CsvDataSets. + * + * You can incrementally add CSV files as tables to your datasets + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DataSet_YamlDataSet extends PHPUnit_Extensions_Database_DataSet_AbstractDataSet +{ + /** + * @var array + */ + protected $tables = array(); + + /** + * Creates a new YAML dataset + * + * @param string $yamlFile + * @param string $enclosure + * @param string $escape + */ + public function __construct($yamlFile) + { + $this->addYamlFile($yamlFile); + } + + /** + * Adds a new yaml file to the dataset. + * @param string $yamlFile + */ + public function addYamlFile($yamlFile) + { + $data = sfYaml::load($yamlFile); + + foreach ($data as $tableName => $rows) { + if (!isset($rows)) { + $rows = array(); + } + + if (!is_array($rows)) { + continue; + } + + if (!array_key_exists($tableName, $this->tables)) { + $columns = $this->getColumns($rows); + + $tableMetaData = new PHPUnit_Extensions_Database_DataSet_DefaultTableMetaData( + $tableName, $columns + ); + + $this->tables[$tableName] = new PHPUnit_Extensions_Database_DataSet_DefaultTable( + $tableMetaData + ); + } + + foreach ($rows as $row) { + $this->tables[$tableName]->addRow($row); + } + } + } + + /** + * Creates a unique list of columns from all the rows in a table. + * If the table is defined another time in the Yaml, and if the Yaml + * parser could return the multiple occerrences, then this would be + * insufficient unless we grouped all the occurences of the table + * into onwe row set. sfYaml, however, does not provide multiple tables + * with the same name, it only supplies the last table. + * + * @params all the rows in a table. + */ + private function getColumns($rows) { + $columns = array(); + + foreach ($rows as $row) { + $columns = array_merge($columns, array_keys($row)); + } + + return array_values(array_unique($columns)); + } + + /** + * Creates an iterator over the tables in the data set. If $reverse is + * true a reverse iterator will be returned. + * + * @param bool $reverse + * @return PHPUnit_Extensions_Database_DataSet_ITableIterator + */ + protected function createIterator($reverse = FALSE) + { + return new PHPUnit_Extensions_Database_DataSet_DefaultTableIterator( + $this->tables, $reverse + ); + } + + /** + * Saves a given $dataset to $filename in YAML format + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataset + * @param string $filename + */ + public static function write(PHPUnit_Extensions_Database_DataSet_IDataSet $dataset, $filename) + { + $pers = new PHPUnit_Extensions_Database_DataSet_Persistors_Yaml(); + $pers->setFileName($filename); + + try { + $pers->write($dataset); + } + + catch (RuntimeException $e) { + throw new PHPUnit_Framework_Exception( + __METHOD__ . ' called with an unwritable file.' + ); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DefaultTester.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DefaultTester.php new file mode 100644 index 0000000..0e5c8cb --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/DefaultTester.php @@ -0,0 +1,84 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * This is the default implementation of the database tester. It receives its + * connection object from the constructor. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_DefaultTester extends PHPUnit_Extensions_Database_AbstractTester +{ + + /** + * @var PHPUnit_Extensions_Database_DB_IDatabaseConnection + */ + protected $connection; + + /** + * Creates a new default database tester using the given connection. + * + * @param PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection + */ + public function __construct(PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection) + { + $this->connection = $connection; + } + + /** + * Returns the test database connection. + * + * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection + */ + public function getConnection() + { + return $this->connection; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/IDatabaseListConsumer.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/IDatabaseListConsumer.php new file mode 100644 index 0000000..7e9c41d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/IDatabaseListConsumer.php @@ -0,0 +1,64 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * An interface for classes that require a list of databases to operate. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_IDatabaseListConsumer +{ + /** + * Sets the database for the spec + * + * @param array $databases + */ + public function setDatabases(array $databases); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/ITester.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/ITester.php new file mode 100644 index 0000000..3672853 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/ITester.php @@ -0,0 +1,119 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * This is the interface for DatabaseTester objects. These objects are used to + * add database testing to existing test cases using composition instead of + * extension. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_ITester +{ + + /** + * Closes the specified connection. + * + * @param PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection + */ + public function closeConnection(PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection); + + /** + * Returns the test database connection. + * + * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection + */ + public function getConnection(); + + /** + * Returns the test dataset. + * + * @return PHPUnit_Extensions_Database_DataSet_IDataSet + */ + public function getDataSet(); + + /** + * TestCases must call this method inside setUp(). + */ + public function onSetUp(); + + /** + * TestCases must call this method inside teadDown(). + */ + public function onTearDown(); + + /** + * Sets the test dataset to use. + * + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet + */ + public function setDataSet(PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet); + + /** + * Sets the schema value. + * + * @param string $schema + */ + public function setSchema($schema); + + /** + * Sets the DatabaseOperation to call when starting the test. + * + * @param PHPUnit_Extensions_Database_Operation_DatabaseOperation $setUpOperation + */ + public function setSetUpOperation(PHPUnit_Extensions_Database_Operation_IDatabaseOperation $setUpOperation); + + /** + * Sets the DatabaseOperation to call when starting the test. + * + * @param PHPUnit_Extensions_Database_Operation_DatabaseOperation $tearDownOperation + */ + public function setTearDownOperation(PHPUnit_Extensions_Database_Operation_IDatabaseOperation $tearDownOperation); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Composite.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Composite.php new file mode 100644 index 0000000..db1e187 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Composite.php @@ -0,0 +1,94 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * This class facilitates combining database operations. To create a composite + * operation pass an array of classes that implement + * PHPUnit_Extensions_Database_Operation_IDatabaseOperation and they will be + * executed in that order against all data sets. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_Operation_Composite implements PHPUnit_Extensions_Database_Operation_IDatabaseOperation +{ + + /** + * @var array + */ + protected $operations = array(); + + /** + * Creates a composite operation. + * + * @param array $operations + */ + public function __construct(Array $operations) + { + foreach ($operations as $operation) { + if ($operation instanceof PHPUnit_Extensions_Database_Operation_IDatabaseOperation) { + $this->operations[] = $operation; + } else { + throw new InvalidArgumentException("Only database operation instances can be passed to a composite database operation."); + } + } + } + + public function execute(PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection, PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet) + { + try { + foreach ($this->operations as $operation) { + /* @var $operation PHPUnit_Extensions_Database_Operation_IDatabaseOperation */ + $operation->execute($connection, $dataSet); + } + } catch (PHPUnit_Extensions_Database_Operation_Exception $e) { + throw new PHPUnit_Extensions_Database_Operation_Exception("COMPOSITE[{$e->getOperation()}]", $e->getQuery(), $e->getArgs(), $e->getTable(), $e->getError()); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Delete.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Delete.php new file mode 100644 index 0000000..132c596 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Delete.php @@ -0,0 +1,86 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Deletes the rows in a given dataset using primary key columns. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_Operation_Delete extends PHPUnit_Extensions_Database_Operation_RowBased +{ + + protected $operationName = 'DELETE'; + + protected $iteratorDirection = self::ITERATOR_TYPE_REVERSE; + + protected function buildOperationQuery(PHPUnit_Extensions_Database_DataSet_ITableMetaData $databaseTableMetaData, PHPUnit_Extensions_Database_DataSet_ITable $table, PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection) + { + $keys = $databaseTableMetaData->getPrimaryKeys(); + + $whereStatement = 'WHERE ' . implode(' AND ', $this->buildPreparedColumnArray($keys, $connection)); + + $query = " + DELETE FROM {$connection->quoteSchemaObject($table->getTableMetaData()->getTableName())} + {$whereStatement} + "; + + return $query; + } + + protected function buildOperationArguments(PHPUnit_Extensions_Database_DataSet_ITableMetaData $databaseTableMetaData, PHPUnit_Extensions_Database_DataSet_ITable $table, $row) + { + $args = array(); + foreach ($databaseTableMetaData->getPrimaryKeys() as $columnName) { + $args[] = $table->getValue($row, $columnName); + } + + return $args; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/DeleteAll.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/DeleteAll.php new file mode 100644 index 0000000..e4812be --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/DeleteAll.php @@ -0,0 +1,75 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Deletes all rows from all tables in a dataset. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_Operation_DeleteAll implements PHPUnit_Extensions_Database_Operation_IDatabaseOperation +{ + + public function execute(PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection, PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet) + { + foreach ($dataSet->getReverseIterator() as $table) { + /* @var $table PHPUnit_Extensions_Database_DataSet_ITable */ + + $query = " + DELETE FROM {$connection->quoteSchemaObject($table->getTableMetaData()->getTableName())} + "; + + try { + $connection->getConnection()->query($query); + } catch (PDOException $e) { + throw new PHPUnit_Extensions_Database_Operation_Exception('DELETE_ALL', $query, array(), $table, $e->getMessage()); + } + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Exception.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Exception.php new file mode 100644 index 0000000..4354f78 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Exception.php @@ -0,0 +1,129 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Thrown for exceptions encountered with database operations. Provides + * information regarding which operations failed and the query (if any) it + * failed on. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_Operation_Exception extends RuntimeException +{ + + /** + * @var string + */ + protected $operation; + + /** + * @var string + */ + protected $preparedQuery; + + /** + * @var array + */ + protected $preparedArgs; + + /** + * @var PHPUnit_Extensions_Database_DataSet_ITable + */ + protected $table; + + /** + * @var string + */ + protected $error; + + /** + * Creates a new dbunit operation exception + * + * @param string $operation + * @param string $current_query + * @param PHPUnit_Extensions_Database_DataSet_ITable $current_table + * @param string $error + */ + public function __construct($operation, $current_query, $current_args, $current_table, $error) + { + parent::__construct("{$operation} operation failed on query: {$current_query} using args: " . print_r($current_args, TRUE) . " [{$error}]"); + + $this->operation = $operation; + $this->preparedQuery = $current_query; + $this->preparedArgs = $current_args; + $this->table = $current_table; + $this->error = $error; + } + + public function getOperation() + { + return $this->operation; + } + + public function getQuery() + { + return $this->preparedQuery; + } + + public function getTable() + { + return $this->table; + } + + public function getArgs() + { + return $this->preparedArgs; + } + + public function getError() + { + return $this->error; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Factory.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Factory.php new file mode 100644 index 0000000..314e044 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Factory.php @@ -0,0 +1,138 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * A class factory to easily return database operations. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_Operation_Factory +{ + + /** + * Returns a null database operation + * + * @return PHPUnit_Extensions_Database_Operation_IDatabaseOperation + */ + public static function NONE() + { + return new PHPUnit_Extensions_Database_Operation_Null(); + } + + /** + * Returns a clean insert database operation. It will remove all contents + * from the table prior to re-inserting rows. + * + * @param bool $cascadeTruncates Set to true to force truncates to cascade on databases that support this. + * @return PHPUnit_Extensions_Database_Operation_IDatabaseOperation + */ + public static function CLEAN_INSERT($cascadeTruncates = FALSE) + { + return new PHPUnit_Extensions_Database_Operation_Composite(array( + self::TRUNCATE($cascadeTruncates), + self::INSERT() + )); + } + + /** + * Returns an insert database operation. + * + * @return PHPUnit_Extensions_Database_Operation_IDatabaseOperation + */ + public static function INSERT() + { + return new PHPUnit_Extensions_Database_Operation_Insert(); + } + + /** + * Returns a truncate database operation. + * + * @param bool $cascadeTruncates Set to true to force truncates to cascade on databases that support this. + * @return PHPUnit_Extensions_Database_Operation_IDatabaseOperation + */ + public static function TRUNCATE($cascadeTruncates = FALSE) + { + $truncate = new PHPUnit_Extensions_Database_Operation_Truncate(); + $truncate->setCascade($cascadeTruncates); + + return $truncate; + } + + /** + * Returns a delete database operation. + * + * @return PHPUnit_Extensions_Database_Operation_IDatabaseOperation + */ + public static function DELETE() + { + return new PHPUnit_Extensions_Database_Operation_Delete(); + } + + /** + * Returns a delete_all database operation. + * + * @return PHPUnit_Extensions_Database_Operation_IDatabaseOperation + */ + public static function DELETE_ALL() + { + return new PHPUnit_Extensions_Database_Operation_DeleteAll(); + } + + /** + * Returns an update database operation. + * + * @return PHPUnit_Extensions_Database_Operation_IDatabaseOperation + */ + public static function UPDATE() + { + return new PHPUnit_Extensions_Database_Operation_Update(); + } + +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/IDatabaseOperation.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/IDatabaseOperation.php new file mode 100644 index 0000000..1bc301a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/IDatabaseOperation.php @@ -0,0 +1,69 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides a basic interface and functionality for executing database + * operations against a connection using a specific dataSet. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_Operation_IDatabaseOperation +{ + + /** + * Executes the database operation against the given $connection for the + * given $dataSet. + * + * @param PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet + * @throws PHPUnit_Extensions_Database_Operation_Exception + */ + public function execute(PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection, PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Insert.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Insert.php new file mode 100644 index 0000000..cfff743 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Insert.php @@ -0,0 +1,96 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * This class provides functionality for inserting rows from a dataset into a database. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_Operation_Insert extends PHPUnit_Extensions_Database_Operation_RowBased +{ + + protected $operationName = 'INSERT'; + + protected function buildOperationQuery(PHPUnit_Extensions_Database_DataSet_ITableMetaData $databaseTableMetaData, PHPUnit_Extensions_Database_DataSet_ITable $table, PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection) + { + $columnCount = count($table->getTableMetaData()->getColumns()); + + if ($columnCount > 0) { + $placeHolders = implode(', ', array_fill(0, $columnCount, '?')); + + $columns = ''; + foreach ($table->getTableMetaData()->getColumns() as $column) { + $columns .= $connection->quoteSchemaObject($column).', '; + } + + $columns = substr($columns, 0, -2); + + $query = " + INSERT INTO {$connection->quoteSchemaObject($table->getTableMetaData()->getTableName())} + ({$columns}) + VALUES + ({$placeHolders}) + "; + + return $query; + } else { + return FALSE; + } + } + + protected function buildOperationArguments(PHPUnit_Extensions_Database_DataSet_ITableMetaData $databaseTableMetaData, PHPUnit_Extensions_Database_DataSet_ITable $table, $row) + { + $args = array(); + foreach ($table->getTableMetaData()->getColumns() as $columnName) { + $args[] = $table->getValue($row, $columnName); + } + return $args; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Null.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Null.php new file mode 100644 index 0000000..2120131 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Null.php @@ -0,0 +1,63 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * This class represents a null database operation. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_Operation_Null implements PHPUnit_Extensions_Database_Operation_IDatabaseOperation +{ + + public function execute(PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection, PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet) + { + /* do nothing */ + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Replace.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Replace.php new file mode 100644 index 0000000..806f03f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Replace.php @@ -0,0 +1,142 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Updates the rows in a given dataset using primary key columns. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_Operation_Replace extends PHPUnit_Extensions_Database_Operation_RowBased +{ + + protected $operationName = 'REPLACE'; + + protected function buildOperationQuery(PHPUnit_Extensions_Database_DataSet_ITableMetaData $databaseTableMetaData, PHPUnit_Extensions_Database_DataSet_ITable $table, PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection) + { + $keys = $databaseTableMetaData->getPrimaryKeys(); + + $whereStatement = 'WHERE ' . implode(' AND ', $this->buildPreparedColumnArray($keys, $connection)); + + $query = " + SELECT COUNT(*) + FROM {$connection->quoteSchemaObject($table->getTableMetaData()->getTableName())} + {$whereStatement} + "; + + return $query; + } + + protected function buildOperationArguments(PHPUnit_Extensions_Database_DataSet_ITableMetaData $databaseTableMetaData, PHPUnit_Extensions_Database_DataSet_ITable $table, $row) + { + $args = array(); + + foreach ($databaseTableMetaData->getPrimaryKeys() as $columnName) { + $args[] = $table->getValue($row, $columnName); + } + + return $args; + } + + /** + * @param PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet + */ + public function execute(PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection, PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet) + { + $insertOperation = new PHPUnit_Extensions_Database_Operation_Insert; + $updateOperation = new PHPUnit_Extensions_Database_Operation_Update; + $databaseDataSet = $connection->createDataSet(); + + foreach ($dataSet as $table) { + /* @var $table PHPUnit_Extensions_Database_DataSet_ITable */ + $databaseTableMetaData = $databaseDataSet->getTableMetaData($table->getTableMetaData()->getTableName()); + + $insertQuery = $insertOperation->buildOperationQuery($databaseTableMetaData, $table, $connection); + $updateQuery = $updateOperation->buildOperationQuery($databaseTableMetaData, $table, $connection); + $selectQuery = $this->buildOperationQuery($databaseTableMetaData, $table, $connection); + + $insertStatement = $connection->getConnection()->prepare($insertQuery); + $updateStatement = $connection->getConnection()->prepare($updateQuery); + $selectStatement = $connection->getConnection()->prepare($selectQuery); + + $rowCount = $table->getRowCount(); + + for ($i = 0; $i < $rowCount; $i++) { + $selectArgs = $this->buildOperationArguments($databaseTableMetaData, $table, $i); + $query = $selectQuery; + $args = $selectArgs; + + try { + $selectStatement->execute($selectArgs); + + if ($selectStatement->fetchColumn(0) > 0) { + $updateArgs = $updateOperation->buildOperationArguments($databaseTableMetaData, $table, $i); + $query = $updateQuery; + $args = $updateArgs; + + $updateStatement->execute($updateArgs); + } else { + $insertArgs = $insertOperation->buildOperationArguments($databaseTableMetaData, $table, $i); + $query = $insertQuery; + $args = $insertArgs; + + $insertStatement->execute($insertArgs); + } + } + + catch (Exception $e) { + throw new PHPUnit_Extensions_Database_Operation_Exception( + $this->operationName, $query, $args, $table, $e->getMessage() + ); + } + } + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/RowBased.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/RowBased.php new file mode 100644 index 0000000..f0b63b8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/RowBased.php @@ -0,0 +1,122 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Provides basic functionality for row based operations. + * + * To create a row based operation you must create two functions. The first + * one, buildOperationQuery(), must return a query that will be used to create + * a prepared statement. The second one, buildOperationArguments(), should + * return an array containing arguments for each row. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +abstract class PHPUnit_Extensions_Database_Operation_RowBased implements PHPUnit_Extensions_Database_Operation_IDatabaseOperation +{ + const ITERATOR_TYPE_FORWARD = 0; + const ITERATOR_TYPE_REVERSE = 1; + + protected $operationName; + + protected $iteratorDirection = self::ITERATOR_TYPE_FORWARD; + + protected abstract function buildOperationQuery(PHPUnit_Extensions_Database_DataSet_ITableMetaData $databaseTableMetaData, PHPUnit_Extensions_Database_DataSet_ITable $table, PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection); + + protected abstract function buildOperationArguments(PHPUnit_Extensions_Database_DataSet_ITableMetaData $databaseTableMetaData, PHPUnit_Extensions_Database_DataSet_ITable $table, $row); + + /** + * @param PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection + * @param PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet + */ + public function execute(PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection, PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet) + { + $databaseDataSet = $connection->createDataSet(); + + $dsIterator = $this->iteratorDirection == self::ITERATOR_TYPE_REVERSE ? $dataSet->getReverseIterator() : $dataSet->getIterator(); + + foreach ($dsIterator as $table) { + /* @var $table PHPUnit_Extensions_Database_DataSet_ITable */ + $databaseTableMetaData = $databaseDataSet->getTableMetaData($table->getTableMetaData()->getTableName()); + $query = $this->buildOperationQuery($databaseTableMetaData, $table, $connection); + + if ($query === FALSE && $table->getRowCount() > 0) { + throw new PHPUnit_Extensions_Database_Operation_Exception($this->operationName, '', array(), $table, "Rows requested for insert, but no columns provided!"); + } + + $statement = $connection->getConnection()->prepare($query); + $rowCount = $table->getRowCount(); + + for ($i = 0; $i < $rowCount; $i++) { + $args = $this->buildOperationArguments($databaseTableMetaData, $table, $i); + + try { + $statement->execute($args); + } + + catch (Exception $e) { + throw new PHPUnit_Extensions_Database_Operation_Exception( + $this->operationName, $query, $args, $table, $e->getMessage() + ); + } + } + } + } + + protected function buildPreparedColumnArray($columns, PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection) + { + $columnArray = array(); + + foreach ($columns as $columnName) { + $columnArray[] = "{$connection->quoteSchemaObject($columnName)} = ?"; + } + + return $columnArray; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Truncate.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Truncate.php new file mode 100644 index 0000000..46eb6e9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Truncate.php @@ -0,0 +1,84 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Executes a truncate against all tables in a dataset. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_Operation_Truncate implements PHPUnit_Extensions_Database_Operation_IDatabaseOperation +{ + protected $useCascade = FALSE; + + public function setCascade($cascade = TRUE) + { + $this->useCascade = $cascade; + } + + public function execute(PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection, PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet) + { + foreach ($dataSet->getReverseIterator() as $table) { + /* @var $table PHPUnit_Extensions_Database_DataSet_ITable */ + $query = " + {$connection->getTruncateCommand()} {$connection->quoteSchemaObject($table->getTableMetaData()->getTableName())} + "; + + if ($this->useCascade && $connection->allowsCascading()) { + $query .= " CASCADE"; + } + + try { + $connection->getConnection()->query($query); + } catch (PDOException $e) { + throw new PHPUnit_Extensions_Database_Operation_Exception('TRUNCATE', $query, array(), $table, $e->getMessage()); + } + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Update.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Update.php new file mode 100644 index 0000000..51d531c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/Operation/Update.php @@ -0,0 +1,90 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Updates the rows in a given dataset using primary key columns. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_Operation_Update extends PHPUnit_Extensions_Database_Operation_RowBased +{ + + protected $operationName = 'UPDATE'; + + protected function buildOperationQuery(PHPUnit_Extensions_Database_DataSet_ITableMetaData $databaseTableMetaData, PHPUnit_Extensions_Database_DataSet_ITable $table, PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection) + { + $keys = $databaseTableMetaData->getPrimaryKeys(); + $columns = $table->getTableMetaData()->getColumns(); + $whereStatement = 'WHERE ' . implode(' AND ', $this->buildPreparedColumnArray($keys, $connection)); + $setStatement = 'SET ' . implode(', ', $this->buildPreparedColumnArray($columns, $connection)); + + $query = " + UPDATE {$connection->quoteSchemaObject($table->getTableMetaData()->getTableName())} + {$setStatement} + {$whereStatement} + "; + + return $query; + } + + protected function buildOperationArguments(PHPUnit_Extensions_Database_DataSet_ITableMetaData $databaseTableMetaData, PHPUnit_Extensions_Database_DataSet_ITable $table, $row) + { + $args = array(); + foreach ($table->getTableMetaData()->getColumns() as $columnName) { + $args[] = $table->getValue($row, $columnName); + } + + foreach ($databaseTableMetaData->getPrimaryKeys() as $columnName) { + $args[] = $table->getValue($row, $columnName); + } + + return $args; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/TestCase.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/TestCase.php new file mode 100644 index 0000000..3cf513c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/TestCase.php @@ -0,0 +1,250 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * A TestCase extension that provides functionality for testing and asserting + * against a real database. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +abstract class PHPUnit_Extensions_Database_TestCase extends PHPUnit_Framework_TestCase +{ + + /** + * @var PHPUnit_Extensions_Database_ITester + */ + protected $databaseTester; + + /** + * Closes the specified connection. + * + * @param PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection + */ + protected function closeConnection(PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection) + { + $this->getDatabaseTester()->closeConnection($connection); + } + + /** + * Returns the test database connection. + * + * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection + */ + protected abstract function getConnection(); + + /** + * Gets the IDatabaseTester for this testCase. If the IDatabaseTester is + * not set yet, this method calls newDatabaseTester() to obtain a new + * instance. + * + * @return PHPUnit_Extensions_Database_ITester + */ + protected function getDatabaseTester() + { + if (empty($this->databaseTester)) { + $this->databaseTester = $this->newDatabaseTester(); + } + + return $this->databaseTester; + } + + /** + * Returns the test dataset. + * + * @return PHPUnit_Extensions_Database_DataSet_IDataSet + */ + protected abstract function getDataSet(); + + /** + * Returns the database operation executed in test setup. + * + * @return PHPUnit_Extensions_Database_Operation_DatabaseOperation + */ + protected function getSetUpOperation() + { + return PHPUnit_Extensions_Database_Operation_Factory::CLEAN_INSERT(); + } + + /** + * Returns the database operation executed in test cleanup. + * + * @return PHPUnit_Extensions_Database_Operation_DatabaseOperation + */ + protected function getTearDownOperation() + { + return PHPUnit_Extensions_Database_Operation_Factory::NONE(); + } + + /** + * Creates a IDatabaseTester for this testCase. + * + * @return PHPUnit_Extensions_Database_ITester + */ + protected function newDatabaseTester() + { + return new PHPUnit_Extensions_Database_DefaultTester($this->getConnection()); + } + + /** + * Creates a new DefaultDatabaseConnection using the given PDO connection + * and database schema name. + * + * @param PDO $connection + * @param string $schema + * @return PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection + */ + protected function createDefaultDBConnection(PDO $connection, $schema = '') + { + return new PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection($connection, $schema); + } + + /** + * Creates a new FlatXmlDataSet with the given $xmlFile. (absolute path.) + * + * @param string $xmlFile + * @return PHPUnit_Extensions_Database_DataSet_FlatXmlDataSet + */ + protected function createFlatXMLDataSet($xmlFile) + { + return new PHPUnit_Extensions_Database_DataSet_FlatXmlDataSet($xmlFile); + } + + /** + * Creates a new XMLDataSet with the given $xmlFile. (absolute path.) + * + * @param string $xmlFile + * @return PHPUnit_Extensions_Database_DataSet_XmlDataSet + */ + protected function createXMLDataSet($xmlFile) + { + return new PHPUnit_Extensions_Database_DataSet_XmlDataSet($xmlFile); + } + + /** + * Create a a new MysqlXmlDataSet with the given $xmlFile. (absolute path.) + * + * @param string $xmlFile + * @return PHPUnit_Extensions_Database_DataSet_MysqlXmlDataSet + * @since Method available since Release 1.0.0 + */ + protected function createMySQLXMLDataSet($xmlFile) + { + return new PHPUnit_Extensions_Database_DataSet_MysqlXmlDataSet($xmlFile); + } + + /** + * Returns an operation factory instance that can be used to instantiate + * new operations. + * + * @return PHPUnit_Extensions_Database_Operation_Factory + */ + protected function getOperations() + { + return new PHPUnit_Extensions_Database_Operation_Factory(); + } + + /** + * Performs operation returned by getSetUpOperation(). + */ + protected function setUp() + { + parent::setUp(); + + $this->databaseTester = NULL; + + $this->getDatabaseTester()->setSetUpOperation($this->getSetUpOperation()); + $this->getDatabaseTester()->setDataSet($this->getDataSet()); + $this->getDatabaseTester()->onSetUp(); + } + + /** + * Performs operation returned by getSetUpOperation(). + */ + protected function tearDown() + { + $this->getDatabaseTester()->setTearDownOperation($this->getTearDownOperation()); + $this->getDatabaseTester()->setDataSet($this->getDataSet()); + $this->getDatabaseTester()->onTearDown(); + + /** + * Destroy the tester after the test is run to keep DB connections + * from piling up. + */ + $this->databaseTester = NULL; + } + + /** + * Asserts that two given tables are equal. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $expected + * @param PHPUnit_Extensions_Database_DataSet_ITable $actual + * @param string $message + */ + public static function assertTablesEqual(PHPUnit_Extensions_Database_DataSet_ITable $expected, PHPUnit_Extensions_Database_DataSet_ITable $actual, $message = '') + { + $constraint = new PHPUnit_Extensions_Database_Constraint_TableIsEqual($expected); + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that two given datasets are equal. + * + * @param PHPUnit_Extensions_Database_DataSet_ITable $expected + * @param PHPUnit_Extensions_Database_DataSet_ITable $actual + * @param string $message + */ + public static function assertDataSetsEqual(PHPUnit_Extensions_Database_DataSet_IDataSet $expected, PHPUnit_Extensions_Database_DataSet_IDataSet $actual, $message = '') + { + $constraint = new PHPUnit_Extensions_Database_Constraint_DataSetIsEqual($expected); + + self::assertThat($actual, $constraint, $message); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Command.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Command.php new file mode 100644 index 0000000..56e3a9b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Command.php @@ -0,0 +1,89 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Delegates database extension commands to the appropriate mode classes. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_UI_Command +{ + /** + * @var PHPUnit_Extensions_Database_UI_IModeFactory + */ + protected $modeFactory; + + /** + * @param PHPUnit_Extensions_Database_UI_IModeFactory $modeFactory + */ + public function __construct(PHPUnit_Extensions_Database_UI_IModeFactory $modeFactory) + { + $this->modeFactory = $modeFactory; + } + + /** + * Executes the database extension ui. + * + * @param PHPUnit_Extensions_Database_UI_IMedium $medium + * @param PHPUnit_Extensions_Database_UI_Context $context + */ + public function main(PHPUnit_Extensions_Database_UI_IMedium $medium, PHPUnit_Extensions_Database_UI_Context $context) + { + try { + $medium->buildContext($context); + $mode = $this->modeFactory->getMode($context->getMode()); + $mode->execute($context->getModeArguments(), $medium); + + } catch (Exception $e) { + $medium->handleException($e); + } + } +} + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Context.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Context.php new file mode 100644 index 0000000..3c7760d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Context.php @@ -0,0 +1,100 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Holds the context of a particular database extension ui call. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_UI_Context +{ + /** + * @var string + */ + protected $mode; + + /** + * @var array + */ + protected $modeArguments; + + /** + * @param string $mode + */ + public function setMode($mode) + { + $this->mode = $mode; + } + + /** + * @return string + */ + public function getMode() + { + return $this->mode; + } + + /** + * @param array $arguments + */ + public function setModeArguments(array $arguments) + { + $this->mode_arguments = $arguments; + } + + /** + * @return array + */ + public function getModeArguments() + { + return $this->mode_arguments; + } +} + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IMedium.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IMedium.php new file mode 100644 index 0000000..6870669 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IMedium.php @@ -0,0 +1,72 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Defines the interface necessary to create new mediums. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_UI_IMedium extends PHPUnit_Extensions_Database_UI_IMediumPrinter +{ + /** + * Builds the context for the application. + * + * @param PHPUnit_Extensions_Database_UI_Context $context + */ + public function buildContext(PHPUnit_Extensions_Database_UI_Context $context); + + /** + * Handles the displaying of exceptions received from the application. + * + * @param Exception $e + */ + public function handleException(Exception $e); +} + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IMediumPrinter.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IMediumPrinter.php new file mode 100644 index 0000000..9bfece5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IMediumPrinter.php @@ -0,0 +1,72 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Defines the interface necessary to create new medium printers. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_UI_IMediumPrinter +{ + /** + * Prints standard output messages. + * + * @param string $message + */ + public function output($message); + + /** + * Prints standard error messages. + * + * @param string $message + */ + public function error($message); +} + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IMode.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IMode.php new file mode 100644 index 0000000..5663fce --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IMode.php @@ -0,0 +1,66 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Defines the interface necessary to create new modes + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_UI_IMode +{ + /** + * Executes the mode using the given arguments and medium. + * + * @param array $modeArguments + * @param PHPUnit_Extensions_Database_UI_IMediumPrinter $medium + */ + public function execute(array $modeArguments, PHPUnit_Extensions_Database_UI_IMediumPrinter $medium); +} + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IModeFactory.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IModeFactory.php new file mode 100644 index 0000000..f856664 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/IModeFactory.php @@ -0,0 +1,73 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Defines the interface necessary to create new mode factories + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +interface PHPUnit_Extensions_Database_UI_IModeFactory +{ + /** + * Generates a new mode based on a given name. + * + * @param string $mode + * @return PHPUnit_Extensions_Database_UI_IMode + */ + public function getMode($mode); + + /** + * Returns the names of valid modes this factory can create. + * + * @return array + */ + public function getModeList(); +} + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/InvalidModeException.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/InvalidModeException.php new file mode 100644 index 0000000..aa372dd --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/InvalidModeException.php @@ -0,0 +1,96 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * An exception thrown when an invalid mode is requested from a mode factory. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_UI_InvalidModeException extends LogicException +{ + /** + * @var string + */ + protected $mode; + + /** + * @var PHPUnit_Extensions_Database_UI_IModeFactory + */ + protected $modeFactory; + + /** + * @param string $mode + * @param string $msg + * @param PHPUnit_Extensions_Database_UI_IModeFactory $modeFactory + */ + public function __construct($mode, $msg, PHPUnit_Extensions_Database_UI_IModeFactory $modeFactory) + { + $this->mode = $mode; + $this->modeFactory = $modeFactory; + parent::__construct($msg); + } + + /** + * @return string + */ + public function getMode() + { + return $this->mode; + } + + /** + * @return array + */ + public function getValidModes() + { + return $this->modeFactory->getModeList(); + } +} + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Mediums/Text.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Mediums/Text.php new file mode 100644 index 0000000..d08c626 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Mediums/Text.php @@ -0,0 +1,138 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * A text medium for the database extension tool. + * + * This class builds the call context based on command line parameters and + * prints output to stdout and stderr as appropriate. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_UI_Mediums_Text implements PHPUnit_Extensions_Database_UI_IMedium +{ + /** + * @var array + */ + protected $arguments; + + /** + * @var string + */ + protected $command; + + /** + * @param array $arguments + */ + public function __construct(Array $arguments) + { + $this->arguments = $arguments; + } + + /** + * Builds the context for the application. + * + * @param PHPUnit_Extensions_Database_UI_Context $context + */ + public function buildContext(PHPUnit_Extensions_Database_UI_Context $context) + { + $arguments = $this->arguments; + $this->command = array_shift($arguments); + + $context->setMode(array_shift($arguments)); + $context->setModeArguments($arguments); + } + + /** + * Handles the displaying of exceptions received from the application. + * + * @param Exception $e + */ + public function handleException(Exception $e) + { + try { + throw $e; + } catch (PHPUnit_Extensions_Database_UI_InvalidModeException $invalidMode) { + if ($invalidMode->getMode() == '') { + $this->error('Please Specify a Command!' . PHP_EOL); + } else { + $this->error('Command Does Not Exist: ' . $invalidMode->getMode() . PHP_EOL); + } + $this->error('Valid Commands:' . PHP_EOL); + + foreach ($invalidMode->getValidModes() as $mode) { + $this->error(' ' . $mode . PHP_EOL); + } + } catch (Exception $e) { + $this->error('Unknown Error: ' . $e->getMessage() . PHP_EOL); + } + } + + /** + * Prints the message to stdout. + * + * @param string $message + */ + public function output($message) + { + echo $message; + } + + /** + * Prints the message to stderr + * + * @param string $message + */ + public function error($message) + { + fputs(STDERR, $message); + } +} + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/ModeFactory.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/ModeFactory.php new file mode 100644 index 0000000..51fbb97 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/ModeFactory.php @@ -0,0 +1,130 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * The default factory for db extension modes. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de//** + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_UI_ModeFactory implements PHPUnit_Extensions_Database_UI_IModeFactory +{ + /** + * Generates a new mode based on a given name. + * + * @param string $mode + * @return PHPUnit_Extensions_Database_UI_IMode + */ + public function getMode($mode) + { + if ($mode == '') { + throw new PHPUnit_Extensions_Database_UI_InvalidModeException($mode, 'A mode was not provided.', $this); + } + + $modeMap = $this->getModeMap(); + if (isset($modeMap[$mode])) { + $modeClass = $this->getModeClass($mode, $modeMap[$mode]); + + return new $modeClass(); + } else { + throw new PHPUnit_Extensions_Database_UI_InvalidModeException($mode, 'The mode does not exist. Attempting to load mode ' . $mode, $this); + } + } + + /** + * Returns the names of valid modes this factory can create. + * + * @return array + */ + public function getModeList() + { + return array_keys($this->getModeMap()); + } + + /** + * Returns a map of modes to class name parts + * + * @return array + */ + protected function getModeMap() + { + return array('export-dataset' => 'ExportDataSet'); + } + + /** + * Given a $mode label and a $mode_name class part attempts to return the + * class name necessary to instantiate the mode. + * + * @param string $mode + * @param string $mode_name + * @return string + */ + protected function getModeClass($mode, $mode_name) + { + $modeClass = 'PHPUnit_Extensions_Database_UI_Modes_' . $mode_name; + $modeFile = dirname(__FILE__) . '/Modes/' . $mode_name . '.php'; + + if (class_exists($modeClass)) { + return $modeClass; + } + + if (!is_readable($modeFile)) { + throw new PHPUnit_Extensions_Database_UI_InvalidModeException($mode, 'The mode\'s file could not be loaded. Trying file ' . $modeFile, $this); + } + + require_once ($modeFile); + + if (!class_exists($modeClass)) { + throw new PHPUnit_Extensions_Database_UI_InvalidModeException($mode, 'The mode class was not found in the file. Expecting class name ' . $modeClass, $this); + } + + return $modeClass; + } +} + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Modes/ExportDataSet.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Modes/ExportDataSet.php new file mode 100644 index 0000000..007d719 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Modes/ExportDataSet.php @@ -0,0 +1,119 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * The class for the export-dataset command. + * + * This command is used to convert existing data sets or data in the database + * into a valid data set format. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_UI_Modes_ExportDataSet implements PHPUnit_Extensions_Database_UI_IMode +{ + /** + * Executes the export dataset command. + * + * @param array $modeArguments + * @param PHPUnit_Extensions_Database_UI_IMediumPrinter $medium + */ + public function execute(array $modeArguments, PHPUnit_Extensions_Database_UI_IMediumPrinter $medium) + { + $arguments = new PHPUnit_Extensions_Database_UI_Modes_ExportDataSet_Arguments($modeArguments); + + if (FALSE && !$arguments->areValid()) { + throw new InvalidArgumentException("The arguments for this command are incorrect."); + } + + $datasets = array(); + foreach ($arguments->getArgumentArray('dataset') as $argString) { + $datasets[] = $this->getDataSetFromArgument($argString, $arguments->getDatabases()); + } + + $finalDataset = new PHPUnit_Extensions_Database_DataSet_CompositeDataSet($datasets); + + $outputDataset = $this->getPersistorFromArgument($arguments->getSingleArgument('output')); + $outputDataset->write($finalDataset); + } + + /** + * Returns the correct dataset given an argument containing a dataset spec. + * + * @param string $argString + * @param array $databaseList + * @return PHPUnit_Extensions_Database_DataSet_IDataSet + */ + protected function getDataSetFromArgument($argString, $databaseList) + { + $dataSetSpecFactory = new PHPUnit_Extensions_Database_DataSet_Specs_Factory(); + list($type, $dataSetSpecStr) = explode(':', $argString, 2); + $dataSetSpec = $dataSetSpecFactory->getDataSetSpecByType($type); + + if ($dataSetSpec instanceof PHPUnit_Extensions_Database_IDatabaseListConsumer) { + $dataSetSpec->setDatabases($databaseList); + } + + return $dataSetSpec->getDataSet($dataSetSpecStr); + } + + /** + * Returns the correct persistor given an argument containing a persistor spec. + * + * @param string $argString + * @return PHPUnit_Extensions_Database_DataSet_IPersistable + */ + protected function getPersistorFromArgument($argString) + { + $persistorFactory = new PHPUnit_Extensions_Database_DataSet_Persistors_Factory(); + list($type, $spec) = explode(':', $argString, 2); + return $persistorFactory->getPersistorBySpec($type, $spec); + } +} + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Modes/ExportDataSet/Arguments.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Modes/ExportDataSet/Arguments.php new file mode 100644 index 0000000..d7b0a79 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Database/UI/Modes/ExportDataSet/Arguments.php @@ -0,0 +1,153 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Represents arguments received from a medium. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2010 Mike Lively + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_Database_UI_Modes_ExportDataSet_Arguments +{ + /** + * @var array + */ + protected $arguments = array(); + + /** + * @param array $arguments + */ + public function __construct(array $arguments) + { + foreach ($arguments as $argument) { + list($argName, $argValue) = explode('=', $argument, 2); + + $argName = trim($argName, '-'); + + if (!isset($this->arguments[$argName])) { + $this->arguments[$argName] = array(); + } + + $this->arguments[$argName][] = $argValue; + } + } + + /** + * Returns an array of arguments matching the given $argName + * + * @param string $argName + * @return array + */ + public function getArgumentArray($argName) + { + if ($this->argumentIsSet($argName)) { + return $this->arguments[$argName]; + } else { + return NULL; + } + } + + /** + * Returns a single argument value. + * + * If $argName points to an array the first argument will be returned. + * + * @param string $argName + * @return mixed + */ + public function getSingleArgument($argName) + { + if ($this->argumentIsSet($argName)) { + return reset($this->arguments[$argName]); + } else { + return NULL; + } + } + + /** + * Returns whether an argument is set. + * + * @param string $argName + * @return bool + */ + public function argumentIsSet($argName) + { + return array_key_exists($argName, $this->arguments); + } + + /** + * Returns an array containing the names of all arguments provided. + * + * @return array + */ + public function getArgumentNames() + { + return array_keys($this->arguments); + } + + /** + * Returns an array of database arguments keyed by name. + * + * @todo this should be moved. + * @return array + */ + public function getDatabases() + { + $databases = $this->getArgumentArray('database'); + + $retDb = array(); + foreach ($databases as $db) { + list($name, $arg) = explode(':', $db, 2); + $retDb[$name] = $arg; + } + + return $retDb; + } +} + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/GroupTestSuite.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/GroupTestSuite.php new file mode 100644 index 0000000..bb84df0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/GroupTestSuite.php @@ -0,0 +1,100 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +/** + * We have a TestSuite object A. + * In TestSuite object A we have Tests tagged with @group. + * We want a TestSuite object B that contains TestSuite objects C, D, ... + * for the Tests tagged with @group C, @group D, ... + * Running the Tests from TestSuite object B results in Tests tagged with both + * @group C and @group D in TestSuite object A to be run twice . + * + * + * $suite = new PHPUnit_Extensions_GroupTestSuite($A, array('C', 'D')); + * + * + * @package PHPUnit + * @subpackage Extensions + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Extensions_GroupTestSuite extends PHPUnit_Framework_TestSuite +{ + public function __construct(PHPUnit_Framework_TestSuite $suite, array $groups) + { + $groupSuites = array(); + $name = $suite->getName(); + + foreach ($groups as $group) { + $groupSuites[$group] = new PHPUnit_Framework_TestSuite($name . ' - ' . $group); + $this->addTest($groupSuites[$group]); + } + + $tests = new RecursiveIteratorIterator( + new PHPUnit_Util_TestSuiteIterator($suite), + RecursiveIteratorIterator::LEAVES_ONLY + ); + + foreach ($tests as $test) { + if ($test instanceof PHPUnit_Framework_TestCase) { + $testGroups = PHPUnit_Util_Test::getGroups( + get_class($test), $test->getName(FALSE) + ); + + foreach ($groups as $group) { + foreach ($testGroups as $testGroup) { + if ($group == $testGroup) { + $groupSuites[$group]->addTest($test); + } + } + } + } + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/OutputTestCase.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/OutputTestCase.php new file mode 100644 index 0000000..8da2346 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/OutputTestCase.php @@ -0,0 +1,202 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * A TestCase that expects a specified output. + * + * @package PHPUnit + * @subpackage Extensions + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +abstract class PHPUnit_Extensions_OutputTestCase extends PHPUnit_Framework_TestCase +{ + /** + * @var string + */ + protected $expectedRegex = NULL; + + /** + * @var string + */ + protected $expectedString = NULL; + + /** + * @var string + */ + protected $output = ''; + + /** + * @var boolean + */ + protected $obActive = FALSE; + + /** + * @var mixed + */ + protected $outputCallback = FALSE; + + /** + * @return bool + */ + public function setOutputCallback($callback) + { + if (is_callable($callback)) { + $this->outputCallback = $callback; + return TRUE; + } + + return FALSE; + } + + /** + * @return string + */ + public function normalizeOutput($buffer) + { + return str_replace("\r", '', $buffer); + } + + /** + * @return string + */ + public function getActualOutput() + { + if (!$this->obActive) { + return $this->output; + } else { + return ob_get_contents(); + } + } + + /** + * @return string + */ + public function expectedRegex() + { + return $this->expectedRegex; + } + + /** + * @param string $expectedRegex + */ + public function expectOutputRegex($expectedRegex) + { + if ($this->expectedString !== NULL) { + throw new PHPUnit_Framework_Exception; + } + + if (is_string($expectedRegex) || is_null($expectedRegex)) { + $this->expectedRegex = $expectedRegex; + } + } + + /** + * @return string + */ + public function expectedString() + { + return $this->expectedString; + } + + /** + * @param string $expectedString + */ + public function expectOutputString($expectedString) + { + if ($this->expectedRegex !== NULL) { + throw new PHPUnit_Framework_Exception; + } + + if (is_string($expectedString) || is_null($expectedString)) { + $this->expectedString = $expectedString; + } + } + + /** + * @return mixed + * @throws RuntimeException + */ + protected function runTest() + { + ob_start(); + $this->obActive = TRUE; + + try { + $testResult = parent::runTest(); + } + + catch (Exception $e) { + ob_end_clean(); + $this->obActive = FALSE; + throw $e; + } + + if ($this->outputCallback === FALSE) { + $this->output = ob_get_contents(); + } else { + $this->output = call_user_func_array($this->outputCallback, array(ob_get_contents())); + } + + ob_end_clean(); + $this->obActive = FALSE; + + if ($this->expectedRegex !== NULL) { + $this->assertRegExp($this->expectedRegex, $this->output); + $this->expectedRegex = NULL; + } + + else if ($this->expectedString !== NULL) { + $this->assertEquals($this->expectedString, $this->output); + $this->expectedString = NULL; + } + + return $testResult; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/PhptTestCase.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/PhptTestCase.php new file mode 100644 index 0000000..71b381d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/PhptTestCase.php @@ -0,0 +1,277 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions_PhptTestCase + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.1.4 + */ + +if (PHPUnit_Util_Filesystem::fileExistsInIncludePath('PEAR/RunTest.php')) { + $currentErrorReporting = error_reporting(E_ERROR | E_WARNING | E_PARSE); + PHPUnit_Util_Filesystem::collectStart(); + require_once 'PEAR/RunTest.php'; + error_reporting($currentErrorReporting); + + PHPUnit_Util_Filesystem::collectEndAndAddToBlacklist(); +} + +require_once 'PHP/CodeCoverage.php'; +require_once 'PHP/Timer.php'; + +/** + * Wrapper to run .phpt test cases. + * + * @package PHPUnit + * @subpackage Extensions_PhptTestCase + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.1.4 + */ +class PHPUnit_Extensions_PhptTestCase implements PHPUnit_Framework_Test, PHPUnit_Framework_SelfDescribing +{ + /** + * The filename of the .phpt file. + * + * @var string + */ + protected $filename; + + /** + * Options for PEAR_RunTest. + * + * @var array + */ + protected $options = array(); + + /** + * Constructs a test case with the given filename. + * + * @param string $filename + * @param array $options + */ + public function __construct($filename, array $options = array()) + { + if (!is_string($filename)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_file($filename)) { + throw new PHPUnit_Framework_Exception( + sprintf( + 'File "%s" does not exist.', + $filename + ) + ); + } + + $this->filename = $filename; + $this->options = $options; + } + + /** + * Counts the number of test cases executed by run(TestResult result). + * + * @return integer + */ + public function count() + { + return 1; + } + + /** + * Runs a test and collects its result in a TestResult instance. + * + * @param PHPUnit_Framework_TestResult $result + * @param array $options + * @return PHPUnit_Framework_TestResult + */ + public function run(PHPUnit_Framework_TestResult $result = NULL, array $options = array()) + { + if (!class_exists('PEAR_RunTest', FALSE)) { + throw new PHPUnit_Framework_Exception('Class PEAR_RunTest not found.'); + } + + if (isset($GLOBALS['_PEAR_destructor_object_list']) && + is_array($GLOBALS['_PEAR_destructor_object_list']) && + !empty($GLOBALS['_PEAR_destructor_object_list'])) { + $pearDestructorObjectListCount = count($GLOBALS['_PEAR_destructor_object_list']); + } else { + $pearDestructorObjectListCount = 0; + } + + if ($result === NULL) { + $result = new PHPUnit_Framework_TestResult; + } + + $coverage = $result->getCollectCodeCoverageInformation(); + $options = array_merge($options, $this->options); + + if (!isset($options['include_path'])) { + $options['include_path'] = get_include_path(); + } + + if ($coverage) { + $options['coverage'] = TRUE; + } else { + $options['coverage'] = FALSE; + } + + $currentErrorReporting = error_reporting(E_ERROR | E_WARNING | E_PARSE); + $runner = new PEAR_RunTest(new PHPUnit_Extensions_PhptTestCase_Logger, $options); + + if ($coverage) { + $runner->xdebug_loaded = TRUE; + } else { + $runner->xdebug_loaded = FALSE; + } + + $result->startTest($this); + + PHP_Timer::start(); + + $buffer = $runner->run($this->filename, $options); + $time = PHP_Timer::stop(); + + error_reporting($currentErrorReporting); + + $base = basename($this->filename); + $path = dirname($this->filename); + $coverageFile = $path . DIRECTORY_SEPARATOR . str_replace( + '.phpt', '.xdebug', $base + ); + $diffFile = $path . DIRECTORY_SEPARATOR . str_replace( + '.phpt', '.diff', $base + ); + $expFile = $path . DIRECTORY_SEPARATOR . str_replace( + '.phpt', '.exp', $base + ); + $logFile = $path . DIRECTORY_SEPARATOR . str_replace( + '.phpt', '.log', $base + ); + $outFile = $path . DIRECTORY_SEPARATOR . str_replace( + '.phpt', '.out', $base + ); + $phpFile = $path . DIRECTORY_SEPARATOR . str_replace( + '.phpt', '.php', $base + ); + + if (file_exists($phpFile)) { + PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist( + $phpFile, 'TESTS' + ); + } + + if (is_object($buffer) && $buffer instanceof PEAR_Error) { + $result->addError( + $this, + new RuntimeException($buffer->getMessage()), + $time + ); + } + + else if ($buffer == 'SKIPPED') { + $result->addFailure($this, new PHPUnit_Framework_SkippedTestError, 0); + } + + else if ($buffer != 'PASSED') { + $result->addFailure( + $this, + PHPUnit_Framework_ComparisonFailure::diffEqual( + file_get_contents($expFile), + file_get_contents($outFile) + ), + $time + ); + } + + foreach (array($diffFile, $expFile, $logFile, $phpFile, $outFile) as $file) { + if (file_exists($file)) { + unlink($file); + } + } + + if ($coverage && file_exists($coverageFile)) { + eval('$coverageData = ' . file_get_contents($coverageFile) . ';'); + unset($coverageData[$phpFile]); + + $result->getCodeCoverage()->append($coverageData, $this); + unlink($coverageFile); + } + + $result->endTest($this, $time); + + // Do not invoke PEAR's destructor mechanism for PHP 4 + // as it raises an E_STRICT. + if ($pearDestructorObjectListCount == 0) { + unset($GLOBALS['_PEAR_destructor_object_list']); + } else { + $count = count($GLOBALS['_PEAR_destructor_object_list']) - $pearDestructorObjectListCount; + + for ($i = 0; $i < $count; $i++) { + array_pop($GLOBALS['_PEAR_destructor_object_list']); + } + } + + return $result; + } + + /** + * Returns the name of the test case. + * + * @return string + */ + public function getName() + { + return $this->toString(); + } + + /** + * Returns a string representation of the test case. + * + * @return string + */ + public function toString() + { + return $this->filename; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/PhptTestCase/Logger.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/PhptTestCase/Logger.php new file mode 100644 index 0000000..0d27a5e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/PhptTestCase/Logger.php @@ -0,0 +1,63 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions_PhptTestCase + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.1.4 + */ + +/** + * Dummy logger for PEAR_RunTest. + * + * @package PHPUnit + * @subpackage Extensions_PhptTestCase + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.1.4 + */ +class PHPUnit_Extensions_PhptTestCase_Logger +{ + public function log($level, $msg, $append_crlf = TRUE) + { + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/PhptTestSuite.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/PhptTestSuite.php new file mode 100644 index 0000000..c5f7d44 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/PhptTestSuite.php @@ -0,0 +1,86 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions_PhptTestCase + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.1.4 + */ + +require_once 'File/Iterator/Factory.php'; + +/** + * Suite for .phpt test cases. + * + * @package PHPUnit + * @subpackage Extensions_PhptTestCase + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.1.4 + */ +class PHPUnit_Extensions_PhptTestSuite extends PHPUnit_Framework_TestSuite +{ + /** + * Constructs a new TestSuite for .phpt test cases. + * + * @param string $directory + * @param array $options Array with ini settings for the php instance run, + * key being the name if the setting, value the ini value. + * @throws InvalidArgumentException + */ + public function __construct($directory, array $options = array()) + { + if (is_string($directory) && is_dir($directory)) { + $this->setName($directory); + + $iterator = File_Iterator_Factory::getFileIterator( + $directory, '.phpt' + ); + + foreach ($iterator as $testFile) { + $this->addTestFile($testFile->getPathname(), TRUE, $options); + } + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'directory name'); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/RepeatedTest.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/RepeatedTest.php new file mode 100644 index 0000000..34d4882 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/RepeatedTest.php @@ -0,0 +1,154 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * A Decorator that runs a test repeatedly. + * + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +class PHPUnit_Extensions_RepeatedTest extends PHPUnit_Extensions_TestDecorator +{ + /** + * @var mixed + */ + protected $filter = FALSE; + + /** + * @var array + */ + protected $groups = array(); + + /** + * @var array + */ + protected $excludeGroups = array(); + + /** + * @var boolean + */ + protected $processIsolation = FALSE; + + /** + * @var integer + */ + protected $timesRepeat = 1; + + /** + * Constructor. + * + * @param PHPUnit_Framework_Test $test + * @param integer $timesRepeat + * @param mixed $filter + * @param array $groups + * @param array $excludeGroups + * @param boolean $processIsolation + * @throws InvalidArgumentException + */ + public function __construct(PHPUnit_Framework_Test $test, $timesRepeat = 1, $filter = FALSE, array $groups = array(), array $excludeGroups = array(), $processIsolation = FALSE) + { + parent::__construct($test); + + if (is_integer($timesRepeat) && + $timesRepeat >= 0) { + $this->timesRepeat = $timesRepeat; + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory( + 2, 'positive integer' + ); + } + + $this->filter = $filter; + $this->groups = $groups; + $this->excludeGroups = $excludeGroups; + $this->processIsolation = $processIsolation; + } + + /** + * Counts the number of test cases that + * will be run by this test. + * + * @return integer + */ + public function count() + { + return $this->timesRepeat * count($this->test); + } + + /** + * Runs the decorated test and collects the + * result in a TestResult. + * + * @param PHPUnit_Framework_TestResult $result + * @return PHPUnit_Framework_TestResult + * @throws InvalidArgumentException + */ + public function run(PHPUnit_Framework_TestResult $result = NULL) + { + if ($result === NULL) { + $result = $this->createResult(); + } + + for ($i = 0; $i < $this->timesRepeat && !$result->shouldStop(); $i++) { + if ($this->test instanceof PHPUnit_Framework_TestSuite) { + $this->test->run( + $result, + $this->filter, + $this->groups, + $this->excludeGroups, + $this->processIsolation + ); + } else { + $this->test->run($result); + } + } + + return $result; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase.php new file mode 100644 index 0000000..a38647d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase.php @@ -0,0 +1,1067 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_Selenium + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +require_once 'File/Iterator/Factory.php'; + +/** + * TestCase class that uses Selenium to provide + * the functionality required for web testing. + * + * @package PHPUnit_Selenium + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.3 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + * + * @method unknown addLocationStrategy() + * @method unknown addLocationStrategyAndWait() + * @method unknown addScript() + * @method unknown addScriptAndWait() + * @method unknown addSelection() + * @method unknown addSelectionAndWait() + * @method unknown allowNativeXpath() + * @method unknown allowNativeXpathAndWait() + * @method unknown altKeyDown() + * @method unknown altKeyDownAndWait() + * @method unknown altKeyUp() + * @method unknown altKeyUpAndWait() + * @method unknown answerOnNextPrompt() + * @method unknown assignId() + * @method unknown assignIdAndWait() + * @method unknown attachFile() + * @method unknown break() + * @method unknown captureEntirePageScreenshot() + * @method unknown captureEntirePageScreenshotAndWait() + * @method unknown captureEntirePageScreenshotToStringAndWait() + * @method unknown captureScreenshotAndWait() + * @method unknown captureScreenshotToStringAndWait() + * @method unknown check() + * @method unknown checkAndWait() + * @method unknown chooseCancelOnNextConfirmation() + * @method unknown chooseCancelOnNextConfirmationAndWait() + * @method unknown chooseOkOnNextConfirmation() + * @method unknown chooseOkOnNextConfirmationAndWait() + * @method unknown click() + * @method unknown clickAndWait() + * @method unknown clickAt() + * @method unknown clickAtAndWait() + * @method unknown close() + * @method unknown contextMenu() + * @method unknown contextMenuAndWait() + * @method unknown contextMenuAt() + * @method unknown contextMenuAtAndWait() + * @method unknown controlKeyDown() + * @method unknown controlKeyDownAndWait() + * @method unknown controlKeyUp() + * @method unknown controlKeyUpAndWait() + * @method unknown createCookie() + * @method unknown createCookieAndWait() + * @method unknown deleteAllVisibleCookies() + * @method unknown deleteAllVisibleCookiesAndWait() + * @method unknown deleteCookie() + * @method unknown deleteCookieAndWait() + * @method unknown deselectPopUp() + * @method unknown deselectPopUpAndWait() + * @method unknown doubleClick() + * @method unknown doubleClickAndWait() + * @method unknown doubleClickAt() + * @method unknown doubleClickAtAndWait() + * @method unknown dragAndDrop() + * @method unknown dragAndDropAndWait() + * @method unknown dragAndDropToObject() + * @method unknown dragAndDropToObjectAndWait() + * @method unknown dragDrop() + * @method unknown dragDropAndWait() + * @method unknown echo() + * @method unknown fireEvent() + * @method unknown fireEventAndWait() + * @method unknown focus() + * @method unknown focusAndWait() + * @method string getAlert() + * @method array getAllButtons() + * @method array getAllFields() + * @method array getAllLinks() + * @method array getAllWindowIds() + * @method array getAllWindowNames() + * @method array getAllWindowTitles() + * @method string getAttribute() + * @method array getAttributeFromAllWindows() + * @method string getBodyText() + * @method string getConfirmation() + * @method string getCookie() + * @method string getCookieByName() + * @method integer getCursorPosition() + * @method integer getElementHeight() + * @method integer getElementIndex() + * @method integer getElementPositionLeft() + * @method integer getElementPositionTop() + * @method integer getElementWidth() + * @method string getEval() + * @method string getExpression() + * @method string getHtmlSource() + * @method string getLocation() + * @method string getLogMessages() + * @method integer getMouseSpeed() + * @method string getPrompt() + * @method array getSelectOptions() + * @method string getSelectedId() + * @method array getSelectedIds() + * @method string getSelectedIndex() + * @method array getSelectedIndexes() + * @method string getSelectedLabel() + * @method array getSelectedLabels() + * @method string getSelectedValue() + * @method array getSelectedValues() + * @method unknown getSpeed() + * @method unknown getSpeedAndWait() + * @method string getTable() + * @method string getText() + * @method string getTitle() + * @method string getValue() + * @method boolean getWhetherThisFrameMatchFrameExpression() + * @method boolean getWhetherThisWindowMatchWindowExpression() + * @method integer getXpathCount() + * @method unknown goBack() + * @method unknown goBackAndWait() + * @method unknown highlight() + * @method unknown highlightAndWait() + * @method unknown ignoreAttributesWithoutValue() + * @method unknown ignoreAttributesWithoutValueAndWait() + * @method boolean isAlertPresent() + * @method boolean isChecked() + * @method boolean isConfirmationPresent() + * @method boolean isCookiePresent() + * @method boolean isEditable() + * @method boolean isElementPresent() + * @method boolean isOrdered() + * @method boolean isPromptPresent() + * @method boolean isSomethingSelected() + * @method boolean isTextPresent() + * @method boolean isVisible() + * @method unknown keyDown() + * @method unknown keyDownAndWait() + * @method unknown keyDownNative() + * @method unknown keyDownNativeAndWait() + * @method unknown keyPress() + * @method unknown keyPressAndWait() + * @method unknown keyPressNative() + * @method unknown keyPressNativeAndWait() + * @method unknown keyUp() + * @method unknown keyUpAndWait() + * @method unknown keyUpNative() + * @method unknown keyUpNativeAndWait() + * @method unknown metaKeyDown() + * @method unknown metaKeyDownAndWait() + * @method unknown metaKeyUp() + * @method unknown metaKeyUpAndWait() + * @method unknown mouseDown() + * @method unknown mouseDownAndWait() + * @method unknown mouseDownAt() + * @method unknown mouseDownAtAndWait() + * @method unknown mouseMove() + * @method unknown mouseMoveAndWait() + * @method unknown mouseMoveAt() + * @method unknown mouseMoveAtAndWait() + * @method unknown mouseOut() + * @method unknown mouseOutAndWait() + * @method unknown mouseOver() + * @method unknown mouseOverAndWait() + * @method unknown mouseUp() + * @method unknown mouseUpAndWait() + * @method unknown mouseUpAt() + * @method unknown mouseUpAtAndWait() + * @method unknown mouseUpRight() + * @method unknown mouseUpRightAndWait() + * @method unknown mouseUpRightAt() + * @method unknown mouseUpRightAtAndWait() + * @method unknown open() + * @method unknown openWindow() + * @method unknown openWindowAndWait() + * @method unknown pause() + * @method unknown refresh() + * @method unknown refreshAndWait() + * @method unknown removeAllSelections() + * @method unknown removeAllSelectionsAndWait() + * @method unknown removeScript() + * @method unknown removeScriptAndWait() + * @method unknown removeSelection() + * @method unknown removeSelectionAndWait() + * @method unknown retrieveLastRemoteControlLogs() + * @method unknown rollup() + * @method unknown rollupAndWait() + * @method unknown runScript() + * @method unknown runScriptAndWait() + * @method unknown select() + * @method unknown selectAndWait() + * @method unknown selectFrame() + * @method unknown selectPopUp() + * @method unknown selectPopUpAndWait() + * @method unknown selectWindow() + * @method unknown setBrowserLogLevel() + * @method unknown setBrowserLogLevelAndWait() + * @method unknown setContext() + * @method unknown setCursorPosition() + * @method unknown setCursorPositionAndWait() + * @method unknown setMouseSpeed() + * @method unknown setMouseSpeedAndWait() + * @method unknown setSpeed() + * @method unknown setSpeedAndWait() + * @method unknown shiftKeyDown() + * @method unknown shiftKeyDownAndWait() + * @method unknown shiftKeyUp() + * @method unknown shiftKeyUpAndWait() + * @method unknown shutDownSeleniumServer() + * @method unknown store() + * @method unknown submit() + * @method unknown submitAndWait() + * @method unknown type() + * @method unknown typeAndWait() + * @method unknown typeKeys() + * @method unknown typeKeysAndWait() + * @method unknown uncheck() + * @method unknown uncheckAndWait() + * @method unknown useXpathLibrary() + * @method unknown useXpathLibraryAndWait() + * @method unknown waitForCondition() + * @method unknown waitForPageToLoad() + * @method unknown waitForPopUp() + * @method unknown windowFocus() + * @method unknown windowMaximize() + */ +abstract class PHPUnit_Extensions_SeleniumTestCase extends PHPUnit_Framework_TestCase +{ + /** + * @var array + */ + public static $browsers = array(); + + /** + * @var string + */ + protected $browserName; + + /** + * @var boolean + */ + protected $collectCodeCoverageInformation = FALSE; + + /** + * @var string + */ + protected $coverageScriptUrl = ''; + + /** + * @var PHPUnit_Extensions_SeleniumTestCase_Driver[] + */ + protected $drivers = array(); + + /** + * @var boolean + */ + protected $inDefaultAssertions = FALSE; + + /** + * @var string + */ + protected $testId; + + /** + * @var array + * @access protected + */ + protected $verificationErrors = array(); + + /** + * @var boolean + */ + protected $captureScreenshotOnFailure = FALSE; + + /** + * @var string + */ + protected $screenshotPath = ''; + + /** + * @var string + */ + protected $screenshotUrl = ''; + + /** + * @param string $name + * @param array $data + * @param string $dataName + * @param array $browser + * @throws InvalidArgumentException + */ + public function __construct($name = NULL, array $data = array(), $dataName = '', array $browser = array()) + { + parent::__construct($name, $data, $dataName); + $this->testId = md5(uniqid(rand(), TRUE)); + $this->getDriver($browser); + } + + /** + * @param string $className + * @return PHPUnit_Framework_TestSuite + */ + public static function suite($className) + { + $suite = new PHPUnit_Framework_TestSuite; + $suite->setName($className); + + $class = new ReflectionClass($className); + $classGroups = PHPUnit_Util_Test::getGroups($className); + $staticProperties = $class->getStaticProperties(); + + // Create tests from Selenese/HTML files. + if (isset($staticProperties['seleneseDirectory']) && + is_dir($staticProperties['seleneseDirectory'])) { + $files = array_merge( + self::getSeleneseFiles($staticProperties['seleneseDirectory'], '.htm'), + self::getSeleneseFiles($staticProperties['seleneseDirectory'], '.html') + ); + + // Create tests from Selenese/HTML files for multiple browsers. + if (!empty($staticProperties['browsers'])) { + foreach ($staticProperties['browsers'] as $browser) { + $browserSuite = new PHPUnit_Framework_TestSuite; + $browserSuite->setName($className . ': ' . $browser['name']); + + foreach ($files as $file) { + $browserSuite->addTest( + new $className($file, array(), '', $browser), + $classGroups + ); + } + + $suite->addTest($browserSuite); + } + } + + // Create tests from Selenese/HTML files for single browser. + else { + foreach ($files as $file) { + $suite->addTest(new $className($file), $classGroups); + } + } + } + + // Create tests from test methods for multiple browsers. + if (!empty($staticProperties['browsers'])) { + foreach ($staticProperties['browsers'] as $browser) { + $browserSuite = new PHPUnit_Framework_TestSuite; + $browserSuite->setName($className . ': ' . $browser['name']); + + foreach ($class->getMethods() as $method) { + if (PHPUnit_Framework_TestSuite::isPublicTestMethod($method)) { + $name = $method->getName(); + $data = PHPUnit_Util_Test::getProvidedData($className, $name); + $groups = PHPUnit_Util_Test::getGroups($className, $name); + + // Test method with @dataProvider. + if (is_array($data) || $data instanceof Iterator) { + $dataSuite = new PHPUnit_Framework_TestSuite_DataProvider( + $className . '::' . $name + ); + + foreach ($data as $_dataName => $_data) { + $dataSuite->addTest( + new $className($name, $_data, $_dataName, $browser), + $groups + ); + } + + $browserSuite->addTest($dataSuite); + } + + // Test method with invalid @dataProvider. + else if ($data === FALSE) { + $browserSuite->addTest( + new PHPUnit_Framework_Warning( + sprintf( + 'The data provider specified for %s::%s is invalid.', + $className, + $name + ) + ) + ); + } + + // Test method without @dataProvider. + else { + $browserSuite->addTest( + new $className($name, array(), '', $browser), $groups + ); + } + } + } + + $suite->addTest($browserSuite); + } + } + + // Create tests from test methods for single browser. + else { + foreach ($class->getMethods() as $method) { + if (PHPUnit_Framework_TestSuite::isPublicTestMethod($method)) { + $name = $method->getName(); + $data = PHPUnit_Util_Test::getProvidedData($className, $name); + $groups = PHPUnit_Util_Test::getGroups($className, $name); + + // Test method with @dataProvider. + if (is_array($data) || $data instanceof Iterator) { + $dataSuite = new PHPUnit_Framework_TestSuite_DataProvider( + $className . '::' . $name + ); + + foreach ($data as $_dataName => $_data) { + $dataSuite->addTest( + new $className($name, $_data, $_dataName), + $groups + ); + } + + $suite->addTest($dataSuite); + } + + // Test method with invalid @dataProvider. + else if ($data === FALSE) { + $suite->addTest( + new PHPUnit_Framework_Warning( + sprintf( + 'The data provider specified for %s::%s is invalid.', + $className, + $name + ) + ) + ); + } + + // Test method without @dataProvider. + else { + $suite->addTest( + new $className($name), $groups + ); + } + } + } + } + + return $suite; + } + + /** + * Runs the test case and collects the results in a TestResult object. + * If no TestResult object is passed a new one will be created. + * + * @param PHPUnit_Framework_TestResult $result + * @return PHPUnit_Framework_TestResult + * @throws InvalidArgumentException + */ + public function run(PHPUnit_Framework_TestResult $result = NULL) + { + if ($result === NULL) { + $result = $this->createResult(); + } + + $this->result = $result; + + $this->collectCodeCoverageInformation = $result->getCollectCodeCoverageInformation(); + + foreach ($this->drivers as $driver) { + $driver->setCollectCodeCoverageInformation( + $this->collectCodeCoverageInformation + ); + } + + if (!$this->handleDependencies()) { + return; + } + + $result->run($this); + + if ($this->collectCodeCoverageInformation) { + $result->getCodeCoverage()->append( + $this->getCodeCoverage(), $this + ); + } + + return $result; + } + + /** + * @param array $browser + * @return PHPUnit_Extensions_SeleniumTestCase_Driver + * @since Method available since Release 1.0.0 + */ + protected function getDriver(array $browser) + { + if (isset($browser['name'])) { + if (!is_string($browser['name'])) { + throw new InvalidArgumentException( + 'Array element "name" is no string.' + ); + } + } else { + $browser['name'] = ''; + } + + if (isset($browser['browser'])) { + if (!is_string($browser['browser'])) { + throw new InvalidArgumentException( + 'Array element "browser" is no string.' + ); + } + } else { + $browser['browser'] = ''; + } + + if (isset($browser['host'])) { + if (!is_string($browser['host'])) { + throw new InvalidArgumentException( + 'Array element "host" is no string.' + ); + } + } else { + $browser['host'] = 'localhost'; + } + + if (isset($browser['port'])) { + if (!is_int($browser['port'])) { + throw new InvalidArgumentException( + 'Array element "port" is no integer.' + ); + } + } else { + $browser['port'] = 4444; + } + + if (isset($browser['timeout'])) { + if (!is_int($browser['timeout'])) { + throw new InvalidArgumentException( + 'Array element "timeout" is no integer.' + ); + } + } else { + $browser['timeout'] = 30; + } + + if (isset($browser['httpTimeout'])) { + if (!is_int($browser['httpTimeout'])) { + throw new InvalidArgumentException( + 'Array element "httpTimeout" is no integer.' + ); + } + } else { + $browser['httpTimeout'] = 45; + } + + $driver = new PHPUnit_Extensions_SeleniumTestCase_Driver; + $driver->setName($browser['name']); + $driver->setBrowser($browser['browser']); + $driver->setHost($browser['host']); + $driver->setPort($browser['port']); + $driver->setTimeout($browser['timeout']); + $driver->setHttpTimeout($browser['httpTimeout']); + $driver->setTestCase($this); + $driver->setTestId($this->testId); + + $this->drivers[] = $driver; + + return $driver; + } + + /** + * @throws RuntimeException + */ + protected function runTest() + { + $this->start(); + + if (!is_file($this->getName(FALSE))) { + parent::runTest(); + } else { + $this->runSelenese($this->getName(FALSE)); + } + + if (!empty($this->verificationErrors)) { + $this->fail(implode("\n", $this->verificationErrors)); + } + + try { + $this->stop(); + } + + catch (RuntimeException $e) { + } + } + + /** + * Returns a string representation of the test case. + * + * @return string + */ + public function toString() + { + $buffer = parent::toString(); + + if (!empty($this->browserName)) { + $buffer .= ' with browser ' . $this->browserName; + } + + return $buffer; + } + + /** + * Runs a test from a Selenese (HTML) specification. + * + * @param string $filename + */ + public function runSelenese($filename) + { + $document = PHPUnit_Util_XML::loadFile($filename, TRUE); + $xpath = new DOMXPath($document); + $rows = $xpath->query('body/table/tbody/tr'); + + foreach ($rows as $row) { + $action = NULL; + $arguments = array(); + $columns = $xpath->query('td', $row); + + foreach ($columns as $column) { + if ($action === NULL) { + $action = PHPUnit_Util_XML::nodeToText($column); + } else { + $arguments[] = PHPUnit_Util_XML::nodeToText($column); + } + } + + if (method_exists($this, $action)) { + call_user_func_array(array($this, $action), $arguments); + } else { + $this->__call($action, $arguments); + } + } + } + + /** + * Delegate method calls to the driver. + * + * @param string $command + * @param array $arguments + * @return mixed + */ + public function __call($command, $arguments) + { + $result = call_user_func_array( + array($this->drivers[0], $command), $arguments + ); + + $this->verificationErrors = array_merge( + $this->verificationErrors, $this->drivers[0]->getVerificationErrors() + ); + + $this->drivers[0]->clearVerificationErrors(); + + return $result; + } + + /** + * Asserts that an element's value is equal to a given string. + * + * @param string $locator + * @param string $text + * @param string $message + */ + public function assertElementValueEquals($locator, $text, $message = '') + { + $this->assertEquals($text, $this->getValue($locator), $message); + } + + /** + * Asserts that an element's value is not equal to a given string. + * + * @param string $locator + * @param string $text + * @param string $message + */ + public function assertElementValueNotEquals($locator, $text, $message = '') + { + $this->assertNotEquals($text, $this->getValue($locator), $message); + } + + /** + * Asserts that an element's value contains a given string. + * + * @param string $locator + * @param string $text + * @param string $message + */ + public function assertElementValueContains($locator, $text, $message = '') + { + $this->assertContains($text, $this->getValue($locator), $message); + } + + /** + * Asserts that an element's value does not contain a given string. + * + * @param string $locator + * @param string $text + * @param string $message + */ + public function assertElementValueNotContains($locator, $text, $message = '') + { + $this->assertNotContains($text, $this->getValue($locator), $message); + } + + /** + * Asserts that an element contains a given string. + * + * @param string $locator + * @param string $text + * @param string $message + */ + public function assertElementContainsText($locator, $text, $message = '') + { + $this->assertContains($text, $this->getText($locator), $message); + } + + /** + * Asserts that an element does not contain a given string. + * + * @param string $locator + * @param string $text + * @param string $message + */ + public function assertElementNotContainsText($locator, $text, $message = '') + { + $this->assertNotContains($text, $this->getText($locator), $message); + } + + /** + * Asserts that a select element has a specific option. + * + * @param string $selectLocator + * @param string $option + * @param string $message + * @since Method available since Release 3.2.0 + */ + public function assertSelectHasOption($selectLocator, $option, $message = '') + { + $this->assertContains($option, $this->getSelectOptions($selectLocator), $message); + } + + /** + * Asserts that a select element does not have a specific option. + * + * @param string $selectLocator + * @param string $option + * @param string $message + * @since Method available since Release 3.2.0 + */ + public function assertSelectNotHasOption($selectLocator, $option, $message = '') + { + $this->assertNotContains($option, $this->getSelectOptions($selectLocator), $message); + } + + /** + * Asserts that a specific label is selected. + * + * @param string $selectLocator + * @param string $value + * @param string $message + * @since Method available since Release 3.2.0 + */ + public function assertSelected($selectLocator, $option, $message = '') + { + if ($message == '') { + $message = sprintf( + 'Label "%s" not selected in "%s".', + $option, + $selectLocator + ); + } + + $this->assertEquals( + $option, + $this->getSelectedLabel($selectLocator), + $message + ); + } + + /** + * Asserts that a specific label is not selected. + * + * @param string $selectLocator + * @param string $value + * @param string $message + * @since Method available since Release 3.2.0 + */ + public function assertNotSelected($selectLocator, $option, $message = '') + { + if ($message == '') { + $message = sprintf( + 'Label "%s" selected in "%s".', + $option, + $selectLocator + ); + } + + $this->assertNotEquals( + $option, + $this->getSelectedLabel($selectLocator), + $message + ); + } + + /** + * Asserts that a specific value is selected. + * + * @param string $selectLocator + * @param string $value + * @param string $message + */ + public function assertIsSelected($selectLocator, $value, $message = '') + { + if ($message == '') { + $message = sprintf( + 'Value "%s" not selected in "%s".', + $value, + $selectLocator + ); + } + + $this->assertEquals( + $value, $this->getSelectedValue($selectLocator), + $message + ); + } + + /** + * Asserts that a specific value is not selected. + * + * @param string $selectLocator + * @param string $value + * @param string $message + */ + public function assertIsNotSelected($selectLocator, $value, $message = '') + { + if ($message == '') { + $message = sprintf( + 'Value "%s" selected in "%s".', + $value, + $selectLocator + ); + } + + $this->assertNotEquals( + $value, + $this->getSelectedValue($selectLocator), + $message + ); + } + + /** + * Template Method that is called after Selenium actions. + * + * @param string $action + * @since Method available since Release 3.1.0 + */ + protected function defaultAssertions($action) + { + } + + /** + * @return array + * @since Method available since Release 3.2.0 + */ + protected function getCodeCoverage() + { + if (!empty($this->coverageScriptUrl)) { + $url = sprintf( + '%s?PHPUNIT_SELENIUM_TEST_ID=%s', + $this->coverageScriptUrl, + $this->testId + ); + + $buffer = @file_get_contents($url); + + if ($buffer !== FALSE) { + return $this->matchLocalAndRemotePaths(unserialize($buffer)); + } + } + + return array(); + } + + /** + * @param array $coverage + * @return array + * @author Mattis Stordalen Flister + * @since Method available since Release 3.2.9 + */ + protected function matchLocalAndRemotePaths(array $coverage) + { + $coverageWithLocalPaths = array(); + + foreach ($coverage as $originalRemotePath => $data) { + $remotePath = $originalRemotePath; + $separator = $this->findDirectorySeparator($remotePath); + + while (!($localpath = PHPUnit_Util_Filesystem::fileExistsInIncludePath($remotePath)) && + strpos($remotePath, $separator) !== FALSE) { + $remotePath = substr($remotePath, strpos($remotePath, $separator) + 1); + } + + if ($localpath && md5_file($localpath) == $data['md5']) { + $coverageWithLocalPaths[$localpath] = $data['coverage']; + } + } + + return $coverageWithLocalPaths; + } + + /** + * @param string $path + * @return string + * @author Mattis Stordalen Flister + * @since Method available since Release 3.2.9 + */ + protected function findDirectorySeparator($path) + { + if (strpos($path, '/') !== FALSE) { + return '/'; + } + + return '\\'; + } + + /** + * @param string $path + * @return array + * @author Mattis Stordalen Flister + * @since Method available since Release 3.2.9 + */ + protected function explodeDirectories($path) + { + return explode($this->findDirectorySeparator($path), dirname($path)); + } + + /** + * @param string $directory + * @param string $suffix + * @return array + * @since Method available since Release 1.0.0 + */ + protected static function getSeleneseFiles($directory, $suffix) + { + $files = array(); + $iterator = File_Iterator_Factory::getFileIterator($directory, $suffix); + + foreach ($iterator as $file) { + $files[] = (string)$file; + } + + return $files; + } + + /** + * @param string $action + * @since Method available since Release 3.2.0 + */ + public function runDefaultAssertions($action) + { + if (!$this->inDefaultAssertions) { + $this->inDefaultAssertions = TRUE; + $this->defaultAssertions($action); + $this->inDefaultAssertions = FALSE; + } + } + + /** + * This method is called when a test method did not execute successfully. + * + * @param Exception $e + * @since Method available since Release 3.4.0 + */ + protected function onNotSuccessfulTest(Exception $e) + { + if ($e instanceof PHPUnit_Framework_ExpectationFailedException) { + $buffer = 'Current URL: ' . $this->drivers[0]->getLocation() . + "\n"; + $message = $e->getCustomMessage(); + + if ($this->captureScreenshotOnFailure && + !empty($this->screenshotPath) && + !empty($this->screenshotUrl)) { + $this->drivers[0]->captureEntirePageScreenshot( + $this->screenshotPath . DIRECTORY_SEPARATOR . $this->testId . + '.png' + ); + + $buffer .= 'Screenshot: ' . $this->screenshotUrl . '/' . + $this->testId . ".png\n"; + } + } + + try { + $this->stop(); + } + + catch (RuntimeException $e) { + } + + if ($e instanceof PHPUnit_Framework_ExpectationFailedException) { + if (!empty($message)) { + $buffer .= "\n" . $message; + } + + $e->setCustomMessage($buffer); + } + + throw $e; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/Driver.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/Driver.php new file mode 100644 index 0000000..d058c4f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/Driver.php @@ -0,0 +1,1218 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_Selenium + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * Implementation of the Selenium RC client/server protocol. + * + * @package PHPUnit_Selenium + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.3 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Extensions_SeleniumTestCase_Driver +{ + /** + * @var PHPUnit_Extensions_SeleniumTestCase + */ + protected $testCase; + + /** + * @var string + */ + protected $testId; + + /** + * @var string + */ + protected $name; + + /** + * @var string + */ + protected $browser; + + /** + * @var string + */ + protected $browserUrl; + + /** + * @var boolean + */ + protected $collectCodeCoverageInformation = FALSE; + + /** + * @var string + */ + protected $host = 'localhost'; + + /** + * @var integer + */ + protected $port = 4444; + + /** + * @var integer + */ + protected $httpTimeout = 45; + + /** + * @var integer + */ + protected $seleniumTimeout = 30; + + /** + * @var string + */ + protected $sessionId; + + /** + * @var integer + */ + protected $sleep = 0; + + /** + * @var boolean + */ + protected $useWaitForPageToLoad = TRUE; + + /** + * @var boolean + */ + protected $wait = 5; + + /** + * @var array + */ + protected static $autoGeneratedCommands = array(); + + /** + * @var array + */ + protected $commands = array(); + + /** + * @var array + */ + protected $verificationErrors = array(); + + public function __construct() + { + if (empty(self::$autoGeneratedCommands)) { + self::autoGenerateCommands(); + } + } + + /** + * @return string + */ + public function start() + { + if ($this->browserUrl == NULL) { + throw new PHPUnit_Framework_Exception( + 'setBrowserUrl() needs to be called before start().' + ); + } + + if (!isset($this->sessionId)) { + $this->sessionId = $this->getString( + 'getNewBrowserSession', + array($this->browser, $this->browserUrl) + ); + + $this->doCommand('setTimeout', array($this->seleniumTimeout * 1000)); + } + + return $this->sessionId; + } + + /** + */ + public function stop() + { + if (!isset($this->sessionId)) { + return; + } + + $this->doCommand('testComplete'); + + $this->sessionId = NULL; + } + + /** + * @param boolean $flag + * @throws InvalidArgumentException + */ + public function setCollectCodeCoverageInformation($flag) + { + if (!is_bool($flag)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); + } + + $this->collectCodeCoverageInformation = $flag; + } + + /** + * @param PHPUnit_Extensions_SeleniumTestCase $testCase + */ + public function setTestCase(PHPUnit_Extensions_SeleniumTestCase $testCase) + { + $this->testCase = $testCase; + } + + /** + * @param integer $testId + */ + public function setTestId($testId) + { + $this->testId = $testId; + } + + /** + * @param string $name + * @throws InvalidArgumentException + */ + public function setName($name) + { + if (!is_string($name)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + $this->name = $name; + } + + /** + * @param string $browser + * @throws InvalidArgumentException + */ + public function setBrowser($browser) + { + if (!is_string($browser)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + $this->browser = $browser; + } + + /** + * @param string $browserUrl + * @throws InvalidArgumentException + */ + public function setBrowserUrl($browserUrl) + { + if (!is_string($browserUrl)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + $this->browserUrl = $browserUrl; + } + + /** + * @param string $host + * @throws InvalidArgumentException + */ + public function setHost($host) + { + if (!is_string($host)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + $this->host = $host; + } + + /** + * @param integer $port + * @throws InvalidArgumentException + */ + public function setPort($port) + { + if (!is_int($port)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer'); + } + + $this->port = $port; + } + + /** + * @param integer $timeout for Selenium RC in seconds + * @throws InvalidArgumentException + */ + public function setTimeout($timeout) + { + if (!is_int($timeout)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer'); + } + + $this->seleniumTimeout = $timeout; + } + + /** + * @param integer $timeout for HTTP connection to Selenium RC in seconds + * @throws InvalidArgumentException + */ + public function setHttpTimeout($timeout) + { + if (!is_int($timeout)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer'); + } + + $this->httpTimeout = $timeout; + } + + /** + * @param integer $seconds + * @throws InvalidArgumentException + */ + public function setSleep($seconds) + { + if (!is_int($seconds)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer'); + } + + $this->sleep = $seconds; + } + + /** + * Sets the number of seconds to sleep() after *AndWait commands + * when setWaitForPageToLoad(FALSE) is used. + * + * @param integer $seconds + * @throws InvalidArgumentException + */ + public function setWait($seconds) + { + if (!is_int($seconds)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer'); + } + + $this->wait = $seconds; + } + + /** + * Sets whether waitForPageToLoad (TRUE) or sleep() (FALSE) + * is used after *AndWait commands. + * + * @param boolean $flag + * @throws InvalidArgumentException + */ + public function setWaitForPageToLoad($flag) + { + if (!is_bool($flag)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); + } + + $this->useWaitForPageToLoad = $flag; + } + + /** + * This method implements the Selenium RC protocol. + * + * @param string $command + * @param array $arguments + * @return mixed + * @method unknown addLocationStrategy() + * @method unknown addLocationStrategyAndWait() + * @method unknown addScript() + * @method unknown addScriptAndWait() + * @method unknown addSelection() + * @method unknown addSelectionAndWait() + * @method unknown allowNativeXpath() + * @method unknown allowNativeXpathAndWait() + * @method unknown altKeyDown() + * @method unknown altKeyDownAndWait() + * @method unknown altKeyUp() + * @method unknown altKeyUpAndWait() + * @method unknown answerOnNextPrompt() + * @method unknown assignId() + * @method unknown assignIdAndWait() + * @method unknown attachFile() + * @method unknown break() + * @method unknown captureEntirePageScreenshot() + * @method unknown captureEntirePageScreenshotAndWait() + * @method unknown captureEntirePageScreenshotToStringAndWait() + * @method unknown captureScreenshotAndWait() + * @method unknown captureScreenshotToStringAndWait() + * @method unknown check() + * @method unknown checkAndWait() + * @method unknown chooseCancelOnNextConfirmation() + * @method unknown chooseCancelOnNextConfirmationAndWait() + * @method unknown chooseOkOnNextConfirmation() + * @method unknown chooseOkOnNextConfirmationAndWait() + * @method unknown click() + * @method unknown clickAndWait() + * @method unknown clickAt() + * @method unknown clickAtAndWait() + * @method unknown close() + * @method unknown contextMenu() + * @method unknown contextMenuAndWait() + * @method unknown contextMenuAt() + * @method unknown contextMenuAtAndWait() + * @method unknown controlKeyDown() + * @method unknown controlKeyDownAndWait() + * @method unknown controlKeyUp() + * @method unknown controlKeyUpAndWait() + * @method unknown createCookie() + * @method unknown createCookieAndWait() + * @method unknown deleteAllVisibleCookies() + * @method unknown deleteAllVisibleCookiesAndWait() + * @method unknown deleteCookie() + * @method unknown deleteCookieAndWait() + * @method unknown deselectPopUp() + * @method unknown deselectPopUpAndWait() + * @method unknown doubleClick() + * @method unknown doubleClickAndWait() + * @method unknown doubleClickAt() + * @method unknown doubleClickAtAndWait() + * @method unknown dragAndDrop() + * @method unknown dragAndDropAndWait() + * @method unknown dragAndDropToObject() + * @method unknown dragAndDropToObjectAndWait() + * @method unknown dragDrop() + * @method unknown dragDropAndWait() + * @method unknown echo() + * @method unknown fireEvent() + * @method unknown fireEventAndWait() + * @method unknown focus() + * @method unknown focusAndWait() + * @method string getAlert() + * @method array getAllButtons() + * @method array getAllFields() + * @method array getAllLinks() + * @method array getAllWindowIds() + * @method array getAllWindowNames() + * @method array getAllWindowTitles() + * @method string getAttribute() + * @method array getAttributeFromAllWindows() + * @method string getBodyText() + * @method string getConfirmation() + * @method string getCookie() + * @method string getCookieByName() + * @method integer getCursorPosition() + * @method integer getElementHeight() + * @method integer getElementIndex() + * @method integer getElementPositionLeft() + * @method integer getElementPositionTop() + * @method integer getElementWidth() + * @method string getEval() + * @method string getExpression() + * @method string getHtmlSource() + * @method string getLocation() + * @method string getLogMessages() + * @method integer getMouseSpeed() + * @method string getPrompt() + * @method array getSelectOptions() + * @method string getSelectedId() + * @method array getSelectedIds() + * @method string getSelectedIndex() + * @method array getSelectedIndexes() + * @method string getSelectedLabel() + * @method array getSelectedLabels() + * @method string getSelectedValue() + * @method array getSelectedValues() + * @method unknown getSpeed() + * @method unknown getSpeedAndWait() + * @method string getTable() + * @method string getText() + * @method string getTitle() + * @method string getValue() + * @method boolean getWhetherThisFrameMatchFrameExpression() + * @method boolean getWhetherThisWindowMatchWindowExpression() + * @method integer getXpathCount() + * @method unknown goBack() + * @method unknown goBackAndWait() + * @method unknown highlight() + * @method unknown highlightAndWait() + * @method unknown ignoreAttributesWithoutValue() + * @method unknown ignoreAttributesWithoutValueAndWait() + * @method boolean isAlertPresent() + * @method boolean isChecked() + * @method boolean isConfirmationPresent() + * @method boolean isCookiePresent() + * @method boolean isEditable() + * @method boolean isElementPresent() + * @method boolean isOrdered() + * @method boolean isPromptPresent() + * @method boolean isSomethingSelected() + * @method boolean isTextPresent() + * @method boolean isVisible() + * @method unknown keyDown() + * @method unknown keyDownAndWait() + * @method unknown keyDownNative() + * @method unknown keyDownNativeAndWait() + * @method unknown keyPress() + * @method unknown keyPressAndWait() + * @method unknown keyPressNative() + * @method unknown keyPressNativeAndWait() + * @method unknown keyUp() + * @method unknown keyUpAndWait() + * @method unknown keyUpNative() + * @method unknown keyUpNativeAndWait() + * @method unknown metaKeyDown() + * @method unknown metaKeyDownAndWait() + * @method unknown metaKeyUp() + * @method unknown metaKeyUpAndWait() + * @method unknown mouseDown() + * @method unknown mouseDownAndWait() + * @method unknown mouseDownAt() + * @method unknown mouseDownAtAndWait() + * @method unknown mouseMove() + * @method unknown mouseMoveAndWait() + * @method unknown mouseMoveAt() + * @method unknown mouseMoveAtAndWait() + * @method unknown mouseOut() + * @method unknown mouseOutAndWait() + * @method unknown mouseOver() + * @method unknown mouseOverAndWait() + * @method unknown mouseUp() + * @method unknown mouseUpAndWait() + * @method unknown mouseUpAt() + * @method unknown mouseUpAtAndWait() + * @method unknown mouseUpRight() + * @method unknown mouseUpRightAndWait() + * @method unknown mouseUpRightAt() + * @method unknown mouseUpRightAtAndWait() + * @method unknown open() + * @method unknown openWindow() + * @method unknown openWindowAndWait() + * @method unknown pause() + * @method unknown refresh() + * @method unknown refreshAndWait() + * @method unknown removeAllSelections() + * @method unknown removeAllSelectionsAndWait() + * @method unknown removeScript() + * @method unknown removeScriptAndWait() + * @method unknown removeSelection() + * @method unknown removeSelectionAndWait() + * @method unknown retrieveLastRemoteControlLogs() + * @method unknown rollup() + * @method unknown rollupAndWait() + * @method unknown runScript() + * @method unknown runScriptAndWait() + * @method unknown select() + * @method unknown selectAndWait() + * @method unknown selectFrame() + * @method unknown selectPopUp() + * @method unknown selectPopUpAndWait() + * @method unknown selectWindow() + * @method unknown setBrowserLogLevel() + * @method unknown setBrowserLogLevelAndWait() + * @method unknown setContext() + * @method unknown setCursorPosition() + * @method unknown setCursorPositionAndWait() + * @method unknown setMouseSpeed() + * @method unknown setMouseSpeedAndWait() + * @method unknown setSpeed() + * @method unknown setSpeedAndWait() + * @method unknown shiftKeyDown() + * @method unknown shiftKeyDownAndWait() + * @method unknown shiftKeyUp() + * @method unknown shiftKeyUpAndWait() + * @method unknown shutDownSeleniumServer() + * @method unknown store() + * @method unknown submit() + * @method unknown submitAndWait() + * @method unknown type() + * @method unknown typeAndWait() + * @method unknown typeKeys() + * @method unknown typeKeysAndWait() + * @method unknown uncheck() + * @method unknown uncheckAndWait() + * @method unknown useXpathLibrary() + * @method unknown useXpathLibraryAndWait() + * @method unknown waitForCondition() + * @method unknown waitForPageToLoad() + * @method unknown waitForPopUp() + * @method unknown windowFocus() + * @method unknown windowMaximize() + */ + public function __call($command, $arguments) + { + $wait = FALSE; + + if (substr($command, -7, 7) == 'AndWait') { + $command = substr($command, 0, -7); + $wait = TRUE; + } + + switch ($command) { + case 'addLocationStrategy': + case 'addScript': + case 'addSelection': + case 'allowNativeXpath': + case 'altKeyDown': + case 'altKeyUp': + case 'answerOnNextPrompt': + case 'assignId': + case 'attachFile': + case 'break': + case 'captureEntirePageScreenshot': + case 'captureScreenshot': + case 'check': + case 'chooseCancelOnNextConfirmation': + case 'chooseOkOnNextConfirmation': + case 'click': + case 'clickAt': + case 'close': + case 'contextMenu': + case 'contextMenuAt': + case 'controlKeyDown': + case 'controlKeyUp': + case 'createCookie': + case 'deleteAllVisibleCookies': + case 'deleteCookie': + case 'deselectPopUp': + case 'doubleClick': + case 'doubleClickAt': + case 'dragAndDrop': + case 'dragAndDropToObject': + case 'dragDrop': + case 'echo': + case 'fireEvent': + case 'focus': + case 'goBack': + case 'highlight': + case 'ignoreAttributesWithoutValue': + case 'keyDown': + case 'keyDownNative': + case 'keyPress': + case 'keyPressNative': + case 'keyUp': + case 'keyUpNative': + case 'metaKeyDown': + case 'metaKeyUp': + case 'mouseDown': + case 'mouseDownAt': + case 'mouseMove': + case 'mouseMoveAt': + case 'mouseOut': + case 'mouseOver': + case 'mouseUp': + case 'mouseUpAt': + case 'mouseUpRight': + case 'mouseUpRightAt': + case 'open': + case 'openWindow': + case 'pause': + case 'refresh': + case 'removeAllSelections': + case 'removeScript': + case 'removeSelection': + case 'retrieveLastRemoteControlLogs': + case 'rollup': + case 'runScript': + case 'select': + case 'selectFrame': + case 'selectPopUp': + case 'selectWindow': + case 'setBrowserLogLevel': + case 'setContext': + case 'setCursorPosition': + case 'setMouseSpeed': + case 'setSpeed': + case 'shiftKeyDown': + case 'shiftKeyUp': + case 'shutDownSeleniumServer': + case 'store': + case 'submit': + case 'type': + case 'typeKeys': + case 'uncheck': + case 'useXpathLibrary': + case 'windowFocus': + case 'windowMaximize': + case isset(self::$autoGeneratedCommands[$command]): { + // Pre-Command Actions + switch ($command) { + case 'open': + case 'openWindow': { + if ($this->collectCodeCoverageInformation) { + $this->deleteCookie('PHPUNIT_SELENIUM_TEST_ID', 'path=/'); + + $this->createCookie( + 'PHPUNIT_SELENIUM_TEST_ID=' . $this->testId, + 'path=/' + ); + } + } + break; + case 'store': + // store is a synonym of storeExpression + // and RC only understands storeExpression + $command = 'storeExpression'; + break; + } + + if (isset(self::$autoGeneratedCommands[$command]) && self::$autoGeneratedCommands[$command]['functionHelper']) { + $helperArguments = array($command, $arguments, self::$autoGeneratedCommands[$command]); + call_user_func_array(array($this, self::$autoGeneratedCommands[$command]['functionHelper']), $helperArguments); + } else { + $this->doCommand($command, $arguments); + } + + // Post-Command Actions + switch ($command) { + case 'addLocationStrategy': + case 'allowNativeXpath': + case 'assignId': + case 'captureEntirePageScreenshot': + case 'captureScreenshot': { + // intentionally empty + } + break; + + default: { + if ($wait) { + if ($this->useWaitForPageToLoad) { + $this->waitForPageToLoad($this->seleniumTimeout * 1000); + } else { + sleep($this->wait); + } + } + + if ($this->sleep > 0) { + sleep($this->sleep); + } + + $this->testCase->runDefaultAssertions($command); + } + } + } + break; + + case 'getWhetherThisFrameMatchFrameExpression': + case 'getWhetherThisWindowMatchWindowExpression': + case 'isAlertPresent': + case 'isChecked': + case 'isConfirmationPresent': + case 'isCookiePresent': + case 'isEditable': + case 'isElementPresent': + case 'isOrdered': + case 'isPromptPresent': + case 'isSomethingSelected': + case 'isTextPresent': + case 'isVisible': { + return $this->getBoolean($command, $arguments); + } + break; + + case 'getCursorPosition': + case 'getElementHeight': + case 'getElementIndex': + case 'getElementPositionLeft': + case 'getElementPositionTop': + case 'getElementWidth': + case 'getMouseSpeed': + case 'getSpeed': + case 'getXpathCount': { + $result = $this->getNumber($command, $arguments); + + if ($wait) { + $this->waitForPageToLoad($this->seleniumTimeout * 1000); + } + + return $result; + } + break; + + case 'getAlert': + case 'getAttribute': + case 'getBodyText': + case 'getConfirmation': + case 'getCookie': + case 'getCookieByName': + case 'getEval': + case 'getExpression': + case 'getHtmlSource': + case 'getLocation': + case 'getLogMessages': + case 'getPrompt': + case 'getSelectedId': + case 'getSelectedIndex': + case 'getSelectedLabel': + case 'getSelectedValue': + case 'getTable': + case 'getText': + case 'getTitle': + case 'captureEntirePageScreenshotToString': + case 'captureScreenshotToString': + case 'getValue': { + $result = $this->getString($command, $arguments); + + if ($wait) { + $this->waitForPageToLoad($this->seleniumTimeout * 1000); + } + + return $result; + } + break; + + case 'getAllButtons': + case 'getAllFields': + case 'getAllLinks': + case 'getAllWindowIds': + case 'getAllWindowNames': + case 'getAllWindowTitles': + case 'getAttributeFromAllWindows': + case 'getSelectedIds': + case 'getSelectedIndexes': + case 'getSelectedLabels': + case 'getSelectedValues': + case 'getSelectOptions': { + $result = $this->getStringArray($command, $arguments); + + if ($wait) { + $this->waitForPageToLoad($this->seleniumTimeout * 1000); + } + + return $result; + } + break; + + case 'waitForCondition': + case 'waitForFrameToLoad': + case 'waitForPopUp': { + if (count($arguments) == 1) { + $arguments[] = $this->seleniumTimeout * 1000; + } + + $this->doCommand($command, $arguments); + $this->testCase->runDefaultAssertions($command); + } + break; + + case 'waitForPageToLoad': { + if (empty($arguments)) { + $arguments[] = $this->seleniumTimeout * 1000; + } + + $this->doCommand($command, $arguments); + $this->testCase->runDefaultAssertions($command); + } + break; + + default: { + $this->stop(); + + throw new BadMethodCallException( + "Method $command not defined." + ); + } + } + } + + /** + * Send a command to the Selenium RC server. + * + * @param string $command + * @param array $arguments + * @return string + * @author Shin Ohno + * @author Bjoern Schotte + */ + protected function doCommand($command, array $arguments = array()) + { + if (!ini_get('allow_url_fopen')) { + throw new PHPUnit_Framework_Exception( + 'Could not connect to the Selenium RC server because allow_url_fopen is disabled.' + ); + } + + $url = sprintf( + 'http://%s:%s/selenium-server/driver/?cmd=%s', + $this->host, + $this->port, + urlencode($command) + ); + + $numArguments = count($arguments); + + for ($i = 0; $i < $numArguments; $i++) { + $argNum = strval($i + 1); + $url .= sprintf('&%s=%s', $argNum, urlencode(trim($arguments[$i]))); + } + + if (isset($this->sessionId)) { + $url .= sprintf('&%s=%s', 'sessionId', $this->sessionId); + } + + $this->commands[] = sprintf('%s(%s)', $command, join(', ', $arguments)); + + $context = stream_context_create( + array( + 'http' => array( + 'timeout' => $this->httpTimeout + ) + ) + ); + + $handle = @fopen($url, 'r', FALSE, $context); + + if (!$handle) { + throw new PHPUnit_Framework_Exception( + 'Could not connect to the Selenium RC server.' + ); + } + + stream_set_blocking($handle, 1); + stream_set_timeout($handle, $this->httpTimeout); + + /* Tell the web server that we will not be sending more data + so that it can start processing our request */ + stream_socket_shutdown($handle, STREAM_SHUT_WR); + + $response = stream_get_contents($handle); + + fclose($handle); + + if (!preg_match('/^OK/', $response)) { + $this->stop(); + + throw new PHPUnit_Framework_Exception( + sprintf( + "Response from Selenium RC server for %s.\n%s.\n", + $this->commands[count($this->commands)-1], + $response + ) + ); + } + + return $response; + } + + /** + * Send a command to the Selenium RC server and treat the result + * as a boolean. + * + * @param string $command + * @param array $arguments + * @return boolean + * @author Shin Ohno + * @author Bjoern Schotte + */ + protected function getBoolean($command, array $arguments) + { + $result = $this->getString($command, $arguments); + + switch ($result) { + case 'true': return TRUE; + + case 'false': return FALSE; + + default: { + $this->stop(); + + throw new PHPUnit_Framework_Exception( + 'Result is neither "true" nor "false": ' . PHPUnit_Util_Type::toString($result, TRUE) + ); + } + } + } + + /** + * Send a command to the Selenium RC server and treat the result + * as a number. + * + * @param string $command + * @param array $arguments + * @return numeric + * @author Shin Ohno + * @author Bjoern Schotte + */ + protected function getNumber($command, array $arguments) + { + $result = $this->getString($command, $arguments); + + if (!is_numeric($result)) { + $this->stop(); + + throw new PHPUnit_Framework_Exception( + 'Result is not numeric: ' . PHPUnit_Util_Type::toString($result, TRUE) + ); + } + + return $result; + } + + /** + * Send a command to the Selenium RC server and treat the result + * as a string. + * + * @param string $command + * @param array $arguments + * @return string + * @author Shin Ohno + * @author Bjoern Schotte + */ + protected function getString($command, array $arguments) + { + try { + $result = $this->doCommand($command, $arguments); + } + + catch (RuntimeException $e) { + $this->stop(); + + throw $e; + } + + return (strlen($result) > 3) ? substr($result, 3) : ''; + } + + /** + * Send a command to the Selenium RC server and treat the result + * as an array of strings. + * + * @param string $command + * @param array $arguments + * @return array + * @author Shin Ohno + * @author Bjoern Schotte + */ + protected function getStringArray($command, array $arguments) + { + $csv = $this->getString($command, $arguments); + $token = ''; + $tokens = array(); + $letters = preg_split('//', $csv, -1, PREG_SPLIT_NO_EMPTY); + $count = count($letters); + + for ($i = 0; $i < $count; $i++) { + $letter = $letters[$i]; + + switch($letter) { + case '\\': { + $letter = $letters[++$i]; + $token .= $letter; + } + break; + + case ',': { + $tokens[] = $token; + $token = ''; + } + break; + + default: { + $token .= $letter; + } + } + } + + $tokens[] = $token; + + return $tokens; + } + + public function getVerificationErrors() + { + return $this->verificationErrors; + } + + public function clearVerificationErrors() + { + $this->verificationErrors = array(); + } + + protected function assertCommand($command, $arguments, $info) + { + $method = $info['originalMethod']; + $result = $this->__call($method, $arguments); + + if ($info['isBoolean']) { + if (!isset($info['negative']) || !$info['negative']) { + PHPUnit_Framework_Assert::assertTrue($result, $arguments[ count($arguments) - 1 ]); + } else { + PHPUnit_Framework_Assert::assertFalse($result, $arguments[ count($arguments) - 1 ]); + } + } else { + $expected = array_pop($arguments); + + if (strpos($expected, 'exact:') === 0) { + $expected = substr($expected, strlen('exact:')); + + if (!isset($info['negative']) || !$info['negative']) { + PHPUnit_Framework_Assert::assertEquals($expected, $result); + } else { + PHPUnit_Framework_Assert::assertNotEquals($expected, $result); + } + } else { + $caseInsensitive = FALSE; + + if (strpos($expected, 'regexp:') === 0) { + $expected = substr($expected, strlen('regexp:')); + } else if (strpos($expected, 'regexpi:') === 0) { + $expected = substr($expected, strlen('regexpi:')); + $caseInsensitive = TRUE; + } else { + if (strpos($expected, 'glob:') === 0) { + $expected = substr($expected, strlen('glob:')); + } + + $expected = str_replace( + array('*', '?'), array('.*', '.?'), $expected + ); + } + + $expected = '/' . str_replace('/', '\/', $expected) . '/'; + + if ($caseInsensitive) { + $expected .= 'i'; + } + + if (!isset($info['negative']) || !$info['negative']) { + PHPUnit_Framework_Assert::assertRegExp( + $expected, $result + ); + } else { + PHPUnit_Framework_Assert::assertNotRegExp( + $expected, $result + ); + } + } + } + } + + protected function verifyCommand($command, $arguments, $info) + { + try { + $this->assertCommand($command, $arguments, $info); + } + + catch (PHPUnit_Framework_AssertionFailedError $e) { + array_push($this->verificationErrors, $e->toString()); + } + } + + protected function waitForCommand($command, $arguments, $info) + { + for ($second = 0; ; $second++) { + if ($second > $this->httpTimeout) { + PHPUnit_Framework_Assert::fail('timeout'); + } + + try { + $this->assertCommand($command, $arguments, $info); + return; + } + + catch (Exception $e) { + } + + sleep(1); + } + } + + /** + * Parses the docblock of PHPUnit_Extensions_SeleniumTestCase_Driver::__call + * for get*(), is*(), assert*(), verify*(), assertNot*(), verifyNot*(), + * store*(), waitFor*(), and waitForNot*() methods. + */ + protected static function autoGenerateCommands() + { + $method = new ReflectionMethod(__CLASS__, '__call'); + $docComment = $method->getDocComment(); + + if (preg_match_all('(@method\s+(\w+)\s+([\w]+)\(\))', $docComment, $matches)) { + foreach ($matches[2] as $method) { + if (preg_match('/^(get|is)([A-Z].+)$/', $method, $matches)) { + $baseName = $matches[2]; + $isBoolean = $matches[1] == 'is'; + + if (preg_match('/^(.*)Present$/', $baseName, $matches)) { + $notBaseName = $matches[1].'NotPresent'; + } else { + $notBaseName = 'Not'.$baseName; + } + + self::$autoGeneratedCommands['store' . $baseName] = array( + 'functionHelper' => FALSE + ); + + self::$autoGeneratedCommands['assert' . $baseName] = array( + 'originalMethod' => $method, + 'isBoolean' => $isBoolean, + 'functionHelper' => 'assertCommand' + ); + + self::$autoGeneratedCommands['assert' . $notBaseName] = array( + 'originalMethod' => $method, + 'isBoolean' => $isBoolean, + 'negative' => TRUE, + 'functionHelper' => 'assertCommand' + ); + + self::$autoGeneratedCommands['verify' . $baseName] = array( + 'originalMethod' => $method, + 'isBoolean' => $isBoolean, + 'functionHelper' => 'verifyCommand' + ); + + self::$autoGeneratedCommands['verify' . $notBaseName] = array( + 'originalMethod' => $method, + 'isBoolean' => $isBoolean, + 'negative' => TRUE, + 'functionHelper' => 'verifyCommand' + ); + + self::$autoGeneratedCommands['waitFor' . $baseName] = array( + 'originalMethod' => $method, + 'isBoolean' => $isBoolean, + 'functionHelper' => 'waitForCommand' + ); + + self::$autoGeneratedCommands['waitFor' . $notBaseName] = array( + 'originalMethod' => $method, + 'isBoolean' => $isBoolean, + 'negative' => TRUE, + 'functionHelper' => 'waitForCommand' + ); + } + } + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/append.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/append.php new file mode 100644 index 0000000..f9b2d58 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/append.php @@ -0,0 +1,69 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_Selenium + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +if ( isset($_COOKIE['PHPUNIT_SELENIUM_TEST_ID']) && + !isset($_GET['PHPUNIT_SELENIUM_TEST_ID']) && + extension_loaded('xdebug')) { + $GLOBALS['PHPUNIT_FILTERED_FILES'][] = __FILE__; + + $data = xdebug_get_code_coverage(); + xdebug_stop_code_coverage(); + + foreach ($GLOBALS['PHPUNIT_FILTERED_FILES'] as $file) { + unset($data[$file]); + } + + if (is_string($GLOBALS['PHPUNIT_COVERAGE_DATA_DIRECTORY']) && + is_dir($GLOBALS['PHPUNIT_COVERAGE_DATA_DIRECTORY'])) { + $file = $GLOBALS['PHPUNIT_COVERAGE_DATA_DIRECTORY'] . + DIRECTORY_SEPARATOR . md5($_SERVER['SCRIPT_FILENAME']); + } else { + $file = $_SERVER['SCRIPT_FILENAME']; + } + + file_put_contents( + $file . '.' . md5(uniqid(rand(), TRUE)) . '.' . $_COOKIE['PHPUNIT_SELENIUM_TEST_ID'], + serialize($data) + ); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/phpunit_coverage.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/phpunit_coverage.php new file mode 100644 index 0000000..b98e014 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/phpunit_coverage.php @@ -0,0 +1,86 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_Selenium + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +require_once 'File/Iterator/Factory.php'; +require_once 'PHP/CodeCoverage/Filter.php'; + +// Set this to the directory that contains the code coverage files. +// It defaults to getcwd(). If you have configured a different directory +// in prepend.php, you need to configure the same directory here. +$GLOBALS['PHPUNIT_COVERAGE_DATA_DIRECTORY'] = getcwd(); + +if (isset($_GET['PHPUNIT_SELENIUM_TEST_ID'])) { + $files = File_Iterator_Factory::getFileIterator( + $GLOBALS['PHPUNIT_COVERAGE_DATA_DIRECTORY'], + $_GET['PHPUNIT_SELENIUM_TEST_ID'] + ); + + $coverage = array(); + + foreach ($files as $file) { + $filename = $file->getPathName(); + $data = unserialize(file_get_contents($filename)); + @unlink($filename); + unset($filename); + + foreach ($data as $filename => $lines) { + if (PHP_CodeCoverage_Filter::isFile($filename)) { + if (!isset($coverage[$filename])) { + $coverage[$filename] = array( + 'md5' => md5_file($filename), 'coverage' => $lines + ); + } else { + foreach ($lines as $line => $flag) { + if (!isset($coverage[$filename]['coverage'][$line]) || + $flag > $coverage[$filename]['coverage'][$line]) { + $coverage[$filename]['coverage'][$line] = $flag; + } + } + } + } + } + } + + print serialize($coverage); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/prepend.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/prepend.php new file mode 100644 index 0000000..aecde84 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/SeleniumTestCase/prepend.php @@ -0,0 +1,59 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_Selenium + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +// By default the code coverage files are written to the same directory +// that contains the covered sourcecode files. Use this setting to change +// the default behaviour and set a specific directory to write the files to. +// If you change the default setting, please make sure to also configure +// the same directory in phpunit_coverage.php. Also note that the webserver +// needs write access to the directory. +$GLOBALS['PHPUNIT_COVERAGE_DATA_DIRECTORY'] = FALSE; + +if ( isset($_COOKIE['PHPUNIT_SELENIUM_TEST_ID']) && + !isset($_GET['PHPUNIT_SELENIUM_TEST_ID']) && + extension_loaded('xdebug')) { + $GLOBALS['PHPUNIT_FILTERED_FILES'] = array(__FILE__); + + xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Given.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Given.php new file mode 100644 index 0000000..b9c2623 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Given.php @@ -0,0 +1,71 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +/** + * A "Given" step. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Extensions_Story_Given extends PHPUnit_Extensions_Story_Step +{ + /** + * Returns this step's name. + * + * @return string + */ + public function getName() + { + return 'Given'; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter.php new file mode 100644 index 0000000..ecb3aed --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter.php @@ -0,0 +1,102 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +/** + * Base for Story result printers. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Extensions_Story_ResultPrinter extends PHPUnit_Util_TestDox_ResultPrinter +{ + /** + * A test ended. + * + * @param PHPUnit_Framework_Test $test + * @param float $time + */ + public function endTest(PHPUnit_Framework_Test $test, $time) + { + if ($test instanceof PHPUnit_Extensions_Story_TestCase || + $test instanceof PHPUnit_Extensions_Story_SeleniumTestCase) { + if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) { + $this->successful++; + $success = TRUE; + } else { + $success = FALSE; + } + + $this->onTest( + $this->currentTestMethodPrettified, + $success, + $test->getScenario()->getSteps() + ); + } + } + + /** + */ + protected function doEndClass() + { + $this->endClass($this->testClass); + } + + /** + * Handler for 'on test' event. + * + * @param string $name + * @param boolean $success + * @param array $steps + */ + protected function onTest($name, $success = TRUE, array $steps = array()) + { + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/HTML.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/HTML.php new file mode 100644 index 0000000..805092d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/HTML.php @@ -0,0 +1,212 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +/** + * Prints stories in HTML format. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Extensions_Story_ResultPrinter_HTML extends PHPUnit_Extensions_Story_ResultPrinter +{ + /** + * @var boolean + */ + protected $printsHTML = TRUE; + + /** + * @var integer + */ + protected $id = 0; + + /** + * @var string + */ + protected $scenarios = ''; + + /** + * @var string + */ + protected $templatePath; + + /** + * Constructor. + * + * @param mixed $out + * @throws InvalidArgumentException + */ + public function __construct($out = NULL) + { + parent::__construct($out); + + $this->templatePath = sprintf( + '%s%sTemplate%s', + + dirname(__FILE__), + DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR + ); + } + + /** + * Handler for 'start class' event. + * + * @param string $name + */ + protected function startClass($name) + { + $scenarioHeaderTemplate = new Text_Template( + $this->templatePath . 'scenario_header.html' + ); + + $scenarioHeaderTemplate->setVar( + array( + 'name' => $this->currentTestClassPrettified + ) + ); + + $this->scenarios .= $scenarioHeaderTemplate->render(); + } + + /** + * Handler for 'on test' event. + * + * @param string $name + * @param boolean $success + * @param array $steps + */ + protected function onTest($name, $success = TRUE, array $steps = array()) + { + if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE) { + $scenarioStatus = 'scenarioFailed'; + } + + else if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED) { + $scenarioStatus = 'scenarioSkipped'; + } + + else if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE) { + $scenarioStatus = 'scenarioIncomplete'; + } + + else { + $scenarioStatus = 'scenarioSuccess'; + } + + $lastStepName = ''; + $stepsBuffer = ''; + + foreach ($steps as $step) { + $currentStepName = $step->getName(); + + if ($lastStepName == $currentStepName) { + $stepText = 'and'; + } else { + $stepText = $currentStepName; + } + + $lastStepName = $currentStepName; + + $stepTemplate = new Text_Template( + $this->templatePath . 'step.html' + ); + + $stepTemplate->setVar( + array( + 'text' => $stepText, + 'action' => $step->getAction() . ' ' . $step->getArguments(TRUE), + ) + ); + + $stepsBuffer .= $stepTemplate->render(); + } + + $scenarioTemplate = new Text_Template( + $this->templatePath . 'scenario.html' + ); + + $scenarioTemplate->setVar( + array( + 'id' => ++$this->id, + 'name' => $name, + 'scenarioStatus' => $scenarioStatus, + 'steps' => $stepsBuffer, + ) + ); + + $this->scenarios .= $scenarioTemplate->render(); + } + + /** + * Handler for 'end run' event. + * + */ + protected function endRun() + { + $scenariosTemplate = new Text_Template( + $this->templatePath . 'scenarios.html' + ); + + $scenariosTemplate->setVar( + array( + 'scenarios' => $this->scenarios, + 'successfulScenarios' => $this->successful, + 'failedScenarios' => $this->failed, + 'skippedScenarios' => $this->skipped, + 'incompleteScenarios' => $this->incomplete + ) + ); + + $this->write($scenariosTemplate->render()); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/scenario.html.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/scenario.html.dist new file mode 100644 index 0000000..caa149a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/scenario.html.dist @@ -0,0 +1,13 @@ + + + + + + + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/scenario_header.html.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/scenario_header.html.dist new file mode 100644 index 0000000..7b205d1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/scenario_header.html.dist @@ -0,0 +1,6 @@ + + + + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/scenarios.html.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/scenarios.html.dist new file mode 100644 index 0000000..21bf38e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/scenarios.html.dist @@ -0,0 +1,60 @@ + + + + + + +
    +

    [+] {name}

    +
    + +{steps} +
    +
    +

    {name}

    +
    +{scenarios} + + + +
    +

    [+] Summary:

    + +
    + + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/step.html.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/step.html.dist new file mode 100644 index 0000000..bcdce3f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/step.html.dist @@ -0,0 +1,6 @@ + + {text} + {action} +   + + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Text.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Text.php new file mode 100644 index 0000000..1a3cc91 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/ResultPrinter/Text.php @@ -0,0 +1,150 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +/** + * Prints stories in HTML format. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Extensions_Story_ResultPrinter_Text extends PHPUnit_Extensions_Story_ResultPrinter +{ + /** + * Handler for 'start class' event. + * + * @param string $name + */ + protected function startClass($name) + { + $this->write($this->currentTestClassPrettified . "\n"); + } + + /** + * Handler for 'on test' event. + * + * @param string $name + * @param boolean $success + * @param array $steps + */ + protected function onTest($name, $success = TRUE, array $steps = array()) + { + if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE) { + $scenarioStatus = 'failed'; + } + + else if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED) { + $scenarioStatus = 'skipped'; + } + + else if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE) { + $scenarioStatus = 'incomplete'; + } + + else { + $scenarioStatus = 'successful'; + } + + $this->write( + sprintf( + " [%s] %s\n\n", + $scenarioStatus == 'successful' ? 'x' : ' ', + $name + ) + ); + + $lastStepName = ''; + $stepsBuffer = ''; + + foreach ($steps as $step) { + $currentStepName = $step->getName(); + + if ($lastStepName == $currentStepName) { + $stepText = 'and'; + } else { + $stepText = $currentStepName; + } + + $lastStepName = $currentStepName; + + $this->write( + sprintf( + " %5s %s %s\n", + $stepText, + $step->getAction(), + $step->getArguments(TRUE) + ) + ); + } + + $this->write("\n"); + } + + /** + * Handler for 'end run' event. + * + */ + protected function endRun() + { + $this->write( + sprintf( + "Scenarios: %d, Failed: %d, Skipped: %d, Incomplete: %d.\n", + + $this->successful + $this->failed + + $this->skipped + $this->incomplete, + $this->failed, + $this->skipped, + $this->incomplete + ) + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Scenario.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Scenario.php new file mode 100644 index 0000000..3ac94cf --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Scenario.php @@ -0,0 +1,189 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +/** + * A scenario. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Extensions_Story_Scenario +{ + /** + * @var PHPUnit_Extensions_Story_TestCase + */ + protected $test; + + /** + * @var array + */ + protected $steps = array(); + + /** + * @var string + */ + protected $lastCalledMethod; + + /** + * Constructor. + * + * @param PHPUnit_Extensions_Story_TestCase $caller + */ + public function __construct($test) + { + if ($test instanceof PHPUnit_Extensions_Story_TestCase || + $test instanceof PHPUnit_Extensions_Story_SeleniumTestCase) { + $this->test = $test; + } else { + throw new Exception('$test must either be PHPUnit_Extensions_Story_TestCase or PHPUnit_Extensions_Story_SeleniumTestCase'); + } + } + + /** + * Adds a "Given" step to the scenario. + * + * @param array $arguments + * @return PHPUnit_Extensions_Story_TestCase + */ + public function given($arguments) + { + return $this->addStep(new PHPUnit_Extensions_Story_Given($arguments)); + } + + /** + * Adds a "When" step to the scenario. + * + * @param array $arguments + * @return PHPUnit_Extensions_Story_TestCase + */ + public function when($arguments) + { + return $this->addStep(new PHPUnit_Extensions_Story_When($arguments)); + } + + /** + * Adds a "Then" step to the scenario. + * + * @param array $arguments + * @return PHPUnit_Extensions_Story_TestCase + */ + public function then($arguments) + { + return $this->addStep(new PHPUnit_Extensions_Story_Then($arguments)); + } + + /** + * Add another step of the same type as the step that was added before. + * + * @param array $arguments + * @return PHPUnit_Extensions_Story_TestCase + */ + public function _and($arguments) + { + $lastCalledStepClass = get_class($this->steps[count($this->steps)-1]); + + return $this->addStep(new $lastCalledStepClass($arguments)); + } + + /** + * Runs this scenario. + * + * @param array $world + */ + public function run(array &$world) + { + foreach ($this->steps as $step) + { + if ($step instanceof PHPUnit_Extensions_Story_Given) { + $this->test->runGiven( + $world, $step->getAction(), $step->getArguments() + ); + } + + else if ($step instanceof PHPUnit_Extensions_Story_When) { + $this->test->runWhen( + $world, $step->getAction(), $step->getArguments() + ); + } + + else { + $this->test->runThen( + $world, $step->getAction(), $step->getArguments() + ); + } + } + } + + /** + * Adds a step to the scenario. + * + * @param PHPUnit_Extensions_Story_Step $step + * @return PHPUnit_Extensions_Story_TestCase + */ + protected function addStep(PHPUnit_Extensions_Story_Step $step) + { + $this->steps[] = $step; + + return $this->test; + } + + /** + * Returns the steps of this scenario. + * + * @return array + */ + public function getSteps() + { + return $this->steps; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/SeleniumTestCase.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/SeleniumTestCase.php new file mode 100644 index 0000000..9c047dd --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/SeleniumTestCase.php @@ -0,0 +1,204 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_Selenium + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +/** + * + * + * @package PHPUnit_Selenium + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.3 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +abstract class PHPUnit_Extensions_Story_SeleniumTestCase extends PHPUnit_Extensions_SeleniumTestCase +{ + protected $scenario; + protected $world = array(); + + public function __construct($name = NULL, array $data = array(), $dataName = '', array $browser = array()) + { + parent::__construct($name, $data, $dataName, $browser); + $this->scenario = new PHPUnit_Extensions_Story_Scenario($this); + } + + /** + * @method PHPUnit_Extensions_Story_Step and($contextOrOutcome) + */ + public function __call($command, $arguments) + { + switch($command) { + case 'and': { + return $this->scenario->_and($arguments); + } + break; + + default: { + return parent::__call($command, $arguments); + } + } + } + + /** + * Returns this test's scenario. + * + * @return PHPUnit_Extensions_Story_Scenario + */ + public function getScenario() + { + return $this->scenario; + } + + /** + * This method is used by __call + * + */ + protected function notImplemented($action) + { + if (strstr($action, ' ')) { + $this->markTestIncomplete("step: $action not implemented."); + } + + throw new BadMethodCallException("Method $action not defined."); + } + + /** + * Adds a "Given" step to the scenario. + * + * @param array $arguments + * @return PHPUnit_Extensions_Story_TestCase + */ + protected function given($context) + { + return $this->scenario->given(func_get_args()); + } + + /** + * Adds a "When" step to the scenario. + * + * @param array $arguments + * @return PHPUnit_Extensions_Story_TestCase + */ + protected function when($event) + { + return $this->scenario->when(func_get_args()); + } + + /** + * Adds a "Then" step to the scenario. + * + * @param array $arguments + * @return PHPUnit_Extensions_Story_TestCase + */ + protected function then($outcome) + { + return $this->scenario->then(func_get_args()); + } + + /** + * Add another step of the same type as the step that was added before. + * + * @param array $arguments + * @return PHPUnit_Extensions_Story_TestCase + */ + protected function _and($contextOrOutcome) + { + return $this->scenario->_and(func_get_args()); + } + + /** + * Run this test's scenario. + * + * @return mixed + * @throws RuntimeException + */ + protected function runTest() + { + $autostop = $this->autoStop; + $this->autoStop = FALSE; + + try { + $testResult = parent::runTest(); + $this->scenario->run($this->world); + $this->autoStop = $autostop; + } + + catch (Exception $e) { + $this->autoStop = $autostop; + throw $e; + } + + return $testResult; + } + + /** + * Implementation for "Given" steps. + * + * @param array $world + * @param string $action + * @param array $arguments + */ + abstract protected function runGiven(&$world, $action, $arguments); + + /** + * Implementation for "When" steps. + * + * @param array $world + * @param string $action + * @param array $arguments + */ + abstract protected function runWhen(&$world, $action, $arguments); + + /** + * Implementation for "Then" steps. + * + * @param array $world + * @param string $action + * @param array $arguments + */ + abstract protected function runThen(&$world, $action, $arguments); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Step.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Step.php new file mode 100644 index 0000000..2f42ce4 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Step.php @@ -0,0 +1,128 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +/** + * A step of a scenario. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +abstract class PHPUnit_Extensions_Story_Step +{ + /** + * @var string + */ + protected $action; + + /** + * @var array + */ + protected $arguments; + + /** + * Constructor. + * + * @param array $arguments + */ + public function __construct(array $arguments) + { + $this->action = array_shift($arguments); + $this->arguments = $arguments; + } + + /** + * Returns this step's action. + * + * @return string + */ + public function getAction() + { + return $this->action; + } + + /** + * Returns this step's arguments. + * + * @param boolean $asString + * @return array|string + */ + public function getArguments($asString = FALSE) + { + if (!$asString) { + return $this->arguments; + } else { + switch (count($this->arguments)) { + case 0: { + return ''; + } + break; + + case 1: { + return $this->arguments[0]; + } + break; + + default: { + return var_export($this->arguments, TRUE); + } + } + } + } + + /** + * Returns this step's name. + * + * @return string + */ + abstract public function getName(); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/TestCase.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/TestCase.php new file mode 100644 index 0000000..6be29c6 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/TestCase.php @@ -0,0 +1,210 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +/** + * A story test case. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +abstract class PHPUnit_Extensions_Story_TestCase extends PHPUnit_Framework_TestCase +{ + /** + * @var PHPUnit_Extensions_Story_Scenario + */ + protected $scenario; + + /** + * @var array + */ + protected $world = array(); + + /** + * Constructs a test case with the given name. + * + * @param string $name + * @param array $data + * @param string $dataName + */ + public function __construct($name = NULL, array $data = array(), $dataName = '') + { + parent::__construct($name, $data, $dataName); + $this->scenario = new PHPUnit_Extensions_Story_Scenario($this); + } + + /** + * @method PHPUnit_Extensions_Story_Step and($contextOrOutcome) + */ + public function __call($command, $arguments) + { + switch ($command) { + case 'and': { + return $this->scenario->_and($arguments); + } + break; + + default: { + throw new BadMethodCallException( + "Method $command not defined." + ); + } + } + } + + /** + * Returns this test's scenario. + * + * @return PHPUnit_Extensions_Story_Scenario + */ + public function getScenario() + { + return $this->scenario; + } + + /** + * + * + */ + protected function notImplemented($action) + { + if (strstr($action, ' ')) { + $this->markTestIncomplete("step: $action not implemented."); + } + + throw new BadMethodCallException("Method $action not defined."); + } + + /** + * Adds a "Given" step to the scenario. + * + * @param array $arguments + * @return PHPUnit_Extensions_Story_TestCase + */ + protected function given($context) + { + return $this->scenario->given(func_get_args()); + } + + /** + * Adds a "When" step to the scenario. + * + * @param array $arguments + * @return PHPUnit_Extensions_Story_TestCase + */ + protected function when($event) + { + return $this->scenario->when(func_get_args()); + } + + /** + * Adds a "Then" step to the scenario. + * + * @param array $arguments + * @return PHPUnit_Extensions_Story_TestCase + */ + protected function then($outcome) + { + return $this->scenario->then(func_get_args()); + } + + /** + * Add another step of the same type as the step that was added before. + * + * @param array $arguments + * @return PHPUnit_Extensions_Story_TestCase + */ + protected function _and($contextOrOutcome) + { + return $this->scenario->_and(func_get_args()); + } + + /** + * Run this test's scenario. + * + * @return mixed + * @throws RuntimeException + */ + protected function runTest() + { + $testResult = parent::runTest(); + $this->scenario->run($this->world); + return $testResult; + } + + /** + * Implementation for "Given" steps. + * + * @param array $world + * @param string $action + * @param array $arguments + */ + abstract protected function runGiven(&$world, $action, $arguments); + + /** + * Implementation for "When" steps. + * + * @param array $world + * @param string $action + * @param array $arguments + */ + abstract protected function runWhen(&$world, $action, $arguments); + + /** + * Implementation for "Then" steps. + * + * @param array $world + * @param string $action + * @param array $arguments + */ + abstract protected function runThen(&$world, $action, $arguments); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Then.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Then.php new file mode 100644 index 0000000..dd746ad --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/Then.php @@ -0,0 +1,71 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +/** + * A "Then" step. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Extensions_Story_Then extends PHPUnit_Extensions_Story_Step +{ + /** + * Returns this step's name. + * + * @return string + */ + public function getName() + { + return 'Then'; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/When.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/When.php new file mode 100644 index 0000000..66d13ac --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/Story/When.php @@ -0,0 +1,71 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +/** + * A "When" step. + * + * @package PHPUnit + * @subpackage Extensions_Story + * @author Mattis Stordalen Flister + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Extensions_Story_When extends PHPUnit_Extensions_Story_Step +{ + /** + * Returns this step's name. + * + * @return string + */ + public function getName() + { + return 'When'; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TestDecorator.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TestDecorator.php new file mode 100644 index 0000000..50a4e25 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TestDecorator.php @@ -0,0 +1,151 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * A Decorator for Tests. + * + * Use TestDecorator as the base class for defining new + * test decorators. Test decorator subclasses can be introduced + * to add behaviour before or after a test is run. + * + * @package PHPUnit + * @subpackage Extensions + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +class PHPUnit_Extensions_TestDecorator extends PHPUnit_Framework_Assert implements PHPUnit_Framework_Test, PHPUnit_Framework_SelfDescribing +{ + /** + * The Test to be decorated. + * + * @var object + */ + protected $test = NULL; + + /** + * Constructor. + * + * @param PHPUnit_Framework_Test $test + */ + public function __construct(PHPUnit_Framework_Test $test) + { + $this->test = $test; + } + + /** + * Returns a string representation of the test. + * + * @return string + */ + public function toString() + { + return $this->test->toString(); + } + + /** + * Runs the test and collects the + * result in a TestResult. + * + * @param PHPUnit_Framework_TestResult $result + */ + public function basicRun(PHPUnit_Framework_TestResult $result) + { + $this->test->run($result); + } + + /** + * Counts the number of test cases that + * will be run by this test. + * + * @return integer + */ + public function count() + { + return count($this->test); + } + + /** + * Creates a default TestResult object. + * + * @return PHPUnit_Framework_TestResult + */ + protected function createResult() + { + return new PHPUnit_Framework_TestResult; + } + + /** + * Returns the test to be run. + * + * @return PHPUnit_Framework_Test + */ + public function getTest() + { + return $this->test; + } + + /** + * Runs the decorated test and collects the + * result in a TestResult. + * + * @param PHPUnit_Framework_TestResult $result + * @return PHPUnit_Framework_TestResult + * @throws InvalidArgumentException + */ + public function run(PHPUnit_Framework_TestResult $result = NULL) + { + if ($result === NULL) { + $result = $this->createResult(); + } + + $this->basicRun($result); + + return $result; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener.php new file mode 100644 index 0000000..c9e2d70 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener.php @@ -0,0 +1,225 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions_TicketListener + * @author Sean Coates + * @author Raphael Stolt + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.4.0 + */ + +/** + * Base class for test listeners that interact with an issue tracker. + * + * @package PHPUnit + * @subpackage Extensions_TicketListener + * @author Sean Coates + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.4.0 + */ +abstract class PHPUnit_Extensions_TicketListener implements PHPUnit_Framework_TestListener +{ + /** + * @var array + */ + protected $ticketCounts = array(); + + /** + * @var boolean + */ + protected $ran = FALSE; + + /** + * An error occurred. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) + { + } + + /** + * A failure occurred. + * + * @param PHPUnit_Framework_Test $test + * @param PHPUnit_Framework_AssertionFailedError $e + * @param float $time + */ + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) + { + } + + /** + * Incomplete test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + } + + /** + * Skipped test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + * @since Method available since Release 3.0.0 + */ + public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + } + + /** + * A test suite started. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit_Framework_TestSuite $suite) + { + } + + /** + * A test suite ended. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit_Framework_TestSuite $suite) + { + } + + /** + * A test started. + * + * @param PHPUnit_Framework_Test $test + */ + public function startTest(PHPUnit_Framework_Test $test) + { + if (!$test instanceof PHPUnit_Framework_Warning) { + if ($this->ran) { + return; + } + + $name = $test->getName(FALSE); + $tickets = PHPUnit_Util_Test::getTickets(get_class($test), $name); + + foreach ($tickets as $ticket) { + $this->ticketCounts[$ticket][$name] = 1; + } + + $this->ran = TRUE; + } + } + + /** + * A test ended. + * + * @param PHPUnit_Framework_Test $test + * @param float $time + */ + public function endTest(PHPUnit_Framework_Test $test, $time) + { + if (!$test instanceof PHPUnit_Framework_Warning) { + if ($test->getStatus() == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) { + $ifStatus = array('assigned', 'new', 'reopened'); + $newStatus = 'closed'; + $message = 'Automatically closed by PHPUnit (test passed).'; + $resolution = 'fixed'; + $cumulative = TRUE; + } + + else if ($test->getStatus() == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE) { + $ifStatus = array('closed'); + $newStatus = 'reopened'; + $message = 'Automatically reopened by PHPUnit (test failed).'; + $resolution = ''; + $cumulative = FALSE; + } + + else { + return; + } + + $name = $test->getName(FALSE); + $tickets = PHPUnit_Util_Test::getTickets(get_class($test), $name); + + foreach ($tickets as $ticket) { + // Remove this test from the totals (if it passed). + if ($test->getStatus() == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) { + unset($this->ticketCounts[$ticket][$name]); + } + + // Only close tickets if ALL referenced cases pass + // but reopen tickets if a single test fails. + if ($cumulative) { + // Determine number of to-pass tests: + if (count($this->ticketCounts[$ticket]) > 0) { + // There exist remaining test cases with this reference. + $adjustTicket = FALSE; + } else { + // No remaining tickets, go ahead and adjust. + $adjustTicket = TRUE; + } + } else { + $adjustTicket = TRUE; + } + + $ticketInfo = $this->getTicketInfo($ticket); + + if ($adjustTicket && in_array($ticketInfo['status'], $ifStatus)) { + $this->updateTicket($ticket, $newStatus, $message, $resolution); + } + } + } + } + + abstract protected function getTicketInfo($ticketId = NULL); + abstract protected function updateTicket($ticketId, $newStatus, $message, $resolution); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener/GitHub.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener/GitHub.php new file mode 100644 index 0000000..11c277a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener/GitHub.php @@ -0,0 +1,204 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions_TicketListener + * @author Raphael Stolt + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.5.0 + */ + +/** + * A ticket listener that interacts with the GitHub issue API. + * + * @package PHPUnit + * @subpackage Extensions_TicketListener + * @author Raphael Stolt + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.5.0 + */ +class PHPUnit_Extensions_TicketListener_GitHub extends PHPUnit_Extensions_TicketListener +{ + const STATUS_CLOSE = 'closed'; + const STATUS_REOPEN = 'reopened'; + + private $username; + private $apiToken; + private $repository; + private $apiPath = 'http://github.com/api/v2/json/issues'; + private $printTicketStateChanges; + + /** + * @param string $username The username associated with the GitHub account. + * @param string $apiToken The API token associated with the GitHub account. + * @param string $repository The repository of the system under test (SUT) on GitHub. + * @param string $printTicketChanges Boolean flag to print the ticket state + * changes in the test result. + * @throws RuntimeException + */ + public function __construct($username, $apiToken, $repository, $printTicketStateChanges = FALSE) + { + if (!extension_loaded('curl')) { + throw new RuntimeException('ext/curl is not available'); + } + + if (!extension_loaded('json')) { + throw new RuntimeException('ext/json is not available'); + } + + $this->username = $username; + $this->apiToken = $apiToken; + $this->repository = $repository; + $this->printTicketStateChanges = $printTicketStateChanges; + } + + /** + * @param integer $ticketId + * @return string + * @throws RuntimeException + */ + public function getTicketInfo($ticketId = NULL) + { + if (!is_numeric($ticketId)) { + return array('status' => 'invalid_ticket_id'); + } + + $ticket = $this->callGitHub( + $this->apiPath . '/show/' . $this->username . '/' . + $this->repository . '/' . $ticketId, + TRUE + ); + + if ($ticket['state'] === 'open') { + return array('status' => 'new'); + } + + if ($ticket['state'] === 'closed') { + return array('status' => 'closed'); + } + + if ($ticket['state'] === 'unknown_ticket') { + return array('status' => 'unknown_ticket'); + } + } + + /** + * @param string $ticketId The ticket number of the ticket under test (TUT). + * @param string $statusToBe The status of the TUT after running the associated test. + * @param string $message The additional message for the TUT. + * @param string $resolution The resolution for the TUT. + * @throws RuntimeException + */ + protected function updateTicket($ticketId, $statusToBe, $message, $resolution) + { + $acceptedResponseIssueStates = array('open', 'closed'); + + if ($statusToBe === self::STATUS_CLOSE) { + $apiEndpoint = $this->apiPath . '/close/' . + $this->username . '/' . $this->repository . '/' . + $ticketId; + } + + else if ($statusToBe === self::STATUS_REOPEN) { + $apiEndpoint = $this->apiPath . '/reopen/' . + $this->username . '/' . $this->repository . '/' . + $ticketId; + } + + if (isset($apiEndpoint)) { + $ticket = $this->callGitHub($apiEndpoint); + + if (!in_array($ticket['state'], $acceptedResponseIssueStates)) { + throw new RuntimeException( + 'Received an unaccepted issue state from the GitHub Api' + ); + } + + if ($this->printTicketStateChanges) { + printf( + "\nUpdating GitHub issue #%d, status: %s\n", + $ticketId, + $statusToBe + ); + } + } + } + + /** + * @param string $apiEndpoint API endpoint to call against the GitHub issue API. + * @param boolean $isShowMethodCall Show method of the GitHub issue API is called? + * @return array + * @throws RuntimeException + */ + private function callGitHub($apiEndpoint, $isShowMethodCall = FALSE) + { + $curlHandle = curl_init(); + + curl_setopt($curlHandle, CURLOPT_URL, $apiEndpoint); + curl_setopt($curlHandle, CURLOPT_FOLLOWLOCATION, TRUE); + curl_setopt($curlHandle, CURLOPT_FAILONERROR, TRUE); + curl_setopt($curlHandle, CURLOPT_FRESH_CONNECT, TRUE); + curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($curlHandle, CURLOPT_HTTPPROXYTUNNEL, TRUE); + curl_setopt($curlHandle, CURLOPT_USERAGENT, __CLASS__); + curl_setopt( + $curlHandle, + CURLOPT_POSTFIELDS, + 'login=' . $this->username . '&token=' . $this->apiToken + ); + + $response = curl_exec($curlHandle); + + if (!$response && $isShowMethodCall) { + return array('state' => 'unknown_ticket'); + } + + if (!$response) { + throw new RuntimeException(curl_error($curlHandle)); + } + + curl_close($curlHandle); + + $issue = (array)json_decode($response); + + return (array)$issue['issue']; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener/GoogleCode.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener/GoogleCode.php new file mode 100644 index 0000000..96e7e1d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener/GoogleCode.php @@ -0,0 +1,275 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Extensions_TicketListener + * @author Jan Sorgalla + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.5.0 + */ + +/** + * A ticket listener that interacts with the GoogleCode issue API. + * + * @package PHPUnit + * @subpackage Extensions_TicketListener + * @author Jan Sorgalla + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.5.0 + */ +class PHPUnit_Extensions_TicketListener_GoogleCode extends PHPUnit_Extensions_TicketListener +{ + private $email; + private $password; + private $project; + + private $statusClosed; + private $statusReopened; + + private $printTicketStateChanges; + + private $authUrl = 'https://www.google.com/accounts/ClientLogin'; + private $apiBaseUrl = 'http://code.google.com/feeds/issues/p/%s/issues'; + private $authToken; + + /** + * @param string $email The email associated with the Google account. + * @param string $password The password associated with the Google account. + * @param string $project The project name of the system under test (SUT) on Google Code. + * @param string $printTicketChanges Boolean flag to print the ticket state changes in the test result. + * @param string $statusClosed The status name of the closed state. + * @param string $statusReopened The status name of the reopened state. + * @throws RuntimeException + */ + public function __construct($email, $password, $project, $printTicketStateChanges = FALSE, $statusClosed = 'Fixed', $statusReopened = 'Started') + { + if (!extension_loaded('curl')) { + throw new RuntimeException('ext/curl is not available'); + } + + if (!extension_loaded('simplexml')) { + throw new RuntimeException('ext/simplexml is not available'); + } + + $this->email = $email; + $this->password = $password; + $this->project = $project; + $this->statusClosed = $statusClosed; + $this->statusReopened = $statusReopened; + $this->printTicketStateChanges = $printTicketStateChanges; + $this->apiBaseUrl = sprintf($this->apiBaseUrl, $project); + } + + /** + * @param integer $ticketId + * @return array + * @throws RuntimeException + */ + public function getTicketInfo($ticketId = NULL) + { + if (!is_numeric($ticketId)) { + return array('status' => 'invalid_ticket_id'); + } + + $url = $this->apiBaseUrl . '/full/' . $ticketId; + $header = array( + 'Authorization: GoogleLogin auth=' . $this->getAuthToken() + ); + + list($status, $response) = $this->callGoogleCode($url, $header); + + if ($status != 200 || !$response) { + return array('state' => 'unknown_ticket'); + } + + $ticket = new SimpleXMLElement(str_replace("xmlns=", "ns=", $response)); + $result = $ticket->xpath('//issues:state'); + $state = (string)$result[0]; + + if ($state === 'open') { + return array('status' => 'new'); + } + + if ($state === 'closed') { + return array('status' => 'closed'); + } + + return array('status' => $state); + } + + /** + * @param string $ticketId The ticket number of the ticket under test (TUT). + * @param string $statusToBe The status of the TUT after running the associated test. + * @param string $message The additional message for the TUT. + * @param string $resolution The resolution for the TUT. + * @throws RuntimeException + */ + protected function updateTicket($ticketId, $statusToBe, $message, $resolution) + { + $url = $this->apiBaseUrl . '/' . $ticketId . '/comments/full'; + + $header = array( + 'Authorization: GoogleLogin auth=' . $this->getAuthToken(), + 'Content-Type: application/atom+xml' + ); + + if ($statusToBe == 'closed') { + $ticketStatus = $this->statusClosed; + } else { + $ticketStatus = $this->statusReopened; + } + + list($author,) = explode('@', $this->email); + + $post = '' . + '' . + ' ' . htmlspecialchars($message, ENT_COMPAT, 'UTF-8') . '' . + ' ' . + ' ' . htmlspecialchars($author, ENT_COMPAT, 'UTF-8') . '' . + ' ' . + ' ' . + ' ' . htmlspecialchars($ticketStatus, ENT_COMPAT, 'UTF-8') . '' . + ' ' . + ''; + + list($status, $response) = $this->callGoogleCode($url, $header, $post); + + if ($status != 201) { + throw new RuntimeException('Updating GoogleCode issue failed with status code ' . $status); + } + + if ($this->printTicketStateChanges) { + printf( + "\nUpdating GoogleCode issue #%d, status: %s\n", + $ticketId, + $statusToBe + ); + } + } + + /** + * @return string The auth token + * @throws RuntimeException + */ + private function getAuthToken() + { + if (NULL !== $this->authToken) { + return $this->authToken; + } + + $header = array( + 'Content-Type: application/x-www-form-urlencoded', + ); + + $post = array( + 'accountType' => 'GOOGLE', + 'Email' => $this->email, + 'Passwd' => $this->password, + 'service' => 'code', + 'source' => 'PHPUnit-TicketListener_GoogleCode-' . PHPUnit_Runner_Version::id(), + ); + + list($status, $response) = $this->callGoogleCode( + $this->authUrl, + $header, + http_build_query($post, NULL, '&') + ); + + if ($status != 200) { + throw new RuntimeException('Google account authentication failed'); + } + + foreach (explode("\n", $response) as $line) { + if (strpos(trim($line), 'Auth') === 0) { + list($name, $token) = explode('=', $line); + $this->authToken = trim($token); + break; + } + } + + if (NULL === $this->authToken) { + throw new RuntimeException('Could not detect auth token in response'); + } + + return $this->authToken; + } + + /** + * @param string $url URL to call + * @param array $header Header + * @param string $post Post data + * @return array + */ + private function callGoogleCode($url, array $header = NULL, $post = NULL) + { + $curlHandle = curl_init(); + + curl_setopt($curlHandle, CURLOPT_URL, $url); + curl_setopt($curlHandle, CURLOPT_FOLLOWLOCATION, TRUE); + curl_setopt($curlHandle, CURLOPT_FAILONERROR, TRUE); + curl_setopt($curlHandle, CURLOPT_FRESH_CONNECT, TRUE); + curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($curlHandle, CURLOPT_HTTPPROXYTUNNEL, TRUE); + curl_setopt($curlHandle, CURLOPT_USERAGENT, __CLASS__); + curl_setopt($curlHandle, CURLOPT_SSL_VERIFYPEER, FALSE); + + if (NULL !== $header) { + curl_setopt($curlHandle, CURLOPT_HTTPHEADER, $header); + } + + if (NULL !== $post) { + curl_setopt($curlHandle, CURLOPT_POST, TRUE); + curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $post); + } + + $response = curl_exec($curlHandle); + $status = curl_getinfo($curlHandle, CURLINFO_HTTP_CODE); + + if (!$response) { + throw new RuntimeException(curl_error($curlHandle)); + } + + curl_close($curlHandle); + + return array($status, $response); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener/Trac.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener/Trac.php new file mode 100644 index 0000000..1e323cc --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Extensions/TicketListener/Trac.php @@ -0,0 +1,189 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit + * @author Graham Christensen + * @author Sean Coates + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since Class available since Release 3.5.4 + */ + +/** + * A ticket listener that interacts with Trac. + * + * + * + * + * + * + * + * + * trac_username + * trac_password + * + * + * 127.0.0.1/trac/login/xmlrpc + * + * + * + * + * + * + * @category Testing + * @package PHPUnit + * @author Graham Christensen + * @author Sean Coates + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.5.4 + */ +class PHPUnit_Extensions_TicketListener_Trac extends PHPUnit_Extensions_TicketListener +{ + protected $username; + protected $password; + protected $hostpath; + protected $scheme; + private $printTicketStateChanges; + + /** + * Constructor + * + * @param string $username Trac-XMLRPC username + * @param string $password Trac-XMLRPC password + * @param string $hostpath Trac-XMLRPC Host+Path (e.g. example.com/trac/login/xmlrpc) + * @param string $scheme Trac scheme (http or https) + * @param bool $printTicketStateChanges To display changes or not + */ + public function __construct($username, $password, $hostpath, $scheme = 'http', $printTicketStateChanges = FALSE) + { + $this->username = $username; + $this->password = $password; + $this->hostpath = $hostpath; + $this->scheme = $scheme; + $this->printTicketStateChanges = $printTicketStateChanges; + } + + /** + * Get the status of a ticket message + * + * @param integer $ticketId The ticket ID + * @return array('status' => $status) ($status = new|closed|unknown_ticket) + */ + public function getTicketInfo($ticketId = NULL) + { + if (!is_numeric($ticketId)) { + return array('status' => 'invalid_ticket_id'); + } + + try { + $info = $this->getClient()->get($ticketId); + + switch ($info[3]['status']) { + case 'closed': { + return array('status' => 'closed'); + } + break; + + case 'new': + case 'reopened': { + return array('status' => 'new'); + } + break; + + default: { + return array('status' => 'unknown_ticket'); + } + } + } + + catch (Exception $e) { + return array('status' => 'unknown_ticket'); + } + } + + /** + * Update a ticket with a new status + * + * @param string $ticketId The ticket number of the ticket under test (TUT). + * @param string $statusToBe The status of the TUT after running the associated test. + * @param string $message The additional message for the TUT. + * @param string $resolution The resolution for the TUT. + */ + protected function updateTicket($ticketId, $statusToBe, $message, $resolution) + { + $change = array('status' => $statusToBe, 'resolution' => $resolution); + + $this->getClient()->update((int)$ticketId, $message, $change); + + if ($this->printTicketStateChanges) { + printf( + "\nUpdating Trac issue #%d, status: %s\n", $ticketId, $statusToBe + ); + } + } + + /** + * Get a Trac XML_RPC2 client + * + * @return XML_RPC2_Client + */ + protected function getClient() + { + if (!PHPUnit_Util_Filesystem::fileExistsInIncludePath('XML/RPC2/Client.php')) { + throw new PHPUnit_Framework_Exception('PEAR/XML_RPC2 is not available.'); + } + + require_once 'XML/RPC2/Client.php'; + + $url = sprintf( + '%s://%s:%s@%s', + $this->scheme, + $this->username, + $this->password, + $this->hostpath + ); + + return XML_RPC2_Client::create($url, array('prefix' => 'ticket.')); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework.php new file mode 100644 index 0000000..55d0b5c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework.php @@ -0,0 +1,50 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +require_once 'PHP/CodeCoverage/Filter.php'; +PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'PHPUNIT'); + +trigger_error( + 'Please no longer include "PHPUnit/Framework.php".', E_USER_NOTICE +); diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Assert.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Assert.php new file mode 100644 index 0000000..02ce907 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Assert.php @@ -0,0 +1,2620 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * A set of assert methods. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +abstract class PHPUnit_Framework_Assert +{ + /** + * @var integer + */ + private static $count = 0; + + /** + * Asserts that an array has a specified key. + * + * @param mixed $key + * @param array $array + * @param string $message + * @since Method available since Release 3.0.0 + */ + public static function assertArrayHasKey($key, array $array, $message = '') + { + if (!(is_integer($key) || is_string($key))) { + throw PHPUnit_Util_InvalidArgumentHelper::factory( + 1, 'integer or string' + ); + } + + $constraint = new PHPUnit_Framework_Constraint_ArrayHasKey($key); + + self::assertThat($array, $constraint, $message); + } + + /** + * Asserts that an array does not have a specified key. + * + * @param mixed $key + * @param array $array + * @param string $message + * @since Method available since Release 3.0.0 + */ + public static function assertArrayNotHasKey($key, array $array, $message = '') + { + if (!(is_integer($key) || is_string($key))) { + throw PHPUnit_Util_InvalidArgumentHelper::factory( + 1, 'integer or string' + ); + } + + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_ArrayHasKey($key) + ); + + self::assertThat($array, $constraint, $message); + } + + /** + * Asserts that a haystack contains a needle. + * + * @param mixed $needle + * @param mixed $haystack + * @param string $message + * @param boolean $ignoreCase + * @since Method available since Release 2.1.0 + */ + public static function assertContains($needle, $haystack, $message = '', $ignoreCase = FALSE) + { + if (is_array($haystack) || + is_object($haystack) && $haystack instanceof Traversable) { + $constraint = new PHPUnit_Framework_Constraint_TraversableContains( + $needle + ); + } + + else if (is_string($haystack)) { + $constraint = new PHPUnit_Framework_Constraint_StringContains( + $needle, $ignoreCase + ); + } + + else { + throw PHPUnit_Util_InvalidArgumentHelper::factory( + 2, 'array, iterator or string' + ); + } + + self::assertThat($haystack, $constraint, $message); + } + + /** + * Asserts that a haystack that is stored in a static attribute of a class + * or an attribute of an object contains a needle. + * + * @param mixed $needle + * @param string $haystackAttributeName + * @param mixed $haystackClassOrObject + * @param string $message + * @param boolean $ignoreCase + * @since Method available since Release 3.0.0 + */ + public static function assertAttributeContains($needle, $haystackAttributeName, $haystackClassOrObject, $message = '', $ignoreCase = FALSE) + { + self::assertContains( + $needle, + self::readAttribute($haystackClassOrObject, $haystackAttributeName), + $message, + $ignoreCase + ); + } + + /** + * Asserts that a haystack does not contain a needle. + * + * @param mixed $needle + * @param mixed $haystack + * @param string $message + * @param boolean $ignoreCase + * @since Method available since Release 2.1.0 + */ + public static function assertNotContains($needle, $haystack, $message = '', $ignoreCase = FALSE) + { + if (is_array($haystack) || + is_object($haystack) && $haystack instanceof Traversable) { + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_TraversableContains($needle) + ); + } + + else if (is_string($haystack)) { + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_StringContains( + $needle, $ignoreCase + ) + ); + } + + else { + throw PHPUnit_Util_InvalidArgumentHelper::factory( + 2, 'array, iterator or string' + ); + } + + self::assertThat($haystack, $constraint, $message); + } + + /** + * Asserts that a haystack that is stored in a static attribute of a class + * or an attribute of an object does not contain a needle. + * + * @param mixed $needle + * @param string $haystackAttributeName + * @param mixed $haystackClassOrObject + * @param string $message + * @param boolean $ignoreCase + * @since Method available since Release 3.0.0 + */ + public static function assertAttributeNotContains($needle, $haystackAttributeName, $haystackClassOrObject, $message = '', $ignoreCase = FALSE) + { + self::assertNotContains( + $needle, + self::readAttribute($haystackClassOrObject, $haystackAttributeName), + $message, + $ignoreCase + ); + } + + /** + * Asserts that a haystack contains only values of a given type. + * + * @param string $type + * @param mixed $haystack + * @param boolean $isNativeType + * @param string $message + * @since Method available since Release 3.1.4 + */ + public static function assertContainsOnly($type, $haystack, $isNativeType = NULL, $message = '') + { + if (!(is_array($haystack) || + is_object($haystack) && $haystack instanceof Traversable)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory( + 2, 'array or iterator' + ); + } + + if ($isNativeType == NULL) { + $isNativeType = PHPUnit_Util_Type::isType($type); + } + + self::assertThat( + $haystack, + new PHPUnit_Framework_Constraint_TraversableContainsOnly( + $type, $isNativeType + ), + $message + ); + } + + /** + * Asserts that a haystack that is stored in a static attribute of a class + * or an attribute of an object contains only values of a given type. + * + * @param string $type + * @param string $haystackAttributeName + * @param mixed $haystackClassOrObject + * @param boolean $isNativeType + * @param string $message + * @since Method available since Release 3.1.4 + */ + public static function assertAttributeContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType = NULL, $message = '') + { + self::assertContainsOnly( + $type, + self::readAttribute($haystackClassOrObject, $haystackAttributeName), + $isNativeType, + $message + ); + } + + /** + * Asserts that a haystack does not contain only values of a given type. + * + * @param string $type + * @param mixed $haystack + * @param boolean $isNativeType + * @param string $message + * @since Method available since Release 3.1.4 + */ + public static function assertNotContainsOnly($type, $haystack, $isNativeType = NULL, $message = '') + { + if (!(is_array($haystack) || + is_object($haystack) && $haystack instanceof Traversable)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory( + 2, 'array or iterator' + ); + } + + if ($isNativeType == NULL) { + $isNativeType = PHPUnit_Util_Type::isType($type); + } + + self::assertThat( + $haystack, + new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_TraversableContainsOnly( + $type, $isNativeType + ) + ), + $message + ); + } + + /** + * Asserts that a haystack that is stored in a static attribute of a class + * or an attribute of an object does not contain only values of a given + * type. + * + * @param string $type + * @param string $haystackAttributeName + * @param mixed $haystackClassOrObject + * @param boolean $isNativeType + * @param string $message + * @since Method available since Release 3.1.4 + */ + public static function assertAttributeNotContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType = NULL, $message = '') + { + self::assertNotContainsOnly( + $type, + self::readAttribute($haystackClassOrObject, $haystackAttributeName), + $isNativeType, + $message + ); + } + + /** + * Asserts that two variables are equal. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @param float $delta + * @param integer $maxDepth + * @param boolean $canonicalize + * @param boolean $ignoreCase + */ + public static function assertEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) + { + $constraint = new PHPUnit_Framework_Constraint_IsEqual( + $expected, $delta, $maxDepth, $canonicalize, $ignoreCase + ); + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that a variable is equal to an attribute of an object. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param string $actualClassOrObject + * @param string $message + * @param float $delta + * @param integer $maxDepth + * @param boolean $canonicalize + * @param boolean $ignoreCase + */ + public static function assertAttributeEquals($expected, $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) + { + self::assertEquals( + $expected, + self::readAttribute($actualClassOrObject, $actualAttributeName), + $message, + $delta, + $maxDepth, + $canonicalize, + $ignoreCase + ); + } + + /** + * Asserts that two variables are not equal. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @param float $delta + * @param integer $maxDepth + * @param boolean $canonicalize + * @param boolean $ignoreCase + * @since Method available since Release 2.3.0 + */ + public static function assertNotEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) + { + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_IsEqual( + $expected, $delta, $maxDepth, $canonicalize, $ignoreCase + ) + ); + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that a variable is not equal to an attribute of an object. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param string $actualClassOrObject + * @param string $message + * @param float $delta + * @param integer $maxDepth + * @param boolean $canonicalize + * @param boolean $ignoreCase + */ + public static function assertAttributeNotEquals($expected, $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) + { + self::assertNotEquals( + $expected, + self::readAttribute($actualClassOrObject, $actualAttributeName), + $message, + $delta, + $maxDepth, + $canonicalize, + $ignoreCase + ); + } + + /** + * Asserts that a variable is empty. + * + * @param mixed $actual + * @param string $message + * @throws PHPUnit_Framework_AssertionFailedError + */ + public static function assertEmpty($actual, $message = '') + { + self::assertThat($actual, self::isEmpty(), $message); + } + + /** + * Asserts that a static attribute of a class or an attribute of an object + * is empty. + * + * @param string $haystackAttributeName + * @param mixed $haystackClassOrObject + * @param string $message + * @since Method available since Release 3.5.0 + */ + public static function assertAttributeEmpty($haystackAttributeName, $haystackClassOrObject, $message = '') + { + self::assertEmpty( + self::readAttribute($haystackClassOrObject, $haystackAttributeName), + $message + ); + } + + /** + * Asserts that a variable is not empty. + * + * @param mixed $actual + * @param string $message + * @throws PHPUnit_Framework_AssertionFailedError + */ + public static function assertNotEmpty($actual, $message = '') + { + self::assertThat($actual, self::logicalNot(self::isEmpty()), $message); + } + + /** + * Asserts that a static attribute of a class or an attribute of an object + * is not empty. + * + * @param string $haystackAttributeName + * @param mixed $haystackClassOrObject + * @param string $message + * @since Method available since Release 3.5.0 + */ + public static function assertAttributeNotEmpty($haystackAttributeName, $haystackClassOrObject, $message = '') + { + self::assertNotEmpty( + self::readAttribute($haystackClassOrObject, $haystackAttributeName), + $message + ); + } + + /** + * Asserts that a value is greater than another value. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertGreaterThan($expected, $actual, $message = '') + { + self::assertThat($actual, self::greaterThan($expected), $message); + } + + /** + * Asserts that an attribute is greater than another value. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param string $actualClassOrObject + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertAttributeGreaterThan($expected, $actualAttributeName, $actualClassOrObject, $message = '') + { + self::assertGreaterThan( + $expected, + self::readAttribute($actualClassOrObject, $actualAttributeName), + $message + ); + } + + /** + * Asserts that a value is greater than or equal to another value. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertGreaterThanOrEqual($expected, $actual, $message = '') + { + self::assertThat( + $actual, self::greaterThanOrEqual($expected), $message + ); + } + + /** + * Asserts that an attribute is greater than or equal to another value. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param string $actualClassOrObject + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertAttributeGreaterThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message = '') + { + self::assertGreaterThanOrEqual( + $expected, + self::readAttribute($actualClassOrObject, $actualAttributeName), + $message + ); + } + + /** + * Asserts that a value is smaller than another value. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertLessThan($expected, $actual, $message = '') + { + self::assertThat($actual, self::lessThan($expected), $message); + } + + /** + * Asserts that an attribute is smaller than another value. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param string $actualClassOrObject + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertAttributeLessThan($expected, $actualAttributeName, $actualClassOrObject, $message = '') + { + self::assertLessThan( + $expected, + self::readAttribute($actualClassOrObject, $actualAttributeName), + $message + ); + } + + /** + * Asserts that a value is smaller than or equal to another value. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertLessThanOrEqual($expected, $actual, $message = '') + { + self::assertThat($actual, self::lessThanOrEqual($expected), $message); + } + + /** + * Asserts that an attribute is smaller than or equal to another value. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param string $actualClassOrObject + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertAttributeLessThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message = '') + { + self::assertLessThanOrEqual( + $expected, + self::readAttribute($actualClassOrObject, $actualAttributeName), + $message + ); + } + + /** + * Asserts that the contents of one file is equal to the contents of another + * file. + * + * @param string $expected + * @param string $actual + * @param string $message + * @param boolean $canonicalize + * @param boolean $ignoreCase + * @since Method available since Release 3.2.14 + */ + public static function assertFileEquals($expected, $actual, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) + { + self::assertFileExists($expected, $message); + self::assertFileExists($actual, $message); + + self::assertEquals( + file_get_contents($expected), + file_get_contents($actual), + $message, + 0, + 10, + $canonicalize, + $ignoreCase + ); + } + + /** + * Asserts that the contents of one file is not equal to the contents of + * another file. + * + * @param string $expected + * @param string $actual + * @param string $message + * @param boolean $canonicalize + * @param boolean $ignoreCase + * @since Method available since Release 3.2.14 + */ + public static function assertFileNotEquals($expected, $actual, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) + { + self::assertFileExists($expected, $message); + self::assertFileExists($actual, $message); + + self::assertNotEquals( + file_get_contents($expected), + file_get_contents($actual), + $message, + 0, + 10, + $canonicalize, + $ignoreCase + ); + } + + /** + * Asserts that the contents of a string is equal + * to the contents of a file. + * + * @param string $expectedFile + * @param string $actualString + * @param string $message + * @param boolean $canonicalize + * @param boolean $ignoreCase + * @since Method available since Release 3.3.0 + */ + public static function assertStringEqualsFile($expectedFile, $actualString, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) + { + self::assertFileExists($expectedFile, $message); + + self::assertEquals( + file_get_contents($expectedFile), + $actualString, + $message, + 0, + 10, + $canonicalize, + $ignoreCase + ); + } + + /** + * Asserts that the contents of a string is not equal + * to the contents of a file. + * + * @param string $expectedFile + * @param string $actualString + * @param string $message + * @param boolean $canonicalize + * @param boolean $ignoreCase + * @since Method available since Release 3.3.0 + */ + public static function assertStringNotEqualsFile($expectedFile, $actualString, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) + { + self::assertFileExists($expectedFile, $message); + + self::assertNotEquals( + file_get_contents($expectedFile), + $actualString, + $message, + 0, + 10, + $canonicalize, + $ignoreCase + ); + } + + /** + * Asserts that a file exists. + * + * @param string $filename + * @param string $message + * @since Method available since Release 3.0.0 + */ + public static function assertFileExists($filename, $message = '') + { + if (!is_string($filename)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + $constraint = new PHPUnit_Framework_Constraint_FileExists; + + self::assertThat($filename, $constraint, $message); + } + + /** + * Asserts that a file does not exist. + * + * @param string $filename + * @param string $message + * @since Method available since Release 3.0.0 + */ + public static function assertFileNotExists($filename, $message = '') + { + if (!is_string($filename)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_FileExists + ); + + self::assertThat($filename, $constraint, $message); + } + + /** + * Asserts that a condition is true. + * + * @param boolean $condition + * @param string $message + * @throws PHPUnit_Framework_AssertionFailedError + */ + public static function assertTrue($condition, $message = '') + { + self::assertThat($condition, self::isTrue(), $message); + } + + /** + * Asserts that a condition is false. + * + * @param boolean $condition + * @param string $message + * @throws PHPUnit_Framework_AssertionFailedError + */ + public static function assertFalse($condition, $message = '') + { + self::assertThat($condition, self::isFalse(), $message); + } + + /** + * Asserts that a variable is not NULL. + * + * @param mixed $actual + * @param string $message + */ + public static function assertNotNull($actual, $message = '') + { + self::assertThat($actual, self::logicalNot(self::isNull()), $message); + } + + /** + * Asserts that a variable is NULL. + * + * @param mixed $actual + * @param string $message + */ + public static function assertNull($actual, $message = '') + { + self::assertThat($actual, self::isNull(), $message); + } + + /** + * Asserts that a class has a specified attribute. + * + * @param string $attributeName + * @param string $className + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertClassHasAttribute($attributeName, $className, $message = '') + { + if (!is_string($attributeName)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_string($className) || !class_exists($className, FALSE)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'class name'); + } + + $constraint = new PHPUnit_Framework_Constraint_ClassHasAttribute( + $attributeName + ); + + self::assertThat($className, $constraint, $message); + } + + /** + * Asserts that a class does not have a specified attribute. + * + * @param string $attributeName + * @param string $className + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertClassNotHasAttribute($attributeName, $className, $message = '') + { + if (!is_string($attributeName)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_string($className) || !class_exists($className, FALSE)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'class name'); + } + + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_ClassHasAttribute($attributeName) + ); + + self::assertThat($className, $constraint, $message); + } + + /** + * Asserts that a class has a specified static attribute. + * + * @param string $attributeName + * @param string $className + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertClassHasStaticAttribute($attributeName, $className, $message = '') + { + if (!is_string($attributeName)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_string($className) || !class_exists($className, FALSE)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'class name'); + } + + $constraint = new PHPUnit_Framework_Constraint_ClassHasStaticAttribute( + $attributeName + ); + + self::assertThat($className, $constraint, $message); + } + + /** + * Asserts that a class does not have a specified static attribute. + * + * @param string $attributeName + * @param string $className + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertClassNotHasStaticAttribute($attributeName, $className, $message = '') + { + if (!is_string($attributeName)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_string($className) || !class_exists($className, FALSE)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'class name'); + } + + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_ClassHasStaticAttribute( + $attributeName + ) + ); + + self::assertThat($className, $constraint, $message); + } + + /** + * Asserts that an object has a specified attribute. + * + * @param string $attributeName + * @param object $object + * @param string $message + * @since Method available since Release 3.0.0 + */ + public static function assertObjectHasAttribute($attributeName, $object, $message = '') + { + if (!is_string($attributeName)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_object($object)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'object'); + } + + $constraint = new PHPUnit_Framework_Constraint_ObjectHasAttribute( + $attributeName + ); + + self::assertThat($object, $constraint, $message); + } + + /** + * Asserts that an object does not have a specified attribute. + * + * @param string $attributeName + * @param object $object + * @param string $message + * @since Method available since Release 3.0.0 + */ + public static function assertObjectNotHasAttribute($attributeName, $object, $message = '') + { + if (!is_string($attributeName)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_object($object)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'object'); + } + + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_ObjectHasAttribute($attributeName) + ); + + self::assertThat($object, $constraint, $message); + } + + /** + * Asserts that two variables have the same type and value. + * Used on objects, it asserts that two variables reference + * the same object. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + */ + public static function assertSame($expected, $actual, $message = '') + { + if (is_bool($expected) && is_bool($actual)) { + self::assertEquals($expected, $actual, $message); + } else { + $constraint = new PHPUnit_Framework_Constraint_IsIdentical( + $expected + ); + + self::assertThat($actual, $constraint, $message); + } + } + + /** + * Asserts that a variable and an attribute of an object have the same type + * and value. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param object $actualClassOrObject + * @param string $message + */ + public static function assertAttributeSame($expected, $actualAttributeName, $actualClassOrObject, $message = '') + { + self::assertSame( + $expected, + self::readAttribute($actualClassOrObject, $actualAttributeName), + $message + ); + } + + /** + * Asserts that two variables do not have the same type and value. + * Used on objects, it asserts that two variables do not reference + * the same object. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + */ + public static function assertNotSame($expected, $actual, $message = '') + { + if (is_bool($expected) && is_bool($actual)) { + self::assertNotEquals($expected, $actual, $message); + } else { + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_IsIdentical($expected) + ); + + self::assertThat($actual, $constraint, $message); + } + } + + /** + * Asserts that a variable and an attribute of an object do not have the + * same type and value. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param object $actualClassOrObject + * @param string $message + */ + public static function assertAttributeNotSame($expected, $actualAttributeName, $actualClassOrObject, $message = '') + { + self::assertNotSame( + $expected, + self::readAttribute($actualClassOrObject, $actualAttributeName), + $message + ); + } + + /** + * Asserts that a variable is of a given type. + * + * @param string $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.5.0 + */ + public static function assertInstanceOf($expected, $actual, $message = '') + { + if (is_string($expected)) { + if (class_exists($expected) || interface_exists($expected)) { + $constraint = new PHPUnit_Framework_Constraint_IsInstanceOf( + $expected + ); + } + + else { + throw PHPUnit_Util_InvalidArgumentHelper::factory( + 1, 'class or interface name' + ); + } + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that an attribute is of a given type. + * + * @param string $expected + * @param string $attributeName + * @param mixed $classOrObject + * @param string $message + * @since Method available since Release 3.5.0 + */ + public static function assertAttributeInstanceOf($expected, $attributeName, $classOrObject, $message = '') + { + self::assertInstanceOf( + $expected, + self::readAttribute($classOrObject, $attributeName), + $message + ); + } + + /** + * Asserts that a variable is not of a given type. + * + * @param string $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.5.0 + */ + public static function assertNotInstanceOf($expected, $actual, $message = '') + { + if (is_string($expected)) { + if (class_exists($expected) || interface_exists($expected)) { + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_IsInstanceOf($expected) + ); + } + + else { + throw PHPUnit_Util_InvalidArgumentHelper::factory( + 1, 'class or interface name' + ); + } + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that an attribute is of a given type. + * + * @param string $expected + * @param string $attributeName + * @param mixed $classOrObject + * @param string $message + * @since Method available since Release 3.5.0 + */ + public static function assertAttributeNotInstanceOf($expected, $attributeName, $classOrObject, $message = '') + { + self::assertNotInstanceOf( + $expected, + self::readAttribute($classOrObject, $attributeName), + $message + ); + } + + /** + * Asserts that a variable is of a given type. + * + * @param string $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.5.0 + */ + public static function assertInternalType($expected, $actual, $message = '') + { + if (is_string($expected)) { + $constraint = new PHPUnit_Framework_Constraint_IsType( + $expected + ); + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that an attribute is of a given type. + * + * @param string $expected + * @param string $attributeName + * @param mixed $classOrObject + * @param string $message + * @since Method available since Release 3.5.0 + */ + public static function assertAttributeInternalType($expected, $attributeName, $classOrObject, $message = '') + { + self::assertInternalType( + $expected, + self::readAttribute($classOrObject, $attributeName), + $message + ); + } + + /** + * Asserts that a variable is not of a given type. + * + * @param string $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.5.0 + */ + public static function assertNotInternalType($expected, $actual, $message = '') + { + if (is_string($expected)) { + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_IsType($expected) + ); + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that an attribute is of a given type. + * + * @param string $expected + * @param string $attributeName + * @param mixed $classOrObject + * @param string $message + * @since Method available since Release 3.5.0 + */ + public static function assertAttributeNotInternalType($expected, $attributeName, $classOrObject, $message = '') + { + self::assertNotInternalType( + $expected, + self::readAttribute($classOrObject, $attributeName), + $message + ); + } + + /** + * Asserts that a variable is of a given type. + * + * @param string $expected + * @param mixed $actual + * @param string $message + * @deprecated + */ + public static function assertType($expected, $actual, $message = '') + { + PHPUnit_Util_DeprecatedFeature_Logger::log( + 'assertType() will be removed in PHPUnit 3.6 and should no longer ' . + 'be used. assertInternalType() should be used for asserting ' . + 'internal types such as "integer" or "string" whereas ' . + 'assertInstanceOf() should be used for asserting that an object is ' . + 'an instance of a specified class or interface.' + ); + + if (is_string($expected)) { + if (PHPUnit_Util_Type::isType($expected)) { + $constraint = new PHPUnit_Framework_Constraint_IsType( + $expected + ); + } + + else if (class_exists($expected) || interface_exists($expected)) { + $constraint = new PHPUnit_Framework_Constraint_IsInstanceOf( + $expected + ); + } + + else { + throw PHPUnit_Util_InvalidArgumentHelper::factory( + 1, 'class or interface name' + ); + } + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that an attribute is of a given type. + * + * @param string $expected + * @param string $attributeName + * @param mixed $classOrObject + * @param string $message + * @since Method available since Release 3.4.0 + * @deprecated + */ + public static function assertAttributeType($expected, $attributeName, $classOrObject, $message = '') + { + PHPUnit_Util_DeprecatedFeature_Logger::log( + 'assertAttributeType() will be removed in PHPUnit 3.6 and should ' . + 'no longer be used. assertAttributeInternalType() should be used ' . + 'for asserting internal types such as "integer" or "string" ' . + 'whereas assertAttributeInstanceOf() should be used for asserting ' . + 'that an object is an instance of a specified class or interface.' + ); + + self::assertType( + $expected, + self::readAttribute($classOrObject, $attributeName), + $message + ); + } + + /** + * Asserts that a variable is not of a given type. + * + * @param string $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 2.2.0 + * @deprecated + */ + public static function assertNotType($expected, $actual, $message = '') + { + PHPUnit_Util_DeprecatedFeature_Logger::log( + 'assertNotType() will be removed in PHPUnit 3.6 and should no ' . + 'longer be used. assertNotInternalType() should be used for ' . + 'asserting internal types such as "integer" or "string" whereas ' . + 'assertNotInstanceOf() should be used for asserting that an object ' . + 'is not an instance of a specified class or interface.' + ); + + if (is_string($expected)) { + if (PHPUnit_Util_Type::isType($expected)) { + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_IsType($expected) + ); + } + + else if (class_exists($expected) || interface_exists($expected)) { + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_IsInstanceOf($expected) + ); + } + + else { + throw PHPUnit_Util_InvalidArgumentHelper::factory( + 1, 'class or interface name' + ); + } + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that an attribute is of a given type. + * + * @param string $expected + * @param string $attributeName + * @param mixed $classOrObject + * @param string $message + * @since Method available since Release 3.4.0 + * @deprecated + */ + public static function assertAttributeNotType($expected, $attributeName, $classOrObject, $message = '') + { + PHPUnit_Util_DeprecatedFeature_Logger::log( + 'assertAttributeNotType() will be removed in PHPUnit 3.6 and ' . + 'should no longer be used. assertAttributeNotInternalType() should ' . + 'be used for asserting internal types such as "integer" or ' . + '"string" whereas assertAttributeNotInstanceOf() should be used ' . + 'for asserting that an object is an instance of a specified class ' . + 'or interface.' + ); + + self::assertNotType( + $expected, + self::readAttribute($classOrObject, $attributeName), + $message + ); + } + + /** + * Asserts that a string matches a given regular expression. + * + * @param string $pattern + * @param string $string + * @param string $message + */ + public static function assertRegExp($pattern, $string, $message = '') + { + if (!is_string($pattern)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_string($string)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); + } + + $constraint = new PHPUnit_Framework_Constraint_PCREMatch($pattern); + + self::assertThat($string, $constraint, $message); + } + + /** + * Asserts that a string does not match a given regular expression. + * + * @param string $pattern + * @param string $string + * @param string $message + * @since Method available since Release 2.1.0 + */ + public static function assertNotRegExp($pattern, $string, $message = '') + { + if (!is_string($pattern)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_string($string)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); + } + + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_PCREMatch($pattern) + ); + + self::assertThat($string, $constraint, $message); + } + + /** + * Asserts that a string matches a given format string. + * + * @param string $format + * @param string $string + * @param string $message + * @since Method available since Release 3.5.0 + */ + public static function assertStringMatchesFormat($format, $string, $message = '') + { + if (!is_string($format)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_string($string)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); + } + + $constraint = new PHPUnit_Framework_Constraint_StringMatches($format); + + self::assertThat($string, $constraint, $message); + } + + /** + * Asserts that a string does not match a given format string. + * + * @param string $format + * @param string $string + * @param string $message + * @since Method available since Release 3.5.0 + */ + public static function assertStringNotMatchesFormat($format, $string, $message = '') + { + if (!is_string($format)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_string($string)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); + } + + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_StringMatches($format) + ); + + self::assertThat($string, $constraint, $message); + } + + /** + * Asserts that a string matches a given format file. + * + * @param string $formatFile + * @param string $string + * @param string $message + * @since Method available since Release 3.5.0 + */ + public static function assertStringMatchesFormatFile($formatFile, $string, $message = '') + { + self::assertFileExists($formatFile, $message); + + if (!is_string($string)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); + } + + $constraint = new PHPUnit_Framework_Constraint_StringMatches( + file_get_contents($formatFile) + ); + + self::assertThat($string, $constraint, $message); + } + + /** + * Asserts that a string does not match a given format string. + * + * @param string $formatFile + * @param string $string + * @param string $message + * @since Method available since Release 3.5.0 + */ + public static function assertStringNotMatchesFormatFile($formatFile, $string, $message = '') + { + self::assertFileExists($formatFile, $message); + + if (!is_string($string)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); + } + + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_StringMatches( + file_get_contents($formatFile) + ) + ); + + self::assertThat($string, $constraint, $message); + } + + /** + * Asserts that a string starts with a given prefix. + * + * @param string $prefix + * @param string $string + * @param string $message + * @since Method available since Release 3.4.0 + */ + public static function assertStringStartsWith($prefix, $string, $message = '') + { + if (!is_string($prefix)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_string($string)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); + } + + $constraint = new PHPUnit_Framework_Constraint_StringStartsWith( + $prefix + ); + + self::assertThat($string, $constraint, $message); + } + + /** + * Asserts that a string starts not with a given prefix. + * + * @param string $prefix + * @param string $string + * @param string $message + * @since Method available since Release 3.4.0 + */ + public static function assertStringStartsNotWith($prefix, $string, $message = '') + { + if (!is_string($prefix)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_string($string)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); + } + + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_StringStartsWith($prefix) + ); + + self::assertThat($string, $constraint, $message); + } + + /** + * Asserts that a string ends with a given prefix. + * + * @param string $suffix + * @param string $string + * @param string $message + * @since Method available since Release 3.4.0 + */ + public static function assertStringEndsWith($suffix, $string, $message = '') + { + if (!is_string($suffix)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_string($string)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); + } + + $constraint = new PHPUnit_Framework_Constraint_StringEndsWith($suffix); + + self::assertThat($string, $constraint, $message); + } + + /** + * Asserts that a string ends not with a given prefix. + * + * @param string $suffix + * @param string $string + * @param string $message + * @since Method available since Release 3.4.0 + */ + public static function assertStringEndsNotWith($suffix, $string, $message = '') + { + if (!is_string($suffix)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_string($string)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); + } + + $constraint = new PHPUnit_Framework_Constraint_Not( + new PHPUnit_Framework_Constraint_StringEndsWith($suffix) + ); + + self::assertThat($string, $constraint, $message); + } + + /** + * Asserts that two XML files are equal. + * + * @param string $expectedFile + * @param string $actualFile + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertXmlFileEqualsXmlFile($expectedFile, $actualFile, $message = '') + { + self::assertFileExists($expectedFile); + self::assertFileExists($actualFile); + + $expected = new DOMDocument; + $expected->preserveWhiteSpace = FALSE; + $expected->load($expectedFile); + + $actual = new DOMDocument; + $actual->preserveWhiteSpace = FALSE; + $actual->load($actualFile); + + self::assertEquals($expected, $actual, $message); + } + + /** + * Asserts that two XML files are not equal. + * + * @param string $expectedFile + * @param string $actualFile + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertXmlFileNotEqualsXmlFile($expectedFile, $actualFile, $message = '') + { + self::assertFileExists($expectedFile); + self::assertFileExists($actualFile); + + $expected = new DOMDocument; + $expected->preserveWhiteSpace = FALSE; + $expected->load($expectedFile); + + $actual = new DOMDocument; + $actual->preserveWhiteSpace = FALSE; + $actual->load($actualFile); + + self::assertNotEquals($expected, $actual, $message); + } + + /** + * Asserts that two XML documents are equal. + * + * @param string $expectedFile + * @param string $actualXml + * @param string $message + * @since Method available since Release 3.3.0 + */ + public static function assertXmlStringEqualsXmlFile($expectedFile, $actualXml, $message = '') + { + self::assertFileExists($expectedFile); + + $expected = new DOMDocument; + $expected->preserveWhiteSpace = FALSE; + $expected->load($expectedFile); + + $actual = new DOMDocument; + $actual->preserveWhiteSpace = FALSE; + $actual->loadXML($actualXml); + + self::assertEquals($expected, $actual, $message); + } + + /** + * Asserts that two XML documents are not equal. + * + * @param string $expectedFile + * @param string $actualXml + * @param string $message + * @since Method available since Release 3.3.0 + */ + public static function assertXmlStringNotEqualsXmlFile($expectedFile, $actualXml, $message = '') + { + self::assertFileExists($expectedFile); + + $expected = new DOMDocument; + $expected->preserveWhiteSpace = FALSE; + $expected->load($expectedFile); + + $actual = new DOMDocument; + $actual->preserveWhiteSpace = FALSE; + $actual->loadXML($actualXml); + + self::assertNotEquals($expected, $actual, $message); + } + + /** + * Asserts that two XML documents are equal. + * + * @param string $expectedXml + * @param string $actualXml + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertXmlStringEqualsXmlString($expectedXml, $actualXml, $message = '') + { + $expected = new DOMDocument; + $expected->preserveWhiteSpace = FALSE; + $expected->loadXML($expectedXml); + + $actual = new DOMDocument; + $actual->preserveWhiteSpace = FALSE; + $actual->loadXML($actualXml); + + self::assertEquals($expected, $actual, $message); + } + + /** + * Asserts that two XML documents are not equal. + * + * @param string $expectedXml + * @param string $actualXml + * @param string $message + * @since Method available since Release 3.1.0 + */ + public static function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, $message = '') + { + $expected = new DOMDocument; + $expected->preserveWhiteSpace = FALSE; + $expected->loadXML($expectedXml); + + $actual = new DOMDocument; + $actual->preserveWhiteSpace = FALSE; + $actual->loadXML($actualXml); + + self::assertNotEquals($expected, $actual, $message); + } + + /** + * Asserts that a hierarchy of DOMNodes matches. + * + * @param DOMNode $expectedNode + * @param DOMNode $actualNode + * @param boolean $checkAttributes + * @param string $message + * @author Mattis Stordalen Flister + * @since Method available since Release 3.3.0 + */ + public static function assertEqualXMLStructure(DOMNode $expectedNode, DOMNode $actualNode, $checkAttributes = FALSE, $message = '') + { + self::assertEquals( + $expectedNode->tagName, + $actualNode->tagName, + $message + ); + + if ($checkAttributes) { + self::assertEquals( + $expectedNode->attributes->length, + $actualNode->attributes->length, + sprintf( + '%s%sNumber of attributes on node "%s" does not match', + $message, + !empty($message) ? "\n" : '', + $expectedNode->tagName + ) + ); + + for ($i = 0 ; $i < $expectedNode->attributes->length; $i++) { + $expectedAttribute = $expectedNode->attributes->item($i); + $actualAttribute = $actualNode->attributes->getNamedItem( + $expectedAttribute->name + ); + + if (!$actualAttribute) { + self::fail( + sprintf( + '%s%sCould not find attribute "%s" on node "%s"', + $message, + !empty($message) ? "\n" : '', + $expectedAttribute->name, + $expectedNode->tagName + ) + ); + } + } + } + + PHPUnit_Util_XML::removeCharacterDataNodes($expectedNode); + PHPUnit_Util_XML::removeCharacterDataNodes($actualNode); + + self::assertEquals( + $expectedNode->childNodes->length, + $actualNode->childNodes->length, + sprintf( + '%s%sNumber of child nodes of "%s" differs', + $message, + !empty($message) ? "\n" : '', + $expectedNode->tagName + ) + ); + + for ($i = 0; $i < $expectedNode->childNodes->length; $i++) { + self::assertEqualXMLStructure( + $expectedNode->childNodes->item($i), + $actualNode->childNodes->item($i), + $checkAttributes, + $message + ); + } + } + + /** + * Assert the presence, absence, or count of elements in a document matching + * the CSS $selector, regardless of the contents of those elements. + * + * The first argument, $selector, is the CSS selector used to match + * the elements in the $actual document. + * + * The second argument, $count, can be either boolean or numeric. + * When boolean, it asserts for presence of elements matching the selector + * (TRUE) or absence of elements (FALSE). + * When numeric, it asserts the count of elements. + * + * assertSelectCount("#binder", true, $xml); // any? + * assertSelectCount(".binder", 3, $xml); // exactly 3? + * + * @param array $selector + * @param integer $count + * @param mixed $actual + * @param string $message + * @param boolean $isHtml + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + */ + public static function assertSelectCount($selector, $count, $actual, $message = '', $isHtml = TRUE) + { + self::assertSelectEquals( + $selector, TRUE, $count, $actual, $message, $isHtml + ); + } + + /** + * assertSelectRegExp("#binder .name", "/Mike|Derek/", true, $xml); // any? + * assertSelectRegExp("#binder .name", "/Mike|Derek/", 3, $xml); // 3? + * + * @param array $selector + * @param string $pattern + * @param integer $count + * @param mixed $actual + * @param string $message + * @param boolean $isHtml + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + */ + public static function assertSelectRegExp($selector, $pattern, $count, $actual, $message = '', $isHtml = TRUE) + { + self::assertSelectEquals( + $selector, "regexp:$pattern", $count, $actual, $message, $isHtml + ); + } + + /** + * assertSelectEquals("#binder .name", "Chuck", true, $xml); // any? + * assertSelectEquals("#binder .name", "Chuck", false, $xml); // none? + * + * @param array $selector + * @param string $content + * @param integer $count + * @param mixed $actual + * @param string $message + * @param boolean $isHtml + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + */ + public static function assertSelectEquals($selector, $content, $count, $actual, $message = '', $isHtml = TRUE) + { + $tags = PHPUnit_Util_XML::cssSelect( + $selector, $content, $actual, $isHtml + ); + + // assert specific number of elements + if (is_numeric($count)) { + $counted = $tags ? count($tags) : 0; + self::assertEquals($count, $counted, $message); + } + + // assert any elements exist if true, assert no elements exist if false + else if (is_bool($count)) { + $any = count($tags) > 0 && $tags[0] instanceof DOMNode; + + if ($count) { + self::assertTrue($any, $message); + } else { + self::assertFalse($any, $message); + } + } + + // check for range number of elements + else if (is_array($count) && + (isset($count['>']) || isset($count['<']) || + isset($count['>=']) || isset($count['<=']))) { + $counted = $tags ? count($tags) : 0; + + if (isset($count['>'])) { + self::assertTrue($counted > $count['>'], $message); + } + + if (isset($count['>='])) { + self::assertTrue($counted >= $count['>='], $message); + } + + if (isset($count['<'])) { + self::assertTrue($counted < $count['<'], $message); + } + + if (isset($count['<='])) { + self::assertTrue($counted <= $count['<='], $message); + } + } else { + throw new InvalidArgumentException(); + } + } + + /** + * Evaluate an HTML or XML string and assert its structure and/or contents. + * + * The first argument ($matcher) is an associative array that specifies the + * match criteria for the assertion: + * + * - `id` : the node with the given id attribute must match the + * corresponsing value. + * - `tag` : the node type must match the corresponding value. + * - `attributes` : a hash. The node's attributres must match the + * corresponsing values in the hash. + * - `content` : The text content must match the given value. + * - `parent` : a hash. The node's parent must match the + * corresponsing hash. + * - `child` : a hash. At least one of the node's immediate children + * must meet the criteria described by the hash. + * - `ancestor` : a hash. At least one of the node's ancestors must + * meet the criteria described by the hash. + * - `descendant` : a hash. At least one of the node's descendants must + * meet the criteria described by the hash. + * - `children` : a hash, for counting children of a node. + * Accepts the keys: + * - `count` : a number which must equal the number of children + * that match + * - `less_than` : the number of matching children must be greater + * than this number + * - `greater_than` : the number of matching children must be less than + * this number + * - `only` : another hash consisting of the keys to use to match + * on the children, and only matching children will be + * counted + * + * + * // Matcher that asserts that there is an element with an id="my_id". + * $matcher = array('id' => 'my_id'); + * + * // Matcher that asserts that there is a "span" tag. + * $matcher = array('tag' => 'span'); + * + * // Matcher that asserts that there is a "span" tag with the content + * // "Hello World". + * $matcher = array('tag' => 'span', 'content' => 'Hello World'); + * + * // Matcher that asserts that there is a "span" tag with content matching + * // the regular expression pattern. + * $matcher = array('tag' => 'span', 'content' => '/Try P(HP|ython)/'); + * + * // Matcher that asserts that there is a "span" with an "list" class + * // attribute. + * $matcher = array( + * 'tag' => 'span', + * 'attributes' => array('class' => 'list') + * ); + * + * // Matcher that asserts that there is a "span" inside of a "div". + * $matcher = array( + * 'tag' => 'span', + * 'parent' => array('tag' => 'div') + * ); + * + * // Matcher that asserts that there is a "span" somewhere inside a + * // "table". + * $matcher = array( + * 'tag' => 'span', + * 'ancestor' => array('tag' => 'table') + * ); + * + * // Matcher that asserts that there is a "span" with at least one "em" + * // child. + * $matcher = array( + * 'tag' => 'span', + * 'child' => array('tag' => 'em') + * ); + * + * // Matcher that asserts that there is a "span" containing a (possibly + * // nested) "strong" tag. + * $matcher = array( + * 'tag' => 'span', + * 'descendant' => array('tag' => 'strong') + * ); + * + * // Matcher that asserts that there is a "span" containing 5-10 "em" tags + * // as immediate children. + * $matcher = array( + * 'tag' => 'span', + * 'children' => array( + * 'less_than' => 11, + * 'greater_than' => 4, + * 'only' => array('tag' => 'em') + * ) + * ); + * + * // Matcher that asserts that there is a "div", with an "ul" ancestor and + * // a "li" parent (with class="enum"), and containing a "span" descendant + * // that contains an element with id="my_test" and the text "Hello World". + * $matcher = array( + * 'tag' => 'div', + * 'ancestor' => array('tag' => 'ul'), + * 'parent' => array( + * 'tag' => 'li', + * 'attributes' => array('class' => 'enum') + * ), + * 'descendant' => array( + * 'tag' => 'span', + * 'child' => array( + * 'id' => 'my_test', + * 'content' => 'Hello World' + * ) + * ) + * ); + * + * // Use assertTag() to apply a $matcher to a piece of $html. + * $this->assertTag($matcher, $html); + * + * // Use assertTag() to apply a $matcher to a piece of $xml. + * $this->assertTag($matcher, $xml, '', FALSE); + * + * + * The second argument ($actual) is a string containing either HTML or + * XML text to be tested. + * + * The third argument ($message) is an optional message that will be + * used if the assertion fails. + * + * The fourth argument ($html) is an optional flag specifying whether + * to load the $actual string into a DOMDocument using the HTML or + * XML load strategy. It is TRUE by default, which assumes the HTML + * load strategy. In many cases, this will be acceptable for XML as well. + * + * @param array $matcher + * @param string $actual + * @param string $message + * @param boolean $isHtml + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + */ + public static function assertTag($matcher, $actual, $message = '', $isHtml = TRUE) + { + $dom = PHPUnit_Util_XML::load($actual, $isHtml); + $tags = PHPUnit_Util_XML::findNodes($dom, $matcher, $isHtml); + $matched = count($tags) > 0 && $tags[0] instanceof DOMNode; + + self::assertTrue($matched, $message); + } + + /** + * This assertion is the exact opposite of assertTag(). + * + * Rather than asserting that $matcher results in a match, it asserts that + * $matcher does not match. + * + * @param array $matcher + * @param string $actual + * @param string $message + * @param boolean $isHtml + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + */ + public static function assertNotTag($matcher, $actual, $message = '', $isHtml = TRUE) + { + $dom = PHPUnit_Util_XML::load($actual, $isHtml); + $tags = PHPUnit_Util_XML::findNodes($dom, $matcher, $isHtml); + $matched = count($tags) > 0 && $tags[0] instanceof DOMNode; + + self::assertFalse($matched, $message); + } + + /** + * Evaluates a PHPUnit_Framework_Constraint matcher object. + * + * @param mixed $value + * @param PHPUnit_Framework_Constraint $constraint + * @param string $message + * @since Method available since Release 3.0.0 + */ + public static function assertThat($value, PHPUnit_Framework_Constraint $constraint, $message = '') + { + self::$count += count($constraint); + + if (!$constraint->evaluate($value)) { + $constraint->fail($value, $message); + } + } + + /** + * Returns a PHPUnit_Framework_Constraint_And matcher object. + * + * @return PHPUnit_Framework_Constraint_And + * @since Method available since Release 3.0.0 + */ + public static function logicalAnd() + { + $constraints = func_get_args(); + + $constraint = new PHPUnit_Framework_Constraint_And; + $constraint->setConstraints($constraints); + + return $constraint; + } + + /** + * Returns a PHPUnit_Framework_Constraint_Or matcher object. + * + * @return PHPUnit_Framework_Constraint_Or + * @since Method available since Release 3.0.0 + */ + public static function logicalOr() + { + $constraints = func_get_args(); + + $constraint = new PHPUnit_Framework_Constraint_Or; + $constraint->setConstraints($constraints); + + return $constraint; + } + + /** + * Returns a PHPUnit_Framework_Constraint_Not matcher object. + * + * @param PHPUnit_Framework_Constraint $constraint + * @return PHPUnit_Framework_Constraint_Not + * @since Method available since Release 3.0.0 + */ + public static function logicalNot(PHPUnit_Framework_Constraint $constraint) + { + return new PHPUnit_Framework_Constraint_Not($constraint); + } + + /** + * Returns a PHPUnit_Framework_Constraint_Xor matcher object. + * + * @return PHPUnit_Framework_Constraint_Xor + * @since Method available since Release 3.0.0 + */ + public static function logicalXor() + { + $constraints = func_get_args(); + + $constraint = new PHPUnit_Framework_Constraint_Xor; + $constraint->setConstraints($constraints); + + return $constraint; + } + + /** + * Returns a PHPUnit_Framework_Constraint_IsAnything matcher object. + * + * @return PHPUnit_Framework_Constraint_IsAnything + * @since Method available since Release 3.0.0 + */ + public static function anything() + { + return new PHPUnit_Framework_Constraint_IsAnything; + } + + /** + * Returns a PHPUnit_Framework_Constraint_IsTrue matcher object. + * + * @return PHPUnit_Framework_Constraint_IsTrue + * @since Method available since Release 3.3.0 + */ + public static function isTrue() + { + return new PHPUnit_Framework_Constraint_IsTrue; + } + + /** + * Returns a PHPUnit_Framework_Constraint_IsFalse matcher object. + * + * @return PHPUnit_Framework_Constraint_IsFalse + * @since Method available since Release 3.3.0 + */ + public static function isFalse() + { + return new PHPUnit_Framework_Constraint_IsFalse; + } + + /** + * Returns a PHPUnit_Framework_Constraint_IsNull matcher object. + * + * @return PHPUnit_Framework_Constraint_IsNull + * @since Method available since Release 3.3.0 + */ + public static function isNull() + { + return new PHPUnit_Framework_Constraint_IsNull; + } + + /** + * Returns a PHPUnit_Framework_Constraint_Attribute matcher object. + * + * @param PHPUnit_Framework_Constraint $constraint + * @param string $attributeName + * @return PHPUnit_Framework_Constraint_Attribute + * @since Method available since Release 3.1.0 + */ + public static function attribute(PHPUnit_Framework_Constraint $constraint, $attributeName) + { + return new PHPUnit_Framework_Constraint_Attribute( + $constraint, $attributeName + ); + } + + /** + * Returns a PHPUnit_Framework_Constraint_TraversableContains matcher + * object. + * + * @param mixed $value + * @return PHPUnit_Framework_Constraint_TraversableContains + * @since Method available since Release 3.0.0 + */ + public static function contains($value) + { + return new PHPUnit_Framework_Constraint_TraversableContains($value); + } + + /** + * Returns a PHPUnit_Framework_Constraint_TraversableContainsOnly matcher + * object. + * + * @param string $type + * @return PHPUnit_Framework_Constraint_TraversableContainsOnly + * @since Method available since Release 3.1.4 + */ + public static function containsOnly($type) + { + return new PHPUnit_Framework_Constraint_TraversableContainsOnly($type); + } + + /** + * Returns a PHPUnit_Framework_Constraint_ArrayHasKey matcher object. + * + * @param mixed $key + * @return PHPUnit_Framework_Constraint_ArrayHasKey + * @since Method available since Release 3.0.0 + */ + public static function arrayHasKey($key) + { + return new PHPUnit_Framework_Constraint_ArrayHasKey($key); + } + + /** + * Returns a PHPUnit_Framework_Constraint_IsEqual matcher object. + * + * @param mixed $value + * @param float $delta + * @param integer $maxDepth + * @param boolean $canonicalize + * @param boolean $ignoreCase + * @return PHPUnit_Framework_Constraint_IsEqual + * @since Method available since Release 3.0.0 + */ + public static function equalTo($value, $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) + { + return new PHPUnit_Framework_Constraint_IsEqual( + $value, $delta, $maxDepth, $canonicalize, $ignoreCase + ); + } + + /** + * Returns a PHPUnit_Framework_Constraint_IsEqual matcher object + * that is wrapped in a PHPUnit_Framework_Constraint_Attribute matcher + * object. + * + * @param string $attributeName + * @param mixed $value + * @param float $delta + * @param integer $maxDepth + * @param boolean $canonicalize + * @param boolean $ignoreCase + * @return PHPUnit_Framework_Constraint_Attribute + * @since Method available since Release 3.1.0 + */ + public static function attributeEqualTo($attributeName, $value, $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) + { + return self::attribute( + self::equalTo( + $value, $delta, $maxDepth, $canonicalize, $ignoreCase + ), + $attributeName + ); + } + + /** + * Returns a PHPUnit_Framework_Constraint_IsEmpty matcher object. + * + * @return PHPUnit_Framework_Constraint_IsEmpty + * @since Method available since Release 3.5.0 + */ + public static function isEmpty() + { + return new PHPUnit_Framework_Constraint_IsEmpty; + } + /** + * Returns a PHPUnit_Framework_Constraint_FileExists matcher object. + * + * @return PHPUnit_Framework_Constraint_FileExists + * @since Method available since Release 3.0.0 + */ + public static function fileExists() + { + return new PHPUnit_Framework_Constraint_FileExists; + } + + /** + * Returns a PHPUnit_Framework_Constraint_GreaterThan matcher object. + * + * @param mixed $value + * @return PHPUnit_Framework_Constraint_GreaterThan + * @since Method available since Release 3.0.0 + */ + public static function greaterThan($value) + { + return new PHPUnit_Framework_Constraint_GreaterThan($value); + } + + /** + * Returns a PHPUnit_Framework_Constraint_Or matcher object that wraps + * a PHPUnit_Framework_Constraint_IsEqual and a + * PHPUnit_Framework_Constraint_GreaterThan matcher object. + * + * @param mixed $value + * @return PHPUnit_Framework_Constraint_Or + * @since Method available since Release 3.1.0 + */ + public static function greaterThanOrEqual($value) + { + return self::logicalOr( + new PHPUnit_Framework_Constraint_IsEqual($value), + new PHPUnit_Framework_Constraint_GreaterThan($value) + ); + } + + /** + * Returns a PHPUnit_Framework_Constraint_ClassHasAttribute matcher object. + * + * @param string $attributeName + * @return PHPUnit_Framework_Constraint_ClassHasAttribute + * @since Method available since Release 3.1.0 + */ + public static function classHasAttribute($attributeName) + { + return new PHPUnit_Framework_Constraint_ClassHasAttribute( + $attributeName + ); + } + + /** + * Returns a PHPUnit_Framework_Constraint_ClassHasStaticAttribute matcher + * object. + * + * @param string $attributeName + * @return PHPUnit_Framework_Constraint_ClassHasStaticAttribute + * @since Method available since Release 3.1.0 + */ + public static function classHasStaticAttribute($attributeName) + { + return new PHPUnit_Framework_Constraint_ClassHasStaticAttribute( + $attributeName + ); + } + + /** + * Returns a PHPUnit_Framework_Constraint_ObjectHasAttribute matcher object. + * + * @param string $attributeName + * @return PHPUnit_Framework_Constraint_ObjectHasAttribute + * @since Method available since Release 3.0.0 + */ + public static function objectHasAttribute($attributeName) + { + return new PHPUnit_Framework_Constraint_ObjectHasAttribute( + $attributeName + ); + } + + /** + * Returns a PHPUnit_Framework_Constraint_IsIdentical matcher object. + * + * @param mixed $value + * @return PHPUnit_Framework_Constraint_IsIdentical + * @since Method available since Release 3.0.0 + */ + public static function identicalTo($value) + { + return new PHPUnit_Framework_Constraint_IsIdentical($value); + } + + /** + * Returns a PHPUnit_Framework_Constraint_IsInstanceOf matcher object. + * + * @param string $className + * @return PHPUnit_Framework_Constraint_IsInstanceOf + * @since Method available since Release 3.0.0 + */ + public static function isInstanceOf($className) + { + return new PHPUnit_Framework_Constraint_IsInstanceOf($className); + } + + /** + * Returns a PHPUnit_Framework_Constraint_IsType matcher object. + * + * @param string $type + * @return PHPUnit_Framework_Constraint_IsType + * @since Method available since Release 3.0.0 + */ + public static function isType($type) + { + return new PHPUnit_Framework_Constraint_IsType($type); + } + + /** + * Returns a PHPUnit_Framework_Constraint_LessThan matcher object. + * + * @param mixed $value + * @return PHPUnit_Framework_Constraint_LessThan + * @since Method available since Release 3.0.0 + */ + public static function lessThan($value) + { + return new PHPUnit_Framework_Constraint_LessThan($value); + } + + /** + * Returns a PHPUnit_Framework_Constraint_Or matcher object that wraps + * a PHPUnit_Framework_Constraint_IsEqual and a + * PHPUnit_Framework_Constraint_LessThan matcher object. + * + * @param mixed $value + * @return PHPUnit_Framework_Constraint_Or + * @since Method available since Release 3.1.0 + */ + public static function lessThanOrEqual($value) + { + return self::logicalOr( + new PHPUnit_Framework_Constraint_IsEqual($value), + new PHPUnit_Framework_Constraint_LessThan($value) + ); + } + + /** + * Returns a PHPUnit_Framework_Constraint_PCREMatch matcher object. + * + * @param string $pattern + * @return PHPUnit_Framework_Constraint_PCREMatch + * @since Method available since Release 3.0.0 + */ + public static function matchesRegularExpression($pattern) + { + return new PHPUnit_Framework_Constraint_PCREMatch($pattern); + } + + /** + * Returns a PHPUnit_Framework_Constraint_StringMatches matcher object. + * + * @param string $string + * @return PHPUnit_Framework_Constraint_StringMatches + * @since Method available since Release 3.5.0 + */ + public static function matches($string) + { + return new PHPUnit_Framework_Constraint_StringMatches($string); + } + + /** + * Returns a PHPUnit_Framework_Constraint_StringStartsWith matcher object. + * + * @param mixed $prefix + * @return PHPUnit_Framework_Constraint_StringStartsWith + * @since Method available since Release 3.4.0 + */ + public static function stringStartsWith($prefix) + { + return new PHPUnit_Framework_Constraint_StringStartsWith($prefix); + } + + /** + * Returns a PHPUnit_Framework_Constraint_StringContains matcher object. + * + * @param string $string + * @param boolean $case + * @return PHPUnit_Framework_Constraint_StringContains + * @since Method available since Release 3.0.0 + */ + public static function stringContains($string, $case = TRUE) + { + return new PHPUnit_Framework_Constraint_StringContains($string, $case); + } + + /** + * Returns a PHPUnit_Framework_Constraint_StringEndsWith matcher object. + * + * @param mixed $suffix + * @return PHPUnit_Framework_Constraint_StringEndsWith + * @since Method available since Release 3.4.0 + */ + public static function stringEndsWith($suffix) + { + return new PHPUnit_Framework_Constraint_StringEndsWith($suffix); + } + + /** + * Fails a test with the given message. + * + * @param string $message + * @throws PHPUnit_Framework_AssertionFailedError + */ + public static function fail($message = '') + { + throw new PHPUnit_Framework_AssertionFailedError($message); + } + + /** + * Fails a test with a synthetic error. + * + * @param string $message + * @param string $file + * @param integer $line + * @param array $trace + * @throws PHPUnit_Framework_SyntheticError + */ + public static function syntheticFail($message = '', $file = '', $line = 0, $trace = array()) + { + throw new PHPUnit_Framework_SyntheticError($message, 0, $file, $line, $trace); + } + + /** + * Returns the value of an attribute of a class or an object. + * This also works for attributes that are declared protected or private. + * + * @param mixed $classOrObject + * @param string $attributeName + * @return mixed + * @throws InvalidArgumentException + */ + public static function readAttribute($classOrObject, $attributeName) + { + if (!is_string($attributeName)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); + } + + if (is_string($classOrObject)) { + if (!class_exists($classOrObject)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory( + 1, 'class name' + ); + } + + return PHPUnit_Util_Class::getStaticAttribute( + $classOrObject, + $attributeName + ); + } + + else if (is_object($classOrObject)) { + return PHPUnit_Util_Class::getObjectAttribute( + $classOrObject, + $attributeName + ); + } + + else { + throw PHPUnit_Util_InvalidArgumentHelper::factory( + 1, 'class name or object' + ); + } + } + + /** + * Mark the test as incomplete. + * + * @param string $message + * @throws PHPUnit_Framework_IncompleteTestError + * @since Method available since Release 3.0.0 + */ + public static function markTestIncomplete($message = '') + { + throw new PHPUnit_Framework_IncompleteTestError($message); + } + + /** + * Mark the test as skipped. + * + * @param string $message + * @throws PHPUnit_Framework_SkippedTestError + * @since Method available since Release 3.0.0 + */ + public static function markTestSkipped($message = '') + { + throw new PHPUnit_Framework_SkippedTestError($message); + } + + /** + * Return the current assertion count. + * + * @return integer + * @since Method available since Release 3.3.3 + */ + public static function getCount() + { + return self::$count; + } + + /** + * Reset the assertion counter. + * + * @since Method available since Release 3.3.3 + */ + public static function resetCount() + { + self::$count = 0; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Assert/Functions.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Assert/Functions.php new file mode 100644 index 0000000..b8de30e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Assert/Functions.php @@ -0,0 +1,1831 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.5.0 + */ + +/** + * Returns a matcher that matches when the method it is evaluated for + * is executed zero or more times. + * + * @return PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount + * @since Method available since Release 3.0.0 + */ +function any() +{ + return PHPUnit_Framework_TestCase::any(); +} + +/** + * Returns a PHPUnit_Framework_Constraint_IsAnything matcher object. + * + * @return PHPUnit_Framework_Constraint_IsAnything + * @since Method available since Release 3.0.0 + */ +function anything() +{ + return PHPUnit_Framework_Assert::anything(); +} + +/** + * Returns a PHPUnit_Framework_Constraint_ArrayHasKey matcher object. + * + * @param mixed $key + * @return PHPUnit_Framework_Constraint_ArrayHasKey + * @since Method available since Release 3.0.0 + */ +function arrayHasKey($key) +{ + return PHPUnit_Framework_Assert::arrayHasKey($key); +} + +/** + * Asserts that an array has a specified key. + * + * @param mixed $key + * @param array $array + * @param string $message + * @since Method available since Release 3.0.0 + */ +function assertArrayHasKey($key, array $array, $message = '') +{ + return PHPUnit_Framework_Assert::assertArrayHasKey($key, $array, $message); +} + +/** + * Asserts that an array does not have a specified key. + * + * @param mixed $key + * @param array $array + * @param string $message + * @since Method available since Release 3.0.0 + */ +function assertArrayNotHasKey($key, array $array, $message = '') +{ + return PHPUnit_Framework_Assert::assertArrayNotHasKey($key, $array, $message); +} + +/** + * Asserts that a haystack that is stored in a static attribute of a class + * or an attribute of an object contains a needle. + * + * @param mixed $needle + * @param string $haystackAttributeName + * @param mixed $haystackClassOrObject + * @param string $message + * @param boolean $ignoreCase + * @since Method available since Release 3.0.0 + */ +function assertAttributeContains($needle, $haystackAttributeName, $haystackClassOrObject, $message = '', $ignoreCase = FALSE) +{ + return PHPUnit_Framework_Assert::assertAttributeContains($needle, $haystackAttributeName, $haystackClassOrObject, $message, $ignoreCase); +} + +/** + * Asserts that a haystack that is stored in a static attribute of a class + * or an attribute of an object contains only values of a given type. + * + * @param string $type + * @param string $haystackAttributeName + * @param mixed $haystackClassOrObject + * @param boolean $isNativeType + * @param string $message + * @since Method available since Release 3.1.4 + */ +function assertAttributeContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType = NULL, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType, $message); +} + +/** + * Asserts that a static attribute of a class or an attribute of an object + * is empty. + * + * @param string $haystackAttributeName + * @param mixed $haystackClassOrObject + * @param string $message + * @since Method available since Release 3.5.0 + */ +function assertAttributeEmpty($haystackAttributeName, $haystackClassOrObject, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeEmpty($haystackAttributeName, $haystackClassOrObject, $message); +} + +/** + * Asserts that a variable is equal to an attribute of an object. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param string $actualClassOrObject + * @param string $message + * @param float $delta + * @param integer $maxDepth + * @param boolean $canonicalize + * @param boolean $ignoreCase + */ +function assertAttributeEquals($expected, $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) +{ + return PHPUnit_Framework_Assert::assertAttributeEquals($expected, $actualAttributeName, $actualClassOrObject, $message, $delta, $maxDepth, $canonicalize, $ignoreCase); +} + +/** + * Asserts that an attribute is greater than another value. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param string $actualClassOrObject + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertAttributeGreaterThan($expected, $actualAttributeName, $actualClassOrObject, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeGreaterThan($expected, $actualAttributeName, $actualClassOrObject, $message); +} + +/** + * Asserts that an attribute is greater than or equal to another value. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param string $actualClassOrObject + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertAttributeGreaterThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeGreaterThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message); +} + +/** + * Asserts that an attribute is of a given type. + * + * @param string $expected + * @param string $attributeName + * @param mixed $classOrObject + * @param string $message + * @since Method available since Release 3.5.0 + */ +function assertAttributeInstanceOf($expected, $attributeName, $classOrObject, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeInstanceOf($expected, $attributeName, $classOrObject, $message); +} + +/** + * Asserts that an attribute is of a given type. + * + * @param string $expected + * @param string $attributeName + * @param mixed $classOrObject + * @param string $message + * @since Method available since Release 3.5.0 + */ +function assertAttributeInternalType($expected, $attributeName, $classOrObject, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeInternalType($expected, $attributeName, $classOrObject, $message); +} + +/** + * Asserts that an attribute is smaller than another value. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param string $actualClassOrObject + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertAttributeLessThan($expected, $actualAttributeName, $actualClassOrObject, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeLessThan($expected, $actualAttributeName, $actualClassOrObject, $message); +} + +/** + * Asserts that an attribute is smaller than or equal to another value. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param string $actualClassOrObject + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertAttributeLessThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeLessThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message); +} + +/** + * Asserts that a haystack that is stored in a static attribute of a class + * or an attribute of an object does not contain a needle. + * + * @param mixed $needle + * @param string $haystackAttributeName + * @param mixed $haystackClassOrObject + * @param string $message + * @param boolean $ignoreCase + * @since Method available since Release 3.0.0 + */ +function assertAttributeNotContains($needle, $haystackAttributeName, $haystackClassOrObject, $message = '', $ignoreCase = FALSE) +{ + return PHPUnit_Framework_Assert::assertAttributeNotContains($needle, $haystackAttributeName, $haystackClassOrObject, $message, $ignoreCase); +} + +/** + * Asserts that a haystack that is stored in a static attribute of a class + * or an attribute of an object does not contain only values of a given + * type. + * + * @param string $type + * @param string $haystackAttributeName + * @param mixed $haystackClassOrObject + * @param boolean $isNativeType + * @param string $message + * @since Method available since Release 3.1.4 + */ +function assertAttributeNotContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType = NULL, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeNotContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType, $message); +} + +/** + * Asserts that a static attribute of a class or an attribute of an object + * is not empty. + * + * @param string $haystackAttributeName + * @param mixed $haystackClassOrObject + * @param string $message + * @since Method available since Release 3.5.0 + */ +function assertAttributeNotEmpty($haystackAttributeName, $haystackClassOrObject, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeNotEmpty($haystackAttributeName, $haystackClassOrObject, $message); +} + +/** + * Asserts that a variable is not equal to an attribute of an object. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param string $actualClassOrObject + * @param string $message + * @param float $delta + * @param integer $maxDepth + * @param boolean $canonicalize + * @param boolean $ignoreCase + */ +function assertAttributeNotEquals($expected, $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) +{ + return PHPUnit_Framework_Assert::assertAttributeNotEquals($expected, $actualAttributeName, $actualClassOrObject, $message, $delta, $maxDepth, $canonicalize, $ignoreCase); +} + +/** + * Asserts that an attribute is of a given type. + * + * @param string $expected + * @param string $attributeName + * @param mixed $classOrObject + * @param string $message + * @since Method available since Release 3.5.0 + */ +function assertAttributeNotInstanceOf($expected, $attributeName, $classOrObject, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeNotInstanceOf($expected, $attributeName, $classOrObject, $message); +} + +/** + * Asserts that an attribute is of a given type. + * + * @param string $expected + * @param string $attributeName + * @param mixed $classOrObject + * @param string $message + * @since Method available since Release 3.5.0 + */ +function assertAttributeNotInternalType($expected, $attributeName, $classOrObject, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeNotInternalType($expected, $attributeName, $classOrObject, $message); +} + +/** + * Asserts that a variable and an attribute of an object do not have the + * same type and value. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param object $actualClassOrObject + * @param string $message + */ +function assertAttributeNotSame($expected, $actualAttributeName, $actualClassOrObject, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeNotSame($expected, $actualAttributeName, $actualClassOrObject, $message); +} + +/** + * Asserts that an attribute is of a given type. + * + * @param string $expected + * @param string $attributeName + * @param mixed $classOrObject + * @param string $message + * @since Method available since Release 3.4.0 + * @deprecated + */ +function assertAttributeNotType($expected, $attributeName, $classOrObject, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeNotType($expected, $attributeName, $classOrObject, $message); +} + +/** + * Asserts that a variable and an attribute of an object have the same type + * and value. + * + * @param mixed $expected + * @param string $actualAttributeName + * @param object $actualClassOrObject + * @param string $message + */ +function assertAttributeSame($expected, $actualAttributeName, $actualClassOrObject, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeSame($expected, $actualAttributeName, $actualClassOrObject, $message); +} + +/** + * Asserts that an attribute is of a given type. + * + * @param string $expected + * @param string $attributeName + * @param mixed $classOrObject + * @param string $message + * @since Method available since Release 3.4.0 + * @deprecated + */ +function assertAttributeType($expected, $attributeName, $classOrObject, $message = '') +{ + return PHPUnit_Framework_Assert::assertAttributeType($expected, $attributeName, $classOrObject, $message); +} + +/** + * Asserts that a class has a specified attribute. + * + * @param string $attributeName + * @param string $className + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertClassHasAttribute($attributeName, $className, $message = '') +{ + return PHPUnit_Framework_Assert::assertClassHasAttribute($attributeName, $className, $message); +} + +/** + * Asserts that a class has a specified static attribute. + * + * @param string $attributeName + * @param string $className + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertClassHasStaticAttribute($attributeName, $className, $message = '') +{ + return PHPUnit_Framework_Assert::assertClassHasStaticAttribute($attributeName, $className, $message); +} + +/** + * Asserts that a class does not have a specified attribute. + * + * @param string $attributeName + * @param string $className + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertClassNotHasAttribute($attributeName, $className, $message = '') +{ + return PHPUnit_Framework_Assert::assertClassNotHasAttribute($attributeName, $className, $message); +} + +/** + * Asserts that a class does not have a specified static attribute. + * + * @param string $attributeName + * @param string $className + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertClassNotHasStaticAttribute($attributeName, $className, $message = '') +{ + return PHPUnit_Framework_Assert::assertClassNotHasStaticAttribute($attributeName, $className, $message); +} + +/** + * Asserts that a haystack contains a needle. + * + * @param mixed $needle + * @param mixed $haystack + * @param string $message + * @param boolean $ignoreCase + * @since Method available since Release 2.1.0 + */ +function assertContains($needle, $haystack, $message = '', $ignoreCase = FALSE) +{ + return PHPUnit_Framework_Assert::assertContains($needle, $haystack, $message, $ignoreCase); +} + +/** + * Asserts that a haystack contains only values of a given type. + * + * @param string $type + * @param mixed $haystack + * @param boolean $isNativeType + * @param string $message + * @since Method available since Release 3.1.4 + */ +function assertContainsOnly($type, $haystack, $isNativeType = NULL, $message = '') +{ + return PHPUnit_Framework_Assert::assertContainsOnly($type, $haystack, $isNativeType, $message); +} + +/** + * Asserts that a variable is empty. + * + * @param mixed $actual + * @param string $message + * @throws PHPUnit_Framework_AssertionFailedError + */ +function assertEmpty($actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertEmpty($actual, $message); +} + +/** + * Asserts that a hierarchy of DOMNodes matches. + * + * @param DOMNode $expectedNode + * @param DOMNode $actualNode + * @param boolean $checkAttributes + * @param string $message + * @author Mattis Stordalen Flister + * @since Method available since Release 3.3.0 + */ +function assertEqualXMLStructure(DOMNode $expectedNode, DOMNode $actualNode, $checkAttributes = FALSE, $message = '') +{ + return PHPUnit_Framework_Assert::assertEqualXMLStructure($expectedNode, $actualNode, $checkAttributes, $message); +} + +/** + * Asserts that two variables are equal. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @param float $delta + * @param integer $maxDepth + * @param boolean $canonicalize + * @param boolean $ignoreCase + */ +function assertEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) +{ + return PHPUnit_Framework_Assert::assertEquals($expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase); +} + +/** + * Asserts that a condition is false. + * + * @param boolean $condition + * @param string $message + * @throws PHPUnit_Framework_AssertionFailedError + */ +function assertFalse($condition, $message = '') +{ + return PHPUnit_Framework_Assert::assertFalse($condition, $message); +} + +/** + * Asserts that the contents of one file is equal to the contents of another + * file. + * + * @param string $expected + * @param string $actual + * @param string $message + * @param boolean $canonicalize + * @param boolean $ignoreCase + * @since Method available since Release 3.2.14 + */ +function assertFileEquals($expected, $actual, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) +{ + return PHPUnit_Framework_Assert::assertFileEquals($expected, $actual, $message, $canonicalize, $ignoreCase); +} + +/** + * Asserts that a file exists. + * + * @param string $filename + * @param string $message + * @since Method available since Release 3.0.0 + */ +function assertFileExists($filename, $message = '') +{ + return PHPUnit_Framework_Assert::assertFileExists($filename, $message); +} + +/** + * Asserts that the contents of one file is not equal to the contents of + * another file. + * + * @param string $expected + * @param string $actual + * @param string $message + * @param boolean $canonicalize + * @param boolean $ignoreCase + * @since Method available since Release 3.2.14 + */ +function assertFileNotEquals($expected, $actual, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) +{ + return PHPUnit_Framework_Assert::assertFileNotEquals($expected, $actual, $message, $canonicalize, $ignoreCase); +} + +/** + * Asserts that a file does not exist. + * + * @param string $filename + * @param string $message + * @since Method available since Release 3.0.0 + */ +function assertFileNotExists($filename, $message = '') +{ + return PHPUnit_Framework_Assert::assertFileNotExists($filename, $message); +} + +/** + * Asserts that a value is greater than another value. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertGreaterThan($expected, $actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertGreaterThan($expected, $actual, $message); +} + +/** + * Asserts that a value is greater than or equal to another value. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertGreaterThanOrEqual($expected, $actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertGreaterThanOrEqual($expected, $actual, $message); +} + +/** + * Asserts that a variable is of a given type. + * + * @param string $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.5.0 + */ +function assertInstanceOf($expected, $actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertInstanceOf($expected, $actual, $message); +} + +/** + * Asserts that a variable is of a given type. + * + * @param string $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.5.0 + */ +function assertInternalType($expected, $actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertInternalType($expected, $actual, $message); +} + +/** + * Asserts that a value is smaller than another value. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertLessThan($expected, $actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertLessThan($expected, $actual, $message); +} + +/** + * Asserts that a value is smaller than or equal to another value. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertLessThanOrEqual($expected, $actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertLessThanOrEqual($expected, $actual, $message); +} + +/** + * Asserts that a haystack does not contain a needle. + * + * @param mixed $needle + * @param mixed $haystack + * @param string $message + * @param boolean $ignoreCase + * @since Method available since Release 2.1.0 + */ +function assertNotContains($needle, $haystack, $message = '', $ignoreCase = FALSE) +{ + return PHPUnit_Framework_Assert::assertNotContains($needle, $haystack, $message, $ignoreCase); +} + +/** + * Asserts that a haystack does not contain only values of a given type. + * + * @param string $type + * @param mixed $haystack + * @param boolean $isNativeType + * @param string $message + * @since Method available since Release 3.1.4 + */ +function assertNotContainsOnly($type, $haystack, $isNativeType = NULL, $message = '') +{ + return PHPUnit_Framework_Assert::assertNotContainsOnly($type, $haystack, $isNativeType, $message); +} + +/** + * Asserts that a variable is not empty. + * + * @param mixed $actual + * @param string $message + * @throws PHPUnit_Framework_AssertionFailedError + */ +function assertNotEmpty($actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertNotEmpty($actual, $message); +} + +/** + * Asserts that two variables are not equal. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + * @param float $delta + * @param integer $maxDepth + * @param boolean $canonicalize + * @param boolean $ignoreCase + * @since Method available since Release 2.3.0 + */ +function assertNotEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) +{ + return PHPUnit_Framework_Assert::assertNotEquals($expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase); +} + +/** + * Asserts that a variable is not of a given type. + * + * @param string $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.5.0 + */ +function assertNotInstanceOf($expected, $actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertNotInstanceOf($expected, $actual, $message); +} + +/** + * Asserts that a variable is not of a given type. + * + * @param string $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 3.5.0 + */ +function assertNotInternalType($expected, $actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertNotInternalType($expected, $actual, $message); +} + +/** + * Asserts that a variable is not NULL. + * + * @param mixed $actual + * @param string $message + */ +function assertNotNull($actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertNotNull($actual, $message); +} + +/** + * Asserts that a string does not match a given regular expression. + * + * @param string $pattern + * @param string $string + * @param string $message + * @since Method available since Release 2.1.0 + */ +function assertNotRegExp($pattern, $string, $message = '') +{ + return PHPUnit_Framework_Assert::assertNotRegExp($pattern, $string, $message); +} + +/** + * Asserts that two variables do not have the same type and value. + * Used on objects, it asserts that two variables do not reference + * the same object. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + */ +function assertNotSame($expected, $actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertNotSame($expected, $actual, $message); +} + +/** + * This assertion is the exact opposite of assertTag(). + * + * Rather than asserting that $matcher results in a match, it asserts that + * $matcher does not match. + * + * @param array $matcher + * @param string $actual + * @param string $message + * @param boolean $isHtml + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + */ +function assertNotTag($matcher, $actual, $message = '', $isHtml = TRUE) +{ + return PHPUnit_Framework_Assert::assertNotTag($matcher, $actual, $message, $isHtml); +} + +/** + * Asserts that a variable is not of a given type. + * + * @param string $expected + * @param mixed $actual + * @param string $message + * @since Method available since Release 2.2.0 + * @deprecated + */ +function assertNotType($expected, $actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertNotType($expected, $actual, $message); +} + +/** + * Asserts that a variable is NULL. + * + * @param mixed $actual + * @param string $message + */ +function assertNull($actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertNull($actual, $message); +} + +/** + * Asserts that an object has a specified attribute. + * + * @param string $attributeName + * @param object $object + * @param string $message + * @since Method available since Release 3.0.0 + */ +function assertObjectHasAttribute($attributeName, $object, $message = '') +{ + return PHPUnit_Framework_Assert::assertObjectHasAttribute($attributeName, $object, $message); +} + +/** + * Asserts that an object does not have a specified attribute. + * + * @param string $attributeName + * @param object $object + * @param string $message + * @since Method available since Release 3.0.0 + */ +function assertObjectNotHasAttribute($attributeName, $object, $message = '') +{ + return PHPUnit_Framework_Assert::assertObjectNotHasAttribute($attributeName, $object, $message); +} + +/** + * Asserts that a string matches a given regular expression. + * + * @param string $pattern + * @param string $string + * @param string $message + */ +function assertRegExp($pattern, $string, $message = '') +{ + return PHPUnit_Framework_Assert::assertRegExp($pattern, $string, $message); +} + +/** + * Asserts that two variables have the same type and value. + * Used on objects, it asserts that two variables reference + * the same object. + * + * @param mixed $expected + * @param mixed $actual + * @param string $message + */ +function assertSame($expected, $actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertSame($expected, $actual, $message); +} + +/** + * Assert the presence, absence, or count of elements in a document matching + * the CSS $selector, regardless of the contents of those elements. + * + * The first argument, $selector, is the CSS selector used to match + * the elements in the $actual document. + * + * The second argument, $count, can be either boolean or numeric. + * When boolean, it asserts for presence of elements matching the selector + * (TRUE) or absence of elements (FALSE). + * When numeric, it asserts the count of elements. + * + * assertSelectCount("#binder", true, $xml); // any? + * assertSelectCount(".binder", 3, $xml); // exactly 3? + * + * @param array $selector + * @param integer $count + * @param mixed $actual + * @param string $message + * @param boolean $isHtml + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + */ +function assertSelectCount($selector, $count, $actual, $message = '', $isHtml = TRUE) +{ + return PHPUnit_Framework_Assert::assertSelectCount($selector, $count, $actual, $message, $isHtml); +} + +/** + * assertSelectEquals("#binder .name", "Chuck", true, $xml); // any? + * assertSelectEquals("#binder .name", "Chuck", false, $xml); // none? + * + * @param array $selector + * @param string $content + * @param integer $count + * @param mixed $actual + * @param string $message + * @param boolean $isHtml + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + */ +function assertSelectEquals($selector, $content, $count, $actual, $message = '', $isHtml = TRUE) +{ + return PHPUnit_Framework_Assert::assertSelectEquals($selector, $content, $count, $actual, $message, $isHtml); +} + +/** + * assertSelectRegExp("#binder .name", "/Mike|Derek/", true, $xml); // any? + * assertSelectRegExp("#binder .name", "/Mike|Derek/", 3, $xml);// 3? + * + * @param array $selector + * @param string $pattern + * @param integer $count + * @param mixed $actual + * @param string $message + * @param boolean $isHtml + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + */ +function assertSelectRegExp($selector, $pattern, $count, $actual, $message = '', $isHtml = TRUE) +{ + return PHPUnit_Framework_Assert::assertSelectRegExp($selector, $pattern, $count, $actual, $message, $isHtml); +} + +/** + * Asserts that a string ends not with a given prefix. + * + * @param string $suffix + * @param string $string + * @param string $message + * @since Method available since Release 3.4.0 + */ +function assertStringEndsNotWith($suffix, $string, $message = '') +{ + return PHPUnit_Framework_Assert::assertStringEndsNotWith($suffix, $string, $message); +} + +/** + * Asserts that a string ends with a given prefix. + * + * @param string $suffix + * @param string $string + * @param string $message + * @since Method available since Release 3.4.0 + */ +function assertStringEndsWith($suffix, $string, $message = '') +{ + return PHPUnit_Framework_Assert::assertStringEndsWith($suffix, $string, $message); +} + +/** + * Asserts that the contents of a string is equal + * to the contents of a file. + * + * @param string $expectedFile + * @param string $actualString + * @param string $message + * @param boolean $canonicalize + * @param boolean $ignoreCase + * @since Method available since Release 3.3.0 + */ +function assertStringEqualsFile($expectedFile, $actualString, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) +{ + return PHPUnit_Framework_Assert::assertStringEqualsFile($expectedFile, $actualString, $message, $canonicalize, $ignoreCase); +} + +/** + * Asserts that a string matches a given format string. + * + * @param string $format + * @param string $string + * @param string $message + * @since Method available since Release 3.5.0 + */ +function assertStringMatchesFormat($format, $string, $message = '') +{ + return PHPUnit_Framework_Assert::assertStringMatchesFormat($format, $string, $message); +} + +/** + * Asserts that a string matches a given format file. + * + * @param string $formatFile + * @param string $string + * @param string $message + * @since Method available since Release 3.5.0 + */ +function assertStringMatchesFormatFile($formatFile, $string, $message = '') +{ + return PHPUnit_Framework_Assert::assertStringMatchesFormatFile($formatFile, $string, $message); +} + +/** + * Asserts that the contents of a string is not equal + * to the contents of a file. + * + * @param string $expectedFile + * @param string $actualString + * @param string $message + * @param boolean $canonicalize + * @param boolean $ignoreCase + * @since Method available since Release 3.3.0 + */ +function assertStringNotEqualsFile($expectedFile, $actualString, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) +{ + return PHPUnit_Framework_Assert::assertStringNotEqualsFile($expectedFile, $actualString, $message, $canonicalize, $ignoreCase); +} + +/** + * Asserts that a string does not match a given format string. + * + * @param string $format + * @param string $string + * @param string $message + * @since Method available since Release 3.5.0 + */ +function assertStringNotMatchesFormat($format, $string, $message = '') +{ + return PHPUnit_Framework_Assert::assertStringNotMatchesFormat($format, $string, $message); +} + +/** + * Asserts that a string does not match a given format string. + * + * @param string $formatFile + * @param string $string + * @param string $message + * @since Method available since Release 3.5.0 + */ +function assertStringNotMatchesFormatFile($formatFile, $string, $message = '') +{ + return PHPUnit_Framework_Assert::assertStringNotMatchesFormatFile($formatFile, $string, $message); +} + +/** + * Asserts that a string starts not with a given prefix. + * + * @param string $prefix + * @param string $string + * @param string $message + * @since Method available since Release 3.4.0 + */ +function assertStringStartsNotWith($prefix, $string, $message = '') +{ + return PHPUnit_Framework_Assert::assertStringStartsNotWith($prefix, $string, $message); +} + +/** + * Asserts that a string starts with a given prefix. + * + * @param string $prefix + * @param string $string + * @param string $message + * @since Method available since Release 3.4.0 + */ +function assertStringStartsWith($prefix, $string, $message = '') +{ + return PHPUnit_Framework_Assert::assertStringStartsWith($prefix, $string, $message); +} + +/** + * Evaluate an HTML or XML string and assert its structure and/or contents. + * + * The first argument ($matcher) is an associative array that specifies the + * match criteria for the assertion: + * + * - `id` : the node with the given id attribute must match the + * corresponsing value. + * - `tag` : the node type must match the corresponding value. + * - `attributes` : a hash. The node's attributres must match the + * corresponsing values in the hash. + * - `content` : The text content must match the given value. + * - `parent` : a hash. The node's parent must match the + * corresponsing hash. + * - `child`: a hash. At least one of the node's immediate children + * must meet the criteria described by the hash. + * - `ancestor` : a hash. At least one of the node's ancestors must + * meet the criteria described by the hash. + * - `descendant` : a hash. At least one of the node's descendants must + * meet the criteria described by the hash. + * - `children` : a hash, for counting children of a node. + * Accepts the keys: + *- `count`: a number which must equal the number of children + * that match + *- `less_than`: the number of matching children must be greater + * than this number + *- `greater_than` : the number of matching children must be less than + * this number + *- `only` : another hash consisting of the keys to use to match + * on the children, and only matching children will be + * counted + * + * + * // Matcher that asserts that there is an element with an id="my_id". + * $matcher = array('id' => 'my_id'); + * + * // Matcher that asserts that there is a "span" tag. + * $matcher = array('tag' => 'span'); + * + * // Matcher that asserts that there is a "span" tag with the content + * // "Hello World". + * $matcher = array('tag' => 'span', 'content' => 'Hello World'); + * + * // Matcher that asserts that there is a "span" tag with content matching + * // the regular expression pattern. + * $matcher = array('tag' => 'span', 'content' => '/Try P(HP|ython)/'); + * + * // Matcher that asserts that there is a "span" with an "list" class + * // attribute. + * $matcher = array( + * 'tag'=> 'span', + * 'attributes' => array('class' => 'list') + * ); + * + * // Matcher that asserts that there is a "span" inside of a "div". + * $matcher = array( + * 'tag'=> 'span', + * 'parent' => array('tag' => 'div') + * ); + * + * // Matcher that asserts that there is a "span" somewhere inside a + * // "table". + * $matcher = array( + * 'tag' => 'span', + * 'ancestor' => array('tag' => 'table') + * ); + * + * // Matcher that asserts that there is a "span" with at least one "em" + * // child. + * $matcher = array( + * 'tag' => 'span', + * 'child' => array('tag' => 'em') + * ); + * + * // Matcher that asserts that there is a "span" containing a (possibly + * // nested) "strong" tag. + * $matcher = array( + * 'tag'=> 'span', + * 'descendant' => array('tag' => 'strong') + * ); + * + * // Matcher that asserts that there is a "span" containing 5-10 "em" tags + * // as immediate children. + * $matcher = array( + * 'tag' => 'span', + * 'children' => array( + * 'less_than'=> 11, + * 'greater_than' => 4, + * 'only' => array('tag' => 'em') + * ) + * ); + * + * // Matcher that asserts that there is a "div", with an "ul" ancestor and + * // a "li" parent (with class="enum"), and containing a "span" descendant + * // that contains an element with id="my_test" and the text "Hello World". + * $matcher = array( + * 'tag'=> 'div', + * 'ancestor' => array('tag' => 'ul'), + * 'parent' => array( + * 'tag'=> 'li', + * 'attributes' => array('class' => 'enum') + * ), + * 'descendant' => array( + * 'tag' => 'span', + * 'child' => array( + * 'id' => 'my_test', + * 'content' => 'Hello World' + * ) + * ) + * ); + * + * // Use assertTag() to apply a $matcher to a piece of $html. + * $this->assertTag($matcher, $html); + * + * // Use assertTag() to apply a $matcher to a piece of $xml. + * $this->assertTag($matcher, $xml, '', FALSE); + * + * + * The second argument ($actual) is a string containing either HTML or + * XML text to be tested. + * + * The third argument ($message) is an optional message that will be + * used if the assertion fails. + * + * The fourth argument ($html) is an optional flag specifying whether + * to load the $actual string into a DOMDocument using the HTML or + * XML load strategy. It is TRUE by default, which assumes the HTML + * load strategy. In many cases, this will be acceptable for XML as well. + * + * @param array $matcher + * @param string $actual + * @param string $message + * @param boolean $isHtml + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + */ +function assertTag($matcher, $actual, $message = '', $isHtml = TRUE) +{ + return PHPUnit_Framework_Assert::assertTag($matcher, $actual, $message, $isHtml); +} + +/** + * Evaluates a PHPUnit_Framework_Constraint matcher object. + * + * @param mixed$value + * @param PHPUnit_Framework_Constraint $constraint + * @param string $message + * @since Method available since Release 3.0.0 + */ +function assertThat($value, PHPUnit_Framework_Constraint $constraint, $message = '') +{ + return PHPUnit_Framework_Assert::assertThat($value, $constraint, $message); +} + +/** + * Asserts that a condition is true. + * + * @param boolean $condition + * @param string $message + * @throws PHPUnit_Framework_AssertionFailedError + */ +function assertTrue($condition, $message = '') +{ + return PHPUnit_Framework_Assert::assertTrue($condition, $message); +} + +/** + * Asserts that a variable is of a given type. + * + * @param string $expected + * @param mixed $actual + * @param string $message + * @deprecated + */ +function assertType($expected, $actual, $message = '') +{ + return PHPUnit_Framework_Assert::assertType($expected, $actual, $message); +} + +/** + * Asserts that two XML files are equal. + * + * @param string $expectedFile + * @param string $actualFile + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertXmlFileEqualsXmlFile($expectedFile, $actualFile, $message = '') +{ + return PHPUnit_Framework_Assert::assertXmlFileEqualsXmlFile($expectedFile, $actualFile, $message); +} + +/** + * Asserts that two XML files are not equal. + * + * @param string $expectedFile + * @param string $actualFile + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertXmlFileNotEqualsXmlFile($expectedFile, $actualFile, $message = '') +{ + return PHPUnit_Framework_Assert::assertXmlFileNotEqualsXmlFile($expectedFile, $actualFile, $message); +} + +/** + * Asserts that two XML documents are equal. + * + * @param string $expectedFile + * @param string $actualXml + * @param string $message + * @since Method available since Release 3.3.0 + */ +function assertXmlStringEqualsXmlFile($expectedFile, $actualXml, $message = '') +{ + return PHPUnit_Framework_Assert::assertXmlStringEqualsXmlFile($expectedFile, $actualXml, $message); +} + +/** + * Asserts that two XML documents are equal. + * + * @param string $expectedXml + * @param string $actualXml + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertXmlStringEqualsXmlString($expectedXml, $actualXml, $message = '') +{ + return PHPUnit_Framework_Assert::assertXmlStringEqualsXmlString($expectedXml, $actualXml, $message); +} + +/** + * Asserts that two XML documents are not equal. + * + * @param string $expectedFile + * @param string $actualXml + * @param string $message + * @since Method available since Release 3.3.0 + */ +function assertXmlStringNotEqualsXmlFile($expectedFile, $actualXml, $message = '') +{ + return PHPUnit_Framework_Assert::assertXmlStringNotEqualsXmlFile($expectedFile, $actualXml, $message); +} + +/** + * Asserts that two XML documents are not equal. + * + * @param string $expectedXml + * @param string $actualXml + * @param string $message + * @since Method available since Release 3.1.0 + */ +function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, $message = '') +{ + return PHPUnit_Framework_Assert::assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, $message); +} + +/** + * Returns a matcher that matches when the method it is evaluated for + * is invoked at the given $index. + * + * @param integer $index + * @return PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex + * @since Method available since Release 3.0.0 + */ +function at($index) +{ + return PHPUnit_Framework_TestCase::at($index); +} + +/** + * Returns a matcher that matches when the method it is evaluated for + * is executed at least once. + * + * @return PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce + * @since Method available since Release 3.0.0 + */ +function atLeastOnce() +{ + return PHPUnit_Framework_TestCase::atLeastOnce(); +} + +/** + * Returns a PHPUnit_Framework_Constraint_Attribute matcher object. + * + * @param PHPUnit_Framework_Constraint $constraint + * @param string $attributeName + * @return PHPUnit_Framework_Constraint_Attribute + * @since Method available since Release 3.1.0 + */ +function attribute(PHPUnit_Framework_Constraint $constraint, $attributeName) +{ + return PHPUnit_Framework_Assert::attribute($constraint, $attributeName); +} + +/** + * Returns a PHPUnit_Framework_Constraint_IsEqual matcher object + * that is wrapped in a PHPUnit_Framework_Constraint_Attribute matcher + * object. + * + * @param string $attributeName + * @param mixed $value + * @param float $delta + * @param integer $maxDepth + * @param boolean $canonicalize + * @param boolean $ignoreCase + * @return PHPUnit_Framework_Constraint_Attribute + * @since Method available since Release 3.1.0 + */ +function attributeEqualTo($attributeName, $value, $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) +{ + return PHPUnit_Framework_Assert::attributeEqualTo($attributeName, $value, $delta, $maxDepth, $canonicalize, $ignoreCase); +} + +/** + * Returns a PHPUnit_Framework_Constraint_ClassHasAttribute matcher object. + * + * @param string $attributeName + * @return PHPUnit_Framework_Constraint_ClassHasAttribute + * @since Method available since Release 3.1.0 + */ +function classHasAttribute($attributeName) +{ + return PHPUnit_Framework_Assert::classHasAttribute($attributeName); +} + +/** + * Returns a PHPUnit_Framework_Constraint_ClassHasStaticAttribute matcher + * object. + * + * @param string $attributeName + * @return PHPUnit_Framework_Constraint_ClassHasStaticAttribute + * @since Method available since Release 3.1.0 + */ +function classHasStaticAttribute($attributeName) +{ + return PHPUnit_Framework_Assert::classHasStaticAttribute($attributeName); +} + +/** + * Returns a PHPUnit_Framework_Constraint_TraversableContains matcher + * object. + * + * @param mixed $value + * @return PHPUnit_Framework_Constraint_TraversableContains + * @since Method available since Release 3.0.0 + */ +function contains($value) +{ + return PHPUnit_Framework_Assert::contains($value); +} + +/** + * Returns a PHPUnit_Framework_Constraint_TraversableContainsOnly matcher + * object. + * + * @param string $type + * @return PHPUnit_Framework_Constraint_TraversableContainsOnly + * @since Method available since Release 3.1.4 + */ +function containsOnly($type) +{ + return PHPUnit_Framework_Assert::containsOnly($type); +} + +/** + * Returns a PHPUnit_Framework_Constraint_IsEqual matcher object. + * + * @param mixed $value + * @param float $delta + * @param integer $maxDepth + * @param boolean $canonicalize + * @param boolean $ignoreCase + * @return PHPUnit_Framework_Constraint_IsEqual + * @since Method available since Release 3.0.0 + */ +function equalTo($value, $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) +{ + return PHPUnit_Framework_Assert::equalTo($value, $delta, $maxDepth, $canonicalize, $ignoreCase); +} + +/** + * Returns a matcher that matches when the method it is evaluated for + * is executed exactly $count times. + * + * @param integer $count + * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount + * @since Method available since Release 3.0.0 + */ +function exactly($count) +{ + return PHPUnit_Framework_TestCase::exactly($count); +} + +/** + * Returns a PHPUnit_Framework_Constraint_FileExists matcher object. + * + * @return PHPUnit_Framework_Constraint_FileExists + * @since Method available since Release 3.0.0 + */ +function fileExists() +{ + return PHPUnit_Framework_Assert::fileExists(); +} + +/** + * Returns a PHPUnit_Framework_Constraint_GreaterThan matcher object. + * + * @param mixed $value + * @return PHPUnit_Framework_Constraint_GreaterThan + * @since Method available since Release 3.0.0 + */ +function greaterThan($value) +{ + return PHPUnit_Framework_Assert::greaterThan($value); +} + +/** + * Returns a PHPUnit_Framework_Constraint_Or matcher object that wraps + * a PHPUnit_Framework_Constraint_IsEqual and a + * PHPUnit_Framework_Constraint_GreaterThan matcher object. + * + * @param mixed $value + * @return PHPUnit_Framework_Constraint_Or + * @since Method available since Release 3.1.0 + */ +function greaterThanOrEqual($value) +{ + return PHPUnit_Framework_Assert::greaterThanOrEqual($value); +} + +/** + * Returns a PHPUnit_Framework_Constraint_IsIdentical matcher object. + * + * @param mixed $value + * @return PHPUnit_Framework_Constraint_IsIdentical + * @since Method available since Release 3.0.0 + */ +function identicalTo($value) +{ + return PHPUnit_Framework_Assert::identicalTo($value); +} + +/** + * Returns a PHPUnit_Framework_Constraint_IsEmpty matcher object. + * + * @return PHPUnit_Framework_Constraint_IsEmpty + * @since Method available since Release 3.5.0 + */ +function isEmpty() +{ + return PHPUnit_Framework_Assert::isEmpty(); +} + +/** + * Returns a PHPUnit_Framework_Constraint_IsFalse matcher object. + * + * @return PHPUnit_Framework_Constraint_IsFalse + * @since Method available since Release 3.3.0 + */ +function isFalse() +{ + return PHPUnit_Framework_Assert::isFalse(); +} + +/** + * Returns a PHPUnit_Framework_Constraint_IsInstanceOf matcher object. + * + * @param string $className + * @return PHPUnit_Framework_Constraint_IsInstanceOf + * @since Method available since Release 3.0.0 + */ +function isInstanceOf($className) +{ + return PHPUnit_Framework_Assert::isInstanceOf($className); +} + +/** + * Returns a PHPUnit_Framework_Constraint_IsNull matcher object. + * + * @return PHPUnit_Framework_Constraint_IsNull + * @since Method available since Release 3.3.0 + */ +function isNull() +{ + return PHPUnit_Framework_Assert::isNull(); +} + +/** + * Returns a PHPUnit_Framework_Constraint_IsTrue matcher object. + * + * @return PHPUnit_Framework_Constraint_IsTrue + * @since Method available since Release 3.3.0 + */ +function isTrue() +{ + return PHPUnit_Framework_Assert::isTrue(); +} + +/** + * Returns a PHPUnit_Framework_Constraint_IsType matcher object. + * + * @param string $type + * @return PHPUnit_Framework_Constraint_IsType + * @since Method available since Release 3.0.0 + */ +function isType($type) +{ + return PHPUnit_Framework_Assert::isType($type); +} + +/** + * Returns a PHPUnit_Framework_Constraint_LessThan matcher object. + * + * @param mixed $value + * @return PHPUnit_Framework_Constraint_LessThan + * @since Method available since Release 3.0.0 + */ +function lessThan($value) +{ + return PHPUnit_Framework_Assert::lessThan($value); +} + +/** + * Returns a PHPUnit_Framework_Constraint_Or matcher object that wraps + * a PHPUnit_Framework_Constraint_IsEqual and a + * PHPUnit_Framework_Constraint_LessThan matcher object. + * + * @param mixed $value + * @return PHPUnit_Framework_Constraint_Or + * @since Method available since Release 3.1.0 + */ +function lessThanOrEqual($value) +{ + return PHPUnit_Framework_Assert::lessThanOrEqual($value); +} + +/** + * Returns a PHPUnit_Framework_Constraint_And matcher object. + * + * @return PHPUnit_Framework_Constraint_And + * @since Method available since Release 3.0.0 + */ +function logicalAnd() +{ + return PHPUnit_Framework_Assert::logicalAnd(); +} + +/** + * Returns a PHPUnit_Framework_Constraint_Not matcher object. + * + * @param PHPUnit_Framework_Constraint $constraint + * @return PHPUnit_Framework_Constraint_Not + * @since Method available since Release 3.0.0 + */ +function logicalNot(PHPUnit_Framework_Constraint $constraint) +{ + return PHPUnit_Framework_Assert::logicalNot($constraint); +} + +/** + * Returns a PHPUnit_Framework_Constraint_Or matcher object. + * + * @return PHPUnit_Framework_Constraint_Or + * @since Method available since Release 3.0.0 + */ +function logicalOr() +{ + return PHPUnit_Framework_Assert::logicalOr(); +} + +/** + * Returns a PHPUnit_Framework_Constraint_Xor matcher object. + * + * @return PHPUnit_Framework_Constraint_Xor + * @since Method available since Release 3.0.0 + */ +function logicalXor() +{ + return PHPUnit_Framework_Assert::logicalXor(); +} + +/** + * Returns a PHPUnit_Framework_Constraint_StringMatches matcher object. + * + * @param string $string + * @return PHPUnit_Framework_Constraint_StringMatches + * @since Method available since Release 3.5.0 + */ +function matches($string) +{ + return PHPUnit_Framework_Assert::matches($string); +} + +/** + * Returns a PHPUnit_Framework_Constraint_PCREMatch matcher object. + * + * @param string $pattern + * @return PHPUnit_Framework_Constraint_PCREMatch + * @since Method available since Release 3.0.0 + */ +function matchesRegularExpression($pattern) +{ + return PHPUnit_Framework_Assert::matchesRegularExpression($pattern); +} + +/** + * Returns a matcher that matches when the method it is evaluated for + * is never executed. + * + * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount + * @since Method available since Release 3.0.0 + */ +function never() +{ + return PHPUnit_Framework_TestCase::never(); +} + +/** + * Returns a PHPUnit_Framework_Constraint_ObjectHasAttribute matcher object. + * + * @param string $attributeName + * @return PHPUnit_Framework_Constraint_ObjectHasAttribute + * @since Method available since Release 3.0.0 + */ +function objectHasAttribute($attributeName) +{ + return PHPUnit_Framework_Assert::objectHasAttribute($attributeName); +} + +/** + * + * + * @param mixed $value, ... + * @return PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls + * @since Method available since Release 3.0.0 + */ +function onConsecutiveCalls() +{ + return PHPUnit_Framework_TestCase::onConsecutiveCalls(); +} + +/** + * Returns a matcher that matches when the method it is evaluated for + * is executed exactly once. + * + * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount + * @since Method available since Release 3.0.0 + */ +function once() +{ + return PHPUnit_Framework_TestCase::once(); +} + +/** + * + * + * @param integer $argumentIndex + * @return PHPUnit_Framework_MockObject_Stub_ReturnArgument + * @since Method available since Release 3.3.0 + */ +function returnArgument($argumentIndex) +{ + return PHPUnit_Framework_TestCase::returnArgument($argumentIndex); +} + +/** + * + * + * @param mixed $callback + * @return PHPUnit_Framework_MockObject_Stub_ReturnCallback + * @since Method available since Release 3.3.0 + */ +function returnCallback($callback) +{ + return PHPUnit_Framework_TestCase::returnCallback($callback); +} + +/** + * + * + * @param mixed $value + * @return PHPUnit_Framework_MockObject_Stub_Return + * @since Method available since Release 3.0.0 + */ +function returnValue($value) +{ + return PHPUnit_Framework_TestCase::returnValue($value); +} + +/** + * Returns a PHPUnit_Framework_Constraint_StringContains matcher object. + * + * @param string $string + * @param boolean $case + * @return PHPUnit_Framework_Constraint_StringContains + * @since Method available since Release 3.0.0 + */ +function stringContains($string, $case = TRUE) +{ + return PHPUnit_Framework_Assert::stringContains($string, $case); +} + +/** + * Returns a PHPUnit_Framework_Constraint_StringEndsWith matcher object. + * + * @param mixed $suffix + * @return PHPUnit_Framework_Constraint_StringEndsWith + * @since Method available since Release 3.4.0 + */ +function stringEndsWith($suffix) +{ + return PHPUnit_Framework_Assert::stringEndsWith($suffix); +} + +/** + * Returns a PHPUnit_Framework_Constraint_StringStartsWith matcher object. + * + * @param mixed $prefix + * @return PHPUnit_Framework_Constraint_StringStartsWith + * @since Method available since Release 3.4.0 + */ +function stringStartsWith($prefix) +{ + return PHPUnit_Framework_Assert::stringStartsWith($prefix); +} + +/** + * + * + * @param Exception $exception + * @return PHPUnit_Framework_MockObject_Stub_Exception + * @since Method available since Release 3.1.0 + */ +function throwException(Exception $exception) +{ + return PHPUnit_Framework_TestCase::throwException($exception); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/AssertionFailedError.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/AssertionFailedError.php new file mode 100644 index 0000000..c8d3f15 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/AssertionFailedError.php @@ -0,0 +1,69 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * Thrown when an assertion failed. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +class PHPUnit_Framework_AssertionFailedError extends Exception implements PHPUnit_Framework_SelfDescribing +{ + /** + * Wrapper for getMessage() which is declared as final. + * + * @return string + */ + public function toString() + { + return $this->getMessage(); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure.php new file mode 100644 index 0000000..31dac8e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure.php @@ -0,0 +1,208 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * Thrown when an assertion for string equality failed. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +abstract class PHPUnit_Framework_ComparisonFailure extends PHPUnit_Framework_AssertionFailedError +{ + /** + * Expected value of the retrieval which does not match $actual. + * @var mixed + */ + protected $expected; + + /** + * Actually retrieved value which does not match $expected. + * @var mixed + */ + protected $actual; + + /** + * @var boolean + */ + protected $identical; + + /** + * Optional message which is placed in front of the first line + * returned by toString(). + * @var string + */ + protected $message; + + /** + * Initialises with the expected value and the actual value. + * + * @param mixed $expected Expected value retrieved. + * @param mixed $actual Actual value retrieved. + * @param boolean $identical + * @param string $message A string which is prefixed on all returned lines + * in the difference output. + */ + public function __construct($expected, $actual, $identical = FALSE, $message = '') + { + $this->expected = $expected; + $this->actual = $actual; + $this->identical = $identical; + $this->message = $message; + } + + /** + * @return mixed + */ + public function getActual() + { + return $this->actual; + } + + /** + * @return mixed + */ + public function getExpected() + { + return $this->expected; + } + + /** + * @return boolean + */ + public function identical() + { + return $this->identical; + } + + /** + * Figures out which diff class to use for the input types then + * instantiates that class and returns the object. + * @note The diff is type sensitive, if the type differs only the types + * are shown. + * + * @param mixed $expected Expected value retrieved. + * @param mixed $actual Actual value retrieved. + * @param string $message A string which is prefixed on all returned lines + * in the difference output. + * @return PHPUnit_Framework_ComparisonFailure + */ + public static function diffIdentical($expected, $actual, $message = '') + { + if (gettype($expected) !== gettype($actual)) { + return new PHPUnit_Framework_ComparisonFailure_Type( + $expected, $actual, TRUE, $message + ); + } + + else if (is_array($expected) && is_array($actual)) { + return new PHPUnit_Framework_ComparisonFailure_Array( + $expected, $actual, TRUE, $message + ); + } + + else if (is_object($expected) && is_object($actual)) { + return new PHPUnit_Framework_ComparisonFailure_Object( + $expected, $actual, TRUE, $message + ); + } + + else if (is_string($expected) && !is_object($actual)) { + return new PHPUnit_Framework_ComparisonFailure_String( + $expected, $actual, TRUE, $message + ); + } + + else if (is_null($expected) || is_scalar($expected)) { + return new PHPUnit_Framework_ComparisonFailure_Scalar( + $expected, $actual, TRUE, $message + ); + } + } + + /** + * Figures out which diff class to use for the input types then + * instantiates that class and returns the object. + * @note The diff is not type sensitive, if the type differs the $actual + * value will be converted to the same type as the $expected. + * + * @param mixed $expected Expected value retrieved. + * @param mixed $actual Actual value retrieved. + * @param string $message A string which is prefixed on all returned lines + * in the difference output. + * @return PHPUnit_Framework_ComparisonFailure + */ + public static function diffEqual($expected, $actual, $message = '') + { + if (is_array($expected) && is_array($actual)) { + return new PHPUnit_Framework_ComparisonFailure_Array( + $expected, $actual, FALSE, $message + ); + } + + else if (is_object($expected) && is_object($actual)) { + return new PHPUnit_Framework_ComparisonFailure_Object( + $expected, $actual, FALSE, $message + ); + } + + else if (is_string($expected) && !is_object($actual)) { + return new PHPUnit_Framework_ComparisonFailure_String( + $expected, $actual, FALSE, $message + ); + } + + else if (is_null($expected) || is_scalar($expected)) { + return new PHPUnit_Framework_ComparisonFailure_Scalar( + $expected, $actual, FALSE, $message + ); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Array.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Array.php new file mode 100644 index 0000000..f77b409 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Array.php @@ -0,0 +1,140 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_ComparisonFailure + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Thrown when an assertion for array equality failed. + * + * @package PHPUnit + * @subpackage Framework_ComparisonFailure + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_ComparisonFailure_Array extends PHPUnit_Framework_ComparisonFailure +{ + /** + * Returns a string describing the difference between the expected and the + * actual array. + * + * @return string + */ + public function toString() + { + if (!$this->identical) { + ksort($this->expected); + ksort($this->actual); + } + + $diff = PHPUnit_Util_Diff::diff( + print_r($this->expected, TRUE), + print_r($this->actual, TRUE) + ); + + if ($diff !== FALSE) { + return trim($diff); + } + + // Fallback: Either diff is not available or the print_r() output for + // the expected and the actual array are equal (but the arrays are not). + + $expectedOnly = array(); + $actualOnly = array(); + $diff = ''; + + foreach ($this->expected as $expectedKey => $expectedValue) { + if (!array_key_exists($expectedKey, $this->actual)) { + $expectedOnly[] = $expectedKey; + continue; + } + + if ($expectedValue === $this->actual[$expectedKey]) { + continue; + } + + $diffObject = PHPUnit_Framework_ComparisonFailure::diffIdentical( + $expectedValue, + $this->actual[$expectedKey], + sprintf( + '%sarray key %s: ', + + $this->message, + PHPUnit_Util_Type::toString($expectedKey) + ) + ); + + $diff .= $diffObject->toString() . "\n"; + } + + foreach ($this->actual as $actualKey => $actualValue) { + if (!array_key_exists($actualKey, $this->expected)) { + $actualOnly[] = $actualKey; + continue; + } + } + + foreach ($expectedOnly as $expectedKey) { + $diff .= sprintf( + "array key %s: only in expected %s\n", + + PHPUnit_Util_Type::toString($expectedKey), + PHPUnit_Util_Type::toString($this->expected[$expectedKey]) + ); + } + + foreach ($actualOnly as $actualKey) { + $diff .= sprintf( + "array key %s: only in actual %s\n", + + PHPUnit_Util_Type::toString($actualKey), + PHPUnit_Util_Type::toString($this->actual[$actualKey]) + ); + } + + return $diff; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Object.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Object.php new file mode 100644 index 0000000..04f6215 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Object.php @@ -0,0 +1,170 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_ComparisonFailure + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Thrown when an assertion for object equality failed. + * + * @package PHPUnit + * @subpackage Framework_ComparisonFailure + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_ComparisonFailure_Object extends PHPUnit_Framework_ComparisonFailure +{ + /** + * Returns a string describing the difference between the expected and the + * actual object. + * + * @return string + */ + public function toString() + { + $diff = PHPUnit_Util_Diff::diff( + print_r($this->expected, TRUE), + print_r($this->actual, TRUE) + ); + + if ($diff !== FALSE) { + return trim($diff); + } + + // Fallback: Either diff is not available or the print_r() output for + // the expected and the actual object are equal (but the objects are + // not). + + $expectedClass = get_class($this->expected); + $actualClass = get_class($this->actual); + + if ($expectedClass !== $actualClass) { + return sprintf( + "%s%sexpected class <%s>\n" . + '%sgot class <%s>', + + $this->message, + ($this->message != '') ? ' ' : '', + $expectedClass, + ($this->message != '') ? str_repeat(' ', strlen($this->message) + 1) : '', + $actualClass + ); + } else { + $expectedReflection = new ReflectionClass($expectedClass); + $actualReflection = new ReflectionClass($actualClass); + + $diff = "in object of class <{$expectedClass}>:\n"; + $i = 0; + + foreach($expectedReflection->getProperties() as $expectedAttribute) { + if ($expectedAttribute->isPrivate() || + $expectedAttribute->isProtected()) { + continue; + } + + $actualAttribute = $actualReflection->getProperty( + $expectedAttribute->getName() + ); + $expectedValue = $expectedAttribute->getValue( + $this->expected + ); + $actualValue = $actualAttribute->getValue($this->actual); + + if ($expectedValue !== $actualValue) { + if ($i > 0) { + $diff .= "\n"; + } + + ++$i; + + $expectedType = gettype($expectedValue); + $actualType = gettype($actualValue); + + if ($expectedType !== $actualType) { + $diffObject = new PHPUnit_Framework_ComparisonFailure_Type( + $expectedValue, + $actualValue, + $this->message . 'attribute <' . + $expectedAttribute->getName() . '>: ' + ); + + $diff .= $diffObject->toString(); + } + + elseif (is_object($expectedValue)) { + if (get_class($expectedValue) !== get_class($actualValue)) { + $diffObject = new PHPUnit_Framework_ComparisonFailure_Type( + $expectedValue, + $actualValue, + $this->message . 'attribute <' . + $expectedAttribute->getName() . '>: ' + ); + + $diff .= $diffObject->toString(); + } else { + $diff .= 'attribute <' . + $expectedAttribute->getName() . + '> contains object <' . + get_class($expectedValue) . + '> with different attributes'; + } + } else { + $diffObject = PHPUnit_Framework_ComparisonFailure::diffIdentical( + $expectedValue, + $actualValue, + $this->message . 'attribute <' . + $expectedAttribute->getName() . '>: ' + ); + + $diff .= $diffObject->toString(); + } + } + } + + return $diff; + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Scalar.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Scalar.php new file mode 100644 index 0000000..7e981ac --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Scalar.php @@ -0,0 +1,74 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_ComparisonFailure + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Thrown when an assertion for scalar equality failed. + * + * @package PHPUnit + * @subpackage Framework_ComparisonFailure + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_ComparisonFailure_Scalar extends PHPUnit_Framework_ComparisonFailure +{ + /** + * Returns a string describing the difference between the expected and the + * actual scalar value. + */ + public function toString() + { + return sprintf( + 'Failed asserting that %s %s %s.', + + PHPUnit_Util_Type::toString($this->actual), + $this->identical ? 'is identical to' : 'matches expected', + PHPUnit_Util_Type::toString($this->expected) + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/String.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/String.php new file mode 100644 index 0000000..67361ae --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/String.php @@ -0,0 +1,82 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_ComparisonFailure + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Thrown when an assertion for string equality failed. + * + * @package PHPUnit + * @subpackage Framework_ComparisonFailure + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_ComparisonFailure_String extends PHPUnit_Framework_ComparisonFailure +{ + /** + * Returns a string describing the difference between + * the expected and the actual string value. + */ + public function toString() + { + $expected = (string)$this->expected; + $actual = (string)$this->actual; + $diff = PHPUnit_Util_Diff::diff($expected, $actual); + + if ($diff === FALSE) { + $diff = ''; + } + + if (!empty($this->message)) { + $buffer = $this->message . "\n"; + } else { + $buffer = ''; + } + + return trim($buffer . $diff); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Type.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Type.php new file mode 100644 index 0000000..12b000f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ComparisonFailure/Type.php @@ -0,0 +1,73 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_ComparisonFailure + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Thrown when an assertion for type equality failed. + * + * @package PHPUnit + * @subpackage Framework_ComparisonFailure + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_ComparisonFailure_Type extends PHPUnit_Framework_ComparisonFailure +{ + /** + * Returns a string describing the type difference between the expected + * and the actual value. + */ + public function toString() + { + return sprintf( + '%s does not match expected type "%s".', + + PHPUnit_Util_Type::toString($this->actual), + gettype($this->expected) + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint.php new file mode 100644 index 0000000..5ba4edb --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint.php @@ -0,0 +1,170 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Abstract base class for constraints. which are placed upon any value. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Interface available since Release 3.0.0 + */ +abstract class PHPUnit_Framework_Constraint implements Countable, PHPUnit_Framework_SelfDescribing +{ + /** + * Counts the number of constraint elements. + * + * @return integer + * @since Method available since Release 3.4.0 + */ + public function count() + { + return 1; + } + + /** + * Creates the appropriate exception for the constraint which can be caught + * by the unit test system. This can be called if a call to evaluate() + * fails. + * + * @param mixed $other The value passed to evaluate() which failed the + * constraint check. + * @param string $description A string with extra description of what was + * going on while the evaluation failed. + * @param boolean $not Flag to indicate negation. + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function fail($other, $description, $not = FALSE) + { + throw new PHPUnit_Framework_ExpectationFailedException( + $this->failureDescription($other, $description, $not), + NULL + ); + } + + /** + * @param mixed $other + * @param string $description + * @param boolean $not + */ + protected function failureDescription($other, $description, $not) + { + $failureDescription = $this->customFailureDescription( + $other, $description, $not + ); + + if ($failureDescription === NULL) { + $failureDescription = sprintf( + 'Failed asserting that %s %s.', + + PHPUnit_Util_Type::toString($other), + $this->toString() + ); + } + + if ($not) { + $failureDescription = self::negate($failureDescription); + } + + if (!empty($description)) { + $failureDescription = $description . "\n" . $failureDescription; + } + + return $failureDescription; + } + + /** + * @param mixed $other + * @param string $description + * @param boolean $not + */ + protected function customFailureDescription($other, $description, $not) + { + } + + /** + * @param string $string + * @return string + */ + public static function negate($string) + { + return str_replace( + array( + 'contains ', + 'exists', + 'has ', + 'is ', + 'matches ', + 'starts with ', + 'ends with ', + 'not not ' + ), + array( + 'does not contain ', + 'does not exist', + 'does not have ', + 'is not ', + 'does not match ', + 'starts not with ', + 'ends not with ', + 'not ' + ), + $string + ); + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + abstract public function evaluate($other); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/And.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/And.php new file mode 100644 index 0000000..fa372a1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/And.php @@ -0,0 +1,160 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Logical AND. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_And extends PHPUnit_Framework_Constraint +{ + /** + * @var PHPUnit_Framework_Constraint[] + */ + protected $constraints = array(); + + /** + * @var PHPUnit_Framework_Constraint + */ + protected $lastConstraint = NULL; + + /** + * @param PHPUnit_Framework_Constraint[] $constraints + */ + public function setConstraints(array $constraints) + { + $this->constraints = array(); + + foreach($constraints as $key => $constraint) { + if (!($constraint instanceof PHPUnit_Framework_Constraint)) { + throw new InvalidArgumentException( + 'All parameters to ' . __CLASS__ . + ' must be a constraint object.' + ); + } + + $this->constraints[] = $constraint; + } + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + $this->lastConstraint = NULL; + + foreach($this->constraints as $constraint) { + $this->lastConstraint = $constraint; + + if (!$constraint->evaluate($other)) { + return FALSE; + } + } + + return TRUE; + } + + /** + * @param mixed $other The value passed to evaluate() which failed the + * constraint check. + * @param string $description A string with extra description of what was + * going on while the evaluation failed. + * @param boolean $not Flag to indicate negation. + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function fail($other, $description, $not = FALSE) + { + $this->lastConstraint->fail($other, $description, $not); + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + $text = ''; + + foreach($this->constraints as $key => $constraint) { + if ($key > 0) { + $text .= ' and '; + } + + $text .= $constraint->toString(); + } + + return $text; + } + + /** + * Counts the number of constraint elements. + * + * @return integer + * @since Method available since Release 3.4.0 + */ + public function count() + { + $count = 0; + + foreach ($this->constraints as $constraint) { + $count += count($constraint); + } + + return $count; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ArrayHasKey.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ArrayHasKey.php new file mode 100644 index 0000000..9903fac --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ArrayHasKey.php @@ -0,0 +1,113 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Constraint that asserts that the array it is evaluated for has a given key. + * + * Uses array_key_exists() to check if the key is found in the input array, if + * not found the evaluaton fails. + * + * The array key is passed in the constructor. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_ArrayHasKey extends PHPUnit_Framework_Constraint +{ + /** + * @var integer|string + */ + protected $key; + + /** + * @param integer|string $key + */ + public function __construct($key) + { + $this->key = $key; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return array_key_exists($this->key, $other); + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return 'has the key ' . PHPUnit_Util_Type::toString($this->key); + } + + /** + * @param mixed $other + * @param string $description + * @param boolean $not + */ + protected function customFailureDescription($other, $description, $not) + { + return sprintf( + 'Failed asserting that an array %s.', + + $this->toString() + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Attribute.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Attribute.php new file mode 100644 index 0000000..e17cd5b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Attribute.php @@ -0,0 +1,149 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.1.0 + */ + +/** + * + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.1.0 + */ + +class PHPUnit_Framework_Constraint_Attribute extends PHPUnit_Framework_Constraint +{ + /** + * @var string + */ + protected $attributeName; + + /** + * @var PHPUnit_Framework_Constraint + */ + protected $constraint; + + /** + * @param PHPUnit_Framework_Constraint $constraint + * @param string $attributeName + */ + public function __construct(PHPUnit_Framework_Constraint $constraint, $attributeName) + { + $this->attributeName = $attributeName; + $this->constraint = $constraint; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return $this->constraint->evaluate( + PHPUnit_Framework_Assert::readAttribute( + $other, $this->attributeName + ) + ); + } + + /** + * @param mixed $other The value passed to evaluate() which failed the + * constraint check. + * @param string $description A string with extra description of what was + * going on while the evaluation failed. + * @param boolean $not Flag to indicate negation. + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function fail($other, $description, $not = FALSE) + { + parent::fail( + PHPUnit_Framework_Assert::readAttribute( + $other, $this->attributeName + ), + $description, + $not + ); + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return 'attribute "' . $this->attributeName . '" ' . + $this->constraint->toString(); + } + + /** + * Counts the number of constraint elements. + * + * @return integer + * @since Method available since Release 3.4.0 + */ + public function count() + { + return count($this->constraint); + } + + /** + * @since Method available since Release 3.4.0 + */ + protected function customFailureDescription($other, $description, $not) + { + return sprintf( + 'Failed asserting that %s.', + + $this->toString() + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ClassHasAttribute.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ClassHasAttribute.php new file mode 100644 index 0000000..fd87b4a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ClassHasAttribute.php @@ -0,0 +1,110 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.1.0 + */ + +/** + * Constraint that asserts that the class it is evaluated for has a given + * attribute. + * + * The attribute name is passed in the constructor. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.1.0 + */ +class PHPUnit_Framework_Constraint_ClassHasAttribute extends PHPUnit_Framework_Constraint +{ + /** + * @var string + */ + protected $attributeName; + + /** + * @param string $attributeName + */ + public function __construct($attributeName) + { + $this->attributeName = $attributeName; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + $class = new ReflectionClass($other); + + return $class->hasProperty($this->attributeName); + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return sprintf( + 'has attribute "%s"', + + $this->attributeName + ); + } + + protected function customFailureDescription($other, $description, $not) + { + return sprintf( + 'Failed asserting that class "%s" %s.', $other, $this->toString() + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ClassHasStaticAttribute.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ClassHasStaticAttribute.php new file mode 100644 index 0000000..10bc8c0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ClassHasStaticAttribute.php @@ -0,0 +1,97 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.1.0 + */ + +/** + * Constraint that asserts that the class it is evaluated for has a given + * static attribute. + * + * The attribute name is passed in the constructor. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.1.0 + */ +class PHPUnit_Framework_Constraint_ClassHasStaticAttribute extends PHPUnit_Framework_Constraint_ClassHasAttribute +{ + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + $class = new ReflectionClass($other); + + if ($class->hasProperty($this->attributeName)) { + $attribute = $class->getProperty($this->attributeName); + + return $attribute->isStatic(); + } else { + return FALSE; + } + } + + /** + * Returns a string representation of the constraint. + * + * @return string + * @since Method available since Release 3.3.0 + */ + public function toString() + { + return sprintf( + 'has static attribute "%s"', + + $this->attributeName + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/FileExists.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/FileExists.php new file mode 100644 index 0000000..51733e4 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/FileExists.php @@ -0,0 +1,112 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Constraint that checks if the file(name) that it is evaluated for exists. + * + * The file path to check is passed as $other in evaluate(). + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_FileExists extends PHPUnit_Framework_Constraint +{ + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return file_exists($other); + } + + /** + * @param mixed $other The value passed to evaluate() which failed the + * constraint check. + * @param string $description A string with extra description of what was + * going on while the evaluation failed. + * @param boolean $not Flag to indicate negation. + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function fail($other, $description, $not = FALSE) + { + $failureDescription = sprintf( + 'Failed asserting that file "%s" exists.', + + $other + ); + + if ($not) { + $failureDescription = self::negate($failureDescription); + } + + if (!empty($description)) { + $failureDescription = $description . "\n" . $failureDescription; + } + + throw new PHPUnit_Framework_ExpectationFailedException( + $failureDescription + ); + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return 'file exists'; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/GreaterThan.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/GreaterThan.php new file mode 100644 index 0000000..8ad85c3 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/GreaterThan.php @@ -0,0 +1,95 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Constraint that asserts that the value it is evaluated for is greater + * than a given value. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_GreaterThan extends PHPUnit_Framework_Constraint +{ + /** + * @var numeric + */ + protected $value; + + /** + * @param numeric $value + */ + public function __construct($value) + { + $this->value = $value; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return $this->value < $other; + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return 'is greater than ' . PHPUnit_Util_Type::toString($this->value); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsAnything.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsAnything.php new file mode 100644 index 0000000..fb8574e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsAnything.php @@ -0,0 +1,103 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Constraint that accepts any input value. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_IsAnything extends PHPUnit_Framework_Constraint +{ + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return TRUE; + } + + /** + * @param mixed $other The value passed to evaluate() which failed the + * constraint check. + * @param string $description A string with extra description of what was + * going on while the evaluation failed. + * @param boolean $not Flag to indicate negation. + */ + public function fail($other, $description, $not = FALSE) + { + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return 'is anything'; + } + + /** + * Counts the number of constraint elements. + * + * @return integer + * @since Method available since Release 3.5.0 + */ + public function count() + { + return 0; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsEmpty.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsEmpty.php new file mode 100644 index 0000000..733a2ce --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsEmpty.php @@ -0,0 +1,102 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.5.0 + */ + +/** + * Constraint that checks whether a variable is empty(). + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.5.0 + */ +class PHPUnit_Framework_Constraint_IsEmpty extends PHPUnit_Framework_Constraint +{ + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return empty($other); + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return 'is empty'; + } + + /** + * @param mixed $other + * @param string $description + * @param boolean $not + */ + protected function customFailureDescription($other, $description, $not) + { + $type = gettype($other); + + if ($type[0] == 'a' || $type[0] == 'o') { + $type = 'an ' . $type; + } else { + $type = 'a ' . $type; + } + + return sprintf( + 'Failed asserting that %s is empty.', + $type + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsEqual.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsEqual.php new file mode 100644 index 0000000..579ddc9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsEqual.php @@ -0,0 +1,386 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Kore Nordmann + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Constraint that checks if one value is equal to another. + * + * Equality is checked with PHP's == operator, the operator is explained in + * detail at {@url http://www.php.net/manual/en/types.comparisons.php}. + * Two values are equal if they have the same value disregarding type. + * + * The expected value is passed in the constructor. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Kore Nordmann + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_IsEqual extends PHPUnit_Framework_Constraint +{ + /** + * @var mixed + */ + protected $value; + + /** + * @var float + */ + protected $delta = 0; + + /** + * @var integer + */ + protected $maxDepth = 10; + + /** + * @var boolean + */ + protected $canonicalize = FALSE; + + /** + * @var boolean + */ + protected $ignoreCase = FALSE; + + /** + * @param mixed $value + * @param float $delta + * @param integer $maxDepth + * @param boolean $canonicalize + * @param boolean $ignoreCase + */ + public function __construct($value, $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) + { + if (!is_numeric($delta)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'numeric'); + } + + if (!is_int($maxDepth)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'integer'); + } + + if (!is_bool($canonicalize)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(4, 'boolean'); + } + + if (!is_bool($ignoreCase)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(5, 'boolean'); + } + + $this->value = $value; + $this->delta = $delta; + $this->maxDepth = $maxDepth; + $this->canonicalize = $canonicalize; + $this->ignoreCase = $ignoreCase; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return $this->recursiveComparison($this->value, $other); + } + + /** + * @param mixed $other The value passed to evaluate() which failed the + * constraint check. + * @param string $description A string with extra description of what was + * going on while the evaluation failed. + * @param boolean $not Flag to indicate negation. + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function fail($other, $description, $not = FALSE) + { + $failureDescription = $this->failureDescription( + $other, + $description, + $not + ); + + if (!$not) { + if ($this->value instanceof DOMDocument) { + $value = $this->domToText($this->value); + } else { + $value = $this->value; + } + + if ($other instanceof DOMDocument) { + $other = $this->domToText($other); + } + + throw new PHPUnit_Framework_ExpectationFailedException( + $failureDescription, + PHPUnit_Framework_ComparisonFailure::diffEqual($value, $other), + $description + ); + } else { + throw new PHPUnit_Framework_ExpectationFailedException( + $failureDescription, + NULL + ); + } + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + $delta = ''; + + if (is_string($this->value)) { + if (strpos($this->value, "\n") !== FALSE) { + return 'is equal to '; + } else { + return sprintf( + 'is equal to ', + + $this->value + ); + } + } else { + if ($this->delta != 0) { + $delta = sprintf( + ' with delta <%F>', + + $this->delta + ); + } + + return sprintf( + 'is equal to %s%s', + + PHPUnit_Util_Type::toString($this->value), + $delta + ); + } + } + + /** + * Perform the actual recursive comparision of two values + * + * @param mixed $a First value + * @param mixed $b Second value + * @param int $depth Depth + * @return bool + */ + protected function recursiveComparison($a, $b, $depth = 0) + { + if ($a === $b) { + return TRUE; + } + + if ($depth >= $this->maxDepth) { + return TRUE; + } + + if (is_numeric($a) XOR is_numeric($b)) { + return FALSE; + } + + if (is_array($a) XOR is_array($b)) { + return FALSE; + } + + if (is_object($a) XOR is_object($b)) { + return FALSE; + } + + if ($a instanceof SplObjectStorage XOR $b instanceof SplObjectStorage) { + return FALSE; + } + + if ($a instanceof SplObjectStorage) { + foreach ($a as $object) { + if (!$b->contains($object)) { + return FALSE; + } + } + + foreach ($b as $object) { + if (!$a->contains($object)) { + return FALSE; + } + } + + return TRUE; + } + + if ($a instanceof DOMDocument || $b instanceof DOMDocument) { + if (!$a instanceof DOMDocument) { + $_a = new DOMDocument; + $_a->preserveWhiteSpace = FALSE; + $_a->loadXML($a); + $a = $_a; + unset($_a); + } + + if (!$b instanceof DOMDocument) { + $_b = new DOMDocument; + $_b->preserveWhiteSpace = FALSE; + $_b->loadXML($b); + $b = $_b; + unset($_b); + } + + return $a->C14N() == $b->C14N(); + } + + if (is_object($a) && is_object($b) && + (get_class($a) !== get_class($b))) { + return FALSE; + } + + // Normal comparision for scalar values. + if ((!is_array($a) && !is_object($a)) || + (!is_array($b) && !is_object($b))) { + if (is_numeric($a) && is_numeric($b)) { + // Optionally apply delta on numeric values. + return $this->numericComparison($a, $b); + } + + if (is_string($a) && is_string($b)) { + if ($this->canonicalize && PHP_EOL != "\n") { + $a = str_replace(PHP_EOL, "\n", $a); + $b = str_replace(PHP_EOL, "\n", $b); + } + + if ($this->ignoreCase) { + $a = strtolower($a); + $b = strtolower($b); + } + } + + return ($a == $b); + } + + if (is_object($a)) { + $isMock = $a instanceof PHPUnit_Framework_MockObject_MockObject; + $a = (array)$a; + $b = (array)$b; + + if ($isMock) { + unset($a["\0*\0invocationMocker"]); + + if (isset($b["\0*\0invocationMocker"])) { + unset($b["\0*\0invocationMocker"]); + } + } + } + + if ($this->canonicalize) { + sort($a); + sort($b); + } + + $keysInB = array_flip(array_keys($b)); + + foreach ($a as $key => $v) { + if (!isset($keysInB[$key])) { + // Abort on missing key in $b. + return FALSE; + } + + if (!$this->recursiveComparison($a[$key], $b[$key], $depth + 1)) { + // FALSE, if child comparision fails. + return FALSE; + } + + // Unset key to check whether all keys of b are compared. + unset($b[$key]); + } + + if (count($b)) { + // There is something in $b, that is missing in $a. + return FALSE; + } + + return TRUE; + } + + /** + * Compares two numeric values - use delta if applicable. + * + * @param mixed $a + * @param mixed $b + * @return bool + */ + protected function numericComparison($a, $b) + { + if ($this->delta === FALSE) { + return ($a == $b); + } else { + return (abs($a - $b) <= $this->delta); + } + } + + /** + * Returns the normalized, whitespace-cleaned, and indented textual + * representation of a DOMDocument. + * + * @param DOMDocument $document + * @return string + */ + protected function domToText(DOMDocument $document) + { + $document->formatOutput = TRUE; + $document->normalizeDocument(); + + return $document->saveXML(); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsFalse.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsFalse.php new file mode 100644 index 0000000..156acd8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsFalse.php @@ -0,0 +1,81 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +/** + * Constraint that accepts FALSE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Framework_Constraint_IsFalse extends PHPUnit_Framework_Constraint +{ + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return $other === FALSE; + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return 'is false'; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsIdentical.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsIdentical.php new file mode 100644 index 0000000..6c7beec --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsIdentical.php @@ -0,0 +1,140 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Constraint that asserts that one value is identical to another. + * + * Identical check is performed with PHP's === operator, the operator is + * explained in detail at + * {@url http://www.php.net/manual/en/types.comparisons.php}. + * Two values are identical if they have the same value and are of the same + * type. + * + * The expected value is passed in the constructor. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_IsIdentical extends PHPUnit_Framework_Constraint +{ + /** + * @var mixed + */ + protected $value; + + /** + * @param mixed $value + */ + public function __construct($value) + { + $this->value = $value; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return $this->value === $other; + } + + /** + * @param mixed $other The value passed to evaluate() which failed the + * constraint check. + * @param string $description A string with extra description of what was + * going on while the evaluation failed. + * @param boolean $not Flag to indicate negation. + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function fail($other, $description, $not = FALSE) + { + $failureDescription = $this->failureDescription( + $other, + $description, + $not + ); + + if (!$not) { + throw new PHPUnit_Framework_ExpectationFailedException( + $failureDescription, + PHPUnit_Framework_ComparisonFailure::diffIdentical( + $this->value, $other + ), + $description + ); + } else { + throw new PHPUnit_Framework_ExpectationFailedException( + $failureDescription, + NULL + ); + } + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + if (is_object($this->value)) { + return 'is identical to an object of class "' . + get_class($this->value) . '"'; + } else { + return 'is identical to ' . + PHPUnit_Util_Type::toString($this->value); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsInstanceOf.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsInstanceOf.php new file mode 100644 index 0000000..95cfb1c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsInstanceOf.php @@ -0,0 +1,128 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Constraint that asserts that the object it is evaluated for is an instance + * of a given class. + * + * The expected class name is passed in the constructor. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_IsInstanceOf extends PHPUnit_Framework_Constraint +{ + /** + * @var string + */ + protected $className; + + /** + * @param string $className + */ + public function __construct($className) + { + $this->className = $className; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return ($other instanceof $this->className); + } + + /** + * Creates the appropriate exception for the constraint which can be caught + * by the unit test system. This can be called if a call to evaluate() + * fails. + * + * @param mixed $other The value passed to evaluate() which failed the + * constraint check. + * @param string $description A string with extra description of what was + * going on while the evaluation failed. + * @param boolean $not Flag to indicate negation. + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function fail($other, $description, $not = FALSE) + { + throw new PHPUnit_Framework_ExpectationFailedException( + sprintf( + '%sFailed asserting that %s is %san instance of class "%s".', + + !empty($description) ? $description . "\n" : '', + PHPUnit_Util_Type::toString($other, TRUE), + $not ? 'not ' : '', + $this->className + ), + NULL + ); + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return sprintf( + 'is instance of class "%s"', + + $this->className + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsNull.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsNull.php new file mode 100644 index 0000000..c179525 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsNull.php @@ -0,0 +1,81 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +/** + * Constraint that accepts NULL. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Framework_Constraint_IsNull extends PHPUnit_Framework_Constraint +{ + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return $other === NULL; + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return 'is null'; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsTrue.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsTrue.php new file mode 100644 index 0000000..fede126 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsTrue.php @@ -0,0 +1,81 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +/** + * Constraint that accepts TRUE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Framework_Constraint_IsTrue extends PHPUnit_Framework_Constraint +{ + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return $other === TRUE; + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return 'is true'; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsType.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsType.php new file mode 100644 index 0000000..38d8af7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/IsType.php @@ -0,0 +1,183 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Constraint that asserts that the value it is evaluated for is of a + * specified type. + * + * The expected value is passed in the constructor. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_IsType extends PHPUnit_Framework_Constraint +{ + const TYPE_ARRAY = 'array'; + const TYPE_BOOL = 'bool'; + const TYPE_FLOAT = 'float'; + const TYPE_INT = 'int'; + const TYPE_NULL = 'null'; + const TYPE_NUMERIC = 'numeric'; + const TYPE_OBJECT = 'object'; + const TYPE_RESOURCE = 'resource'; + const TYPE_STRING = 'string'; + const TYPE_SCALAR = 'scalar'; + + /** + * @var array + */ + protected $types = array( + 'array' => TRUE, + 'boolean' => TRUE, + 'bool' => TRUE, + 'float' => TRUE, + 'integer' => TRUE, + 'int' => TRUE, + 'null' => TRUE, + 'numeric' => TRUE, + 'object' => TRUE, + 'resource' => TRUE, + 'string' => TRUE, + 'scalar' => TRUE + ); + + /** + * @var string + */ + protected $type; + + /** + * @param string $type + * @throws InvalidArgumentException + */ + public function __construct($type) + { + if (!isset($this->types[$type])) { + throw new InvalidArgumentException( + sprintf( + 'Type specified for PHPUnit_Framework_Constraint_IsType <%s> ' . + 'is not a valid type.', + $type + ) + ); + } + + $this->type = $type; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + switch ($this->type) { + case 'numeric': { + return is_numeric($other); + } + + case 'integer': + case 'int': { + return is_integer($other); + } + + case 'float': { + return is_float($other); + } + + case 'string': { + return is_string($other); + } + + case 'boolean': + case 'bool': { + return is_bool($other); + } + + case 'null': { + return is_null($other); + } + + case 'array': { + return is_array($other); + } + + case 'object': { + return is_object($other); + } + + case 'resource': { + return is_resource($other); + } + + case 'scalar': { + return is_scalar($other); + } + } + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return sprintf( + 'is of type "%s"', + + $this->type + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/LessThan.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/LessThan.php new file mode 100644 index 0000000..c560285 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/LessThan.php @@ -0,0 +1,95 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Constraint that asserts that the value it is evaluated for is less than + * a given value. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_LessThan extends PHPUnit_Framework_Constraint +{ + /** + * @var numeric + */ + protected $value; + + /** + * @param numeric $value + */ + public function __construct($value) + { + $this->value = $value; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return $this->value > $other; + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return 'is less than ' . PHPUnit_Util_Type::toString($this->value); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Not.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Not.php new file mode 100644 index 0000000..59bab41 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Not.php @@ -0,0 +1,141 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Logical NOT. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ + +class PHPUnit_Framework_Constraint_Not extends PHPUnit_Framework_Constraint +{ + /** + * @var PHPUnit_Framework_Constraint + */ + protected $constraint; + + /** + * @param PHPUnit_Framework_Constraint $constraint + */ + public function __construct($constraint) + { + if (!($constraint instanceof PHPUnit_Framework_Constraint)) { + $constraint = new PHPUnit_Framework_Constraint_IsEqual($constraint); + } + + $this->constraint = $constraint; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return !$this->constraint->evaluate($other); + } + + /** + * @param mixed $other The value passed to evaluate() which failed the + * constraint check. + * @param string $description A string with extra description of what was + * going on while the evaluation failed. + * @param boolean $not Flag to indicate negation. + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function fail($other, $description, $not = FALSE) + { + if (count($this->constraint) == 1 || + $this->constraint instanceof PHPUnit_Framework_Constraint_Attribute) { + $this->constraint->fail($other, $description, TRUE); + } else { + parent::fail($other, $description, !$not); + } + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + switch (get_class($this->constraint)) { + case 'PHPUnit_Framework_Constraint_And': + case 'PHPUnit_Framework_Constraint_Not': + case 'PHPUnit_Framework_Constraint_Or': { + return 'not( ' . $this->constraint->toString() . ' )'; + } + break; + + default: { + return PHPUnit_Framework_Constraint::negate( + $this->constraint->toString() + ); + } + } + } + + /** + * Counts the number of constraint elements. + * + * @return integer + * @since Method available since Release 3.4.0 + */ + public function count() + { + return count($this->constraint); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ObjectHasAttribute.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ObjectHasAttribute.php new file mode 100644 index 0000000..e63fe5d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/ObjectHasAttribute.php @@ -0,0 +1,84 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Constraint that asserts that the object it is evaluated for has a given + * attribute. + * + * The attribute name is passed in the constructor. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_ObjectHasAttribute extends PHPUnit_Framework_Constraint_ClassHasAttribute +{ + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + $object = new ReflectionObject($other); + + return $object->hasProperty($this->attributeName); + } + + protected function customFailureDescription($other, $description, $not) + { + return sprintf( + 'Failed asserting that object of class "%s" %s.', + get_class($other), $this->toString() + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Or.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Or.php new file mode 100644 index 0000000..356571b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Or.php @@ -0,0 +1,137 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Logical OR. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_Or extends PHPUnit_Framework_Constraint +{ + /** + * @var PHPUnit_Framework_Constraint[] + */ + protected $constraints = array(); + + /** + * @param PHPUnit_Framework_Constraint[] $constraints + */ + public function setConstraints(array $constraints) + { + $this->constraints = array(); + + foreach($constraints as $key => $constraint) { + if (!($constraint instanceof PHPUnit_Framework_Constraint)) { + $constraint = new PHPUnit_Framework_Constraint_IsEqual( + $constraint + ); + } + + $this->constraints[] = $constraint; + } + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + foreach($this->constraints as $constraint) { + if ($constraint->evaluate($other)) { + return TRUE; + } + } + + return FALSE; + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + $text = ''; + + foreach($this->constraints as $key => $constraint) { + if ($key > 0) { + $text .= ' or '; + } + + $text .= $constraint->toString(); + } + + return $text; + } + + /** + * Counts the number of constraint elements. + * + * @return integer + * @since Method available since Release 3.4.0 + */ + public function count() + { + $count = 0; + + foreach ($this->constraints as $constraint) { + $count += count($constraint); + } + + return $count; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/PCREMatch.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/PCREMatch.php new file mode 100644 index 0000000..c0e0c79 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/PCREMatch.php @@ -0,0 +1,104 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Constraint that asserts that the string it is evaluated for matches + * a regular expression. + * + * Checks a given value using the Perl Compatible Regular Expression extension + * in PHP. The pattern is matched by executing preg_match(). + * + * The pattern string passed in the constructor. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_PCREMatch extends PHPUnit_Framework_Constraint +{ + /** + * @var string + */ + protected $pattern; + + /** + * @param string $pattern + */ + public function __construct($pattern) + { + $this->pattern = $pattern; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return preg_match($this->pattern, $other) > 0; + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return sprintf( + 'matches PCRE pattern "%s"', + + $this->pattern + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringContains.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringContains.php new file mode 100644 index 0000000..af19a55 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringContains.php @@ -0,0 +1,121 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Constraint that asserts that the string it is evaluated for contains + * a given string. + * + * Uses strpos() to find the position of the string in the input, if not found + * the evaluaton fails. + * + * The sub-string is passed in the constructor. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_StringContains extends PHPUnit_Framework_Constraint +{ + /** + * @var string + */ + protected $string; + + /** + * @var boolean + */ + protected $ignoreCase; + + /** + * @param string $string + * @param boolean $ignoreCase + */ + public function __construct($string, $ignoreCase = FALSE) + { + $this->string = $string; + $this->ignoreCase = $ignoreCase; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + if ($this->ignoreCase) { + return stripos($other, $this->string) !== FALSE; + } else { + return strpos($other, $this->string) !== FALSE; + } + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + if ($this->ignoreCase) { + $string = strtolower($this->string); + } else { + $string = $this->string; + } + + return sprintf( + 'contains "%s"', + + $string + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringEndsWith.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringEndsWith.php new file mode 100644 index 0000000..0e87363 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringEndsWith.php @@ -0,0 +1,95 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.4.0 + */ + +/** + * Constraint that asserts that the string it is evaluated for ends with a given + * suffix. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.4.0 + */ +class PHPUnit_Framework_Constraint_StringEndsWith extends PHPUnit_Framework_Constraint +{ + /** + * @var string + */ + protected $suffix; + + /** + * @param string $suffix + */ + public function __construct($suffix) + { + $this->suffix = $suffix; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return substr($other, 0 - strlen($this->suffix)) == $this->suffix; + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return 'ends with "' . $this->suffix . '"'; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringMatches.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringMatches.php new file mode 100644 index 0000000..48a6b58 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringMatches.php @@ -0,0 +1,140 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.5.0 + */ + +/** + * ... + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.5.0 + */ +class PHPUnit_Framework_Constraint_StringMatches extends PHPUnit_Framework_Constraint_PCREMatch +{ + /** + * @var string + */ + protected $string; + + /** + * @param string $string + */ + public function __construct($string) + { + $this->pattern = preg_quote(preg_replace('/\r\n/', "\n", $string), '/'); + $this->pattern = str_replace( + array( + '%e', + '%s', + '%S', + '%a', + '%A', + '%w', + '%i', + '%d', + '%x', + '%f', + '%c' + ), + array( + '\\' . DIRECTORY_SEPARATOR, + '[^\r\n]+', + '[^\r\n]*', + '.+', + '.*', + '\s*', + '[+-]?\d+', + '\d+', + '[0-9a-fA-F]+', + '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?', + '.' + ), + $this->pattern + ); + + $this->pattern = '/^' . $this->pattern . '$/s'; + $this->string = $string; + } + + /** + * Creates the appropriate exception for the constraint which can be caught + * by the unit test system. This can be called if a call to evaluate() + * fails. + * + * @param mixed $other The value passed to evaluate() which failed the + * constraint check. + * @param string $description A string with extra description of what was + * going on while the evaluation failed. + * @param boolean $not Flag to indicate negation. + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function fail($other, $description, $not = FALSE) + { + $failureDescription = $this->failureDescription( + $other, + $description, + $not + ); + + if (!$not) { + throw new PHPUnit_Framework_ExpectationFailedException( + $failureDescription, + PHPUnit_Framework_ComparisonFailure::diffEqual( + $this->string, $other + ), + $description + ); + } else { + throw new PHPUnit_Framework_ExpectationFailedException( + $failureDescription, + NULL + ); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringStartsWith.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringStartsWith.php new file mode 100644 index 0000000..02339ce --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/StringStartsWith.php @@ -0,0 +1,95 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.4.0 + */ + +/** + * Constraint that asserts that the string it is evaluated for begins with a + * given prefix. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.4.0 + */ +class PHPUnit_Framework_Constraint_StringStartsWith extends PHPUnit_Framework_Constraint +{ + /** + * @var string + */ + protected $prefix; + + /** + * @param string $prefix + */ + public function __construct($prefix) + { + $this->prefix = $prefix; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + return strpos($other, $this->prefix) === 0; + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return 'starts with "' . $this->prefix . '"'; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/TraversableContains.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/TraversableContains.php new file mode 100644 index 0000000..6dbf7da --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/TraversableContains.php @@ -0,0 +1,127 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Constraint that asserts that the Traversable it is applied to contains + * a given value. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_TraversableContains extends PHPUnit_Framework_Constraint +{ + /** + * @var mixed + */ + protected $value; + + /** + * @param mixed $value + */ + public function __construct($value) + { + $this->value = $value; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + if ($other instanceof SplObjectStorage) { + return $other->contains($this->value); + } + + if (is_object($this->value)) { + foreach ($other as $element) { + if ($element === $this->value) { + return TRUE; + } + } + } else { + foreach ($other as $element) { + if ($element == $this->value) { + return TRUE; + } + } + } + + return FALSE; + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + if (is_string($this->value) && strpos($this->value, "\n") !== FALSE) { + return 'contains "' . $this->value . '"'; + } else { + return 'contains ' . PHPUnit_Util_Type::toString($this->value); + } + } + + protected function customFailureDescription($other, $description, $not) + { + return sprintf( + 'Failed asserting that an %s %s.', + + is_array($other) ? 'array' : 'iterator', + $this->toString() + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/TraversableContainsOnly.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/TraversableContainsOnly.php new file mode 100644 index 0000000..6cb299a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/TraversableContainsOnly.php @@ -0,0 +1,115 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.1.4 + */ + +/** + * Constraint that asserts that the Traversable it is applied to contains + * only values of a given type. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.1.4 + */ +class PHPUnit_Framework_Constraint_TraversableContainsOnly extends PHPUnit_Framework_Constraint +{ + /** + * @var PHPUnit_Framework_Constraint + */ + protected $constraint; + + /** + * @var string + */ + protected $type; + + /** + * @param string $type + * @param boolean $isNativeType + */ + public function __construct($type, $isNativeType = TRUE) + { + if ($isNativeType) { + $this->constraint = new PHPUnit_Framework_Constraint_IsType($type); + } else { + $this->constraint = new PHPUnit_Framework_Constraint_IsInstanceOf( + $type + ); + } + + $this->type = $type; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + foreach ($other as $item) { + if (!$this->constraint->evaluate($item)) { + return FALSE; + } + } + + return TRUE; + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return 'contains only values of type "' . $this->type . '"'; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Xor.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Xor.php new file mode 100644 index 0000000..63e6d02 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Constraint/Xor.php @@ -0,0 +1,144 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Logical XOR. + * + * @package PHPUnit + * @subpackage Framework_Constraint + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_Constraint_Xor extends PHPUnit_Framework_Constraint +{ + /** + * @var PHPUnit_Framework_Constraint[] + */ + protected $constraints = array(); + + /** + * @param PHPUnit_Framework_Constraint[] $constraints + */ + public function setConstraints(array $constraints) + { + $this->constraints = array(); + + foreach($constraints as $key => $constraint) { + if (!($constraint instanceof PHPUnit_Framework_Constraint)) { + $constraint = new PHPUnit_Framework_Constraint_IsEqual( + $constraint + ); + } + + $this->constraints[] = $constraint; + } + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * @return bool + */ + public function evaluate($other) + { + $result = FALSE; + + foreach($this->constraints as $constraint) { + if ($constraint->evaluate($other)) { + if ( $result ) + { + return FALSE; + } + + $result = TRUE; + } + } + + return $result; + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + $text = ''; + + foreach($this->constraints as $key => $constraint) { + if ($key > 0) { + $text .= ' xor '; + } + + $text .= $constraint->toString(); + } + + return $text; + } + + /** + * Counts the number of constraint elements. + * + * @return integer + * @since Method available since Release 3.4.0 + */ + public function count() + { + $count = 0; + + foreach ($this->constraints as $constraint) { + $count += count($constraint); + } + + return $count; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Error.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Error.php new file mode 100644 index 0000000..3beeee6 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Error.php @@ -0,0 +1,77 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.2.0 + */ + +/** + * Wrapper for PHP errors. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.2.0 + */ +class PHPUnit_Framework_Error extends Exception +{ + /** + * Constructor. + * + * @param string $message + * @param integer $code + * @param string $file + * @param integer $line + * @param array $trace + */ + public function __construct($message, $code, $file, $line, $trace) + { + parent::__construct($message, $code); + + $this->file = $file; + $this->line = $line; + $this->trace = $trace; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Error/Notice.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Error/Notice.php new file mode 100644 index 0000000..25f5b65 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Error/Notice.php @@ -0,0 +1,66 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Error + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +/** + * Wrapper for PHP notices. + * You can disable notice-to-exception conversion by setting + * + * + * PHPUnit_Framework_Error_Notice::$enabled = FALSE; + * + * + * @package PHPUnit + * @subpackage Framework_Error + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Framework_Error_Notice extends PHPUnit_Framework_Error +{ + public static $enabled = TRUE; +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Error/Warning.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Error/Warning.php new file mode 100644 index 0000000..4482565 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Error/Warning.php @@ -0,0 +1,66 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_Error + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +/** + * Wrapper for PHP warnings. + * You can disable notice-to-exception conversion by setting + * + * + * PHPUnit_Framework_Error_Warning::$enabled = FALSE; + * + * + * @package PHPUnit + * @subpackage Framework_Error + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Framework_Error_Warning extends PHPUnit_Framework_Error +{ + public static $enabled = TRUE; +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Exception.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Exception.php new file mode 100644 index 0000000..181ecc7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Exception.php @@ -0,0 +1,60 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.4.0 + */ + +/** + * Exception for PHPUnit runtime errors. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.4.0 + */ +class PHPUnit_Framework_Exception extends RuntimeException +{ +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ExpectationFailedException.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ExpectationFailedException.php new file mode 100644 index 0000000..4b250b0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/ExpectationFailedException.php @@ -0,0 +1,124 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Exception for expectations which failed their check. + * + * The exception contains the error message and optionally a + * PHPUnit_Framework_ComparisonFailure which is used to + * generate diff output of the failed expectations. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_ExpectationFailedException extends PHPUnit_Framework_AssertionFailedError +{ + /** + * @var PHPUnit_Framework_ComparisonFailure + */ + protected $comparisonFailure; + + /** + * @var string + */ + protected $description; + + /** + * @var string + */ + protected $customMessage; + + public function __construct($description, PHPUnit_Framework_ComparisonFailure $comparisonFailure = NULL, $message = '') + { + $this->description = $description; + $this->comparisonFailure = $comparisonFailure; + $this->customMessage = $message; + + if (!empty($message)) { + $description .= "\n" . $message; + } + + parent::__construct($description); + } + + /** + * @return PHPUnit_Framework_ComparisonFailure + */ + public function getComparisonFailure() + { + return $this->comparisonFailure; + } + + /** + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * @return string + */ + public function getCustomMessage() + { + return $this->customMessage; + } + + /** + * @param string $customMessage + * @since Method available since Release 3.4.0 + */ + public function setCustomMessage($customMessage) + { + $this->customMessage = $customMessage; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/IncompleteTest.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/IncompleteTest.php new file mode 100644 index 0000000..4d37593 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/IncompleteTest.php @@ -0,0 +1,61 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * A marker interface for marking any exception/error as result of an unit + * test as incomplete implementation or currently not implemented. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Interface available since Release 2.0.0 + */ +interface PHPUnit_Framework_IncompleteTest +{ +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/IncompleteTestError.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/IncompleteTestError.php new file mode 100644 index 0000000..084e89c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/IncompleteTestError.php @@ -0,0 +1,61 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * Extension to PHPUnit_Framework_AssertionFailedError to mark the special + * case of an incomplete test. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +class PHPUnit_Framework_IncompleteTestError extends PHPUnit_Framework_AssertionFailedError implements PHPUnit_Framework_IncompleteTest +{ +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Identity.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Identity.php new file mode 100644 index 0000000..b46901e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Identity.php @@ -0,0 +1,70 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Builder interface for unique identifiers. + * + * Defines the interface for recording unique identifiers. The identifiers + * can be used to define the invocation order of expectations. The expectation + * is recorded using id() and then defined in order using + * PHPUnit_Framework_MockObject_Builder_Match::after(). + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Interface available since Release 1.0.0 + */ +interface PHPUnit_Framework_MockObject_Builder_Identity +{ + /** + * Sets the identification of the expectation to $id. + * + * @note The identifier is unique per mock object. + * @param string $id Unique identifiation of expectation. + */ + public function id($id); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/InvocationMocker.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/InvocationMocker.php new file mode 100644 index 0000000..09a1deb --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/InvocationMocker.php @@ -0,0 +1,193 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Builder for mocked or stubbed invocations. + * + * Provides methods for building expectations without having to resort to + * instantiating the various matchers manually. These methods also form a + * more natural way of reading the expectation. This class should be together + * with the test case PHPUnit_Framework_MockObject_TestCase. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Builder_InvocationMocker implements PHPUnit_Framework_MockObject_Builder_MethodNameMatch +{ + /** + * @var PHPUnit_Framework_MockObject_Stub_MatcherCollection + */ + protected $collection; + + /** + * @var PHPUnit_Framework_MockObject_Matcher + */ + protected $matcher; + + /** + * @param PHPUnit_Framework_MockObject_Stub_MatcherCollection $collection + * @param PHPUnit_Framework_MockObject_Matcher_Invocation $invocationMatcher + */ + public function __construct(PHPUnit_Framework_MockObject_Stub_MatcherCollection $collection, PHPUnit_Framework_MockObject_Matcher_Invocation $invocationMatcher) + { + $this->collection = $collection; + $this->matcher = new PHPUnit_Framework_MockObject_Matcher( + $invocationMatcher + ); + + $this->collection->addMatcher($this->matcher); + } + + /** + * @return PHPUnit_Framework_MockObject_Matcher + */ + public function getMatcher() + { + return $this->matcher; + } + + /** + * @param mixed $id + * @return PHPUnit_Framework_MockObject_Builder_InvocationMocker + */ + public function id($id) + { + $this->collection->registerId($id, $this); + + return $this; + } + + /** + * @param PHPUnit_Framework_MockObject_Stub $stub + * @return PHPUnit_Framework_MockObject_Builder_InvocationMocker + */ + public function will(PHPUnit_Framework_MockObject_Stub $stub) + { + $this->matcher->stub = $stub; + + return $this; + } + + /** + * @param mixed $id + * @return PHPUnit_Framework_MockObject_Builder_InvocationMocker + */ + public function after($id) + { + $this->matcher->afterMatchBuilderId = $id; + + return $this; + } + + /** + * @param mixed $argument, ... + * @return PHPUnit_Framework_MockObject_Builder_InvocationMocker + */ + public function with() + { + $args = func_get_args(); + + if ($this->matcher->methodNameMatcher === NULL) { + throw new PHPUnit_Framework_Exception( + 'Method name matcher is not defined, cannot define parameter ' . + ' matcher without one' + ); + } + + if ($this->matcher->parametersMatcher !== NULL) { + throw new PHPUnit_Framework_Exception( + 'Parameter matcher is already defined, cannot redefine' + ); + } + + $this->matcher->parametersMatcher = new PHPUnit_Framework_MockObject_Matcher_Parameters($args); + + return $this; + } + + /** + * @return PHPUnit_Framework_MockObject_Builder_InvocationMocker + */ + public function withAnyParameters() + { + if ($this->matcher->methodNameMatcher === NULL) { + throw new PHPUnit_Framework_Exception( + 'Method name matcher is not defined, cannot define parameter ' . + 'matcher without one' + ); + } + + if ($this->matcher->parametersMatcher !== NULL) { + throw new PHPUnit_Framework_Exception( + 'Parameter matcher is already defined, cannot redefine' + ); + } + + $this->matcher->parametersMatcher = new PHPUnit_Framework_MockObject_Matcher_AnyParameters; + + return $this; + } + + /** + * @param PHPUnit_Framework_Constraint|string $constraint + * @return PHPUnit_Framework_MockObject_Builder_InvocationMocker + */ + public function method($constraint) + { + if ($this->matcher->methodNameMatcher !== NULL) { + throw new PHPUnit_Framework_Exception( + 'Method name matcher is already defined, cannot redefine' + ); + } + + $this->matcher->methodNameMatcher = new PHPUnit_Framework_MockObject_Matcher_MethodName($constraint); + + return $this; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Match.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Match.php new file mode 100644 index 0000000..5454ac1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Match.php @@ -0,0 +1,66 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Builder interface for invocation order matches. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Interface available since Release 1.0.0 + */ +interface PHPUnit_Framework_MockObject_Builder_Match extends PHPUnit_Framework_MockObject_Builder_Stub +{ + /** + * Defines the expectation which must occur before the current is valid. + * + * @param string $id The identification of the expectation that should + * occur before this one. + * @return PHPUnit_Framework_MockObject_Builder_Stub + */ + public function after($id); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/MethodNameMatch.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/MethodNameMatch.php new file mode 100644 index 0000000..d76246b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/MethodNameMatch.php @@ -0,0 +1,68 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Builder interface for matcher of method names. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Interface available since Release 1.0.0 + */ +interface PHPUnit_Framework_MockObject_Builder_MethodNameMatch extends PHPUnit_Framework_MockObject_Builder_ParametersMatch +{ + /** + * Adds a new method name match and returns the parameter match object for + * further matching possibilities. + * + * @param PHPUnit_Framework_Constraint $name + * Constraint for matching method, if a string is passed it will use + * the PHPUnit_Framework_Constraint_IsEqual. + * @return PHPUnit_Framework_MockObject_Builder_ParametersMatch + */ + public function method($name); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Namespace.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Namespace.php new file mode 100644 index 0000000..300d9cf --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Namespace.php @@ -0,0 +1,79 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Interface for builders which can register builders with a given identification. + * + * This interface relates to PHPUnit_Framework_MockObject_Builder_Identity. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Interface available since Release 1.0.0 + */ +interface PHPUnit_Framework_MockObject_Builder_Namespace +{ + /** + * Looks up the match builder with identification $id and returns it. + * + * @param string $id The identifiction of the match builder. + * @return PHPUnit_Framework_MockObject_Builder_Match + */ + public function lookupId($id); + + /** + * Registers the match builder $builder with the identification $id. The + * builder can later be looked up using lookupId() to figure out if it + * has been invoked. + * + * @param string $id + * The identification of the match builder. + * @param PHPUnit_Framework_MockObject_Builder_Match $builder + * The builder which is being registered. + */ + public function registerId($id, PHPUnit_Framework_MockObject_Builder_Match $builder); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/ParametersMatch.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/ParametersMatch.php new file mode 100644 index 0000000..4fd7677 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/ParametersMatch.php @@ -0,0 +1,89 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Builder interface for parameter matchers. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Interface available since Release 1.0.0 + */ +interface PHPUnit_Framework_MockObject_Builder_ParametersMatch extends PHPUnit_Framework_MockObject_Builder_Match +{ + /** + * Sets the parameters to match for, each parameter to this funtion will + * be part of match. To perform specific matches or constraints create a + * new PHPUnit_Framework_Constraint and use it for the parameter. + * If the parameter value is not a constraint it will use the + * PHPUnit_Framework_Constraint_IsEqual for the value. + * + * Some examples: + * + * // match first parameter with value 2 + * $b->with(2); + * // match first parameter with value 'smock' and second identical to 42 + * $b->with('smock', new PHPUnit_Framework_Constraint_IsEqual(42)); + * + * + * @return PHPUnit_Framework_MockObject_Builder_ParametersMatch + */ + public function with(); + + /** + * Sets a matcher which allows any kind of parameters. + * + * Some examples: + * + * // match any number of parameters + * $b->withAnyParamers(); + * + * + * @return PHPUnit_Framework_MockObject_Matcher_AnyParameters + */ + public function withAnyParameters(); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Stub.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Stub.php new file mode 100644 index 0000000..d50bb87 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Builder/Stub.php @@ -0,0 +1,66 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Builder interface for stubs which are actions replacing an invocation. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Interface available since Release 1.0.0 + */ +interface PHPUnit_Framework_MockObject_Builder_Stub extends PHPUnit_Framework_MockObject_Builder_Identity +{ + /** + * Stubs the matching method with the stub object $stub. Any invocations of + * the matched method will now be handled by the stub instead. + * + * @param PHPUnit_Framework_MockObject_Stub $stub The stub object. + * @return PHPUnit_Framework_MockObject_Builder_Identity + */ + public function will(PHPUnit_Framework_MockObject_Stub $stub); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator.php new file mode 100644 index 0000000..ecc5137 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator.php @@ -0,0 +1,687 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +require_once 'Text/Template.php'; + +/** + * Mock Object Code Generator + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Generator +{ + /** + * @var array + */ + protected static $cache = array(); + + /** + * @var array + */ + protected static $blacklistedMethodNames = array( + '__clone' => TRUE, + 'abstract' => TRUE, + 'and' => TRUE, + 'array' => TRUE, + 'as' => TRUE, + 'break' => TRUE, + 'case' => TRUE, + 'catch' => TRUE, + 'class' => TRUE, + 'clone' => TRUE, + 'const' => TRUE, + 'continue' => TRUE, + 'declare' => TRUE, + 'default' => TRUE, + 'die' => TRUE, + 'do' => TRUE, + 'echo' => TRUE, + 'else' => TRUE, + 'elseif' => TRUE, + 'empty' => TRUE, + 'enddeclare' => TRUE, + 'endfor' => TRUE, + 'endforeach' => TRUE, + 'endif' => TRUE, + 'endswitch' => TRUE, + 'endwhile' => TRUE, + 'eval' => TRUE, + 'exit' => TRUE, + 'extends' => TRUE, + 'final' => TRUE, + 'for' => TRUE, + 'foreach' => TRUE, + 'function' => TRUE, + 'global' => TRUE, + 'goto' => TRUE, + 'if' => TRUE, + 'implements' => TRUE, + 'include' => TRUE, + 'include_once' => TRUE, + 'instanceof' => TRUE, + 'interface' => TRUE, + 'isset' => TRUE, + 'list' => TRUE, + 'namespace' => TRUE, + 'new' => TRUE, + 'or' => TRUE, + 'print' => TRUE, + 'private' => TRUE, + 'protected' => TRUE, + 'public' => TRUE, + 'require' => TRUE, + 'require_once' => TRUE, + 'return' => TRUE, + 'static' => TRUE, + 'switch' => TRUE, + 'throw' => TRUE, + 'try' => TRUE, + 'unset' => TRUE, + 'use' => TRUE, + 'var' => TRUE, + 'while' => TRUE, + 'xor' => TRUE + ); + + /** + * @var boolean + */ + protected static $soapLoaded = NULL; + + /** + * Returns a mock object for the specified class. + * + * @param string $originalClassName + * @param array $methods + * @param array $arguments + * @param string $mockClassName + * @param boolean $callOriginalConstructor + * @param boolean $callOriginalClone + * @param boolean $callAutoload + * @return object + * @throws InvalidArgumentException + * @since Method available since Release 1.0.0 + */ + public static function getMock($originalClassName, $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE) + { + if (!is_string($originalClassName)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_string($mockClassName)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(4, 'string'); + } + + if (!is_array($methods) && !is_null($methods)) { + throw new InvalidArgumentException; + } + + if ($mockClassName != '' && class_exists($mockClassName, FALSE)) { + throw new PHPUnit_Framework_Exception( + sprintf( + 'Class "%s" already exists.', + $mockClassName + ) + ); + } + + $mock = self::generate( + $originalClassName, + $methods, + $mockClassName, + $callOriginalClone, + $callAutoload + ); + + if (!class_exists($mock['mockClassName'], FALSE)) { + eval($mock['code']); + } + + if ($callOriginalConstructor && + !interface_exists($originalClassName, $callAutoload)) { + if (count($arguments) == 0) { + $mockObject = new $mock['mockClassName']; + } else { + $mockClass = new ReflectionClass($mock['mockClassName']); + $mockObject = $mockClass->newInstanceArgs($arguments); + } + } else { + // Use a trick to create a new object of a class + // without invoking its constructor. + $mockObject = unserialize( + sprintf( + 'O:%d:"%s":0:{}', + strlen($mock['mockClassName']), $mock['mockClassName'] + ) + ); + } + + return $mockObject; + } + + /** + * Returns a mock object for the specified abstract class with all abstract + * methods of the class mocked. Concrete methods are not mocked. + * + * @param string $originalClassName + * @param array $arguments + * @param string $mockClassName + * @param boolean $callOriginalConstructor + * @param boolean $callOriginalClone + * @param boolean $callAutoload + * @return object + * @since Method available since Release 1.0.0 + * @throws InvalidArgumentException + */ + public static function getMockForAbstractClass($originalClassName, array $arguments = array(), $mockClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE) + { + if (!is_string($originalClassName)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!is_string($mockClassName)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'string'); + } + + if (class_exists($originalClassName, $callAutoload)) { + $methods = array(); + $reflector = new ReflectionClass($originalClassName); + + foreach ($reflector->getMethods() as $method) { + if ($method->isAbstract()) { + $methods[] = $method->getName(); + } + } + + if (empty($methods)) { + $methods = NULL; + } + + return self::getMock( + $originalClassName, + $methods, + $arguments, + $mockClassName, + $callOriginalConstructor, + $callOriginalClone, + $callAutoload + ); + } else { + throw new PHPUnit_Framework_Exception( + sprintf( + 'Class "%s" does not exist.', + $originalClassName + ) + ); + } + } + + /** + * @param string $originalClassName + * @param array $methods + * @param string $mockClassName + * @param boolean $callOriginalClone + * @param boolean $callAutoload + * @return array + */ + public static function generate($originalClassName, array $methods = NULL, $mockClassName = '', $callOriginalClone = TRUE, $callAutoload = TRUE) + { + if ($mockClassName == '') { + $key = md5( + $originalClassName . + serialize($methods) . + serialize($callOriginalClone) + ); + + if (isset(self::$cache[$key])) { + return self::$cache[$key]; + } + } + + $mock = self::generateMock( + $originalClassName, + $methods, + $mockClassName, + $callOriginalClone, + $callAutoload + ); + + if (isset($key)) { + self::$cache[$key] = $mock; + } + + return $mock; + } + + /** + * @param string $wsdlFile + * @param string $originalClassName + * @param array $methods + * @return array + */ + public static function generateClassFromWsdl($wsdlFile, $originalClassName, array $methods = array()) + { + if (self::$soapLoaded === NULL) { + self::$soapLoaded = extension_loaded('soap'); + } + + if (self::$soapLoaded) { + $client = new SOAPClient($wsdlFile); + $_methods = array_unique($client->__getFunctions()); + unset($client); + + $templateDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . + 'Generator' . DIRECTORY_SEPARATOR; + $methodTemplate = new Text_Template( + $templateDir . 'wsdl_method.tpl' + ); + $methodsBuffer = ''; + + foreach ($_methods as $method) { + $nameStart = strpos($method, ' ') + 1; + $nameEnd = strpos($method, '('); + $name = substr($method, $nameStart, $nameEnd - $nameStart); + + if (empty($methods) || in_array($name, $methods)) { + $args = explode( + ',', + substr( + $method, + $nameEnd + 1, + strpos($method, ')') - $nameEnd - 1 + ) + ); + $numArgs = count($args); + + for ($i = 0; $i < $numArgs; $i++) { + $args[$i] = substr($args[$i], strpos($args[$i], '$')); + } + + $methodTemplate->setVar( + array( + 'method_name' => $name, + 'arguments' => join(', ', $args) + ) + ); + + $methodsBuffer .= $methodTemplate->render(); + } + } + + $classTemplate = new Text_Template( + $templateDir . 'wsdl_class.tpl' + ); + + $classTemplate->setVar( + array( + 'class_name' => $originalClassName, + 'wsdl' => $wsdlFile, + 'methods' => $methodsBuffer + ) + ); + + return $classTemplate->render(); + } else { + throw new PHPUnit_Framework_Exception( + 'The SOAP extension is required to generate a mock object ' . + 'from WSDL.' + ); + } + } + + /** + * @param string $originalClassName + * @param array|null $methods + * @param string $mockClassName + * @param boolean $callOriginalClone + * @param boolean $callAutoload + * @return array + */ + protected static function generateMock($originalClassName, $methods, $mockClassName, $callOriginalClone, $callAutoload) + { + $templateDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Generator' . + DIRECTORY_SEPARATOR; + $classTemplate = new Text_Template( + $templateDir . 'mocked_class.tpl' + ); + $cloneTemplate = ''; + $isClass = FALSE; + $isInterface = FALSE; + + $mockClassName = self::generateMockClassName( + $originalClassName, $mockClassName + ); + + if (class_exists($mockClassName['fullClassName'], $callAutoload)) { + $isClass = TRUE; + } else { + if (interface_exists($mockClassName['fullClassName'], $callAutoload)) { + $isInterface = TRUE; + } + } + + if (!class_exists($mockClassName['fullClassName'], $callAutoload) && + !interface_exists($mockClassName['fullClassName'], $callAutoload)) { + $prologue = 'class ' . $mockClassName['className'] . "\n{\n}\n\n"; + + if (!empty($mockClassName['namespaceName'])) { + $prologue = 'namespace ' . $mockClassName['namespaceName'] . + " {\n\n" . $prologue . "}\n\n" . + "namespace {\n\n"; + + $epilogue = "\n\n}"; + } + + $cloneTemplate = new Text_Template( + $templateDir . 'mocked_clone.tpl' + ); + } else { + $class = new ReflectionClass($mockClassName['fullClassName']); + + if ($class->isFinal()) { + throw new PHPUnit_Framework_Exception( + sprintf( + 'Class "%s" is declared "final" and cannot be mocked.', + $mockClassName['fullClassName'] + ) + ); + } + + if ($class->hasMethod('__clone')) { + $cloneMethod = $class->getMethod('__clone'); + + if (!$cloneMethod->isFinal()) { + if ($callOriginalClone && !$isInterface) { + $cloneTemplate = new Text_Template( + $templateDir . 'unmocked_clone.tpl' + ); + } else { + $cloneTemplate = new Text_Template( + $templateDir . 'mocked_clone.tpl' + ); + } + } + } else { + $cloneTemplate = new Text_Template( + $templateDir . 'mocked_clone.tpl' + ); + } + } + + if (is_object($cloneTemplate)) { + $cloneTemplate = $cloneTemplate->render(); + } + + if (is_array($methods) && empty($methods) && + ($isClass || $isInterface)) { + $methods = get_class_methods($mockClassName['fullClassName']); + } + + if (!is_array($methods)) { + $methods = array(); + } + + $constructor = NULL; + $mockedMethods = ''; + + if (isset($class)) { + if ($class->hasMethod('__construct')) { + $constructor = $class->getMethod('__construct'); + } + + else if ($class->hasMethod($originalClassName)) { + $constructor = $class->getMethod($originalClassName); + } + + foreach ($methods as $methodName) { + try { + $method = $class->getMethod($methodName); + + if (self::canMockMethod($method)) { + $mockedMethods .= self::generateMockedMethodDefinitionFromExisting( + $templateDir, $method + ); + } + } + + catch (ReflectionException $e) { + $mockedMethods .= self::generateMockedMethodDefinition( + $templateDir, $mockClassName['fullClassName'], $methodName + ); + } + } + } else { + foreach ($methods as $methodName) { + $mockedMethods .= self::generateMockedMethodDefinition( + $templateDir, $mockClassName['fullClassName'], $methodName + ); + } + } + + $classTemplate->setVar( + array( + 'prologue' => isset($prologue) ? $prologue : '', + 'epilogue' => isset($epilogue) ? $epilogue : '', + 'class_declaration' => self::generateMockClassDeclaration( + $mockClassName, $isInterface + ), + 'clone' => $cloneTemplate, + 'mock_class_name' => $mockClassName['mockClassName'], + 'mocked_methods' => $mockedMethods + ) + ); + + return array( + 'code' => $classTemplate->render(), + 'mockClassName' => $mockClassName['mockClassName'] + ); + } + + /** + * @param string $originalClassName + * @param string $mockClassName + * @return array + */ + protected static function generateMockClassName($originalClassName, $mockClassName) + { + if ($originalClassName[0] == '\\') { + $originalClassName = substr($originalClassName, 1); + } + + $classNameParts = explode('\\', $originalClassName); + + if (count($classNameParts) > 1) { + $originalClassName = array_pop($classNameParts); + $namespaceName = join('\\', $classNameParts); + $fullClassName = $namespaceName . '\\' . $originalClassName; + } else { + $namespaceName = ''; + $fullClassName = $originalClassName; + } + + if ($mockClassName == '') { + do { + $mockClassName = 'Mock_' . $originalClassName . '_' . + substr(md5(microtime()), 0, 8); + } + while (class_exists($mockClassName, FALSE)); + } + + return array( + 'mockClassName' => $mockClassName, + 'className' => $originalClassName, + 'fullClassName' => $fullClassName, + 'namespaceName' => $namespaceName + ); + } + + /** + * @param array $mockClassName + * @param boolean $isInterface + * @return array + */ + protected static function generateMockClassDeclaration(array $mockClassName, $isInterface) + { + $buffer = 'class '; + + if ($isInterface) { + $buffer .= sprintf( + "%s implements PHPUnit_Framework_MockObject_MockObject, %s%s", + $mockClassName['mockClassName'], + !empty($mockClassName['namespaceName']) ? $mockClassName['namespaceName'] . '\\' : '', + $mockClassName['className'] + ); + } else { + $buffer .= sprintf( + "%s extends %s%s implements PHPUnit_Framework_MockObject_MockObject", + $mockClassName['mockClassName'], + !empty($mockClassName['namespaceName']) ? $mockClassName['namespaceName'] . '\\' : '', + $mockClassName['className'] + ); + } + + return $buffer; + } + + /** + * @param string $templateDir + * @param ReflectionMethod $method + * @return string + */ + protected static function generateMockedMethodDefinitionFromExisting($templateDir, ReflectionMethod $method) + { + if ($method->isPrivate()) { + $modifier = 'private'; + } + + else if ($method->isProtected()) { + $modifier = 'protected'; + } + + else { + $modifier = 'public'; + } + + if ($method->isStatic()) { + $static = TRUE; + } else { + $static = FALSE; + } + + if ($method->returnsReference()) { + $reference = '&'; + } else { + $reference = ''; + } + + return self::generateMockedMethodDefinition( + $templateDir, + $method->getDeclaringClass()->getName(), + $method->getName(), + $modifier, + PHPUnit_Util_Class::getMethodParameters($method), + PHPUnit_Util_Class::getMethodParameters($method, TRUE), + $reference, + $static + ); + } + + /** + * @param string $templateDir + * @param string $className + * @param string $methodName + * @param string $modifier + * @param string $arguments_decl + * @param string $arguments_call + * @param string $reference + * @param boolean $static + * @return string + */ + protected static function generateMockedMethodDefinition($templateDir, $className, $methodName, $modifier = 'public', $arguments_decl = '', $arguments_call = '', $reference = '', $static = FALSE) + { + if ($static) { + $template = new Text_Template( + $templateDir . 'mocked_static_method.tpl' + ); + } else { + $template = new Text_Template( + $templateDir . 'mocked_object_method.tpl' + ); + } + + $template->setVar( + array( + 'arguments_decl' => $arguments_decl, + 'arguments_call' => $arguments_call, + 'arguments_count' => !empty($arguments_call) ? count(explode(',', $arguments_call)) : 0, + 'class_name' => $className, + 'method_name' => $methodName, + 'modifier' => $modifier, + 'reference' => $reference + ) + ); + + return $template->render(); + } + + /** + * @param ReflectionMethod $method + * @return boolean + */ + protected static function canMockMethod(ReflectionMethod $method) + { + if ($method->isConstructor() || $method->isFinal() || + isset(self::$blacklistedMethodNames[$method->getName()])) { + return FALSE; + } + + return TRUE; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_class.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_class.tpl.dist new file mode 100644 index 0000000..feabdc0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_class.tpl.dist @@ -0,0 +1,46 @@ +{prologue}{class_declaration} +{ + protected static $staticInvocationMocker; + protected $invocationMocker; + +{clone}{mocked_methods} + public function expects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher) + { + return $this->__phpunit_getInvocationMocker()->expects($matcher); + } + + public static function staticExpects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher) + { + return self::__phpunit_getStaticInvocationMocker()->expects($matcher); + } + + public function __phpunit_getInvocationMocker() + { + if ($this->invocationMocker === NULL) { + $this->invocationMocker = new PHPUnit_Framework_MockObject_InvocationMocker; + } + + return $this->invocationMocker; + } + + public static function __phpunit_getStaticInvocationMocker() + { + if (self::$staticInvocationMocker === NULL) { + self::$staticInvocationMocker = new PHPUnit_Framework_MockObject_InvocationMocker; + } + + return self::$staticInvocationMocker; + } + + public function __phpunit_verify() + { + self::__phpunit_getStaticInvocationMocker()->verify(); + $this->__phpunit_getInvocationMocker()->verify(); + } + + public function __phpunit_cleanup() + { + self::$staticInvocationMocker = NULL; + $this->invocationMocker = NULL; + } +}{epilogue} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_clone.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_clone.tpl.dist new file mode 100644 index 0000000..9f561b0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_clone.tpl.dist @@ -0,0 +1,4 @@ + public function __clone() + { + $this->invocationMocker = clone $this->__phpunit_getInvocationMocker(); + } diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_object_method.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_object_method.tpl.dist new file mode 100644 index 0000000..9fbf1a6 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_object_method.tpl.dist @@ -0,0 +1,22 @@ + + {modifier} function {reference}{method_name}({arguments_decl}) + { + $arguments = array({arguments_call}); + $count = func_num_args(); + + if ($count > {arguments_count}) { + $_arguments = func_get_args(); + + for ($i = {arguments_count}; $i < $count; $i++) { + $arguments[] = $_arguments[$i]; + } + } + + $result = $this->__phpunit_getInvocationMocker()->invoke( + new PHPUnit_Framework_MockObject_Invocation_Object( + '{class_name}', '{method_name}', $arguments, $this + ) + ); + + return $result; + } diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_static_method.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_static_method.tpl.dist new file mode 100644 index 0000000..570e819 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/mocked_static_method.tpl.dist @@ -0,0 +1,22 @@ + + {modifier} static function {reference}{method_name}({arguments_decl}) + { + $arguments = array({arguments_call}); + $count = func_num_args(); + + if ($count > {arguments_count}) { + $_arguments = func_get_args(); + + for ($i = {arguments_count}; $i < $count; $i++) { + $arguments[] = $_arguments[$i]; + } + } + + $result = self::__phpunit_getStaticInvocationMocker()->invoke( + new PHPUnit_Framework_MockObject_Invocation_Static( + '{class_name}', '{method_name}', $arguments + ) + ); + + return $result; + } diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/unmocked_clone.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/unmocked_clone.tpl.dist new file mode 100644 index 0000000..9d1146d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/unmocked_clone.tpl.dist @@ -0,0 +1,5 @@ + public function __clone() + { + $this->invocationMocker = clone $this->__phpunit_getInvocationMocker(); + parent::__clone(); + } diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/wsdl_class.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/wsdl_class.tpl.dist new file mode 100644 index 0000000..0bd37f5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/wsdl_class.tpl.dist @@ -0,0 +1,7 @@ +class {class_name} extends SOAPClient +{ + public function __construct($wsdl, array $options) + { + parent::__construct('{wsdl}'); + } +{methods}} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/wsdl_method.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/wsdl_method.tpl.dist new file mode 100644 index 0000000..bb16e76 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Generator/wsdl_method.tpl.dist @@ -0,0 +1,4 @@ + + public function {method_name}({arguments}) + { + } diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invocation.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invocation.php new file mode 100644 index 0000000..5bb86ed --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invocation.php @@ -0,0 +1,58 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Interface for invocations. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Interface available since Release 1.0.0 + */ +interface PHPUnit_Framework_MockObject_Invocation +{ +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invocation/Object.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invocation/Object.php new file mode 100644 index 0000000..e29b0db --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invocation/Object.php @@ -0,0 +1,74 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Represents a non-static invocation. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Invocation_Object extends PHPUnit_Framework_MockObject_Invocation_Static +{ + /** + * @var object + */ + public $object; + + /** + * @param string $className + * @param string $methodname + * @param array $parameters + * @param object $object + */ + public function __construct($className, $methodName, array $parameters, $object) + { + parent::__construct($className, $methodName, $parameters); + $this->object = $object; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invocation/Static.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invocation/Static.php new file mode 100644 index 0000000..4161744 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invocation/Static.php @@ -0,0 +1,185 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Represents a static invocation. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Invocation_Static implements PHPUnit_Framework_MockObject_Invocation, PHPUnit_Framework_SelfDescribing +{ + /** + * @var array + */ + protected static $uncloneableExtensions = array( + 'mysqli' => TRUE, + 'SQLite' => TRUE, + 'sqlite3' => TRUE, + 'tidy' => TRUE, + 'xmlwriter' => TRUE, + 'xsl' => TRUE + ); + + /** + * @var array + */ + protected static $uncloneableClasses = array( + 'Closure', + 'COMPersistHelper', + 'IteratorIterator', + 'RecursiveIteratorIterator', + 'SplFileObject', + 'PDORow', + 'ZipArchive' + ); + + /** + * @var string + */ + public $className; + + /** + * @var string + */ + public $methodName; + + /** + * @var array + */ + public $parameters; + + /** + * @param string $className + * @param string $methodname + * @param array $parameters + */ + public function __construct($className, $methodName, array $parameters) + { + $this->className = $className; + $this->methodName = $methodName; + $this->parameters = $parameters; + + foreach ($this->parameters as $key => $value) { + if (is_object($value)) { + $this->parameters[$key] = $this->cloneObject($value); + } + } + } + + /** + * @return string + */ + public function toString() + { + return sprintf( + "%s::%s(%s)", + + $this->className, + $this->methodName, + join( + ', ', + array_map( + array('PHPUnit_Util_Type', 'shortenedExport'), + $this->parameters + ) + ) + ); + } + + /** + * @param object $original + * @return object + */ + protected function cloneObject($original) + { + $cloneable = NULL; + $object = new ReflectionObject($original); + + if (method_exists($object, 'isCloneable')) { + $cloneable = $object->isCloneable(); + } + + if ($cloneable === NULL && + $object->isInternal() && + isset(self::$uncloneableExtensions[$object->getExtensionName()])) { + $cloneable = FALSE; + } + + if ($cloneable === NULL && $object->hasMethod('__clone')) { + $method = $object->getMethod('__clone'); + $cloneable = $method->isPublic(); + } + + if ($cloneable === NULL) { + foreach (self::$uncloneableClasses as $class) { + if ($original instanceof $class) { + $cloneable = FALSE; + break; + } + } + } + + if ($cloneable === NULL) { + $cloneable = TRUE; + } + + if ($cloneable) { + try { + return clone $original; + } + + catch (Exception $e) { + return $original; + } + } else { + return $original; + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/InvocationMocker.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/InvocationMocker.php new file mode 100644 index 0000000..f75da3a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/InvocationMocker.php @@ -0,0 +1,183 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Mocker for invocations which are sent from + * PHPUnit_Framework_MockObject_MockObject objects. + * + * Keeps track of all expectations and stubs as well as registering + * identifications for builders. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_InvocationMocker implements PHPUnit_Framework_MockObject_Stub_MatcherCollection, PHPUnit_Framework_MockObject_Invokable, PHPUnit_Framework_MockObject_Builder_Namespace +{ + /** + * @var PHPUnit_Framework_MockObject_Matcher_Invocation[] + */ + protected $matchers = array(); + + /** + * @var PHPUnit_Framework_MockObject_Builder_Match[] + */ + protected $builderMap = array(); + + /** + * @param PHPUnit_Framework_MockObject_Matcher_Invocation $matcher + */ + public function addMatcher(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher) + { + $this->matchers[] = $matcher; + } + + /** + * @param mixed $id + * @return boolean|null + */ + public function lookupId($id) + { + if (isset($this->builderMap[$id])) { + return $this->builderMap[$id]; + } + + return NULL; + } + + /** + * @param mixed $id + * @param PHPUnit_Framework_MockObject_Builder_Match $builder + * @throws PHPUnit_Framework_Exception + */ + public function registerId($id, PHPUnit_Framework_MockObject_Builder_Match $builder) + { + if (isset($this->builderMap[$id])) { + throw new PHPUnit_Framework_Exception( + 'Match builder with id <' . $id . '> is already registered.' + ); + } + + $this->builderMap[$id] = $builder; + } + + /** + * @param PHPUnit_Framework_MockObject_Matcher_Invocation $matcher + * @return PHPUnit_Framework_MockObject_Builder_InvocationMocker + */ + public function expects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher) + { + return new PHPUnit_Framework_MockObject_Builder_InvocationMocker( + $this, $matcher + ); + } + + /** + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * @return mixed + */ + public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation) + { + $exception = NULL; + $hasReturnValue = FALSE; + + if (strtolower($invocation->methodName) == '__tostring') { + $returnValue = ''; + } else { + $returnValue = NULL; + } + + foreach ($this->matchers as $match) { + try { + if ($match->matches($invocation)) { + $value = $match->invoked($invocation); + + if (!$hasReturnValue) { + $returnValue = $value; + $hasReturnValue = TRUE; + } + } + } + + catch (Exception $e) { + $exception = $e; + } + } + + if ($exception !== NULL) { + throw $exception; + } + + return $returnValue; + } + + /** + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * @return boolean + */ + public function matches(PHPUnit_Framework_MockObject_Invocation $invocation) + { + foreach($this->matchers as $matcher) { + if (!$matcher->matches($invocation)) { + return FALSE; + } + } + + return TRUE; + } + + /** + * @return boolean + */ + public function verify() + { + foreach($this->matchers as $matcher) { + $matcher->verify(); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invokable.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invokable.php new file mode 100644 index 0000000..e73d63b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Invokable.php @@ -0,0 +1,79 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Interface for classes which can be invoked. + * + * The invocation will be taken from a mock object and passed to an object + * of this class. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Interface available since Release 1.0.0 + */ +interface PHPUnit_Framework_MockObject_Invokable extends PHPUnit_Framework_MockObject_Verifiable +{ + /** + * Invokes the invocation object $invocation so that it can be checked for + * expectations or matched against stubs. + * + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * The invocation object passed from mock object. + * @return object + */ + public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation); + + /** + * Checks if the invocation matches. + * + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * The invocation object passed from mock object. + * @return boolean + */ + public function matches(PHPUnit_Framework_MockObject_Invocation $invocation); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher.php new file mode 100644 index 0000000..1798093 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher.php @@ -0,0 +1,303 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Main matcher which defines a full expectation using method, parameter and + * invocation matchers. + * This matcher encapsulates all the other matchers and allows the builder to + * set the specific matchers when the appropriate methods are called (once(), + * where() etc.). + * + * All properties are public so that they can easily be accessed by the builder. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Matcher implements PHPUnit_Framework_MockObject_Matcher_Invocation +{ + /** + * @var PHPUnit_Framework_MockObject_Matcher_Invocation + */ + public $invocationMatcher; + + /** + * @var mixed + */ + public $afterMatchBuilderId = NULL; + + /** + * @var boolean + */ + public $afterMatchBuilderIsInvoked = FALSE; + + /** + * @var PHPUnit_Framework_MockObject_Matcher_MethodName + */ + public $methodNameMatcher = NULL; + + /** + * @var PHPUnit_Framework_MockObject_Matcher_Parameters + */ + public $parametersMatcher = NULL; + + /** + * @var PHPUnit_Framework_MockObject_Stub + */ + public $stub = NULL; + + /** + * @param PHPUnit_Framework_MockObject_Matcher_Invocation $invocationMatcher + */ + public function __construct(PHPUnit_Framework_MockObject_Matcher_Invocation $invocationMatcher) + { + $this->invocationMatcher = $invocationMatcher; + } + + /** + * @return string + */ + public function toString() + { + $list = array(); + + if ($this->invocationMatcher !== NULL) { + $list[] = $this->invocationMatcher->toString(); + } + + if ($this->methodNameMatcher !== NULL) { + $list[] = 'where ' . $this->methodNameMatcher->toString(); + } + + if ($this->parametersMatcher !== NULL) { + $list[] = 'and ' . $this->parametersMatcher->toString(); + } + + if ($this->afterMatchBuilderId !== NULL) { + $list[] = 'after ' . $this->afterMatchBuilderId; + } + + if ($this->stub !== NULL) { + $list[] = 'will ' . $this->stub->toString(); + } + + return join(' ', $list); + } + + /** + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * @return mixed + */ + public function invoked(PHPUnit_Framework_MockObject_Invocation $invocation) + { + if ($this->invocationMatcher === NULL) { + throw new PHPUnit_Framework_Exception( + 'No invocation matcher is set' + ); + } + + if ($this->methodNameMatcher === NULL) { + throw new PHPUnit_Framework_Exception('No method matcher is set'); + } + + if ($this->afterMatchBuilderId !== NULL) { + $builder = $invocation->object + ->__phpunit_getInvocationMocker() + ->lookupId($this->afterMatchBuilderId); + + if (!$builder) { + throw new PHPUnit_Framework_Exception( + sprintf( + 'No builder found for match builder identification <%s>', + + $this->afterMatchBuilderId + ) + ); + } + + $matcher = $builder->getMatcher(); + + if ($matcher && $matcher->invocationMatcher->hasBeenInvoked()) { + $this->afterMatchBuilderIsInvoked = TRUE; + } + } + + $this->invocationMatcher->invoked($invocation); + + try { + if ( $this->parametersMatcher !== NULL && + !$this->parametersMatcher->matches($invocation)) { + $this->parametersMatcher->verify(); + } + } + + catch (PHPUnit_Framework_ExpectationFailedException $e) { + throw new PHPUnit_Framework_ExpectationFailedException( + sprintf( + "Expectation failed for %s when %s\n%s", + + $this->methodNameMatcher->toString(), + $this->invocationMatcher->toString(), + $e->getDescription() + ), + $e->getComparisonFailure() + ); + } + + if ($this->stub) { + return $this->stub->invoke($invocation); + } + + return NULL; + } + + /** + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * @return boolean + */ + public function matches(PHPUnit_Framework_MockObject_Invocation $invocation) + { + if ($this->afterMatchBuilderId !== NULL) { + $builder = $invocation->object + ->__phpunit_getInvocationMocker() + ->lookupId($this->afterMatchBuilderId); + + if (!$builder) { + throw new PHPUnit_Framework_Exception( + sprintf( + 'No builder found for match builder identification <%s>', + + $this->afterMatchBuilderId + ) + ); + } + + $matcher = $builder->getMatcher(); + + if (!$matcher) { + return FALSE; + } + + if (!$matcher->invocationMatcher->hasBeenInvoked()) { + return FALSE; + } + } + + if ($this->invocationMatcher === NULL) { + throw new PHPUnit_Framework_Exception( + 'No invocation matcher is set' + ); + } + + if ($this->methodNameMatcher === NULL) { + throw new PHPUnit_Framework_Exception('No method matcher is set'); + } + + if (!$this->invocationMatcher->matches($invocation)) { + return FALSE; + } + + try { + if (!$this->methodNameMatcher->matches($invocation)) { + return FALSE; + } + } + + catch (PHPUnit_Framework_ExpectationFailedException $e) { + throw new PHPUnit_Framework_ExpectationFailedException( + sprintf( + "Expectation failed for %s when %s\n%s", + + $this->methodNameMatcher->toString(), + $this->invocationMatcher->toString(), + $e->getDescription() + ), + $e->getComparisonFailure() + ); + } + + return TRUE; + } + + /** + * @throws PHPUnit_Framework_Exception + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function verify() + { + if ($this->invocationMatcher === NULL) { + throw new PHPUnit_Framework_Exception( + 'No invocation matcher is set' + ); + } + + if ($this->methodNameMatcher === NULL) { + throw new PHPUnit_Framework_Exception('No method matcher is set'); + } + + try { + $this->invocationMatcher->verify(); + + if ($this->parametersMatcher !== NULL) { + $this->parametersMatcher->verify(); + } + } + + catch (PHPUnit_Framework_ExpectationFailedException $e) { + throw new PHPUnit_Framework_ExpectationFailedException( + sprintf( + "Expectation failed for %s when %s.\n%s", + + $this->methodNameMatcher->toString(), + $this->invocationMatcher->toString(), + $e->getDescription() + ) + ); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/AnyInvokedCount.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/AnyInvokedCount.php new file mode 100644 index 0000000..dc2a995 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/AnyInvokedCount.php @@ -0,0 +1,72 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Invocation matcher which checks if a method has been invoked zero or more + * times. This matcher will always match. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount extends PHPUnit_Framework_MockObject_Matcher_InvokedRecorder +{ + /** + * @return string + */ + public function toString() + { + return 'invoked zero or more times'; + } + + /** + */ + public function verify() + { + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/AnyParameters.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/AnyParameters.php new file mode 100644 index 0000000..7caeb44 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/AnyParameters.php @@ -0,0 +1,74 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Invocation matcher which allos any parameters to a method. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Matcher_AnyParameters extends PHPUnit_Framework_MockObject_Matcher_StatelessInvocation +{ + /** + * @return string + */ + public function toString() + { + return 'with any parameters'; + } + + /** + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * @return boolean + */ + public function matches(PHPUnit_Framework_MockObject_Invocation $invocation) + { + return TRUE; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/Invocation.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/Invocation.php new file mode 100644 index 0000000..402559a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/Invocation.php @@ -0,0 +1,88 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Interface for classes which matches an invocation based on its + * method name, argument, order or call count. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Interface available since Release 1.0.0 + */ +interface PHPUnit_Framework_MockObject_Matcher_Invocation extends PHPUnit_Framework_SelfDescribing, PHPUnit_Framework_MockObject_Verifiable +{ + /** + * Registers the invocation $invocation in the object as being invoked. + * This will only occur after matches() returns true which means the + * current invocation is the correct one. + * + * The matcher can store information from the invocation which can later + * be checked in verify(), or it can check the values directly and throw + * and exception if an expectation is not met. + * + * If the matcher is a stub it will also have a return value. + * + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * Object containing information on a mocked or stubbed method which + * was invoked. + * @return mixed + */ + public function invoked(PHPUnit_Framework_MockObject_Invocation $invocation); + + /** + * Checks if the invocation $invocation matches the current rules. If it does + * the matcher will get the invoked() method called which should check if an + * expectation is met. + * + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * Object containing information on a mocked or stubbed method which + * was invoked. + * @return bool + */ + public function matches(PHPUnit_Framework_MockObject_Invocation $invocation); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedAtIndex.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedAtIndex.php new file mode 100644 index 0000000..ab44350 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedAtIndex.php @@ -0,0 +1,127 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Invocation matcher which checks if a method was invoked at a certain index. + * + * If the expected index number does not match the current invocation index it + * will not match which means it skips all method and parameter matching. Only + * once the index is reached will the method and parameter start matching and + * verifying. + * + * If the index is never reached it will throw an exception in index. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex implements PHPUnit_Framework_MockObject_Matcher_Invocation +{ + /** + * @var integer + */ + protected $sequenceIndex; + + /** + * @var integer + */ + protected $currentIndex = -1; + + /** + * @param integer $sequenceIndex + */ + public function __construct($sequenceIndex) + { + $this->sequenceIndex = $sequenceIndex; + } + + /** + * @return string + */ + public function toString() + { + return 'invoked at sequence index ' . $this->sequenceIndex; + } + + /** + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * @return boolean + */ + public function matches(PHPUnit_Framework_MockObject_Invocation $invocation) + { + $this->currentIndex++; + + return $this->currentIndex == $this->sequenceIndex; + } + + /** + * @param PHPUnit_Framework_MockObject_Invocation $invocation + */ + public function invoked(PHPUnit_Framework_MockObject_Invocation $invocation) + { + } + + /** + * Verifies that the current expectation is valid. If everything is OK the + * code should just return, if not it must throw an exception. + * + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function verify() + { + if ($this->currentIndex < $this->sequenceIndex) { + throw new PHPUnit_Framework_ExpectationFailedException( + sprintf( + 'The expected invocation at index %s was never reached.', + + $this->sequenceIndex + ) + ); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedAtLeastOnce.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedAtLeastOnce.php new file mode 100644 index 0000000..5b8e115 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedAtLeastOnce.php @@ -0,0 +1,85 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Invocation matcher which checks if a method has been invoked at least one + * time. + * + * If the number of invocations is 0 it will throw an exception in verify. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce extends PHPUnit_Framework_MockObject_Matcher_InvokedRecorder +{ + /** + * @return string + */ + public function toString() + { + return 'invoked at least once'; + } + + /** + * Verifies that the current expectation is valid. If everything is OK the + * code should just return, if not it must throw an exception. + * + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function verify() + { + $count = $this->getInvocationCount(); + + if ($count < 1) { + throw new PHPUnit_Framework_ExpectationFailedException( + 'Expected invocation at least once but it never occured.' + ); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedCount.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedCount.php new file mode 100644 index 0000000..00d245b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedCount.php @@ -0,0 +1,143 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Invocation matcher which checks if a method has been invoked a certain amount + * of times. + * If the number of invocations exceeds the value it will immediately throw an + * exception, + * If the number is less it will later be checked in verify() and also throw an + * exception. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Matcher_InvokedCount extends PHPUnit_Framework_MockObject_Matcher_InvokedRecorder +{ + /** + * @var integer + */ + protected $expectedCount; + + /** + * @param interger $expectedCount + */ + public function __construct($expectedCount) + { + $this->expectedCount = $expectedCount; + } + + /** + * @return string + */ + public function toString() + { + return 'invoked ' . $this->expectedCount . ' time(s)'; + } + + /** + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function invoked(PHPUnit_Framework_MockObject_Invocation $invocation) + { + parent::invoked($invocation); + + $count = $this->getInvocationCount(); + + if ($count > $this->expectedCount) { + $message = $invocation->toString() . ' '; + + switch ($this->expectedCount) { + case 0: { + $message .= 'was not expected to be called.'; + } + break; + + case 1: { + $message .= 'was not expected to be called more than once.'; + } + break; + + default: { + $message .= sprintf( + 'was not expected to be called more than %d times.', + + $this->expectedCount + ); + } + } + + throw new PHPUnit_Framework_ExpectationFailedException($message); + } + } + + /** + * Verifies that the current expectation is valid. If everything is OK the + * code should just return, if not it must throw an exception. + * + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function verify() + { + $count = $this->getInvocationCount(); + + if ($count !== $this->expectedCount) { + throw new PHPUnit_Framework_ExpectationFailedException( + sprintf( + 'Method was expected to be called %d times, ' . + 'actually called %d times.', + + $this->expectedCount, + $count + ) + ); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedRecorder.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedRecorder.php new file mode 100644 index 0000000..b23490a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedRecorder.php @@ -0,0 +1,107 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Records invocations and provides convenience methods for checking them later + * on. + * This abstract class can be implemented by matchers which needs to check the + * number of times an invocation has occured. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + * @abstract + */ +abstract class PHPUnit_Framework_MockObject_Matcher_InvokedRecorder implements PHPUnit_Framework_MockObject_Matcher_Invocation +{ + /** + * @var PHPUnit_Framework_MockObject_Invocation[] + */ + protected $invocations = array(); + + /** + * @return integer + */ + public function getInvocationCount() + { + return count($this->invocations); + } + + /** + * @return PHPUnit_Framework_MockObject_Invocation[] + */ + public function getInvocations() + { + return $this->invocations; + } + + /** + * @return boolean + */ + public function hasBeenInvoked() + { + return count($this->invocations) > 0; + } + + /** + * @param PHPUnit_Framework_MockObject_Invocation $invocation + */ + public function invoked(PHPUnit_Framework_MockObject_Invocation $invocation) + { + $this->invocations[] = $invocation; + } + + /** + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * @return boolean + */ + public function matches(PHPUnit_Framework_MockObject_Invocation $invocation) + { + return TRUE; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/MethodName.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/MethodName.php new file mode 100644 index 0000000..e8a5d42 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/MethodName.php @@ -0,0 +1,102 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Invocation matcher which looks for a specific method name in the invocations. + * + * Checks the method name all incoming invocations, the name is checked against + * the defined constraint $constraint. If the constraint is met it will return + * true in matches(). + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Matcher_MethodName extends PHPUnit_Framework_MockObject_Matcher_StatelessInvocation +{ + /** + * @var PHPUnit_Framework_Constraint + */ + protected $constraint; + + /** + * @param PHPUnit_Framework_Constraint|string + * @throws PHPUnit_Framework_Constraint + */ + public function __construct($constraint) + { + if (!$constraint instanceof PHPUnit_Framework_Constraint) { + if (!is_string($constraint)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + $constraint = new PHPUnit_Framework_Constraint_IsEqual( + $constraint, 0, 10, FALSE, TRUE + ); + } + + $this->constraint = $constraint; + } + + /** + * @return string + */ + public function toString() + { + return 'method name ' . $this->constraint->toString(); + } + + /** + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * @return boolean + */ + public function matches(PHPUnit_Framework_MockObject_Invocation $invocation) + { + return $this->constraint->evaluate($invocation->methodName); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/Parameters.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/Parameters.php new file mode 100644 index 0000000..6664138 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/Parameters.php @@ -0,0 +1,162 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Invocation matcher which looks for specific parameters in the invocations. + * + * Checks the parameters of all incoming invocations, the parameter list is + * checked against the defined constraints in $parameters. If the constraint + * is met it will return true in matches(). + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Matcher_Parameters extends PHPUnit_Framework_MockObject_Matcher_StatelessInvocation +{ + /** + * @var array + */ + protected $parameters = array(); + + /** + * @var PHPUnit_Framework_MockObject_Invocation + */ + protected $invocation; + + /** + * @param array $parameters + */ + public function __construct(array $parameters) + { + foreach($parameters as $parameter) { + if (!($parameter instanceof PHPUnit_Framework_Constraint)) { + $parameter = new PHPUnit_Framework_Constraint_IsEqual( + $parameter + ); + } + + $this->parameters[] = $parameter; + } + } + + /** + * @return string + */ + public function toString() + { + $text = 'with parameter'; + + foreach($this->parameters as $index => $parameter) { + if ($index > 0) { + $text .= ' and'; + } + + $text .= ' ' . $index . ' ' . $parameter->toString(); + } + + return $text; + } + + /** + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * @return boolean + */ + public function matches(PHPUnit_Framework_MockObject_Invocation $invocation) + { + $this->invocation = $invocation; + $this->verify(); + + return count($invocation->parameters) < count($this->parameters); + } + + /** + * Checks if the invocation $invocation matches the current rules. If it + * does the matcher will get the invoked() method called which should check + * if an expectation is met. + * + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * Object containing information on a mocked or stubbed method which + * was invoked. + * @return bool + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function verify() + { + if ($this->invocation === NULL) { + throw new PHPUnit_Framework_ExpectationFailedException( + 'Mocked method does not exist.' + ); + } + + if (count($this->invocation->parameters) < count($this->parameters)) { + throw new PHPUnit_Framework_ExpectationFailedException( + sprintf( + 'Parameter count for invocation %s is too low.', + + $this->invocation->toString() + ) + ); + } + + foreach ($this->parameters as $i => $parameter) { + if (!$parameter->evaluate($this->invocation->parameters[$i])) { + $parameter->fail( + $this->invocation->parameters[$i], + sprintf( + 'Parameter %s for invocation %s does not match expected ' . + 'value.', + + $i, + $this->invocation->toString() + ) + ); + } + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/StatelessInvocation.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/StatelessInvocation.php new file mode 100644 index 0000000..ba3de09 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Matcher/StatelessInvocation.php @@ -0,0 +1,96 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Invocation matcher which does not care about previous state from earlier + * invocations. + * + * This abstract class can be implemented by matchers which does not care about + * state but only the current run-time value of the invocation itself. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + * @abstract + */ +abstract class PHPUnit_Framework_MockObject_Matcher_StatelessInvocation implements PHPUnit_Framework_MockObject_Matcher_Invocation +{ + /** + * Registers the invocation $invocation in the object as being invoked. + * This will only occur after matches() returns true which means the + * current invocation is the correct one. + * + * The matcher can store information from the invocation which can later + * be checked in verify(), or it can check the values directly and throw + * and exception if an expectation is not met. + * + * If the matcher is a stub it will also have a return value. + * + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * Object containing information on a mocked or stubbed method which + * was invoked. + * @return mixed + */ + public function invoked(PHPUnit_Framework_MockObject_Invocation $invocation) + { + } + + /** + * Checks if the invocation $invocation matches the current rules. If it does + * the matcher will get the invoked() method called which should check if an + * expectation is met. + * + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * Object containing information on a mocked or stubbed method which + * was invoked. + * @return bool + */ + public function verify() + { + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/MockBuilder.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/MockBuilder.php new file mode 100644 index 0000000..256675e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/MockBuilder.php @@ -0,0 +1,218 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Giorgio Sironi + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Implementation of the Builder pattern for Mock objects. + * + * @package PHPUnit_MockObject + * @author Giorgio Sironi + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_MockBuilder +{ + /** + * @var PHPUnit_Framework_TestCase + */ + protected $testCase; + + /** + * @var string + */ + protected $className; + + /** + * @var array + */ + protected $methods = array(); + + /** + * @var string + */ + protected $mockClassName = ''; + + /** + * @var array + */ + protected $constructorArgs = array(); + + /** + * @var boolean + */ + protected $originalConstructor = TRUE; + + /** + * @var boolean + */ + protected $originalClone = TRUE; + + /** + * @var boolean + */ + protected $autoload = TRUE; + + /** + * @param PHPUnit_Framework_TestCase + * @param string + */ + public function __construct(PHPUnit_Framework_TestCase $testCase, $className) + { + $this->testCase = $testCase; + $this->className = $className; + } + + /** + * Creates a mock object using a fluent interface. + * + * @return PHPUnit_Framework_MockObject_MockObject + */ + public function getMock() + { + return $this->testCase->getMock( + $this->className, + $this->methods, + $this->constructorArgs, + $this->mockClassName, + $this->originalConstructor, + $this->originalClone, + $this->autoload + ); + } + + /** + * Creates a mock object for an abstract class using a fluent interface. + * + * @return PHPUnit_Framework_MockObject_MockObject + */ + public function getMockForAbstractClass() + { + return $this->testCase->getMockForAbstractClass( + $this->className, + $this->constructorArgs, + $this->mockClassName, + $this->originalConstructor, + $this->originalClone, + $this->autoload + ); + } + + /** + * Specifies the subset of methods to mock. Default is to mock all of them. + * + * @param array $methods + * @return PHPUnit_Framework_MockObject_MockBuilder + */ + public function setMethods(array $methods) + { + $this->methods = $methods; + + return $this; + } + + /** + * Specifies the arguments for the constructor. + * + * @param array $args + * @return PHPUnit_Framework_MockObject_MockBuilder + */ + public function setConstructorArgs(array $args) + { + $this->constructorArgs = $args; + + return $this; + } + + /** + * Specifies the name for the mock class. + * + * @param string $name + * @return PHPUnit_Framework_MockObject_MockBuilder + */ + public function setMockClassName($name) + { + $this->mockClassName = $name; + + return $this; + } + + /** + * Suppresses the invocation of the original constructor. + * + * @return PHPUnit_Framework_MockObject_MockBuilder + */ + public function disableOriginalConstructor() + { + $this->originalConstructor = FALSE; + + return $this; + } + + /** + * Suppresses the invocation of the original clone constructor. + * + * @return PHPUnit_Framework_MockObject_MockBuilder + */ + public function disableOriginalClone() + { + $this->originalClone = FALSE; + + return $this; + } + + /** + * Suppresses the use of class autoloading while creating the mock object. + * + * @return PHPUnit_Framework_MockObject_MockBuilder + */ + public function disableAutoload() + { + $this->autoload = FALSE; + + return $this; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/MockObject.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/MockObject.php new file mode 100644 index 0000000..4817e86 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/MockObject.php @@ -0,0 +1,94 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Interface for all mock objects which are generated by + * PHPUnit_Framework_MockObject_Mock. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Interface available since Release 1.0.0 + */ +interface PHPUnit_Framework_MockObject_MockObject /*extends PHPUnit_Framework_MockObject_Verifiable*/ +{ + /** + * Registers a new expectation in the mock object and returns the match + * object which can be infused with further details. + * + * @param PHPUnit_Framework_MockObject_Matcher_Invocation $matcher + * @return PHPUnit_Framework_MockObject_Builder_InvocationMocker + */ + public function expects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher); + + /** + * Registers a new static expectation in the mock object and returns the + * match object which can be infused with further details. + * + * @param PHPUnit_Framework_MockObject_Matcher_Invocation $matcher + * @return PHPUnit_Framework_MockObject_Builder_InvocationMocker + */ + public static function staticExpects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher); + + /** + * @return PHPUnit_Framework_MockObject_InvocationMocker + */ + public function __phpunit_getInvocationMocker(); + + /** + * @return PHPUnit_Framework_MockObject_InvocationMocker + */ + public static function __phpunit_getStaticInvocationMocker(); + + /** + * Verifies that the current expectation is valid. If everything is OK the + * code should just return, if not it must throw an exception. + * + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function __phpunit_verify(); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub.php new file mode 100644 index 0000000..638d22c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub.php @@ -0,0 +1,71 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * An object that stubs the process of a normal method for a mock object. + * + * The stub object will replace the code for the stubbed method and return a + * specific value instead of the original value. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Interface available since Release 1.0.0 + */ +interface PHPUnit_Framework_MockObject_Stub extends PHPUnit_Framework_SelfDescribing +{ + /** + * Fakes the processing of the invocation $invocation by returning a + * specific value. + * + * @param PHPUnit_Framework_MockObject_Invocation $invocation + * The invocation which was mocked and matched by the current method + * and argument matchers. + * @return mixed + */ + public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/ConsecutiveCalls.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/ConsecutiveCalls.php new file mode 100644 index 0000000..ff8ab22 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/ConsecutiveCalls.php @@ -0,0 +1,87 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Patrick Müller + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Stubs a method by returning a user-defined stack of values. + * + * @package PHPUnit_MockObject + * @author Patrick Müller + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls implements PHPUnit_Framework_MockObject_Stub +{ + protected $stack; + protected $value; + + public function __construct($stack) + { + $this->stack = $stack; + } + + public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation) + { + $this->value = array_shift($this->stack); + + if ($this->value instanceof PHPUnit_Framework_MockObject_Stub) { + $this->value = $this->value->invoke($invocation); + } + + return $this->value; + } + + public function toString() + { + return sprintf( + 'return user-specified value %s', + + PHPUnit_Util_Type::toString($this->value) + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/Exception.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/Exception.php new file mode 100644 index 0000000..9b45113 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/Exception.php @@ -0,0 +1,80 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Oliver Schlicht + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Stubs a method by raising a user-defined exception. + * + * @package PHPUnit_MockObject + * @author Oliver Schlicht + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Stub_Exception implements PHPUnit_Framework_MockObject_Stub +{ + protected $exception; + + public function __construct(Exception $exception) + { + $this->exception = $exception; + } + + public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation) + { + throw $this->exception; + } + + public function toString() + { + return sprintf( + 'raise user-specified exception %s', + + PHPUnit_Util_Type::toString($this->exception) + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/MatcherCollection.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/MatcherCollection.php new file mode 100644 index 0000000..2ed18ce --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/MatcherCollection.php @@ -0,0 +1,66 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Stubs a method by returning a user-defined value. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Interface available since Release 1.0.0 + */ +interface PHPUnit_Framework_MockObject_Stub_MatcherCollection +{ + /** + * Adds a new matcher to the collection which can be used as an expectation + * or a stub. + * + * @param PHPUnit_Framework_MockObject_Matcher_Invocation $matcher + * Matcher for invocations to mock objects. + */ + public function addMatcher(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/Return.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/Return.php new file mode 100644 index 0000000..e8eb34a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/Return.php @@ -0,0 +1,78 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Stubs a method by returning a user-defined value. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Stub_Return implements PHPUnit_Framework_MockObject_Stub +{ + protected $value; + + public function __construct($value) + { + $this->value = $value; + } + + public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation) + { + return $this->value; + } + + public function toString() + { + return sprintf( + 'return user-specified value %s', + + PHPUnit_Util_Type::toString($this->value) + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/ReturnArgument.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/ReturnArgument.php new file mode 100644 index 0000000..3e24981 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/ReturnArgument.php @@ -0,0 +1,78 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Stubs a method by returning an argument that was passed to the mocked method. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Stub_ReturnArgument extends PHPUnit_Framework_MockObject_Stub_Return +{ + protected $argumentIndex; + + public function __construct($argumentIndex) + { + $this->argumentIndex = $argumentIndex; + } + + public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation) + { + if (isset($invocation->parameters[$this->argumentIndex])) { + return $invocation->parameters[$this->argumentIndex]; + } else { + return NULL; + } + } + + public function toString() + { + return sprintf('return argument #%d', $this->argumentIndex); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/ReturnCallback.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/ReturnCallback.php new file mode 100644 index 0000000..23952db --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Stub/ReturnCallback.php @@ -0,0 +1,94 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Framework_MockObject_Stub_ReturnCallback implements PHPUnit_Framework_MockObject_Stub +{ + protected $callback; + + public function __construct($callback) + { + $this->callback = $callback; + } + + public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation) + { + return call_user_func_array($this->callback, $invocation->parameters); + } + + public function toString() + { + if (is_array($this->callback)) { + if (is_object($this->callback[0])) { + $class = get_class($this->callback[0]); + $type = '->'; + } else { + $class = $this->callback[0]; + $type = '::'; + } + + return sprintf( + 'return result of user defined callback %s%s%s() with the ' . + 'passed arguments', + + $class, + $type, + $this->callback[1] + ); + } else { + return 'return result of user defined callback ' . $this->callback . + ' with the passed arguments'; + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Verifiable.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Verifiable.php new file mode 100644 index 0000000..b48728d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/MockObject/Verifiable.php @@ -0,0 +1,65 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since File available since Release 1.0.0 + */ + +/** + * Interface for classes which must verify a given expectation. + * + * @package PHPUnit_MockObject + * @author Sebastian Bergmann + * @copyright 2010-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.9 + * @link http://github.com/sebastianbergmann/phpunit-mock-objects + * @since Interface available since Release 1.0.0 + */ +interface PHPUnit_Framework_MockObject_Verifiable +{ + /** + * Verifies that the current expectation is valid. If everything is OK the + * code should just return, if not it must throw an exception. + * + * @throws PHPUnit_Framework_ExpectationFailedException + */ + public function verify(); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Process/TestCaseMethod.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Process/TestCaseMethod.tpl.dist new file mode 100644 index 0000000..2ddd4fa --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Process/TestCaseMethod.tpl.dist @@ -0,0 +1,48 @@ +collectRawCodeCoverageInformation({collectCodeCoverageInformation}); + $result->strictMode({strict}); + + $test = new {className}('{methodName}', unserialize('{data}'), '{dataName}'); + $test->setDependencyInput(unserialize('{dependencyInput}')); + $test->setInIsolation(TRUE); + + ob_end_clean(); + ob_start(); + $test->run($result); + $output = ob_get_clean(); + + print serialize( + array( + 'testResult' => $test->getResult(), + 'numAssertions' => $test->getNumAssertions(), + 'result' => $result, + 'output' => $output + ) + ); + + ob_start(); +} + +{constants} +{included_files} +{globals} + +if (isset($GLOBALS['__PHPUNIT_BOOTSTRAP'])) { + require_once $GLOBALS['__PHPUNIT_BOOTSTRAP']; + unset($GLOBALS['__PHPUNIT_BOOTSTRAP']); +} + +__phpunit_run_isolated_test(); +ob_end_clean(); +?> diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SelfDescribing.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SelfDescribing.php new file mode 100644 index 0000000..4a21f23 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SelfDescribing.php @@ -0,0 +1,66 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Interface for classes that can return a description of itself. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Interface available since Release 3.0.0 + */ +interface PHPUnit_Framework_SelfDescribing +{ + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString(); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SkippedTest.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SkippedTest.php new file mode 100644 index 0000000..503a0a4 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SkippedTest.php @@ -0,0 +1,60 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * A marker interface for marking a unit test as being skipped. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Interface available since Release 3.0.0 + */ +interface PHPUnit_Framework_SkippedTest +{ +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SkippedTestError.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SkippedTestError.php new file mode 100644 index 0000000..5d22e50 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SkippedTestError.php @@ -0,0 +1,61 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Extension to PHPUnit_Framework_AssertionFailedError to mark the special + * case of a skipped test. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Framework_SkippedTestError extends PHPUnit_Framework_AssertionFailedError implements PHPUnit_Framework_SkippedTest +{ +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SkippedTestSuiteError.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SkippedTestSuiteError.php new file mode 100644 index 0000000..9f6b5c7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SkippedTestSuiteError.php @@ -0,0 +1,61 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.1.0 + */ + +/** + * Extension to PHPUnit_Framework_AssertionFailedError to mark the special + * case of a skipped test suite. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.1.0 + */ +class PHPUnit_Framework_SkippedTestSuiteError extends PHPUnit_Framework_AssertionFailedError implements PHPUnit_Framework_SkippedTest +{ +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SyntheticError.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SyntheticError.php new file mode 100644 index 0000000..7a3e2d3 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/SyntheticError.php @@ -0,0 +1,122 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.5.0 + */ + +/** + * Creates a synthetic failed assertion. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.5.0 + */ +class PHPUnit_Framework_SyntheticError extends PHPUnit_Framework_AssertionFailedError +{ + /** + * The synthetic file. + * + * @var string + */ + protected $syntheticFile = ''; + + /** + * The synthetic line number. + * + * @var integer + */ + protected $syntheticLine = 0; + + /** + * The synthetic trace. + * + * @var array + */ + protected $syntheticTrace = array(); + + /** + * Constructor. + * + * @param string $message + * @param integer $code + * @param string $file + * @param integer $line + * @param array $trace + */ + public function __construct($message, $code, $file, $line, $trace) + { + parent::__construct($message, $code); + + $this->syntheticFile = $file; + $this->syntheticLine = $line; + $this->syntheticTrace = $trace; + } + + /** + * @return string + */ + public function getSyntheticFile() + { + return $this->syntheticFile; + } + + /** + * @return integer + */ + public function getSyntheticLine() + { + return $this->syntheticLine; + } + + /** + * @return array + */ + public function getSyntheticTrace() + { + return $this->syntheticTrace; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Test.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Test.php new file mode 100644 index 0000000..63ac4e1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Test.php @@ -0,0 +1,67 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * A Test can be run and collect its results. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Interface available since Release 2.0.0 + */ +interface PHPUnit_Framework_Test extends Countable +{ + /** + * Runs a test and collects its result in a TestResult instance. + * + * @param PHPUnit_Framework_TestResult $result + * @return PHPUnit_Framework_TestResult + */ + public function run(PHPUnit_Framework_TestResult $result = NULL); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestCase.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestCase.php new file mode 100644 index 0000000..eeaf29d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestCase.php @@ -0,0 +1,1513 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +require_once 'Text/Template.php'; + +/** + * A TestCase defines the fixture to run multiple tests. + * + * To define a TestCase + * + * 1) Implement a subclass of PHPUnit_Framework_TestCase. + * 2) Define instance variables that store the state of the fixture. + * 3) Initialize the fixture state by overriding setUp(). + * 4) Clean-up after a test by overriding tearDown(). + * + * Each test runs in its own fixture so there can be no side effects + * among test runs. + * + * Here is an example: + * + * + * value1 = 2; + * $this->value2 = 3; + * } + * } + * ?> + * + * + * For each test implement a method which interacts with the fixture. + * Verify the expected results with assertions specified by calling + * assert with a boolean. + * + * + * assertTrue($this->value1 + $this->value2 == 5); + * } + * ?> + * + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +abstract class PHPUnit_Framework_TestCase extends PHPUnit_Framework_Assert implements PHPUnit_Framework_Test, PHPUnit_Framework_SelfDescribing +{ + /** + * Enable or disable the backup and restoration of the $GLOBALS array. + * Overwrite this attribute in a child class of TestCase. + * Setting this attribute in setUp() has no effect! + * + * @var boolean + */ + protected $backupGlobals = NULL; + + /** + * @var array + */ + protected $backupGlobalsBlacklist = array(); + + /** + * Enable or disable the backup and restoration of static attributes. + * Overwrite this attribute in a child class of TestCase. + * Setting this attribute in setUp() has no effect! + * + * @var boolean + */ + protected $backupStaticAttributes = NULL; + + /** + * @var array + */ + protected $backupStaticAttributesBlacklist = array(); + + /** + * Whether or not this test is to be run in a separate PHP process. + * + * @var boolean + */ + protected $runTestInSeparateProcess = NULL; + + /** + * Whether or not this test should preserve the global state when + * running in a separate PHP process. + * + * @var boolean + */ + protected $preserveGlobalState = TRUE; + + /** + * Whether or not this test is running in a separate PHP process. + * + * @var boolean + */ + private $inIsolation = FALSE; + + /** + * @var array + */ + private $data = array(); + + /** + * @var string + */ + private $dataName = ''; + + /** + * @var boolean + */ + private $useErrorHandler = NULL; + + /** + * @var boolean + */ + private $useOutputBuffering = NULL; + + /** + * The name of the expected Exception. + * + * @var mixed + */ + private $expectedException = NULL; + + /** + * The message of the expected Exception. + * + * @var string + */ + private $expectedExceptionMessage = ''; + + /** + * The code of the expected Exception. + * + * @var integer + */ + private $expectedExceptionCode; + + /** + * The stack trace to where the expected exception was set. + * + * @var array + */ + private $expectedExceptionTrace = array(); + + /** + * The name of the test case. + * + * @var string + */ + private $name = NULL; + + /** + * @var array + */ + private $dependencies = array(); + + /** + * @var array + */ + private $dependencyInput = array(); + + /** + * @var string + */ + private $exceptionMessage = NULL; + + /** + * @var integer + */ + private $exceptionCode = 0; + + /** + * @var Array + */ + private $iniSettings = array(); + + /** + * @var Array + */ + private $locale = array(); + + /** + * @var Array + */ + private $mockObjects = array(); + + /** + * @var integer + */ + private $status; + + /** + * @var string + */ + private $statusMessage = ''; + + /** + * @var integer + */ + private $numAssertions = 0; + + /** + * @var PHPUnit_Framework_TestResult + */ + private $result; + + /** + * @var mixed + */ + private $testResult; + + /** + * Constructs a test case with the given name. + * + * @param string $name + * @param array $data + * @param string $dataName + */ + public function __construct($name = NULL, array $data = array(), $dataName = '') + { + if ($name !== NULL) { + $this->setName($name); + } + + $this->data = $data; + $this->dataName = $dataName; + } + + /** + * Returns a string representation of the test case. + * + * @return string + */ + public function toString() + { + $class = new ReflectionClass($this); + + $buffer = sprintf( + '%s::%s', + + $class->name, + $this->getName(FALSE) + ); + + return $buffer . $this->getDataSetAsString(); + } + + /** + * Counts the number of test cases executed by run(TestResult result). + * + * @return integer + */ + public function count() + { + return 1; + } + + /** + * Returns the annotations for this test. + * + * @return array + * @since Method available since Release 3.4.0 + */ + public function getAnnotations() + { + return PHPUnit_Util_Test::parseTestMethodAnnotations( + get_class($this), $this->name + ); + } + + /** + * Gets the name of a TestCase. + * + * @param boolean $withDataSet + * @return string + */ + public function getName($withDataSet = TRUE) + { + if ($withDataSet) { + return $this->name . $this->getDataSetAsString(FALSE); + } else { + return $this->name; + } + } + + /** + * @return string + * @since Method available since Release 3.2.0 + */ + public function getExpectedException() + { + return $this->expectedException; + } + + /** + * @param mixed $exceptionName + * @param string $exceptionMessage + * @param integer $exceptionCode + * @since Method available since Release 3.2.0 + */ + public function setExpectedException($exceptionName, $exceptionMessage = '', $exceptionCode = 0) + { + $this->expectedException = $exceptionName; + $this->expectedExceptionMessage = $exceptionMessage; + $this->expectedExceptionCode = $exceptionCode; + $this->expectedExceptionTrace = debug_backtrace(); + } + + /** + * @since Method available since Release 3.4.0 + */ + protected function setExpectedExceptionFromAnnotation() + { + try { + $expectedException = PHPUnit_Util_Test::getExpectedException( + get_class($this), $this->name + ); + + if ($expectedException !== FALSE) { + $this->setExpectedException( + $expectedException['class'], + $expectedException['message'], + $expectedException['code'] + ); + } + } + + catch (ReflectionException $e) { + } + } + + /** + * @param boolean $useErrorHandler + * @since Method available since Release 3.4.0 + */ + public function setUseErrorHandler($useErrorHandler) + { + $this->useErrorHandler = $useErrorHandler; + } + + /** + * @since Method available since Release 3.4.0 + */ + protected function setUseErrorHandlerFromAnnotation() + { + try { + $useErrorHandler = PHPUnit_Util_Test::getErrorHandlerSettings( + get_class($this), $this->name + ); + + if ($useErrorHandler !== NULL) { + $this->setUseErrorHandler($useErrorHandler); + } + } + + catch (ReflectionException $e) { + } + } + + /** + * @param boolean $useOutputBuffering + * @since Method available since Release 3.4.0 + */ + public function setUseOutputBuffering($useOutputBuffering) + { + $this->useOutputBuffering = $useOutputBuffering; + } + + /** + * @since Method available since Release 3.4.0 + */ + protected function setUseOutputBufferingFromAnnotation() + { + try { + $useOutputBuffering = PHPUnit_Util_Test::getOutputBufferingSettings( + get_class($this), $this->name + ); + + if ($useOutputBuffering !== NULL) { + $this->setUseOutputBuffering($useOutputBuffering); + } + } + + catch (ReflectionException $e) { + } + } + + /** + * Returns the status of this test. + * + * @return integer + * @since Method available since Release 3.1.0 + */ + public function getStatus() + { + return $this->status; + } + + /** + * Returns the status message of this test. + * + * @return string + * @since Method available since Release 3.3.0 + */ + public function getStatusMessage() + { + return $this->statusMessage; + } + + /** + * Returns whether or not this test has failed. + * + * @return boolean + * @since Method available since Release 3.0.0 + */ + public function hasFailed() + { + $status = $this->getStatus(); + + return $status == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE || + $status == PHPUnit_Runner_BaseTestRunner::STATUS_ERROR; + } + + /** + * Runs the test case and collects the results in a TestResult object. + * If no TestResult object is passed a new one will be created. + * + * @param PHPUnit_Framework_TestResult $result + * @return PHPUnit_Framework_TestResult + * @throws InvalidArgumentException + */ + public function run(PHPUnit_Framework_TestResult $result = NULL) + { + if ($result === NULL) { + $result = $this->createResult(); + } + + $this->result = $result; + + $this->setExpectedExceptionFromAnnotation(); + $this->setUseErrorHandlerFromAnnotation(); + $this->setUseOutputBufferingFromAnnotation(); + + if ($this->useErrorHandler !== NULL) { + $oldErrorHandlerSetting = $result->getConvertErrorsToExceptions(); + $result->convertErrorsToExceptions($this->useErrorHandler); + } + + if (!$this->handleDependencies()) { + return; + } + + if ($this->runTestInSeparateProcess === TRUE && + $this->inIsolation !== TRUE && + !$this instanceof PHPUnit_Extensions_SeleniumTestCase && + !$this instanceof PHPUnit_Extensions_PhptTestCase) { + $class = new ReflectionClass($this); + + $template = new Text_Template( + sprintf( + '%s%sProcess%sTestCaseMethod.tpl', + + dirname(__FILE__), + DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR + ) + ); + + if ($this->preserveGlobalState) { + $constants = PHPUnit_Util_GlobalState::getConstantsAsString(); + $globals = PHPUnit_Util_GlobalState::getGlobalsAsString(); + $includedFiles = PHPUnit_Util_GlobalState::getIncludedFilesAsString(); + } else { + $constants = ''; + $globals = ''; + $includedFiles = ''; + } + + if ($result->getCollectCodeCoverageInformation()) { + $coverage = 'TRUE'; + } else { + $coverage = 'FALSE'; + } + + if ($result->isStrict()) { + $strict = 'TRUE'; + } else { + $strict = 'FALSE'; + } + + $data = addcslashes(serialize($this->data), "'"); + $dependencyInput = addcslashes( + serialize($this->dependencyInput), "'" + ); + $includePath = addslashes(get_include_path()); + + $template->setVar( + array( + 'filename' => $class->getFileName(), + 'className' => $class->getName(), + 'methodName' => $this->name, + 'collectCodeCoverageInformation' => $coverage, + 'data' => $data, + 'dataName' => $this->dataName, + 'dependencyInput' => $dependencyInput, + 'constants' => $constants, + 'globals' => $globals, + 'include_path' => $includePath, + 'included_files' => $includedFiles, + 'strict' => $strict + ) + ); + + $this->prepareTemplate($template); + + $php = PHPUnit_Util_PHP::factory(); + $php->runJob($template->render(), $this, $result); + } else { + $result->run($this); + } + + if ($this->useErrorHandler !== NULL) { + $result->convertErrorsToExceptions($oldErrorHandlerSetting); + } + + $this->result = NULL; + + return $result; + } + + /** + * Runs the bare test sequence. + */ + public function runBare() + { + $this->numAssertions = 0; + + // Backup the $GLOBALS array and static attributes. + if ($this->runTestInSeparateProcess !== TRUE && + $this->inIsolation !== TRUE) { + if ($this->backupGlobals === NULL || + $this->backupGlobals === TRUE) { + PHPUnit_Util_GlobalState::backupGlobals( + $this->backupGlobalsBlacklist + ); + } + + if (version_compare(PHP_VERSION, '5.3', '>') && + $this->backupStaticAttributes === TRUE) { + PHPUnit_Util_GlobalState::backupStaticAttributes( + $this->backupStaticAttributesBlacklist + ); + } + } + + // Start output buffering. + if ($this->useOutputBuffering === TRUE) { + ob_start(); + } + + // Clean up stat cache. + clearstatcache(); + + try { + if ($this->inIsolation) { + $this->setUpBeforeClass(); + } + + $this->setUp(); + $this->assertPreConditions(); + $this->testResult = $this->runTest(); + $this->verifyMockObjects(); + $this->assertPostConditions(); + $this->status = PHPUnit_Runner_BaseTestRunner::STATUS_PASSED; + } + + catch (PHPUnit_Framework_IncompleteTest $e) { + $this->status = PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE; + $this->statusMessage = $e->getMessage(); + } + + catch (PHPUnit_Framework_SkippedTest $e) { + $this->status = PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED; + $this->statusMessage = $e->getMessage(); + } + + catch (PHPUnit_Framework_AssertionFailedError $e) { + $this->status = PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE; + $this->statusMessage = $e->getMessage(); + } + + catch (Exception $e) { + $this->status = PHPUnit_Runner_BaseTestRunner::STATUS_ERROR; + $this->statusMessage = $e->getMessage(); + } + + // Tear down the fixture. An exception raised in tearDown() will be + // caught and passed on when no exception was raised before. + try { + $this->tearDown(); + + if ($this->inIsolation) { + $this->tearDownAfterClass(); + } + } + + catch (Exception $_e) { + if (!isset($e)) { + $e = $_e; + } + } + + // Stop output buffering. + if ($this->useOutputBuffering === TRUE) { + ob_end_clean(); + } + + // Clean up stat cache. + clearstatcache(); + + // Restore the $GLOBALS array and static attributes. + if ($this->runTestInSeparateProcess !== TRUE && + $this->inIsolation !== TRUE) { + if ($this->backupGlobals === NULL || + $this->backupGlobals === TRUE) { + PHPUnit_Util_GlobalState::restoreGlobals( + $this->backupGlobalsBlacklist + ); + } + + if (version_compare(PHP_VERSION, '5.3', '>') && + $this->backupStaticAttributes === TRUE) { + PHPUnit_Util_GlobalState::restoreStaticAttributes(); + } + } + + // Clean up INI settings. + foreach ($this->iniSettings as $varName => $oldValue) { + ini_set($varName, $oldValue); + } + + $this->iniSettings = array(); + + // Clean up locale settings. + foreach ($this->locale as $category => $locale) { + setlocale($category, $locale); + } + + // Workaround for missing "finally". + if (isset($e)) { + $this->onNotSuccessfulTest($e); + } + } + + /** + * Override to run the test and assert its state. + * + * @return mixed + * @throws RuntimeException + */ + protected function runTest() + { + if ($this->name === NULL) { + throw new PHPUnit_Framework_Exception( + 'PHPUnit_Framework_TestCase::$name must not be NULL.' + ); + } + + try { + $class = new ReflectionClass($this); + $method = $class->getMethod($this->name); + } + + catch (ReflectionException $e) { + $this->fail($e->getMessage()); + } + + try { + $testResult = $method->invokeArgs( + $this, array_merge($this->data, $this->dependencyInput) + ); + } + + catch (Exception $e) { + if (!$e instanceof PHPUnit_Framework_IncompleteTest && + !$e instanceof PHPUnit_Framework_SkippedTest && + is_string($this->expectedException) && + $e instanceof $this->expectedException) { + if (is_string($this->expectedExceptionMessage) && + !empty($this->expectedExceptionMessage)) { + $this->assertContains( + $this->expectedExceptionMessage, + $e->getMessage() + ); + } + + if (is_int($this->expectedExceptionCode) && + $this->expectedExceptionCode !== 0) { + $this->assertEquals( + $this->expectedExceptionCode, $e->getCode() + ); + } + + $this->numAssertions++; + + return; + } else { + throw $e; + } + } + + if ($this->expectedException !== NULL) { + $this->numAssertions++; + + $this->syntheticFail( + 'Expected exception ' . $this->expectedException, + '', + 0, + $this->expectedExceptionTrace + ); + } + + return $testResult; + } + + /** + * Verifies the mock object expectations. + * + * @since Method available since Release 3.5.0 + */ + protected function verifyMockObjects() + { + foreach ($this->mockObjects as $mockObject) { + $this->numAssertions++; + $mockObject->__phpunit_verify(); + $mockObject->__phpunit_cleanup(); + } + + $this->mockObjects = array(); + } + + /** + * Sets the name of a TestCase. + * + * @param string + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * Sets the dependencies of a TestCase. + * + * @param array $dependencies + * @since Method available since Release 3.4.0 + */ + public function setDependencies(array $dependencies) + { + $this->dependencies = $dependencies; + } + + /** + * Sets + * + * @param array $dependencyInput + * @since Method available since Release 3.4.0 + */ + public function setDependencyInput(array $dependencyInput) + { + $this->dependencyInput = $dependencyInput; + } + + /** + * Calling this method in setUp() has no effect! + * + * @param boolean $backupGlobals + * @since Method available since Release 3.3.0 + */ + public function setBackupGlobals($backupGlobals) + { + if (is_null($this->backupGlobals) && is_bool($backupGlobals)) { + $this->backupGlobals = $backupGlobals; + } + } + + /** + * Calling this method in setUp() has no effect! + * + * @param boolean $backupStaticAttributes + * @since Method available since Release 3.4.0 + */ + public function setBackupStaticAttributes($backupStaticAttributes) + { + if (is_null($this->backupStaticAttributes) && + is_bool($backupStaticAttributes)) { + $this->backupStaticAttributes = $backupStaticAttributes; + } + } + + /** + * @param boolean $runTestInSeparateProcess + * @throws InvalidArgumentException + * @since Method available since Release 3.4.0 + */ + public function setRunTestInSeparateProcess($runTestInSeparateProcess) + { + if (is_bool($runTestInSeparateProcess)) { + if ($this->runTestInSeparateProcess === NULL) { + $this->runTestInSeparateProcess = $runTestInSeparateProcess; + } + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); + } + } + + /** + * @param boolean $preserveGlobalState + * @throws InvalidArgumentException + * @since Method available since Release 3.4.0 + */ + public function setPreserveGlobalState($preserveGlobalState) + { + if (is_bool($preserveGlobalState)) { + $this->preserveGlobalState = $preserveGlobalState; + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); + } + } + + /** + * @param boolean $inIsolation + * @throws InvalidArgumentException + * @since Method available since Release 3.4.0 + */ + public function setInIsolation($inIsolation) + { + if (is_bool($inIsolation)) { + $this->inIsolation = $inIsolation; + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); + } + } + + /** + * @return mixed + * @since Method available since Release 3.4.0 + */ + public function getResult() + { + return $this->testResult; + } + + /** + * @param mixed $result + * @since Method available since Release 3.4.0 + */ + public function setResult($result) + { + $this->testResult = $result; + } + + /** + * @return PHPUnit_Framework_TestResult + * @since Method available since Release 3.5.7 + */ + public function getTestResultObject() + { + return $this->result; + } + + /** + * This method is a wrapper for the ini_set() function that automatically + * resets the modified php.ini setting to its original value after the + * test is run. + * + * @param string $varName + * @param string $newValue + * @throws InvalidArgumentException + * @throws RuntimeException + * @since Method available since Release 3.0.0 + */ + protected function iniSet($varName, $newValue) + { + if (!is_string($varName)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + $currentValue = ini_set($varName, $newValue); + + if ($currentValue !== FALSE) { + $this->iniSettings[$varName] = $currentValue; + } else { + throw new PHPUnit_Framework_Exception( + sprintf( + 'INI setting "%s" could not be set to "%s".', + $varName, + $newValue + ) + ); + } + } + + /** + * This method is a wrapper for the setlocale() function that automatically + * resets the locale to its original value after the test is run. + * + * @param integer $category + * @param string $locale + * @throws InvalidArgumentException + * @throws RuntimeException + * @since Method available since Release 3.1.0 + */ + protected function setLocale() + { + $args = func_get_args(); + + if (count($args) < 2) { + throw new InvalidArgumentException; + } + + $category = $args[0]; + $locale = $args[1]; + + $categories = array( + LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME + ); + + if (defined('LC_MESSAGES')) { + $categories[] = LC_MESSAGES; + } + + if (!in_array($category, $categories)) { + throw new InvalidArgumentException; + } + + if (!is_array($locale) && !is_string($locale)) { + throw new InvalidArgumentException; + } + + $this->locale[$category] = setlocale($category, NULL); + + $result = call_user_func_array( 'setlocale', $args ); + + if ($result === FALSE) { + throw new PHPUnit_Framework_Exception( + 'The locale functionality is not implemented on your platform, ' . + 'the specified locale does not exist or the category name is ' . + 'invalid.' + ); + } + } + + /** + * Returns a mock object for the specified class. + * + * @param string $originalClassName + * @param array $methods + * @param array $arguments + * @param string $mockClassName + * @param boolean $callOriginalConstructor + * @param boolean $callOriginalClone + * @param boolean $callAutoload + * @return PHPUnit_Framework_MockObject_MockObject + * @throws InvalidArgumentException + * @since Method available since Release 3.0.0 + */ + public function getMock($originalClassName, $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE) + { + $mockObject = PHPUnit_Framework_MockObject_Generator::getMock( + $originalClassName, + $methods, + $arguments, + $mockClassName, + $callOriginalConstructor, + $callOriginalClone, + $callAutoload + ); + + $this->mockObjects[] = $mockObject; + + return $mockObject; + } + + /** + * Returns a builder object to create mock objects using a fluent interface. + * + * @param string $className + * @return PHPUnit_Framework_MockObject_MockBuilder + * @since Method available since Release 3.5.0 + */ + public function getMockBuilder($className) + { + return new PHPUnit_Framework_MockObject_MockBuilder( + $this, $className + ); + } + + /** + * Mocks the specified class and returns the name of the mocked class. + * + * @param string $originalClassName + * @param array $methods + * @param array $arguments + * @param string $mockClassName + * @param boolean $callOriginalConstructor + * @param boolean $callOriginalClone + * @param boolean $callAutoload + * @return string + * @throws InvalidArgumentException + * @since Method available since Release 3.5.0 + */ + protected function getMockClass($originalClassName, $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = FALSE, $callOriginalClone = TRUE, $callAutoload = TRUE) + { + $mock = $this->getMock( + $originalClassName, + $methods, + $arguments, + $mockClassName, + $callOriginalConstructor, + $callOriginalClone, + $callAutoload + ); + + return get_class($mock); + } + + /** + * Returns a mock object for the specified abstract class with all abstract + * methods of the class mocked. Concrete methods are not mocked. + * + * @param string $originalClassName + * @param array $arguments + * @param string $mockClassName + * @param boolean $callOriginalConstructor + * @param boolean $callOriginalClone + * @param boolean $callAutoload + * @return PHPUnit_Framework_MockObject_MockObject + * @since Method available since Release 3.4.0 + * @throws InvalidArgumentException + */ + public function getMockForAbstractClass($originalClassName, array $arguments = array(), $mockClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE) + { + $mockObject = PHPUnit_Framework_MockObject_Generator::getMockForAbstractClass( + $originalClassName, + $arguments, + $mockClassName, + $callOriginalConstructor, + $callOriginalClone, + $callAutoload + ); + + $this->mockObjects[] = $mockObject; + + return $mockObject; + } + + /** + * Returns a mock object based on the given WSDL file. + * + * @param string $wsdlFile + * @param string $originalClassName + * @param string $mockClassName + * @param array $methods + * @param boolean $callOriginalConstructor + * @return PHPUnit_Framework_MockObject_MockObject + * @since Method available since Release 3.4.0 + */ + protected function getMockFromWsdl($wsdlFile, $originalClassName = '', $mockClassName = '', array $methods = array(), $callOriginalConstructor = TRUE) + { + if ($originalClassName === '') { + $originalClassName = str_replace( + '.wsdl', '', basename($wsdlFile) + ); + } + + eval( + PHPUnit_Framework_MockObject_Generator::generateClassFromWsdl( + $wsdlFile, $originalClassName, $methods + ) + ); + + return $this->getMock( + $originalClassName, + $methods, + array('', array()), + $mockClassName, + $callOriginalConstructor, + FALSE, + FALSE + ); + } + + /** + * Adds a value to the assertion counter. + * + * @param integer $count + * @since Method available since Release 3.3.3 + */ + public function addToAssertionCount($count) + { + $this->numAssertions += $count; + } + + /** + * Returns the number of assertions performed by this test. + * + * @return integer + * @since Method available since Release 3.3.0 + */ + public function getNumAssertions() + { + return $this->numAssertions; + } + + /** + * Returns a matcher that matches when the method it is evaluated for + * is executed zero or more times. + * + * @return PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount + * @since Method available since Release 3.0.0 + */ + public static function any() + { + return new PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount; + } + + /** + * Returns a matcher that matches when the method it is evaluated for + * is never executed. + * + * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount + * @since Method available since Release 3.0.0 + */ + public static function never() + { + return new PHPUnit_Framework_MockObject_Matcher_InvokedCount(0); + } + + /** + * Returns a matcher that matches when the method it is evaluated for + * is executed at least once. + * + * @return PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce + * @since Method available since Release 3.0.0 + */ + public static function atLeastOnce() + { + return new PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce; + } + + /** + * Returns a matcher that matches when the method it is evaluated for + * is executed exactly once. + * + * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount + * @since Method available since Release 3.0.0 + */ + public static function once() + { + return new PHPUnit_Framework_MockObject_Matcher_InvokedCount(1); + } + + /** + * Returns a matcher that matches when the method it is evaluated for + * is executed exactly $count times. + * + * @param integer $count + * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount + * @since Method available since Release 3.0.0 + */ + public static function exactly($count) + { + return new PHPUnit_Framework_MockObject_Matcher_InvokedCount($count); + } + + /** + * Returns a matcher that matches when the method it is evaluated for + * is invoked at the given $index. + * + * @param integer $index + * @return PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex + * @since Method available since Release 3.0.0 + */ + public static function at($index) + { + return new PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex($index); + } + + /** + * + * + * @param mixed $value + * @return PHPUnit_Framework_MockObject_Stub_Return + * @since Method available since Release 3.0.0 + */ + public static function returnValue($value) + { + return new PHPUnit_Framework_MockObject_Stub_Return($value); + } + + /** + * + * + * @param integer $argumentIndex + * @return PHPUnit_Framework_MockObject_Stub_ReturnArgument + * @since Method available since Release 3.3.0 + */ + public static function returnArgument($argumentIndex) + { + return new PHPUnit_Framework_MockObject_Stub_ReturnArgument( + $argumentIndex + ); + } + + /** + * + * + * @param mixed $callback + * @return PHPUnit_Framework_MockObject_Stub_ReturnCallback + * @since Method available since Release 3.3.0 + */ + public static function returnCallback($callback) + { + return new PHPUnit_Framework_MockObject_Stub_ReturnCallback($callback); + } + + /** + * + * + * @param Exception $exception + * @return PHPUnit_Framework_MockObject_Stub_Exception + * @since Method available since Release 3.1.0 + */ + public static function throwException(Exception $exception) + { + return new PHPUnit_Framework_MockObject_Stub_Exception($exception); + } + + /** + * + * + * @param mixed $value, ... + * @return PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls + * @since Method available since Release 3.0.0 + */ + public static function onConsecutiveCalls() + { + $args = func_get_args(); + + return new PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls($args); + } + + /** + * @param mixed $data + * @return string + * @since Method available since Release 3.2.1 + */ + protected function dataToString($data) + { + $result = array(); + + foreach ($data as $_data) { + if (is_array($_data)) { + $result[] = 'array(' . $this->dataToString($_data) . ')'; + } + + else if (is_object($_data)) { + $object = new ReflectionObject($_data); + + if ($object->hasMethod('__toString')) { + $result[] = (string)$_data; + } else { + $result[] = get_class($_data); + } + } + + else if (is_resource($_data)) { + $result[] = ''; + } + + else { + $result[] = var_export($_data, TRUE); + } + } + + return join(', ', $result); + } + + /** + * Gets the data set description of a TestCase. + * + * @param boolean $includeData + * @return string + * @since Method available since Release 3.3.0 + */ + protected function getDataSetAsString($includeData = TRUE) + { + $buffer = ''; + + if (!empty($this->data)) { + if (is_int($this->dataName)) { + $buffer .= sprintf(' with data set #%d', $this->dataName); + } else { + $buffer .= sprintf(' with data set "%s"', $this->dataName); + } + + if ($includeData) { + $buffer .= sprintf(' (%s)', $this->dataToString($this->data)); + } + } + + return $buffer; + } + + /** + * Creates a default TestResult object. + * + * @return PHPUnit_Framework_TestResult + */ + protected function createResult() + { + return new PHPUnit_Framework_TestResult; + } + + /** + * @since Method available since Release 3.5.4 + */ + protected function handleDependencies() + { + if (!empty($this->dependencies) && !$this->inIsolation) { + $className = get_class($this); + $passed = $this->result->passed(); + $passedKeys = array_keys($passed); + $numKeys = count($passedKeys); + + for ($i = 0; $i < $numKeys; $i++) { + $pos = strpos($passedKeys[$i], ' with data set'); + + if ($pos !== FALSE) { + $passedKeys[$i] = substr($passedKeys[$i], 0, $pos); + } + } + + $passedKeys = array_flip(array_unique($passedKeys)); + + foreach ($this->dependencies as $dependency) { + if (strpos($dependency, '::') === FALSE) { + $dependency = $className . '::' . $dependency; + } + + if (!isset($passedKeys[$dependency])) { + $this->result->addError( + $this, + new PHPUnit_Framework_SkippedTestError( + sprintf( + 'This test depends on "%s" to pass.', $dependency + ) + ), + 0 + ); + + return FALSE; + } else { + if (isset($passed[$dependency])) { + $this->dependencyInput[] = $passed[$dependency]; + } else { + $this->dependencyInput[] = NULL; + } + } + } + } + + return TRUE; + } + + /** + * This method is called before the first test of this test class is run. + * + * @since Method available since Release 3.4.0 + */ + public static function setUpBeforeClass() + { + } + + /** + * Sets up the fixture, for example, open a network connection. + * This method is called before a test is executed. + * + */ + protected function setUp() + { + } + + /** + * Performs assertions shared by all tests of a test case. + * + * This method is called before the execution of a test starts + * and after setUp() is called. + * + * @since Method available since Release 3.2.8 + */ + protected function assertPreConditions() + { + } + + /** + * Performs assertions shared by all tests of a test case. + * + * This method is called before the execution of a test ends + * and before tearDown() is called. + * + * @since Method available since Release 3.2.8 + */ + protected function assertPostConditions() + { + } + + /** + * Tears down the fixture, for example, close a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } + + /** + * This method is called after the last test of this test class is run. + * + * @since Method available since Release 3.4.0 + */ + public static function tearDownAfterClass() + { + } + + /** + * This method is called when a test method did not execute successfully. + * + * @param Exception $e + * @since Method available since Release 3.4.0 + */ + protected function onNotSuccessfulTest(Exception $e) + { + throw $e; + } + + /** + * Performs custom preparations on the process isolation template. + * + * @param Text_Template $template + * @since Method available since Release 3.4.0 + */ + protected function prepareTemplate(Text_Template $template) + { + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestFailure.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestFailure.php new file mode 100644 index 0000000..b78803f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestFailure.php @@ -0,0 +1,228 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * A TestFailure collects a failed test together with the caught exception. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +class PHPUnit_Framework_TestFailure +{ + /** + * @var PHPUnit_Framework_Test + */ + protected $failedTest; + + /** + * @var Exception + */ + protected $thrownException; + + /** + * Constructs a TestFailure with the given test and exception. + * + * @param PHPUnit_Framework_Test $failedTest + * @param Exception $thrownException + */ + public function __construct(PHPUnit_Framework_Test $failedTest, Exception $thrownException) + { + $this->failedTest = $failedTest; + $this->thrownException = $thrownException; + } + + /** + * Returns a short description of the failure. + * + * @return string + */ + public function toString() + { + return sprintf( + '%s: %s', + + $this->failedTest, + $this->thrownException->getMessage() + ); + } + + /** + * Returns a description for the thrown exception. + * + * @return string + * @since Method available since Release 3.4.0 + */ + public function getExceptionAsString() + { + return self::exceptionToString($this->thrownException); + } + + /** + * Returns a description for an exception. + * + * @param Exception $e + * @return string + * @since Method available since Release 3.2.0 + */ + public static function exceptionToString(Exception $e) + { + if ($e instanceof PHPUnit_Framework_SelfDescribing) { + if ($e instanceof PHPUnit_Framework_ExpectationFailedException) { + $comparisonFailure = $e->getComparisonFailure(); + $description = $e->getDescription(); + $message = $e->getCustomMessage(); + + if ($message == '') { + $buffer = ''; + } else { + $buffer = $message . "\n"; + } + + if ($comparisonFailure !== NULL) { + if ($comparisonFailure->identical()) { + if ($comparisonFailure instanceof PHPUnit_Framework_ComparisonFailure_Object) { + $buffer .= 'Failed asserting that two variables ' . + "reference the same object.\n"; + } else { + $buffer .= $comparisonFailure->toString() . "\n"; + } + } else { + if ($comparisonFailure instanceof PHPUnit_Framework_ComparisonFailure_Scalar) { + $buffer .= $comparisonFailure->toString() . "\n"; + } + + else if ($comparisonFailure instanceof PHPUnit_Framework_ComparisonFailure_Array || + $comparisonFailure instanceof PHPUnit_Framework_ComparisonFailure_Object || + $comparisonFailure instanceof PHPUnit_Framework_ComparisonFailure_String) { + $buffer .= sprintf( + "Failed asserting that two %ss are equal.\n%s\n", + + strtolower( + substr(get_class($comparisonFailure), 36) + ), + $comparisonFailure->toString() + ); + } + } + } else { + $buffer .= $e->toString(); + + if (!empty($buffer)) { + $buffer .= "\n"; + } + + if (strpos($buffer, $description) === FALSE) { + $buffer .= $description . "\n"; + } + } + } + + else { + $buffer = $e->toString(); + + if (!empty($buffer)) { + $buffer .= "\n"; + } + } + } + + else if ($e instanceof PHPUnit_Framework_Error) { + $buffer = $e->getMessage() . "\n"; + } + + else { + $buffer = get_class($e) . ': ' . $e->getMessage() . "\n"; + } + + return $buffer; + } + + /** + * Gets the failed test. + * + * @return Test + */ + public function failedTest() + { + return $this->failedTest; + } + + /** + * Gets the thrown exception. + * + * @return Exception + */ + public function thrownException() + { + return $this->thrownException; + } + + /** + * Returns the exception's message. + * + * @return string + */ + public function exceptionMessage() + { + return $this->thrownException()->getMessage(); + } + + /** + * Returns TRUE if the thrown exception + * is of type AssertionFailedError. + * + * @return boolean + */ + public function isFailure() + { + return ($this->thrownException() instanceof PHPUnit_Framework_AssertionFailedError); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestListener.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestListener.php new file mode 100644 index 0000000..c9e51e5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestListener.php @@ -0,0 +1,127 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * A Listener for test progress. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Interface available since Release 2.0.0 + */ +interface PHPUnit_Framework_TestListener +{ + /** + * An error occurred. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time); + + /** + * A failure occurred. + * + * @param PHPUnit_Framework_Test $test + * @param PHPUnit_Framework_AssertionFailedError $e + * @param float $time + */ + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time); + + /** + * Incomplete test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time); + + /** + * Skipped test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + * @since Method available since Release 3.0.0 + */ + public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time); + + /** + * A test suite started. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit_Framework_TestSuite $suite); + + /** + * A test suite ended. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit_Framework_TestSuite $suite); + + /** + * A test started. + * + * @param PHPUnit_Framework_Test $test + */ + public function startTest(PHPUnit_Framework_Test $test); + + /** + * A test ended. + * + * @param PHPUnit_Framework_Test $test + * @param float $time + */ + public function endTest(PHPUnit_Framework_Test $test, $time); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestResult.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestResult.php new file mode 100644 index 0000000..1ededf8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestResult.php @@ -0,0 +1,907 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +require_once 'PHP/CodeCoverage.php'; +require_once 'PHP/Timer.php'; + +/** + * A TestResult collects the results of executing a test case. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +class PHPUnit_Framework_TestResult implements Countable +{ + /** + * @var boolean + */ + protected static $xdebugLoaded = NULL; + + /** + * @var boolean + */ + protected static $useXdebug = NULL; + + /** + * @var array + */ + protected $passed = array(); + + /** + * @var array + */ + protected $errors = array(); + + /** + * @var array + */ + protected $deprecatedFeatures = array(); + + /** + * @var array + */ + protected $failures = array(); + + /** + * @var array + */ + protected $notImplemented = array(); + + /** + * @var array + */ + protected $skipped = array(); + + /** + * @var array + */ + protected $listeners = array(); + + /** + * @var integer + */ + protected $runTests = 0; + + /** + * @var float + */ + protected $time = 0; + + /** + * @var PHPUnit_Framework_TestSuite + */ + protected $topTestSuite = NULL; + + /** + * Code Coverage information. + * + * @var array + */ + protected $codeCoverage; + + /** + * @var boolean + */ + protected $collectCodeCoverageInformation = FALSE; + + /** + * @var boolean + */ + protected $collectRawCodeCoverageInformation = FALSE; + + /** + * @var array + */ + protected $rawCodeCoverageInformation = array(); + + /** + * @var boolean + */ + protected $convertErrorsToExceptions = TRUE; + + /** + * @var boolean + */ + protected $stop = FALSE; + + /** + * @var boolean + */ + protected $stopOnError = FALSE; + + /** + * @var boolean + */ + protected $stopOnFailure = FALSE; + + /** + * @var boolean + */ + protected $strictMode = FALSE; + + /** + * @var boolean + */ + protected $stopOnIncomplete = FALSE; + + /** + * @var boolean + */ + protected $stopOnSkipped = FALSE; + + /** + * @var boolean + */ + protected $lastTestFailed = FALSE; + + /** + * @param PHP_CodeCoverage $codeCoverage + */ + public function __construct(PHP_CodeCoverage $codeCoverage = NULL) + { + if ($codeCoverage === NULL) { + $codeCoverage = PHP_CodeCoverage::getInstance(); + } + + $this->codeCoverage = $codeCoverage; + } + + /** + * Registers a TestListener. + * + * @param PHPUnit_Framework_TestListener + */ + public function addListener(PHPUnit_Framework_TestListener $listener) + { + $this->listeners[] = $listener; + } + + /** + * Unregisters a TestListener. + * + * @param PHPUnit_Framework_TestListener $listener + */ + public function removeListener(PHPUnit_Framework_TestListener $listener) + { + foreach ($this->listeners as $key => $_listener) { + if ($listener === $_listener) { + unset($this->listeners[$key]); + } + } + } + + /** + * Flushes all flushable TestListeners. + * + * @since Method available since Release 3.0.0 + */ + public function flushListeners() + { + foreach ($this->listeners as $listener) { + if ($listener instanceof PHPUnit_Util_Printer) { + $listener->flush(); + } + } + } + + /** + * Adds an error to the list of errors. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) + { + if ($e instanceof PHPUnit_Framework_IncompleteTest) { + $this->notImplemented[] = new PHPUnit_Framework_TestFailure( + $test, $e + ); + + $notifyMethod = 'addIncompleteTest'; + + if ($this->stopOnIncomplete) { + $this->stop(); + } + } + + else if ($e instanceof PHPUnit_Framework_SkippedTest) { + $this->skipped[] = new PHPUnit_Framework_TestFailure($test, $e); + $notifyMethod = 'addSkippedTest'; + + if ($this->stopOnSkipped) { + $this->stop(); + } + } + + else { + $this->errors[] = new PHPUnit_Framework_TestFailure($test, $e); + $notifyMethod = 'addError'; + + if ($this->stopOnError || $this->stopOnFailure) { + $this->stop(); + } + } + + foreach ($this->listeners as $listener) { + $listener->$notifyMethod($test, $e, $time); + } + + $this->lastTestFailed = TRUE; + $this->time += $time; + } + + /** + * Adds a failure to the list of failures. + * The passed in exception caused the failure. + * + * @param PHPUnit_Framework_Test $test + * @param PHPUnit_Framework_AssertionFailedError $e + * @param float $time + */ + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) + { + if ($e instanceof PHPUnit_Framework_IncompleteTest) { + $this->notImplemented[] = new PHPUnit_Framework_TestFailure( + $test, $e + ); + + $notifyMethod = 'addIncompleteTest'; + + if ($this->stopOnIncomplete) { + $this->stop(); + } + } + + else if ($e instanceof PHPUnit_Framework_SkippedTest) { + $this->skipped[] = new PHPUnit_Framework_TestFailure($test, $e); + $notifyMethod = 'addSkippedTest'; + + if ($this->stopOnSkipped) { + $this->stop(); + } + } + + else { + $this->failures[] = new PHPUnit_Framework_TestFailure($test, $e); + $notifyMethod = 'addFailure'; + + if ($this->stopOnFailure) { + $this->stop(); + } + } + + foreach ($this->listeners as $listener) { + $listener->$notifyMethod($test, $e, $time); + } + + $this->lastTestFailed = TRUE; + $this->time += $time; + } + + /** + * Adds a deprecated feature notice to the list of deprecated features used during run + * + * @param PHPUnit_Util_DeprecatedFeature $deprecatedFeature + */ + public function addDeprecatedFeature(PHPUnit_Util_DeprecatedFeature $deprecatedFeature) + { + $this->deprecatedFeatures[] = $deprecatedFeature; + } + + /** + * Informs the result that a testsuite will be started. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit_Framework_TestSuite $suite) + { + if ($this->topTestSuite === NULL) { + $this->topTestSuite = $suite; + } + + foreach ($this->listeners as $listener) { + $listener->startTestSuite($suite); + } + } + + /** + * Informs the result that a testsuite was completed. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit_Framework_TestSuite $suite) + { + foreach ($this->listeners as $listener) { + $listener->endTestSuite($suite); + } + } + + /** + * Informs the result that a test will be started. + * + * @param PHPUnit_Framework_Test $test + */ + public function startTest(PHPUnit_Framework_Test $test) + { + $this->lastTestFailed = FALSE; + $this->runTests += count($test); + + foreach ($this->listeners as $listener) { + $listener->startTest($test); + } + } + + /** + * Informs the result that a test was completed. + * + * @param PHPUnit_Framework_Test $test + * @param float $time + */ + public function endTest(PHPUnit_Framework_Test $test, $time) + { + foreach ($this->listeners as $listener) { + $listener->endTest($test, $time); + } + + if (!$this->lastTestFailed && $test instanceof PHPUnit_Framework_TestCase) { + $this->passed[get_class($test) . '::' . $test->getName()] = $test->getResult(); + $this->time += $time; + } + } + + /** + * Returns TRUE if no incomplete test occured. + * + * @return boolean + */ + public function allCompletlyImplemented() + { + return $this->notImplementedCount() == 0; + } + + /** + * Gets the number of incomplete tests. + * + * @return integer + */ + public function notImplementedCount() + { + return count($this->notImplemented); + } + + /** + * Returns an Enumeration for the incomplete tests. + * + * @return array + */ + public function notImplemented() + { + return $this->notImplemented; + } + + /** + * Returns TRUE if no test has been skipped. + * + * @return boolean + * @since Method available since Release 3.0.0 + */ + public function noneSkipped() + { + return $this->skippedCount() == 0; + } + + /** + * Gets the number of skipped tests. + * + * @return integer + * @since Method available since Release 3.0.0 + */ + public function skippedCount() + { + return count($this->skipped); + } + + /** + * Returns an Enumeration for the skipped tests. + * + * @return array + * @since Method available since Release 3.0.0 + */ + public function skipped() + { + return $this->skipped; + } + + /** + * Gets the number of detected errors. + * + * @return integer + */ + public function errorCount() + { + return count($this->errors); + } + + /** + * Returns an Enumeration for the errors. + * + * @return array + */ + public function errors() + { + return $this->errors; + } + + /** + * Returns an Enumeration for the deprecated features used. + * + * @return array + * @since Method available since Release 3.5.7 + */ + public function deprecatedFeatures() + { + return $this->deprecatedFeatures; + } + + /** + * Returns an Enumeration for the deprecated features used. + * + * @return array + * @since Method available since Release 3.5.7 + */ + public function deprecatedFeaturesCount() + { + return count($this->deprecatedFeatures); + } + + /** + * Gets the number of detected failures. + * + * @return integer + */ + public function failureCount() + { + return count($this->failures); + } + + /** + * Returns an Enumeration for the failures. + * + * @return array + */ + public function failures() + { + return $this->failures; + } + + /** + * Returns the names of the tests that have passed. + * + * @return array + * @since Method available since Release 3.4.0 + */ + public function passed() + { + return $this->passed; + } + + /** + * Returns the (top) test suite. + * + * @return PHPUnit_Framework_TestSuite + * @since Method available since Release 3.0.0 + */ + public function topTestSuite() + { + return $this->topTestSuite; + } + + /** + * Enables or disables the collection of Code Coverage information. + * + * @param boolean $flag + * @throws InvalidArgumentException + * @since Method available since Release 2.3.0 + */ + public function collectCodeCoverageInformation($flag) + { + if (is_bool($flag)) { + $this->collectCodeCoverageInformation = $flag; + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); + } + } + + /** + * Enables or disables the collection of raw Code Coverage information. + * + * @param boolean $flag + * @throws InvalidArgumentException + * @since Method available since Release 3.4.0 + */ + public function collectRawCodeCoverageInformation($flag) + { + if (is_bool($flag)) { + $this->collectRawCodeCoverageInformation = $flag; + + if ($flag === TRUE) { + $this->collectCodeCoverageInformation = $flag; + } + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); + } + } + + /** + * Returns whether code coverage information should be collected. + * + * @return boolean If code coverage should be collected + * @since Method available since Release 3.2.0 + */ + public function getCollectCodeCoverageInformation() + { + return $this->collectCodeCoverageInformation; + } + + /** + * Returns the raw Code Coverage information. + * + * @return array + * @since Method available since Release 3.4.0 + */ + public function getRawCodeCoverageInformation() + { + return $this->rawCodeCoverageInformation; + } + + /** + * Returns the strict mode configuration option + * + * @return boolean + */ + public function isStrict() + { + return $this->strictMode; + } + + /** + * Runs a TestCase. + * + * @param PHPUnit_Framework_Test $test + */ + public function run(PHPUnit_Framework_Test $test) + { + PHPUnit_Framework_Assert::resetCount(); + + $error = FALSE; + $failure = FALSE; + $incomplete = FALSE; + $skipped = FALSE; + + $this->startTest($test); + + $errorHandlerSet = FALSE; + + if ($this->convertErrorsToExceptions) { + $oldErrorHandler = set_error_handler( + array('PHPUnit_Util_ErrorHandler', 'handleError'), + E_ALL | E_STRICT + ); + + if ($oldErrorHandler === NULL) { + $errorHandlerSet = TRUE; + } else { + restore_error_handler(); + } + } + + if (self::$xdebugLoaded === NULL) { + self::$xdebugLoaded = extension_loaded('xdebug'); + self::$useXdebug = self::$xdebugLoaded; + } + + $useXdebug = self::$useXdebug && + $this->collectCodeCoverageInformation && + !$test instanceof PHPUnit_Extensions_SeleniumTestCase && + !$test instanceof PHPUnit_Framework_Warning; + + if ($useXdebug) { + $this->codeCoverage->start($test); + } + + PHP_Timer::start(); + + try { + $test->runBare(); + } + + catch (PHPUnit_Framework_AssertionFailedError $e) { + $failure = TRUE; + + if ($e instanceof PHPUnit_Framework_IncompleteTestError) { + $incomplete = TRUE; + } + + else if ($e instanceof PHPUnit_Framework_SkippedTestError) { + $skipped = TRUE; + } + } + + catch (Exception $e) { + $error = TRUE; + } + + $time = PHP_Timer::stop(); + $test->addToAssertionCount(PHPUnit_Framework_Assert::getCount()); + + if ($this->strictMode && $test->getNumAssertions() == 0) { + $incomplete = TRUE; + } + + if ($useXdebug) { + $data = $this->codeCoverage->stop(FALSE); + + if (!$incomplete && !$skipped) { + if ($this->collectRawCodeCoverageInformation) { + $this->rawCodeCoverageInformation[] = $data; + } else { + $filterGroups = array('DEFAULT', 'TESTS'); + + if (!defined('PHPUNIT_TESTSUITE')) { + $filterGroups[] = 'PHPUNIT'; + } + + $this->codeCoverage->append($data, $test, $filterGroups); + } + } + + unset($data); + } + + if ($errorHandlerSet === TRUE) { + restore_error_handler(); + } + + if ($error === TRUE) { + $this->addError($test, $e, $time); + } + + else if ($failure === TRUE) { + $this->addFailure($test, $e, $time); + } + + else if ($this->strictMode && $test->getNumAssertions() == 0) { + $this->addFailure( + $test, + new PHPUnit_Framework_IncompleteTestError( + 'This test did not perform any assertions' + ), + $time + ); + } + + $this->endTest($test, $time); + } + + /** + * Gets the number of run tests. + * + * @return integer + */ + public function count() + { + return $this->runTests; + } + + /** + * Checks whether the test run should stop. + * + * @return boolean + */ + public function shouldStop() + { + return $this->stop; + } + + /** + * Marks that the test run should stop. + * + */ + public function stop() + { + $this->stop = TRUE; + } + + /** + * Returns the PHP_CodeCoverage object. + * + * @return PHP_CodeCoverage + * @since Method available since Release 3.5.0 + */ + public function getCodeCoverage() + { + return $this->codeCoverage; + } + + /** + * Enables or disables the error-to-exception conversion. + * + * @param boolean $flag + * @throws InvalidArgumentException + * @since Method available since Release 3.2.14 + */ + public function convertErrorsToExceptions($flag) + { + if (is_bool($flag)) { + $this->convertErrorsToExceptions = $flag; + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); + } + } + + /** + * Returns the error-to-exception conversion setting. + * + * @return boolean + * @since Method available since Release 3.4.0 + */ + public function getConvertErrorsToExceptions() + { + return $this->convertErrorsToExceptions; + } + + /** + * Enables or disables the stopping when an error occurs. + * + * @param boolean $flag + * @throws InvalidArgumentException + * @since Method available since Release 3.5.0 + */ + public function stopOnError($flag) + { + if (is_bool($flag)) { + $this->stopOnError = $flag; + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); + } + } + + /** + * Enables or disables the stopping when a failure occurs. + * + * @param boolean $flag + * @throws InvalidArgumentException + * @since Method available since Release 3.1.0 + */ + public function stopOnFailure($flag) + { + if (is_bool($flag)) { + $this->stopOnFailure = $flag; + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); + } + } + + /** + * Enables or disables the strict mode. + * + * When active + * * Tests that do not assert anything will be marked as incomplete. + * * Tests that are incomplete or skipped yield no code coverage. + * + * @param boolean $flag + * @throws InvalidArgumentException + * @since Method available since Release 3.5.2 + */ + public function strictMode($flag) + { + if (is_bool($flag)) { + $this->strictMode = $flag; + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); + } + } + + /** + * Enables or disables the stopping for incomplete tests. + * + * @param boolean $flag + * @throws InvalidArgumentException + * @since Method available since Release 3.5.0 + */ + public function stopOnIncomplete($flag) + { + if (is_bool($flag)) { + $this->stopOnIncomplete = $flag; + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); + } + } + + /** + * Enables or disables the stopping for skipped tests. + * + * @param boolean $flag + * @throws InvalidArgumentException + * @since Method available since Release 3.1.0 + */ + public function stopOnSkipped($flag) + { + if (is_bool($flag)) { + $this->stopOnSkipped = $flag; + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); + } + } + + /** + * Returns the time spent running the tests. + * + * @return float + */ + public function time() + { + return $this->time; + } + + /** + * Returns whether the entire test was successful or not. + * + * @return boolean + */ + public function wasSuccessful() + { + return empty($this->errors) && empty($this->failures); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestSuite.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestSuite.php new file mode 100644 index 0000000..45acd93 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestSuite.php @@ -0,0 +1,932 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +require_once 'PHP/CodeCoverage.php'; + +/** + * A TestSuite is a composite of Tests. It runs a collection of test cases. + * + * Here is an example using the dynamic test definition. + * + * + * addTest(new MathTest('testPass')); + * ?> + * + * + * Alternatively, a TestSuite can extract the tests to be run automatically. + * To do so you pass a ReflectionClass instance for your + * PHPUnit_Framework_TestCase class to the PHPUnit_Framework_TestSuite + * constructor. + * + * + * + * + * + * This constructor creates a suite with all the methods starting with + * "test" that take no arguments. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +class PHPUnit_Framework_TestSuite implements PHPUnit_Framework_Test, PHPUnit_Framework_SelfDescribing, IteratorAggregate +{ + /** + * Enable or disable the backup and restoration of the $GLOBALS array. + * + * @var boolean + */ + protected $backupGlobals = NULL; + + /** + * Enable or disable the backup and restoration of static attributes. + * + * @var boolean + */ + protected $backupStaticAttributes = NULL; + + /** + * The name of the test suite. + * + * @var string + */ + protected $name = ''; + + /** + * The test groups of the test suite. + * + * @var array + */ + protected $groups = array(); + + /** + * The tests in the test suite. + * + * @var array + */ + protected $tests = array(); + + /** + * The number of tests in the test suite. + * + * @var integer + */ + protected $numTests = -1; + + /** + * @var boolean + */ + protected $testCase = FALSE; + + /** + * Constructs a new TestSuite: + * + * - PHPUnit_Framework_TestSuite() constructs an empty TestSuite. + * + * - PHPUnit_Framework_TestSuite(ReflectionClass) constructs a + * TestSuite from the given class. + * + * - PHPUnit_Framework_TestSuite(ReflectionClass, String) + * constructs a TestSuite from the given class with the given + * name. + * + * - PHPUnit_Framework_TestSuite(String) either constructs a + * TestSuite from the given class (if the passed string is the + * name of an existing class) or constructs an empty TestSuite + * with the given name. + * + * @param mixed $theClass + * @param string $name + * @throws InvalidArgumentException + */ + public function __construct($theClass = '', $name = '') + { + $argumentsValid = FALSE; + + if (is_object($theClass) && + $theClass instanceof ReflectionClass) { + $argumentsValid = TRUE; + } + + else if (is_string($theClass) && + $theClass !== '' && + class_exists($theClass, FALSE)) { + $argumentsValid = TRUE; + + if ($name == '') { + $name = $theClass; + } + + $theClass = new ReflectionClass($theClass); + } + + else if (is_string($theClass)) { + $this->setName($theClass); + return; + } + + if (!$argumentsValid) { + throw new InvalidArgumentException; + } + + if (!$theClass->isSubclassOf('PHPUnit_Framework_TestCase')) { + throw new InvalidArgumentException( + 'Class does not extend PHPUnit_Framework_TestCase.' + ); + } + + $filename = $theClass->getFilename(); + + if (strpos($filename, 'eval()') === FALSE) { + PHP_CodeCoverage::getInstance()->filter()->addFileToBlacklist( + realpath($filename), 'TESTS' + ); + } + + if ($name != '') { + $this->setName($name); + } else { + $this->setName($theClass->getName()); + } + + $constructor = $theClass->getConstructor(); + + if ($constructor !== NULL && + !$constructor->isPublic()) { + $this->addTest( + self::warning( + sprintf( + 'Class "%s" has no public constructor.', + + $theClass->getName() + ) + ) + ); + + return; + } + + foreach ($theClass->getMethods() as $method) { + if (strpos($method->getDeclaringClass()->getName(), 'PHPUnit_') !== 0) { + $this->addTestMethod($theClass, $method); + } + } + + if (empty($this->tests)) { + $this->addTest( + self::warning( + sprintf( + 'No tests found in class "%s".', + + $theClass->getName() + ) + ) + ); + } + + $this->testCase = TRUE; + } + + /** + * Returns a string representation of the test suite. + * + * @return string + */ + public function toString() + { + return $this->getName(); + } + + /** + * Adds a test to the suite. + * + * @param PHPUnit_Framework_Test $test + * @param array $groups + */ + public function addTest(PHPUnit_Framework_Test $test, $groups = array()) + { + $class = new ReflectionClass($test); + + if (!$class->isAbstract()) { + $this->tests[] = $test; + $this->numTests = -1; + + if ($test instanceof PHPUnit_Framework_TestSuite && + empty($groups)) { + $groups = $test->getGroups(); + } + + if (empty($groups)) { + $groups = array('__nogroup__'); + } + + foreach ($groups as $group) { + if (!isset($this->groups[$group])) { + $this->groups[$group] = array($test); + } else { + $this->groups[$group][] = $test; + } + } + } + } + + /** + * Adds the tests from the given class to the suite. + * + * @param mixed $testClass + * @throws InvalidArgumentException + */ + public function addTestSuite($testClass) + { + if (is_string($testClass) && class_exists($testClass)) { + $testClass = new ReflectionClass($testClass); + } + + if (!is_object($testClass)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory( + 1, 'class name or object' + ); + } + + if ($testClass instanceof PHPUnit_Framework_TestSuite) { + $this->addTest($testClass); + } + + else if ($testClass instanceof ReflectionClass) { + $suiteMethod = FALSE; + + if (!$testClass->isAbstract()) { + if ($testClass->hasMethod(PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME)) { + $method = $testClass->getMethod( + PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME + ); + + if ($method->isStatic()) { + $this->addTest( + $method->invoke(NULL, $testClass->getName()) + ); + + $suiteMethod = TRUE; + } + } + } + + if (!$suiteMethod && !$testClass->isAbstract()) { + $this->addTest(new PHPUnit_Framework_TestSuite($testClass)); + } + } + + else { + throw new InvalidArgumentException; + } + } + + /** + * Wraps both addTest() and addTestSuite + * as well as the separate import statements for the user's convenience. + * + * If the named file cannot be read or there are no new tests that can be + * added, a PHPUnit_Framework_Warning will be created instead, + * leaving the current test run untouched. + * + * @param string $filename + * @param boolean $syntaxCheck + * @param array $phptOptions Array with ini settings for the php instance + * run, key being the name if the setting, + * value the ini value. + * @throws InvalidArgumentException + * @since Method available since Release 2.3.0 + * @author Stefano F. Rausch + */ + public function addTestFile($filename, $syntaxCheck = FALSE, $phptOptions = array()) + { + if (!is_string($filename)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (file_exists($filename) && substr($filename, -5) == '.phpt') { + $this->addTest( + new PHPUnit_Extensions_PhptTestCase($filename, $phptOptions) + ); + + return; + } + + PHPUnit_Util_Class::collectStart(); + $filename = PHPUnit_Util_Fileloader::checkAndLoad($filename, $syntaxCheck); + $newClasses = PHPUnit_Util_Class::collectEnd(); + $baseName = str_replace('.php', '', basename($filename)); + + foreach ($newClasses as $className) { + if (substr($className, 0 - strlen($baseName)) == $baseName) { + $class = new ReflectionClass($className); + + if ($class->getFileName() == $filename) { + $newClasses = array($className); + break; + } + } + } + + $testsFound = FALSE; + + foreach ($newClasses as $className) { + $class = new ReflectionClass($className); + + if (!$class->isAbstract()) { + if ($class->hasMethod(PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME)) { + $method = $class->getMethod( + PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME + ); + + if ($method->isStatic()) { + $this->addTest($method->invoke(NULL, $className)); + + $testsFound = TRUE; + } + } + + else if ($class->implementsInterface('PHPUnit_Framework_Test')) { + $this->addTestSuite($class); + + $testsFound = TRUE; + } + } + } + + $this->numTests = -1; + } + + /** + * Wrapper for addTestFile() that adds multiple test files. + * + * @param array|Iterator $filenames + * @throws InvalidArgumentException + * @since Method available since Release 2.3.0 + */ + public function addTestFiles($filenames, $syntaxCheck = FALSE) + { + if (!(is_array($filenames) || + (is_object($filenames) && $filenames instanceof Iterator))) { + throw PHPUnit_Util_InvalidArgumentHelper::factory( + 1, 'array or iterator' + ); + } + + foreach ($filenames as $filename) { + $this->addTestFile((string)$filename, $syntaxCheck); + } + } + + /** + * Counts the number of test cases that will be run by this test. + * + * @return integer + */ + public function count() + { + if ($this->numTests > -1) { + return $this->numTests; + } + + $this->numTests = 0; + + foreach ($this->tests as $test) { + $this->numTests += count($test); + } + + return $this->numTests; + } + + /** + * @param ReflectionClass $theClass + * @param string $name + * @return PHPUnit_Framework_Test + * @throws RuntimeException + */ + public static function createTest(ReflectionClass $theClass, $name) + { + $className = $theClass->getName(); + + if (!$theClass->isInstantiable()) { + return self::warning( + sprintf('Cannot instantiate class "%s".', $className) + ); + } + + $backupSettings = PHPUnit_Util_Test::getBackupSettings( + $className, $name + ); + $preserveGlobalState = PHPUnit_Util_Test::getPreserveGlobalStateSettings( + $className, $name + ); + $runTestInSeparateProcess = PHPUnit_Util_Test::getProcessIsolationSettings( + $className, $name + ); + + $constructor = $theClass->getConstructor(); + + if ($constructor !== NULL) { + $parameters = $constructor->getParameters(); + + // TestCase() or TestCase($name) + if (count($parameters) < 2) { + $test = new $className; + } + + // TestCase($name, $data) + else { + try { + $data = PHPUnit_Util_Test::getProvidedData( + $className, $name + ); + } + + catch (Exception $e) { + $message = sprintf( + 'The data provider specified for %s::%s is invalid.', + $className, + $name + ); + + $_message = $e->getMessage(); + + if (!empty($_message)) { + $message .= "\n" . $_message; + } + + $data = self::warning($message); + } + + // Test method with @dataProvider. + if (isset($data)) { + $test = new PHPUnit_Framework_TestSuite_DataProvider( + $className . '::' . $name + ); + + if (empty($data)) { + $data = self::warning( + sprintf( + 'No tests found in suite "%s".', + $test->getName() + ) + ); + } + + if ($data instanceof PHPUnit_Framework_Warning) { + $test->addTest($data); + } + + else { + $groups = PHPUnit_Util_Test::getGroups($className, $name); + + foreach ($data as $_dataName => $_data) { + $_test = new $className($name, $_data, $_dataName); + + if ($runTestInSeparateProcess) { + $_test->setRunTestInSeparateProcess(TRUE); + + if ($preserveGlobalState !== NULL) { + $_test->setPreserveGlobalState($preserveGlobalState); + } + } + + if ($backupSettings['backupGlobals'] !== NULL) { + $_test->setBackupGlobals( + $backupSettings['backupGlobals'] + ); + } + + if ($backupSettings['backupStaticAttributes'] !== NULL) { + $_test->setBackupStaticAttributes( + $backupSettings['backupStaticAttributes'] + ); + } + + $test->addTest($_test, $groups); + } + } + } + + else { + $test = new $className; + } + } + } + + if (!isset($test)) { + throw new RuntimeException('No valid test provided.'); + } + + if ($test instanceof PHPUnit_Framework_TestCase) { + $test->setName($name); + + if ($runTestInSeparateProcess) { + $test->setRunTestInSeparateProcess(TRUE); + + if ($preserveGlobalState !== NULL) { + $test->setPreserveGlobalState($preserveGlobalState); + } + } + + if ($backupSettings['backupGlobals'] !== NULL) { + $test->setBackupGlobals($backupSettings['backupGlobals']); + } + + if ($backupSettings['backupStaticAttributes'] !== NULL) { + $test->setBackupStaticAttributes( + $backupSettings['backupStaticAttributes'] + ); + } + } + + return $test; + } + + /** + * Creates a default TestResult object. + * + * @return PHPUnit_Framework_TestResult + */ + protected function createResult() + { + return new PHPUnit_Framework_TestResult; + } + + /** + * Returns the name of the suite. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Returns the test groups of the suite. + * + * @return array + * @since Method available since Release 3.2.0 + */ + public function getGroups() + { + return array_keys($this->groups); + } + + /** + * Runs the tests and collects their result in a TestResult. + * + * @param PHPUnit_Framework_TestResult $result + * @param mixed $filter + * @param array $groups + * @param array $excludeGroups + * @param boolean $processIsolation + * @return PHPUnit_Framework_TestResult + * @throws InvalidArgumentException + */ + public function run(PHPUnit_Framework_TestResult $result = NULL, $filter = FALSE, array $groups = array(), array $excludeGroups = array(), $processIsolation = FALSE) + { + if ($result === NULL) { + $result = $this->createResult(); + } + + $result->startTestSuite($this); + + try { + $this->setUp(); + + if ($this->testCase && + method_exists($this->name, 'setUpBeforeClass')) { + call_user_func(array($this->name, 'setUpBeforeClass')); + } + } + + catch (PHPUnit_Framework_SkippedTestSuiteError $e) { + $numTests = count($this); + + for ($i = 0; $i < $numTests; $i++) { + $result->addFailure($this, $e, 0); + } + + return $result; + } + + if (empty($groups)) { + $tests = $this->tests; + } else { + $tests = new SplObjectStorage; + + foreach ($groups as $group) { + if (isset($this->groups[$group])) { + foreach ($this->groups[$group] as $test) { + $tests->attach($test); + } + } + } + } + + foreach ($tests as $test) { + if ($result->shouldStop()) { + break; + } + + if ($test instanceof PHPUnit_Framework_TestSuite) { + $test->setBackupGlobals($this->backupGlobals); + $test->setBackupStaticAttributes($this->backupStaticAttributes); + + $test->run( + $result, $filter, $groups, $excludeGroups, $processIsolation + ); + } else { + $runTest = TRUE; + + if ($filter !== FALSE ) { + $tmp = PHPUnit_Util_Test::describe($test, FALSE); + + if ($tmp[0] != '') { + $name = join('::', $tmp); + } else { + $name = $tmp[1]; + } + + if (preg_match($filter, $name) == 0) { + $runTest = FALSE; + } + } + + if ($runTest && !empty($excludeGroups)) { + foreach ($this->groups as $_group => $_tests) { + if (in_array($_group, $excludeGroups)) { + foreach ($_tests as $_test) { + if ($test === $_test) { + $runTest = FALSE; + break 2; + } + } + } + } + } + + if ($runTest) { + if ($test instanceof PHPUnit_Framework_TestCase) { + $test->setBackupGlobals($this->backupGlobals); + $test->setBackupStaticAttributes( + $this->backupStaticAttributes + ); + $test->setRunTestInSeparateProcess($processIsolation); + } + + $this->runTest($test, $result); + } + } + } + + if ($this->testCase && + method_exists($this->name, 'tearDownAfterClass')) { + call_user_func(array($this->name, 'tearDownAfterClass')); + } + + $this->tearDown(); + $result->endTestSuite($this); + + return $result; + } + + /** + * Runs a test. + * + * @param PHPUnit_Framework_Test $test + * @param PHPUnit_Framework_TestResult $testResult + */ + public function runTest(PHPUnit_Framework_Test $test, PHPUnit_Framework_TestResult $result) + { + $test->run($result); + } + + /** + * Sets the name of the suite. + * + * @param string + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * Returns the test at the given index. + * + * @param integer + * @return PHPUnit_Framework_Test + */ + public function testAt($index) + { + if (isset($this->tests[$index])) { + return $this->tests[$index]; + } else { + return FALSE; + } + } + + /** + * Returns the tests as an enumeration. + * + * @return array + */ + public function tests() + { + return $this->tests; + } + + /** + * Mark the test suite as skipped. + * + * @param string $message + * @throws PHPUnit_Framework_SkippedTestSuiteError + * @since Method available since Release 3.0.0 + */ + public function markTestSuiteSkipped($message = '') + { + throw new PHPUnit_Framework_SkippedTestSuiteError($message); + } + + /** + * @param ReflectionClass $class + * @param ReflectionMethod $method + */ + protected function addTestMethod(ReflectionClass $class, ReflectionMethod $method) + { + $name = $method->getName(); + + if ($this->isPublicTestMethod($method)) { + $test = self::createTest($class, $name); + + if ($test instanceof PHPUnit_Framework_TestCase || + $test instanceof PHPUnit_Framework_TestSuite_DataProvider) { + $test->setDependencies( + PHPUnit_Util_Test::getDependencies($class->getName(), $name) + ); + } + + $this->addTest($test, PHPUnit_Util_Test::getGroups( + $class->getName(), $name) + ); + } + + else if ($this->isTestMethod($method)) { + $this->addTest( + self::warning( + sprintf( + 'Test method "%s" in test class "%s" is not public.', + $name, + $class->getName() + ) + ) + ); + } + } + + /** + * @param ReflectionMethod $method + * @return boolean + */ + public static function isPublicTestMethod(ReflectionMethod $method) + { + return (self::isTestMethod($method) && $method->isPublic()); + } + + /** + * @param ReflectionMethod $method + * @return boolean + */ + public static function isTestMethod(ReflectionMethod $method) + { + if (strpos($method->name, 'test') === 0) { + return TRUE; + } + + // @scenario on TestCase::testMethod() + // @test on TestCase::testMethod() + return strpos($method->getDocComment(), '@test') !== FALSE || + strpos($method->getDocComment(), '@scenario') !== FALSE; + } + + /** + * @param string $message + * @return PHPUnit_Framework_Warning + */ + protected static function warning($message) + { + return new PHPUnit_Framework_Warning($message); + } + + /** + * @param boolean $backupGlobals + * @since Method available since Release 3.3.0 + */ + public function setBackupGlobals($backupGlobals) + { + if (is_null($this->backupGlobals) && is_bool($backupGlobals)) { + $this->backupGlobals = $backupGlobals; + } + } + + /** + * @param boolean $backupStaticAttributes + * @since Method available since Release 3.4.0 + */ + public function setBackupStaticAttributes($backupStaticAttributes) + { + if (is_null($this->backupStaticAttributes) && + is_bool($backupStaticAttributes)) { + $this->backupStaticAttributes = $backupStaticAttributes; + } + } + + /** + * Returns an iterator for this test suite. + * + * @return RecursiveIteratorIterator + * @since Method available since Release 3.1.0 + */ + public function getIterator() + { + return new RecursiveIteratorIterator( + new PHPUnit_Util_TestSuiteIterator($this) + ); + } + + /** + * Template Method that is called before the tests + * of this test suite are run. + * + * @since Method available since Release 3.1.0 + */ + protected function setUp() + { + } + + /** + * Template Method that is called after the tests + * of this test suite have finished running. + * + * @since Method available since Release 3.1.0 + */ + protected function tearDown() + { + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestSuite/DataProvider.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestSuite/DataProvider.php new file mode 100644 index 0000000..e2becf9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/TestSuite/DataProvider.php @@ -0,0 +1,71 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework_TestSuite + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.4.0 + */ + +/** + * + * + * @package PHPUnit + * @subpackage Framework_TestSuite + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.4.0 + */ +class PHPUnit_Framework_TestSuite_DataProvider extends PHPUnit_Framework_TestSuite +{ + /** + * Sets the dependencies of a TestCase. + * + * @param array $dependencies + */ + public function setDependencies(array $dependencies) + { + foreach ($this->tests as $test) { + $test->setDependencies($dependencies); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Warning.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Warning.php new file mode 100644 index 0000000..d201c6d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Framework/Warning.php @@ -0,0 +1,126 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * A warning. + * + * @package PHPUnit + * @subpackage Framework + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +class PHPUnit_Framework_Warning extends PHPUnit_Framework_TestCase +{ + /** + * @var string + */ + protected $message = ''; + + /** + * @var boolean + */ + protected $backupGlobals = FALSE; + + /** + * @var boolean + */ + protected $backupStaticAttributes = FALSE; + + /** + * @var boolean + */ + protected $runTestInSeparateProcess = FALSE; + + /** + * @var boolean + */ + protected $useErrorHandler = FALSE; + + /** + * @var boolean + */ + protected $useOutputBuffering = FALSE; + + /** + * @param string $message + */ + public function __construct($message = '') + { + $this->message = $message; + parent::__construct('Warning'); + } + + /** + * @throws RuntimeException + */ + protected function runTest() + { + $this->fail($this->message); + } + + /** + * @return string + * @since Method available since Release 3.0.0 + */ + public function getMessage() + { + return $this->message; + } + + /** + * Returns a string representation of the test case. + * + * @return string + * @since Method available since Release 3.4.0 + */ + public function toString() + { + return 'Warning'; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/BaseTestRunner.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/BaseTestRunner.php new file mode 100644 index 0000000..d4f99e3 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/BaseTestRunner.php @@ -0,0 +1,190 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Runner + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * Base class for all test runners. + * + * @package PHPUnit + * @subpackage Runner + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +abstract class PHPUnit_Runner_BaseTestRunner +{ + const STATUS_PASSED = 0; + const STATUS_SKIPPED = 1; + const STATUS_INCOMPLETE = 2; + const STATUS_FAILURE = 3; + const STATUS_ERROR = 4; + const SUITE_METHODNAME = 'suite'; + + /** + * Returns the loader to be used. + * + * @return PHPUnit_Runner_TestSuiteLoader + */ + public function getLoader() + { + return new PHPUnit_Runner_StandardTestSuiteLoader; + } + + /** + * Returns the Test corresponding to the given suite. + * This is a template method, subclasses override + * the runFailed() and clearStatus() methods. + * + * @param string $suiteClassName + * @param string $suiteClassFile + * @param boolean $syntaxCheck + * @return PHPUnit_Framework_Test + */ + public function getTest($suiteClassName, $suiteClassFile = '', $syntaxCheck = FALSE) + { + if (is_dir($suiteClassName) && + !is_file($suiteClassName . '.php') && empty($suiteClassFile)) { + $testCollector = new PHPUnit_Runner_IncludePathTestCollector( + array($suiteClassName) + ); + + $suite = new PHPUnit_Framework_TestSuite($suiteClassName); + $suite->addTestFiles($testCollector->collectTests(), $syntaxCheck); + + return $suite; + } + + try { + $testClass = $this->loadSuiteClass( + $suiteClassName, $suiteClassFile, $syntaxCheck + ); + } + + catch (Exception $e) { + $this->runFailed($e->getMessage()); + return NULL; + } + + try { + $suiteMethod = $testClass->getMethod(self::SUITE_METHODNAME); + + if (!$suiteMethod->isStatic()) { + $this->runFailed( + 'suite() method must be static.' + ); + + return NULL; + } + + try { + $test = $suiteMethod->invoke(NULL, $testClass->getName()); + } + + catch (ReflectionException $e) { + $this->runFailed( + sprintf( + "Failed to invoke suite() method.\n%s", + + $e->getMessage() + ) + ); + + return NULL; + } + } + + catch (ReflectionException $e) { + try { + $test = new PHPUnit_Framework_TestSuite($testClass); + } + + catch (InvalidArgumentException $e) { + $test = new PHPUnit_Framework_TestSuite; + $test->setName($suiteClassName); + } + } + + $this->clearStatus(); + + return $test; + } + + /** + * Returns the loaded ReflectionClass for a suite name. + * + * @param string $suiteClassName + * @param string $suiteClassFile + * @param boolean $syntaxCheck + * @return ReflectionClass + */ + protected function loadSuiteClass($suiteClassName, $suiteClassFile = '', $syntaxCheck = FALSE) + { + $loader = $this->getLoader(); + + if ($loader instanceof PHPUnit_Runner_StandardTestSuiteLoader) { + return $loader->load($suiteClassName, $suiteClassFile, $syntaxCheck); + } else { + return $loader->load($suiteClassName, $suiteClassFile); + } + } + + /** + * Clears the status message. + * + */ + protected function clearStatus() + { + } + + /** + * Override to define how to handle a failed loading of + * a test suite. + * + * @param string $message + */ + abstract protected function runFailed($message); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/IncludePathTestCollector.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/IncludePathTestCollector.php new file mode 100644 index 0000000..bf6f131 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/IncludePathTestCollector.php @@ -0,0 +1,144 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Runner + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.1.0 + */ + +require_once 'File/Iterator/Factory.php'; + +/** + * A test collector that collects tests from one or more directories + * recursively. If no directories are specified, the include_path is searched. + * + * + * $testCollector = new PHPUnit_Runner_IncludePathTestCollector( + * array('/path/to/*Test.php files') + * ); + * + * $suite = new PHPUnit_Framework_TestSuite('My Test Suite'); + * $suite->addTestFiles($testCollector->collectTests()); + * + * + * @package PHPUnit + * @subpackage Runner + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.1.0 + */ +class PHPUnit_Runner_IncludePathTestCollector implements PHPUnit_Runner_TestCollector +{ + /** + * @var string + */ + protected $filterIterator; + + /** + * @var array + */ + protected $paths; + + /** + * @var mixed + */ + protected $suffixes; + + /** + * @var mixed + */ + protected $prefixes; + + /** + * @param array $paths + * @param mixed $suffixes + * @param mixed $prefixes + */ + public function __construct(array $paths = array(), $suffixes = array('Test.php', '.phpt'), $prefixes = array()) + { + if (!empty($paths)) { + $this->paths = $paths; + } else { + $this->paths = explode(PATH_SEPARATOR, get_include_path()); + } + + $this->suffixes = $suffixes; + $this->prefixes = $prefixes; + } + + /** + * @return File_Iterator + */ + public function collectTests() + { + $iterator = File_Iterator_Factory::getFileIterator( + $this->paths, $this->suffixes, $this->prefixes + ); + + if ($this->filterIterator !== NULL) { + $class = new ReflectionClass($this->filterIterator); + $iterator = $class->newInstance($iterator); + } + + return $iterator; + } + + /** + * Adds a FilterIterator to filter the source files to be collected. + * + * @param string $filterIterator + * @throws InvalidArgumentException + */ + public function setFilterIterator($filterIterator) + { + if (is_string($filterIterator) && class_exists($filterIterator)) { + $class = new ReflectionClass($filterIterator); + + if ($class->isSubclassOf('FilterIterator')) { + $this->filterIterator = $filterIterator; + } + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'class name'); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/StandardTestSuiteLoader.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/StandardTestSuiteLoader.php new file mode 100644 index 0000000..3fd14c6 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/StandardTestSuiteLoader.php @@ -0,0 +1,153 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Runner + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * The standard test suite loader. + * + * @package PHPUnit + * @subpackage Runner + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +class PHPUnit_Runner_StandardTestSuiteLoader implements PHPUnit_Runner_TestSuiteLoader +{ + /** + * @param string $suiteClassName + * @param string $suiteClassFile + * @param boolean $syntaxCheck + * @return ReflectionClass + * @throws RuntimeException + */ + public function load($suiteClassName, $suiteClassFile = '', $syntaxCheck = FALSE) + { + $suiteClassName = str_replace('.php', '', $suiteClassName); + + if (empty($suiteClassFile)) { + $suiteClassFile = PHPUnit_Util_Filesystem::classNameToFilename( + $suiteClassName + ); + } + + if (!class_exists($suiteClassName, FALSE)) { + PHPUnit_Util_Class::collectStart(); + PHPUnit_Util_Fileloader::checkAndLoad($suiteClassFile, $syntaxCheck); + $loadedClasses = PHPUnit_Util_Class::collectEnd(); + } + + if (!class_exists($suiteClassName, FALSE) && !empty($loadedClasses)) { + $offset = 0 - strlen($suiteClassName); + + foreach ($loadedClasses as $loadedClass) { + if (substr($loadedClass, $offset) === $suiteClassName) { + $suiteClassName = $loadedClass; + break; + } + } + } + + if (!class_exists($suiteClassName, FALSE) && !empty($loadedClasses)) { + $testCaseClass = 'PHPUnit_Framework_TestCase'; + + foreach ($loadedClasses as $loadedClass) { + $class = new ReflectionClass($loadedClass); + $classFile = $class->getFileName(); + + if ($class->isSubclassOf($testCaseClass) && + !$class->isAbstract()) { + $suiteClassName = $loadedClass; + $testCaseClass = $loadedClass; + + if ($classFile == realpath($suiteClassFile)) { + break; + } + } + + if ($class->hasMethod('suite')) { + $method = $class->getMethod('suite'); + + if (!$method->isAbstract() && + $method->isPublic() && + $method->isStatic()) { + $suiteClassName = $loadedClass; + + if ($classFile == realpath($suiteClassFile)) { + break; + } + } + } + } + } + + if (class_exists($suiteClassName, FALSE)) { + $class = new ReflectionClass($suiteClassName); + + if ($class->getFileName() == realpath($suiteClassFile)) { + return $class; + } + } + + throw new PHPUnit_Framework_Exception( + sprintf( + 'Class %s could not be found in %s.', + + $suiteClassName, + $suiteClassFile + ) + ); + } + + /** + * @param ReflectionClass $aClass + * @return ReflectionClass + */ + public function reload(ReflectionClass $aClass) + { + return $aClass; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/TestCollector.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/TestCollector.php new file mode 100644 index 0000000..a9a99a5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/TestCollector.php @@ -0,0 +1,65 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Runner + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * Collects Test class names to be presented + * by the TestSelector. + * + * @package PHPUnit + * @subpackage Runner + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Interface available since Release 2.0.0 + */ +interface PHPUnit_Runner_TestCollector +{ + /** + * @return array + */ + public function collectTests(); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/TestSuiteLoader.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/TestSuiteLoader.php new file mode 100644 index 0000000..2129e1d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/TestSuiteLoader.php @@ -0,0 +1,72 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Runner + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * An interface to define how a test suite should be loaded. + * + * @package PHPUnit + * @subpackage Runner + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Interface available since Release 2.0.0 + */ +interface PHPUnit_Runner_TestSuiteLoader +{ + /** + * @param string $suiteClassName + * @param string $suiteClassFile + * @return ReflectionClass + */ + public function load($suiteClassName, $suiteClassFile = ''); + + /** + * @param ReflectionClass $aClass + * @return ReflectionClass + */ + public function reload(ReflectionClass $aClass); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/Version.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/Version.php new file mode 100644 index 0000000..849ddef --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Runner/Version.php @@ -0,0 +1,77 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Runner + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * This class defines the current version of PHPUnit. + * + * @package PHPUnit + * @subpackage Runner + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +class PHPUnit_Runner_Version +{ + /** + * Returns the current version of PHPUnit. + * + * @return string + */ + public static function id() + { + return '3.5.14'; + } + + /** + * @return string + */ + public static function getVersionString() + { + return 'PHPUnit 3.5.14 by Sebastian Bergmann.'; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/TextUI/Command.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/TextUI/Command.php new file mode 100644 index 0000000..36d75a2 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/TextUI/Command.php @@ -0,0 +1,886 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage TextUI + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * A TestRunner for the Command Line Interface (CLI) + * PHP SAPI Module. + * + * @package PHPUnit + * @subpackage TextUI + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_TextUI_Command +{ + /** + * @var array + */ + protected $arguments = array( + 'listGroups' => FALSE, + 'loader' => NULL, + 'syntaxCheck' => FALSE, + 'useDefaultConfiguration' => TRUE + ); + + /** + * @var array + */ + protected $options = array(); + + /** + * @var array + */ + protected $longOptions = array( + 'colors' => NULL, + 'bootstrap=' => NULL, + 'configuration=' => NULL, + 'coverage-html=' => NULL, + 'coverage-clover=' => NULL, + 'debug' => NULL, + 'exclude-group=' => NULL, + 'filter=' => NULL, + 'group=' => NULL, + 'help' => NULL, + 'include-path=' => NULL, + 'list-groups' => NULL, + 'loader=' => NULL, + 'log-dbus' => NULL, + 'log-json=' => NULL, + 'log-junit=' => NULL, + 'log-tap=' => NULL, + 'process-isolation' => NULL, + 'repeat=' => NULL, + 'skeleton-class' => NULL, + 'skeleton-test' => NULL, + 'stderr' => NULL, + 'stop-on-error' => NULL, + 'stop-on-failure' => NULL, + 'stop-on-incomplete' => NULL, + 'stop-on-skipped' => NULL, + 'story' => NULL, + 'story-html=' => NULL, + 'story-text=' => NULL, + 'strict' => NULL, + 'syntax-check' => NULL, + 'tap' => NULL, + 'testdox' => NULL, + 'testdox-html=' => NULL, + 'testdox-text=' => NULL, + 'no-configuration' => NULL, + 'no-globals-backup' => NULL, + 'static-backup' => NULL, + 'verbose' => NULL, + 'version' => NULL, + 'wait' => NULL + ); + + /** + * @param boolean $exit + */ + public static function main($exit = TRUE) + { + $command = new PHPUnit_TextUI_Command; + $command->run($_SERVER['argv'], $exit); + } + + /** + * @param array $argv + * @param boolean $exit + */ + public function run(array $argv, $exit = TRUE) + { + $this->handleArguments($argv); + + $runner = new PHPUnit_TextUI_TestRunner($this->arguments['loader']); + + if (is_object($this->arguments['test']) && + $this->arguments['test'] instanceof PHPUnit_Framework_Test) { + $suite = $this->arguments['test']; + } else { + $suite = $runner->getTest( + $this->arguments['test'], + $this->arguments['testFile'], + $this->arguments['syntaxCheck'] + ); + } + + if (count($suite) == 0) { + $skeleton = new PHPUnit_Util_Skeleton_Test( + $suite->getName(), + $this->arguments['testFile'] + ); + + $result = $skeleton->generate(TRUE); + + if (!$result['incomplete']) { + eval(str_replace(array(''), '', $result['code'])); + $suite = new PHPUnit_Framework_TestSuite( + $this->arguments['test'] . 'Test' + ); + } + } + + if ($this->arguments['listGroups']) { + PHPUnit_TextUI_TestRunner::printVersionString(); + + print "Available test group(s):\n"; + + $groups = $suite->getGroups(); + sort($groups); + + foreach ($groups as $group) { + print " - $group\n"; + } + + exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT); + } + + unset($this->arguments['test']); + unset($this->arguments['testFile']); + + try { + $result = $runner->doRun($suite, $this->arguments); + } + + catch (PHPUnit_Framework_Exception $e) { + print $e->getMessage() . "\n"; + } + + if ($exit) { + if (isset($result) && $result->wasSuccessful()) { + exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT); + } + + else if (!isset($result) || $result->errorCount() > 0) { + exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT); + } + + else { + exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT); + } + } + } + + /** + * Handles the command-line arguments. + * + * A child class of PHPUnit_TextUI_Command can hook into the argument + * parsing by adding the switch(es) to the $longOptions array and point to a + * callback method that handles the switch(es) in the child class like this + * + * + * longOptions['--my-switch'] = 'myHandler'; + * } + * + * // --my-switch foo -> myHandler('foo') + * protected function myHandler($value) + * { + * } + * } + * + * + * @param array $argv + */ + protected function handleArguments(array $argv) + { + try { + $this->options = PHPUnit_Util_Getopt::getopt( + $argv, + 'd:c:', + array_keys($this->longOptions) + ); + } + + catch (RuntimeException $e) { + PHPUnit_TextUI_TestRunner::showError($e->getMessage()); + } + + $skeletonClass = FALSE; + $skeletonTest = FALSE; + + foreach ($this->options[0] as $option) { + switch ($option[0]) { + case '--colors': { + $this->arguments['colors'] = TRUE; + } + break; + + case '--bootstrap': { + $this->arguments['bootstrap'] = $option[1]; + } + break; + + case 'c': + case '--configuration': { + $this->arguments['configuration'] = $option[1]; + } + break; + + case '--coverage-clover': { + if (extension_loaded('tokenizer') && + extension_loaded('xdebug')) { + $this->arguments['coverageClover'] = $option[1]; + } else { + if (!extension_loaded('tokenizer')) { + $this->showMessage( + 'The tokenizer extension is not loaded.' + ); + } else { + $this->showMessage( + 'The Xdebug extension is not loaded.' + ); + } + } + } + break; + + case '--coverage-html': { + if (extension_loaded('tokenizer') && + extension_loaded('xdebug')) { + $this->arguments['reportDirectory'] = $option[1]; + } else { + if (!extension_loaded('tokenizer')) { + $this->showMessage( + 'The tokenizer extension is not loaded.' + ); + } else { + $this->showMessage( + 'The Xdebug extension is not loaded.' + ); + } + } + } + break; + + case 'd': { + $ini = explode('=', $option[1]); + + if (isset($ini[0])) { + if (isset($ini[1])) { + ini_set($ini[0], $ini[1]); + } else { + ini_set($ini[0], TRUE); + } + } + } + break; + + case '--debug': { + $this->arguments['debug'] = TRUE; + } + break; + + case '--help': { + $this->showHelp(); + exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT); + } + break; + + case '--filter': { + $this->arguments['filter'] = $option[1]; + } + break; + + case '--group': { + $this->arguments['groups'] = explode(',', $option[1]); + } + break; + + case '--exclude-group': { + $this->arguments['excludeGroups'] = explode( + ',', $option[1] + ); + } + break; + + case '--include-path': { + $includePath = $option[1]; + } + break; + + case '--list-groups': { + $this->arguments['listGroups'] = TRUE; + } + break; + + case '--loader': { + $this->arguments['loader'] = $option[1]; + } + break; + + case '--log-dbus': { + $this->arguments['logDbus'] = TRUE; + } + break; + + case '--log-json': { + $this->arguments['jsonLogfile'] = $option[1]; + } + break; + + case '--log-junit': { + $this->arguments['junitLogfile'] = $option[1]; + } + break; + + case '--log-tap': { + $this->arguments['tapLogfile'] = $option[1]; + } + break; + + case '--process-isolation': { + $this->arguments['processIsolation'] = TRUE; + $this->arguments['syntaxCheck'] = FALSE; + } + break; + + case '--repeat': { + $this->arguments['repeat'] = (int)$option[1]; + } + break; + + case '--stderr': { + $this->arguments['printer'] = new PHPUnit_TextUI_ResultPrinter( + 'php://stderr', + isset($this->arguments['verbose']) ? $this->arguments['verbose'] : FALSE + ); + } + break; + + case '--stop-on-error': { + $this->arguments['stopOnError'] = TRUE; + } + break; + + case '--stop-on-failure': { + $this->arguments['stopOnFailure'] = TRUE; + } + break; + + case '--stop-on-incomplete': { + $this->arguments['stopOnIncomplete'] = TRUE; + } + break; + + case '--stop-on-skipped': { + $this->arguments['stopOnSkipped'] = TRUE; + } + break; + + case '--skeleton-test': { + $skeletonTest = TRUE; + $skeletonClass = FALSE; + } + break; + + case '--skeleton-class': { + $skeletonClass = TRUE; + $skeletonTest = FALSE; + } + break; + + case '--tap': { + $this->arguments['printer'] = new PHPUnit_Util_Log_TAP; + } + break; + + case '--story': { + $this->showMessage( + 'The --story functionality is deprecated and ' . + 'will be removed in the future.', + FALSE + ); + + $this->arguments['printer'] = new PHPUnit_Extensions_Story_ResultPrinter_Text; + } + break; + + case '--story-html': { + $this->showMessage( + 'The --story-html functionality is deprecated and ' . + 'will be removed in the future.', + FALSE + ); + + $this->arguments['storyHTMLFile'] = $option[1]; + } + break; + + case '--story-text': { + $this->showMessage( + 'The --story-text functionality is deprecated and ' . + 'will be removed in the future.', + FALSE + ); + + $this->arguments['storyTextFile'] = $option[1]; + } + break; + + case '--syntax-check': { + $this->arguments['syntaxCheck'] = TRUE; + } + break; + + case '--testdox': { + $this->arguments['printer'] = new PHPUnit_Util_TestDox_ResultPrinter_Text; + } + break; + + case '--testdox-html': { + $this->arguments['testdoxHTMLFile'] = $option[1]; + } + break; + + case '--testdox-text': { + $this->arguments['testdoxTextFile'] = $option[1]; + } + break; + + case '--no-configuration': { + $this->arguments['useDefaultConfiguration'] = FALSE; + } + break; + + case '--no-globals-backup': { + $this->arguments['backupGlobals'] = FALSE; + } + break; + + case '--static-backup': { + $this->arguments['backupStaticAttributes'] = TRUE; + } + break; + + case '--verbose': { + $this->arguments['verbose'] = TRUE; + } + break; + + case '--version': { + PHPUnit_TextUI_TestRunner::printVersionString(); + exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT); + } + break; + + case '--wait': { + $this->arguments['wait'] = TRUE; + } + break; + + case '--strict': { + $this->arguments['strict'] = TRUE; + } + break; + + default: { + $optionName = str_replace('--', '', $option[0]); + + if (isset($this->longOptions[$optionName])) { + $handler = $this->longOptions[$optionName]; + } + + else if (isset($this->longOptions[$optionName . '='])) { + $handler = $this->longOptions[$optionName . '=']; + } + + if (isset($handler) && is_callable(array($this, $handler))) { + $this->$handler($option[1]); + } + } + } + } + + if (isset($this->arguments['printer']) && + $this->arguments['printer'] instanceof PHPUnit_Extensions_Story_ResultPrinter_Text && + isset($this->arguments['processIsolation']) && + $this->arguments['processIsolation']) { + $this->showMessage( + 'The story result printer cannot be used in process isolation.' + ); + } + + $this->handleCustomTestSuite(); + + if (!isset($this->arguments['test'])) { + if (isset($this->options[1][0])) { + $this->arguments['test'] = $this->options[1][0]; + } + + if (isset($this->options[1][1])) { + $this->arguments['testFile'] = $this->options[1][1]; + } else { + $this->arguments['testFile'] = ''; + } + + if (isset($this->arguments['test']) && is_file($this->arguments['test'])) { + $this->arguments['testFile'] = realpath($this->arguments['test']); + $this->arguments['test'] = substr($this->arguments['test'], 0, strrpos($this->arguments['test'], '.')); + } + } + + if (isset($includePath)) { + ini_set( + 'include_path', + $includePath . PATH_SEPARATOR . ini_get('include_path') + ); + } + + if (isset($this->arguments['bootstrap'])) { + $this->handleBootstrap($this->arguments['bootstrap'], $this->arguments['syntaxCheck']); + } + + if ($this->arguments['loader'] !== NULL) { + $this->arguments['loader'] = $this->handleLoader($this->arguments['loader']); + } + + if (isset($this->arguments['configuration']) && + is_dir($this->arguments['configuration'])) { + $configurationFile = $this->arguments['configuration'] . + '/phpunit.xml'; + + if (file_exists($configurationFile)) { + $this->arguments['configuration'] = realpath( + $configurationFile + ); + } + + else if (file_exists($configurationFile . '.dist')) { + $this->arguments['configuration'] = realpath( + $configurationFile . '.dist' + ); + } + } + + else if (!isset($this->arguments['configuration']) && + $this->arguments['useDefaultConfiguration']) { + if (file_exists('phpunit.xml')) { + $this->arguments['configuration'] = realpath('phpunit.xml'); + } else if (file_exists('phpunit.xml.dist')) { + $this->arguments['configuration'] = realpath( + 'phpunit.xml.dist' + ); + } + } + + if (isset($this->arguments['configuration'])) { + try { + $configuration = PHPUnit_Util_Configuration::getInstance( + $this->arguments['configuration'] + ); + } + + catch (Exception $e) { + print $e->getMessage() . "\n"; + exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT); + } + + $phpunit = $configuration->getPHPUnitConfiguration(); + + if (isset($phpunit['syntaxCheck'])) { + $this->arguments['syntaxCheck'] = $phpunit['syntaxCheck']; + } + + if (isset($phpunit['testSuiteLoaderClass'])) { + if (isset($phpunit['testSuiteLoaderFile'])) { + $file = $phpunit['testSuiteLoaderFile']; + } else { + $file = ''; + } + + $this->arguments['loader'] = $this->handleLoader( + $phpunit['testSuiteLoaderClass'], $file + ); + } + + $configuration->handlePHPConfiguration(); + + if (!isset($this->arguments['bootstrap'])) { + $phpunitConfiguration = $configuration->getPHPUnitConfiguration(); + + if (isset($phpunitConfiguration['bootstrap'])) { + $this->handleBootstrap($phpunitConfiguration['bootstrap'], $this->arguments['syntaxCheck']); + } + } + + $browsers = $configuration->getSeleniumBrowserConfiguration(); + + if (!empty($browsers)) { + PHPUnit_Extensions_SeleniumTestCase::$browsers = $browsers; + } + + if (!isset($this->arguments['test'])) { + $testSuite = $configuration->getTestSuiteConfiguration( + $this->arguments['syntaxCheck'] + ); + + if ($testSuite !== NULL) { + $this->arguments['test'] = $testSuite; + } + } + } + + if (isset($this->arguments['test']) && is_string($this->arguments['test']) && substr($this->arguments['test'], -5, 5) == '.phpt') { + $test = new PHPUnit_Extensions_PhptTestCase($this->arguments['test']); + + $this->arguments['test'] = new PHPUnit_Framework_TestSuite; + $this->arguments['test']->addTest($test); + } + + if (!isset($this->arguments['test']) || + (isset($this->arguments['testDatabaseLogRevision']) && !isset($this->arguments['testDatabaseDSN']))) { + $this->showHelp(); + exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT); + } + + if (!isset($this->arguments['syntaxCheck'])) { + $this->arguments['syntaxCheck'] = FALSE; + } + + if ($skeletonClass || $skeletonTest) { + if (isset($this->arguments['test']) && $this->arguments['test'] !== FALSE) { + PHPUnit_TextUI_TestRunner::printVersionString(); + + if ($skeletonClass) { + $class = 'PHPUnit_Util_Skeleton_Class'; + } else { + $class = 'PHPUnit_Util_Skeleton_Test'; + } + + try { + $args = array(); + $reflector = new ReflectionClass($class); + + for ($i = 0; $i <= 3; $i++) { + if (isset($this->options[1][$i])) { + $args[] = $this->options[1][$i]; + } + } + + $skeleton = $reflector->newInstanceArgs($args); + $skeleton->write(); + } + + catch (Exception $e) { + print $e->getMessage() . "\n"; + exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT); + } + + printf( + 'Wrote skeleton for "%s" to "%s".' . "\n", + $skeleton->getOutClassName(), + $skeleton->getOutSourceFile() + ); + + exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT); + } else { + $this->showHelp(); + exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT); + } + } + } + + /** + * Handles the loading of the PHPUnit_Runner_TestSuiteLoader implementation. + * + * @param string $loaderClass + * @param string $loaderFile + */ + protected function handleLoader($loaderClass, $loaderFile = '') + { + if (!class_exists($loaderClass, FALSE)) { + if ($loaderFile == '') { + $loaderFile = PHPUnit_Util_Filesystem::classNameToFilename( + $loaderClass + ); + } + + $loaderFile = PHPUnit_Util_Filesystem::fileExistsInIncludePath( + $loaderFile + ); + + if ($loaderFile !== FALSE) { + require $loaderFile; + } + } + + if (class_exists($loaderClass, FALSE)) { + $class = new ReflectionClass($loaderClass); + + if ($class->implementsInterface('PHPUnit_Runner_TestSuiteLoader') && + $class->isInstantiable()) { + $loader = $class->newInstance(); + } + } + + if (!isset($loader)) { + PHPUnit_TextUI_TestRunner::showError( + sprintf( + 'Could not use "%s" as loader.', + + $loaderClass + ) + ); + } + + return $loader; + } + + /** + * Loads a bootstrap file. + * + * @param string $filename + * @param boolean $syntaxCheck + */ + protected function handleBootstrap($filename, $syntaxCheck = FALSE) + { + try { + PHPUnit_Util_Fileloader::checkAndLoad($filename, $syntaxCheck); + } + + catch (RuntimeException $e) { + PHPUnit_TextUI_TestRunner::showError($e->getMessage()); + } + } + + /** + * Shows a message. + * + * @param string $message + * @param boolean $exit + */ + protected function showMessage($message, $exit = TRUE) + { + PHPUnit_TextUI_TestRunner::printVersionString(); + print $message . "\n"; + + if ($exit) { + exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT); + } else { + print "\n"; + } + } + + /** + * Show the help message. + */ + protected function showHelp() + { + PHPUnit_TextUI_TestRunner::printVersionString(); + + print << + + --log-junit Log test execution in JUnit XML format to file. + --log-tap Log test execution in TAP format to file. + --log-dbus Log test execution to DBUS. + --log-json Log test execution in JSON format. + + --coverage-html Generate code coverage report in HTML format. + --coverage-clover Write code coverage data in Clover XML format. + + --testdox-html Write agile documentation in HTML format to file. + --testdox-text Write agile documentation in Text format to file. + + --filter Filter which tests to run. + --group ... Only runs tests from the specified group(s). + --exclude-group ... Exclude tests from the specified group(s). + --list-groups List available test groups. + + --loader TestSuiteLoader implementation to use. + --repeat Runs the test(s) repeatedly. + + --tap Report test execution progress in TAP format. + --testdox Report test execution progress in TestDox format. + + --colors Use colors in output. + --stderr Write to STDERR instead of STDOUT. + --stop-on-error Stop execution upon first error. + --stop-on-failure Stop execution upon first error or failure. + --stop-on-skipped Stop execution upon first skipped test. + --stop-on-incomplete Stop execution upon first incomplete test. + --strict Mark a test as incomplete if no assertions are made. + --verbose Output more verbose information. + --wait Waits for a keystroke after each test. + + --skeleton-class Generate Unit class for UnitTest in UnitTest.php. + --skeleton-test Generate UnitTest class for Unit in Unit.php. + + --process-isolation Run each test in a separate PHP process. + --no-globals-backup Do not backup and restore \$GLOBALS for each test. + --static-backup Backup and restore static attributes for each test. + --syntax-check Try to check source files for syntax errors. + + --bootstrap A "bootstrap" PHP file that is run before the tests. + -c|--configuration Read configuration from XML file. + --no-configuration Ignore default configuration file (phpunit.xml). + --include-path Prepend PHP's include_path with given path(s). + -d key[=value] Sets a php.ini value. + + --help Prints this usage information. + --version Prints the version and exits. + + --debug Output debugging information. + +EOT; + } + + /** + * Custom callback for test suite discovery. + */ + protected function handleCustomTestSuite() + { + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/TextUI/ResultPrinter.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/TextUI/ResultPrinter.php new file mode 100644 index 0000000..421a138 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/TextUI/ResultPrinter.php @@ -0,0 +1,612 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage TextUI + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +require_once 'PHP/Timer.php'; + +/** + * Prints the result of a TextUI TestRunner run. + * + * @package PHPUnit + * @subpackage TextUI + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +class PHPUnit_TextUI_ResultPrinter extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener +{ + const EVENT_TEST_START = 0; + const EVENT_TEST_END = 1; + const EVENT_TESTSUITE_START = 2; + const EVENT_TESTSUITE_END = 3; + + /** + * @var integer + */ + protected $column = 0; + + /** + * @var integer + */ + protected $maxColumn; + + /** + * @var boolean + */ + protected $lastTestFailed = FALSE; + + /** + * @var integer + */ + protected $numAssertions = 0; + + /** + * @var integer + */ + protected $numTests = -1; + + /** + * @var integer + */ + protected $numTestsRun = 0; + + /** + * @var integer + */ + protected $numTestsWidth; + + /** + * @var boolean + */ + protected $colors = FALSE; + + /** + * @var boolean + */ + protected $debug = FALSE; + + /** + * @var boolean + */ + protected $verbose = FALSE; + + /** + * Constructor. + * + * @param mixed $out + * @param boolean $verbose + * @param boolean $colors + * @param boolean $debug + * @throws InvalidArgumentException + * @since Method available since Release 3.0.0 + */ + public function __construct($out = NULL, $verbose = FALSE, $colors = FALSE, $debug = FALSE) + { + parent::__construct($out); + + if (is_bool($verbose)) { + $this->verbose = $verbose; + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'boolean'); + } + + if (is_bool($colors)) { + $this->colors = $colors; + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'boolean'); + } + + if (is_bool($debug)) { + $this->debug = $debug; + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(4, 'boolean'); + } + } + + /** + * @param PHPUnit_Framework_TestResult $result + */ + public function printResult(PHPUnit_Framework_TestResult $result) + { + $this->printHeader(); + + if ($result->errorCount() > 0) { + $this->printErrors($result); + } + + if ($result->failureCount() > 0) { + if ($result->errorCount() > 0) { + print "\n--\n\n"; + } + + $this->printFailures($result); + } + + if ($this->verbose) { + if ($result->deprecatedFeaturesCount() > 0) { + if ($result->failureCount() > 0) { + print "\n--\n\nDeprecated PHPUnit features are being used"; + } + + foreach ($result->deprecatedFeatures() as $deprecatedFeature) { + $this->write($deprecatedFeature . "\n\n"); + } + } + + if ($result->notImplementedCount() > 0) { + if ($result->failureCount() > 0) { + print "\n--\n\n"; + } + + $this->printIncompletes($result); + } + + if ($result->skippedCount() > 0) { + if ($result->notImplementedCount() > 0) { + print "\n--\n\n"; + } + + $this->printSkipped($result); + } + } + + $this->printFooter($result); + } + + /** + * @param array $defects + * @param integer $count + * @param string $type + */ + protected function printDefects(array $defects, $count, $type) + { + static $called = FALSE; + + if ($count == 0) { + return; + } + + $this->write( + sprintf( + "%sThere %s %d %s%s:\n", + + $called ? "\n" : '', + ($count == 1) ? 'was' : 'were', + $count, + $type, + ($count == 1) ? '' : 's' + ) + ); + + $i = 1; + + foreach ($defects as $defect) { + $this->printDefect($defect, $i++); + } + + $called = TRUE; + } + + /** + * @param PHPUnit_Framework_TestFailure $defect + * @param integer $count + */ + protected function printDefect(PHPUnit_Framework_TestFailure $defect, $count) + { + $this->printDefectHeader($defect, $count); + $this->printDefectTrace($defect); + } + + /** + * @param PHPUnit_Framework_TestFailure $defect + * @param integer $count + */ + protected function printDefectHeader(PHPUnit_Framework_TestFailure $defect, $count) + { + $failedTest = $defect->failedTest(); + + if ($failedTest instanceof PHPUnit_Framework_SelfDescribing) { + $testName = $failedTest->toString(); + } else { + $testName = get_class($failedTest); + } + + $this->write( + sprintf( + "\n%d) %s\n", + + $count, + $testName + ) + ); + } + + /** + * @param PHPUnit_Framework_TestFailure $defect + */ + protected function printDefectTrace(PHPUnit_Framework_TestFailure $defect) + { + $this->write( + $defect->getExceptionAsString() . "\n" . + PHPUnit_Util_Filter::getFilteredStacktrace( + $defect->thrownException(), + FALSE + ) + ); + } + + /** + * @param PHPUnit_Framework_TestResult $result + */ + protected function printErrors(PHPUnit_Framework_TestResult $result) + { + $this->printDefects($result->errors(), $result->errorCount(), 'error'); + } + + /** + * @param PHPUnit_Framework_TestResult $result + */ + protected function printFailures(PHPUnit_Framework_TestResult $result) + { + $this->printDefects( + $result->failures(), + $result->failureCount(), + 'failure' + ); + } + + /** + * @param PHPUnit_Framework_TestResult $result + */ + protected function printIncompletes(PHPUnit_Framework_TestResult $result) + { + $this->printDefects( + $result->notImplemented(), + $result->notImplementedCount(), + 'incomplete test' + ); + } + + /** + * @param PHPUnit_Framework_TestResult $result + * @since Method available since Release 3.0.0 + */ + protected function printSkipped(PHPUnit_Framework_TestResult $result) + { + $this->printDefects( + $result->skipped(), + $result->skippedCount(), + 'skipped test' + ); + } + + protected function printHeader() + { + $this->write("\n\n" . PHP_Timer::resourceUsage() . "\n\n"); + } + + /** + * @param PHPUnit_Framework_TestResult $result + */ + protected function printFooter(PHPUnit_Framework_TestResult $result) + { + if ($result->wasSuccessful() && + $result->allCompletlyImplemented() && + $result->noneSkipped()) { + if ($this->colors) { + $this->write("\x1b[30;42m\x1b[2K"); + } + + $this->write( + sprintf( + "OK (%d test%s, %d assertion%s)\n", + + count($result), + (count($result) == 1) ? '' : 's', + $this->numAssertions, + ($this->numAssertions == 1) ? '' : 's' + ) + ); + + if ($this->colors) { + $this->write("\x1b[0m\x1b[2K"); + } + } + + else if ((!$result->allCompletlyImplemented() || + !$result->noneSkipped()) && + $result->wasSuccessful()) { + if ($this->colors) { + $this->write( + "\x1b[30;43m\x1b[2KOK, but incomplete or skipped tests!\n" . + "\x1b[0m\x1b[30;43m\x1b[2K" + ); + } else { + $this->write("OK, but incomplete or skipped tests!\n"); + } + + $this->write( + sprintf( + "Tests: %d, Assertions: %d%s%s.\n", + + count($result), + $this->numAssertions, + $this->getCountString( + $result->notImplementedCount(), 'Incomplete' + ), + $this->getCountString( + $result->skippedCount(), 'Skipped' + ) + ) + ); + + if ($this->colors) { + $this->write("\x1b[0m\x1b[2K"); + } + } + + else { + $this->write("\n"); + + if ($this->colors) { + $this->write( + "\x1b[37;41m\x1b[2KFAILURES!\n\x1b[0m\x1b[37;41m\x1b[2K" + ); + } else { + $this->write("FAILURES!\n"); + } + + $this->write( + sprintf( + "Tests: %d, Assertions: %s%s%s%s%s.\n", + + count($result), + $this->numAssertions, + $this->getCountString($result->failureCount(), 'Failures'), + $this->getCountString($result->errorCount(), 'Errors'), + $this->getCountString( + $result->notImplementedCount(), 'Incomplete' + ), + $this->getCountString($result->skippedCount(), 'Skipped') + ) + ); + + if ($this->colors) { + $this->write("\x1b[0m\x1b[2K"); + } + } + + if (!$this->verbose && + $result->deprecatedFeaturesCount() > 0) { + $message = sprintf( + "Warning: Deprecated PHPUnit features are being used %s times!\n". + "Use --verbose for more information.\n", + $result->deprecatedFeaturesCount() + ); + + if ($this->colors) { + $message = "\x1b[37;41m\x1b[2K" . $message . + "\x1b[0m"; + } + + $this->write("\n" . $message); + } + } + + /** + * @param integer $count + * @param string $name + * @return string + * @since Method available since Release 3.0.0 + */ + protected function getCountString($count, $name) + { + $string = ''; + + if ($count > 0) { + $string = sprintf( + ', %s: %d', + + $name, + $count + ); + } + + return $string; + } + + /** + */ + public function printWaitPrompt() + { + $this->write("\n to continue\n"); + } + + /** + * An error occurred. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) + { + $this->writeProgress('E'); + $this->lastTestFailed = TRUE; + } + + /** + * A failure occurred. + * + * @param PHPUnit_Framework_Test $test + * @param PHPUnit_Framework_AssertionFailedError $e + * @param float $time + */ + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) + { + $this->writeProgress('F'); + $this->lastTestFailed = TRUE; + } + + /** + * Incomplete test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + $this->writeProgress('I'); + $this->lastTestFailed = TRUE; + } + + /** + * Skipped test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + * @since Method available since Release 3.0.0 + */ + public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + $this->writeProgress('S'); + $this->lastTestFailed = TRUE; + } + + /** + * A testsuite started. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit_Framework_TestSuite $suite) + { + if ($this->numTests == -1) { + $this->numTests = count($suite); + $this->numTestsWidth = strlen((string)$this->numTests); + $this->maxColumn = 69 - (2 * $this->numTestsWidth); + } + } + + /** + * A testsuite ended. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit_Framework_TestSuite $suite) + { + } + + /** + * A test started. + * + * @param PHPUnit_Framework_Test $test + */ + public function startTest(PHPUnit_Framework_Test $test) + { + if ($this->debug) { + $this->write( + sprintf( + "\nStarting test '%s'.\n", PHPUnit_Util_Test::describe($test) + ) + ); + } + } + + /** + * A test ended. + * + * @param PHPUnit_Framework_Test $test + * @param float $time + */ + public function endTest(PHPUnit_Framework_Test $test, $time) + { + if (!$this->lastTestFailed) { + $this->writeProgress('.'); + } + + if ($test instanceof PHPUnit_Framework_TestCase) { + $this->numAssertions += $test->getNumAssertions(); + } + + $this->lastTestFailed = FALSE; + } + + /** + * @param string $progress + */ + protected function writeProgress($progress) + { + $this->write($progress); + $this->column++; + $this->numTestsRun++; + + if ($this->column == $this->maxColumn) { + $this->write( + sprintf( + ' %' . $this->numTestsWidth . 'd / %' . + $this->numTestsWidth . 'd (%3s%%)', + + $this->numTestsRun, + $this->numTests, + floor(($this->numTestsRun / $this->numTests) * 100) + ) + ); + + $this->writeNewLine(); + } + } + + protected function writeNewLine() + { + $this->column = 0; + $this->write("\n"); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/TextUI/TestRunner.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/TextUI/TestRunner.php new file mode 100644 index 0000000..a5572d2 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/TextUI/TestRunner.php @@ -0,0 +1,774 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage TextUI + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * A TestRunner for the Command Line Interface (CLI) + * PHP SAPI Module. + * + * @package PHPUnit + * @subpackage TextUI + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +class PHPUnit_TextUI_TestRunner extends PHPUnit_Runner_BaseTestRunner +{ + const SUCCESS_EXIT = 0; + const FAILURE_EXIT = 1; + const EXCEPTION_EXIT = 2; + + /** + * @var PHPUnit_Runner_TestSuiteLoader + */ + protected $loader = NULL; + + /** + * @var PHPUnit_TextUI_ResultPrinter + */ + protected $printer = NULL; + + /** + * @var boolean + */ + protected static $versionStringPrinted = FALSE; + + /** + * @param PHPUnit_Runner_TestSuiteLoader $loader + * @since Method available since Release 3.4.0 + */ + public function __construct(PHPUnit_Runner_TestSuiteLoader $loader = NULL) + { + $this->loader = $loader; + } + + /** + * @param mixed $test + * @param array $arguments + * @throws InvalidArgumentException + */ + public static function run($test, array $arguments = array()) + { + if ($test instanceof ReflectionClass) { + $test = new PHPUnit_Framework_TestSuite($test); + } + + if ($test instanceof PHPUnit_Framework_Test) { + $aTestRunner = new PHPUnit_TextUI_TestRunner; + + return $aTestRunner->doRun( + $test, + $arguments + ); + } else { + throw new InvalidArgumentException( + 'No test case or test suite found.' + ); + } + } + + /** + * Runs a single test and waits until the user types RETURN. + * + * @param PHPUnit_Framework_Test $suite + */ + public static function runAndWait(PHPUnit_Framework_Test $suite) + { + $aTestRunner = new PHPUnit_TextUI_TestRunner; + + $aTestRunner->doRun( + $suite, + array( + 'wait' => TRUE + ) + ); + + } + + /** + * @return PHPUnit_Framework_TestResult + */ + protected function createTestResult() + { + return new PHPUnit_Framework_TestResult; + } + + /** + * @param PHPUnit_Framework_Test $suite + * @param array $arguments + * @return PHPUnit_Framework_TestResult + */ + public function doRun(PHPUnit_Framework_Test $suite, array $arguments = array()) + { + $this->handleConfiguration($arguments); + + if (isset($arguments['bootstrap'])) { + $GLOBALS['__PHPUNIT_BOOTSTRAP'] = $arguments['bootstrap']; + } + + if ($arguments['backupGlobals'] === FALSE) { + $suite->setBackupGlobals(FALSE); + } + + if ($arguments['backupStaticAttributes'] === TRUE) { + $suite->setBackupStaticAttributes(TRUE); + } + + if (is_integer($arguments['repeat'])) { + $suite = new PHPUnit_Extensions_RepeatedTest( + $suite, + $arguments['repeat'], + $arguments['filter'], + $arguments['groups'], + $arguments['excludeGroups'], + $arguments['processIsolation'] + ); + } + + $result = $this->createTestResult(); + + if (!$arguments['convertErrorsToExceptions']) { + $result->convertErrorsToExceptions(FALSE); + } + + if (!$arguments['convertNoticesToExceptions']) { + PHPUnit_Framework_Error_Notice::$enabled = FALSE; + } + + if (!$arguments['convertWarningsToExceptions']) { + PHPUnit_Framework_Error_Warning::$enabled = FALSE; + } + + if ($arguments['stopOnError']) { + $result->stopOnError(TRUE); + } + + if ($arguments['stopOnFailure']) { + $result->stopOnFailure(TRUE); + } + + if ($arguments['stopOnIncomplete']) { + $result->stopOnIncomplete(TRUE); + } + + if ($arguments['stopOnSkipped']) { + $result->stopOnSkipped(TRUE); + } + + if ($this->printer === NULL) { + if (isset($arguments['printer']) && + $arguments['printer'] instanceof PHPUnit_Util_Printer) { + $this->printer = $arguments['printer']; + } else { + $this->printer = new PHPUnit_TextUI_ResultPrinter( + NULL, + $arguments['verbose'], + $arguments['colors'], + $arguments['debug'] + ); + } + } + + if (!$this->printer instanceof PHPUnit_Util_Log_TAP && + !self::$versionStringPrinted) { + $this->printer->write( + PHPUnit_Runner_Version::getVersionString() . "\n\n" + ); + } + + foreach ($arguments['listeners'] as $listener) { + $result->addListener($listener); + } + + $result->addListener($this->printer); + + if ($this->printer instanceof PHPUnit_TextUI_ResultPrinter) { + $result->addListener(new PHPUnit_Util_DeprecatedFeature_Logger); + } + + if (isset($arguments['storyHTMLFile'])) { + $result->addListener( + new PHPUnit_Extensions_Story_ResultPrinter_HTML( + $arguments['storyHTMLFile'] + ) + ); + } + + if (isset($arguments['storyTextFile'])) { + $result->addListener( + new PHPUnit_Extensions_Story_ResultPrinter_Text( + $arguments['storyTextFile'] + ) + ); + } + + if (isset($arguments['testdoxHTMLFile'])) { + $result->addListener( + new PHPUnit_Util_TestDox_ResultPrinter_HTML( + $arguments['testdoxHTMLFile'] + ) + ); + } + + if (isset($arguments['testdoxTextFile'])) { + $result->addListener( + new PHPUnit_Util_TestDox_ResultPrinter_Text( + $arguments['testdoxTextFile'] + ) + ); + } + + if ((isset($arguments['coverageClover']) || + isset($arguments['reportDirectory'])) && + extension_loaded('xdebug')) { + $result->collectCodeCoverageInformation(TRUE); + } + + if (isset($arguments['logDbus'])) { + $result->addListener(new PHPUnit_Util_Log_DBUS); + } + + if (isset($arguments['jsonLogfile'])) { + $result->addListener( + new PHPUnit_Util_Log_JSON($arguments['jsonLogfile']) + ); + } + + if (isset($arguments['tapLogfile'])) { + $result->addListener( + new PHPUnit_Util_Log_TAP($arguments['tapLogfile']) + ); + } + + if (isset($arguments['junitLogfile'])) { + $result->addListener( + new PHPUnit_Util_Log_JUnit( + $arguments['junitLogfile'], $arguments['logIncompleteSkipped'] + ) + ); + } + + if ($arguments['strict']) { + $result->strictMode(TRUE); + } + + $suite->run( + $result, + $arguments['filter'], + $arguments['groups'], + $arguments['excludeGroups'], + $arguments['processIsolation'] + ); + + unset($suite); + $result->flushListeners(); + + if ($this->printer instanceof PHPUnit_TextUI_ResultPrinter) { + $this->printer->printResult($result); + } + + if (extension_loaded('tokenizer') && extension_loaded('xdebug')) { + if (isset($arguments['coverageClover'])) { + $this->printer->write( + "\nWriting code coverage data to XML file, this may take " . + 'a moment.' + ); + + require_once 'PHP/CodeCoverage/Report/Clover.php'; + + $writer = new PHP_CodeCoverage_Report_Clover; + $writer->process( + $result->getCodeCoverage(), $arguments['coverageClover'] + ); + + $this->printer->write("\n"); + unset($writer); + } + + if (isset($arguments['reportDirectory'])) { + $this->printer->write( + "\nGenerating code coverage report, this may take a moment." + ); + + $title = ''; + + if (isset($arguments['configuration'])) { + $loggingConfiguration = $arguments['configuration']->getLoggingConfiguration(); + + if (isset($loggingConfiguration['title'])) { + $title = $loggingConfiguration['title']; + } + } + + require_once 'PHP/CodeCoverage/Report/HTML.php'; + + $writer = new PHP_CodeCoverage_Report_HTML( + array( + 'title' => $title, + 'charset' => $arguments['reportCharset'], + 'yui' => $arguments['reportYUI'], + 'highlight' => $arguments['reportHighlight'], + 'lowUpperBound' => $arguments['reportLowUpperBound'], + 'highLowerBound' => $arguments['reportHighLowerBound'], + 'generator' => ' and PHPUnit ' . PHPUnit_Runner_Version::id() + ) + ); + + $writer->process( + $result->getCodeCoverage(), $arguments['reportDirectory'] + ); + + $this->printer->write("\n"); + unset($writer); + } + } + + $this->pause($arguments['wait']); + + return $result; + } + + /** + * @param boolean $wait + */ + protected function pause($wait) + { + if (!$wait) { + return; + } + + if ($this->printer instanceof PHPUnit_TextUI_ResultPrinter) { + $this->printer->printWaitPrompt(); + } + + fgets(STDIN); + } + + /** + * @param PHPUnit_TextUI_ResultPrinter $resultPrinter + */ + public function setPrinter(PHPUnit_TextUI_ResultPrinter $resultPrinter) + { + $this->printer = $resultPrinter; + } + + /** + * Override to define how to handle a failed loading of + * a test suite. + * + * @param string $message + */ + protected function runFailed($message) + { + self::printVersionString(); + self::write($message); + exit(self::FAILURE_EXIT); + } + + /** + * @param string $buffer + * @since Method available since Release 3.1.0 + */ + protected static function write($buffer) + { + if (PHP_SAPI != 'cli') { + $buffer = htmlspecialchars($buffer); + } + + print $buffer; + } + + /** + * Returns the loader to be used. + * + * @return PHPUnit_Runner_TestSuiteLoader + * @since Method available since Release 2.2.0 + */ + public function getLoader() + { + if ($this->loader === NULL) { + $this->loader = new PHPUnit_Runner_StandardTestSuiteLoader; + } + + return $this->loader; + } + + /** + */ + public static function showError($message) + { + self::printVersionString(); + self::write($message . "\n"); + + exit(self::FAILURE_EXIT); + } + + /** + */ + public static function printVersionString() + { + if (!self::$versionStringPrinted) { + self::write(PHPUnit_Runner_Version::getVersionString() . "\n\n"); + self::$versionStringPrinted = TRUE; + } + } + + /** + * @param array $arguments + * @since Method available since Release 3.2.1 + */ + protected function handleConfiguration(array &$arguments) + { + if (isset($arguments['configuration']) && + !$arguments['configuration'] instanceof PHPUnit_Util_Configuration) { + $arguments['configuration'] = PHPUnit_Util_Configuration::getInstance( + $arguments['configuration'] + ); + } + + $arguments['debug'] = isset($arguments['debug']) ? $arguments['debug'] : FALSE; + $arguments['filter'] = isset($arguments['filter']) ? $arguments['filter'] : FALSE; + $arguments['listeners'] = isset($arguments['listeners']) ? $arguments['listeners'] : array(); + $arguments['wait'] = isset($arguments['wait']) ? $arguments['wait'] : FALSE; + + if (isset($arguments['configuration'])) { + $arguments['configuration']->handlePHPConfiguration(); + + $phpunitConfiguration = $arguments['configuration']->getPHPUnitConfiguration(); + + if (isset($phpunitConfiguration['backupGlobals']) && + !isset($arguments['backupGlobals'])) { + $arguments['backupGlobals'] = $phpunitConfiguration['backupGlobals']; + } + + if (isset($phpunitConfiguration['backupStaticAttributes']) && + !isset($arguments['backupStaticAttributes'])) { + $arguments['backupStaticAttributes'] = $phpunitConfiguration['backupStaticAttributes']; + } + + if (isset($phpunitConfiguration['bootstrap']) && + !isset($arguments['bootstrap'])) { + $arguments['bootstrap'] = $phpunitConfiguration['bootstrap']; + } + + if (isset($phpunitConfiguration['colors']) && + !isset($arguments['colors'])) { + $arguments['colors'] = $phpunitConfiguration['colors']; + } + + if (isset($phpunitConfiguration['convertErrorsToExceptions']) && + !isset($arguments['convertErrorsToExceptions'])) { + $arguments['convertErrorsToExceptions'] = $phpunitConfiguration['convertErrorsToExceptions']; + } + + if (isset($phpunitConfiguration['convertNoticesToExceptions']) && + !isset($arguments['convertNoticesToExceptions'])) { + $arguments['convertNoticesToExceptions'] = $phpunitConfiguration['convertNoticesToExceptions']; + } + + if (isset($phpunitConfiguration['convertWarningsToExceptions']) && + !isset($arguments['convertWarningsToExceptions'])) { + $arguments['convertWarningsToExceptions'] = $phpunitConfiguration['convertWarningsToExceptions']; + } + + if (isset($phpunitConfiguration['processIsolation']) && + !isset($arguments['processIsolation'])) { + $arguments['processIsolation'] = $phpunitConfiguration['processIsolation']; + } + + if (isset($phpunitConfiguration['stopOnFailure']) && + !isset($arguments['stopOnFailure'])) { + $arguments['stopOnFailure'] = $phpunitConfiguration['stopOnFailure']; + } + + if (isset($phpunitConfiguration['strict']) && + !isset($arguments['strict'])) { + $arguments['strict'] = $phpunitConfiguration['strict']; + } + + if (isset($phpunitConfiguration['verbose']) && + !isset($arguments['verbose'])) { + $arguments['verbose'] = $phpunitConfiguration['verbose']; + } + + if (isset($phpunitConfiguration['forceCoversAnnotation']) && + !isset($arguments['forceCoversAnnotation'])) { + $arguments['forceCoversAnnotation'] = $phpunitConfiguration['forceCoversAnnotation']; + } + + if (isset($phpunitConfiguration['mapTestClassNameToCoveredClassName']) && + !isset($arguments['mapTestClassNameToCoveredClassName'])) { + $arguments['mapTestClassNameToCoveredClassName'] = $phpunitConfiguration['mapTestClassNameToCoveredClassName']; + } + + $groupConfiguration = $arguments['configuration']->getGroupConfiguration(); + + if (!empty($groupConfiguration['include']) && + !isset($arguments['groups'])) { + $arguments['groups'] = $groupConfiguration['include']; + } + + if (!empty($groupConfiguration['exclude']) && + !isset($arguments['excludeGroups'])) { + $arguments['excludeGroups'] = $groupConfiguration['exclude']; + } + + foreach ($arguments['configuration']->getListenerConfiguration() as $listener) { + if (!class_exists($listener['class'], FALSE) && + $listener['file'] !== '') { + $file = PHPUnit_Util_Filesystem::fileExistsInIncludePath( + $listener['file'] + ); + + if ($file !== FALSE) { + require $file; + } + } + + if (class_exists($listener['class'], FALSE)) { + if (count($listener['arguments']) == 0) { + $listener = new $listener['class']; + } else { + $listenerClass = new ReflectionClass( + $listener['class'] + ); + $listener = $listenerClass->newInstanceArgs( + $listener['arguments'] + ); + } + + if ($listener instanceof PHPUnit_Framework_TestListener) { + $arguments['listeners'][] = $listener; + } + } + } + + $loggingConfiguration = $arguments['configuration']->getLoggingConfiguration(); + + if (isset($loggingConfiguration['coverage-html']) && + !isset($arguments['reportDirectory'])) { + if (isset($loggingConfiguration['charset']) && + !isset($arguments['reportCharset'])) { + $arguments['reportCharset'] = $loggingConfiguration['charset']; + } + + if (isset($loggingConfiguration['yui']) && + !isset($arguments['reportYUI'])) { + $arguments['reportYUI'] = $loggingConfiguration['yui']; + } + + if (isset($loggingConfiguration['highlight']) && + !isset($arguments['reportHighlight'])) { + $arguments['reportHighlight'] = $loggingConfiguration['highlight']; + } + + if (isset($loggingConfiguration['lowUpperBound']) && + !isset($arguments['reportLowUpperBound'])) { + $arguments['reportLowUpperBound'] = $loggingConfiguration['lowUpperBound']; + } + + if (isset($loggingConfiguration['highLowerBound']) && + !isset($arguments['reportHighLowerBound'])) { + $arguments['reportHighLowerBound'] = $loggingConfiguration['highLowerBound']; + } + + $arguments['reportDirectory'] = $loggingConfiguration['coverage-html']; + } + + if (isset($loggingConfiguration['coverage-clover']) && + !isset($arguments['coverageClover'])) { + $arguments['coverageClover'] = $loggingConfiguration['coverage-clover']; + } + + if (isset($loggingConfiguration['json']) && + !isset($arguments['jsonLogfile'])) { + $arguments['jsonLogfile'] = $loggingConfiguration['json']; + } + + if (isset($loggingConfiguration['plain'])) { + $arguments['listeners'][] = new PHPUnit_TextUI_ResultPrinter( + $loggingConfiguration['plain'], TRUE + ); + } + + if (isset($loggingConfiguration['tap']) && + !isset($arguments['tapLogfile'])) { + $arguments['tapLogfile'] = $loggingConfiguration['tap']; + } + + if (isset($loggingConfiguration['junit']) && + !isset($arguments['junitLogfile'])) { + $arguments['junitLogfile'] = $loggingConfiguration['junit']; + + if (isset($loggingConfiguration['logIncompleteSkipped']) && + !isset($arguments['logIncompleteSkipped'])) { + $arguments['logIncompleteSkipped'] = $loggingConfiguration['logIncompleteSkipped']; + } + } + + if (isset($loggingConfiguration['story-html']) && + !isset($arguments['storyHTMLFile'])) { + $arguments['storyHTMLFile'] = $loggingConfiguration['story-html']; + } + + if (isset($loggingConfiguration['story-text']) && + !isset($arguments['storyTextFile'])) { + $arguments['storsTextFile'] = $loggingConfiguration['story-text']; + } + + if (isset($loggingConfiguration['testdox-html']) && + !isset($arguments['testdoxHTMLFile'])) { + $arguments['testdoxHTMLFile'] = $loggingConfiguration['testdox-html']; + } + + if (isset($loggingConfiguration['testdox-text']) && + !isset($arguments['testdoxTextFile'])) { + $arguments['testdoxTextFile'] = $loggingConfiguration['testdox-text']; + } + } + + if (isset($arguments['configuration'])) { + $filterConfiguration = $arguments['configuration']->getFilterConfiguration(); + + $filter = PHP_CodeCoverage_Filter::getInstance(); + + foreach ($filterConfiguration['blacklist']['include']['directory'] as $dir) { + $filter->addDirectoryToBlacklist( + $dir['path'], $dir['suffix'], $dir['prefix'], $dir['group'] + ); + } + + foreach ($filterConfiguration['blacklist']['include']['file'] as $file) { + $filter->addFileToBlacklist($file); + } + + foreach ($filterConfiguration['blacklist']['exclude']['directory'] as $dir) { + $filter->removeDirectoryFromBlacklist( + $dir['path'], $dir['suffix'], $dir['prefix'], $dir['group'] + ); + } + + foreach ($filterConfiguration['blacklist']['exclude']['file'] as $file) { + $filter->removeFileFromBlacklist($file); + } + + if ((isset($arguments['coverageClover']) || + isset($arguments['reportDirectory'])) && + extension_loaded('xdebug')) { + $coverage = PHP_CodeCoverage::getInstance(); + + $coverage->setProcessUncoveredFilesFromWhitelist( + $filterConfiguration['whitelist']['addUncoveredFilesFromWhitelist'] + ); + + if (isset($arguments['forceCoversAnnotation'])) { + $coverage->setForceCoversAnnotation( + $arguments['forceCoversAnnotation'] + ); + } + + if (isset($arguments['mapTestClassNameToCoveredClassName'])) { + $coverage->setMapTestClassNameToCoveredClassName( + $arguments['mapTestClassNameToCoveredClassName'] + ); + } + + foreach ($filterConfiguration['whitelist']['include']['directory'] as $dir) { + $filter->addDirectoryToWhitelist( + $dir['path'], $dir['suffix'], $dir['prefix'] + ); + } + + foreach ($filterConfiguration['whitelist']['include']['file'] as $file) { + $filter->addFileToWhitelist($file); + } + + foreach ($filterConfiguration['whitelist']['exclude']['directory'] as $dir) { + $filter->removeDirectoryFromWhitelist( + $dir['path'], $dir['suffix'], $dir['prefix'] + ); + } + + foreach ($filterConfiguration['whitelist']['exclude']['file'] as $file) { + $filter->removeFileFromWhitelist($file); + } + } + } + + $arguments['backupGlobals'] = isset($arguments['backupGlobals']) ? $arguments['backupGlobals'] : NULL; + $arguments['backupStaticAttributes'] = isset($arguments['backupStaticAttributes']) ? $arguments['backupStaticAttributes'] : NULL; + $arguments['colors'] = isset($arguments['colors']) ? $arguments['colors'] : FALSE; + $arguments['convertErrorsToExceptions'] = isset($arguments['convertErrorsToExceptions']) ? $arguments['convertErrorsToExceptions'] : TRUE; + $arguments['convertNoticesToExceptions'] = isset($arguments['convertNoticesToExceptions']) ? $arguments['convertNoticesToExceptions'] : TRUE; + $arguments['convertWarningsToExceptions'] = isset($arguments['convertWarningsToExceptions']) ? $arguments['convertWarningsToExceptions'] : TRUE; + $arguments['excludeGroups'] = isset($arguments['excludeGroups']) ? $arguments['excludeGroups'] : array(); + $arguments['groups'] = isset($arguments['groups']) ? $arguments['groups'] : array(); + $arguments['logIncompleteSkipped'] = isset($arguments['logIncompleteSkipped']) ? $arguments['logIncompleteSkipped'] : FALSE; + $arguments['processIsolation'] = isset($arguments['processIsolation']) ? $arguments['processIsolation'] : FALSE; + $arguments['repeat'] = isset($arguments['repeat']) ? $arguments['repeat'] : FALSE; + $arguments['reportCharset'] = isset($arguments['reportCharset']) ? $arguments['reportCharset'] : 'UTF-8'; + $arguments['reportHighlight'] = isset($arguments['reportHighlight']) ? $arguments['reportHighlight'] : FALSE; + $arguments['reportHighLowerBound'] = isset($arguments['reportHighLowerBound']) ? $arguments['reportHighLowerBound'] : 70; + $arguments['reportLowUpperBound'] = isset($arguments['reportLowUpperBound']) ? $arguments['reportLowUpperBound'] : 35; + $arguments['reportYUI'] = isset($arguments['reportYUI']) ? $arguments['reportYUI'] : TRUE; + $arguments['stopOnError'] = isset($arguments['stopOnError']) ? $arguments['stopOnError'] : FALSE; + $arguments['stopOnFailure'] = isset($arguments['stopOnFailure']) ? $arguments['stopOnFailure'] : FALSE; + $arguments['stopOnIncomplete'] = isset($arguments['stopOnIncomplete']) ? $arguments['stopOnIncomplete'] : FALSE; + $arguments['stopOnSkipped'] = isset($arguments['stopOnSkipped']) ? $arguments['stopOnSkipped'] : FALSE; + $arguments['strict'] = isset($arguments['strict']) ? $arguments['strict'] : FALSE; + $arguments['verbose'] = isset($arguments['verbose']) ? $arguments['verbose'] : FALSE; + + if ($arguments['filter'] !== FALSE && + preg_match('/^[a-zA-Z0-9_]/', $arguments['filter'])) { + // Escape delimiters in regular expression. Do NOT use preg_quote, + // to keep magic characters. + $arguments['filter'] = '/' . str_replace( + '/', '\\/', $arguments['filter'] + ) . '/'; + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Class.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Class.php new file mode 100644 index 0000000..f31777e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Class.php @@ -0,0 +1,401 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.1.0 + */ + +if (!defined('T_NAMESPACE')) { + define('T_NAMESPACE', 377); +} + +/** + * Class helpers. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.1.0 + */ +class PHPUnit_Util_Class +{ + protected static $buffer = array(); + + /** + * Starts the collection of loaded classes. + * + */ + public static function collectStart() + { + self::$buffer = get_declared_classes(); + } + + /** + * Stops the collection of loaded classes and + * returns the names of the loaded classes. + * + * @return array + */ + public static function collectEnd() + { + return array_values( + array_diff(get_declared_classes(), self::$buffer) + ); + } + + /** + * Returns the class hierarchy for a given class. + * + * @param string $className + * @param boolean $asReflectionObjects + * @return array + */ + public static function getHierarchy($className, $asReflectionObjects = FALSE) + { + if ($asReflectionObjects) { + $classes = array(new ReflectionClass($className)); + } else { + $classes = array($className); + } + + $done = FALSE; + + while (!$done) { + if ($asReflectionObjects) { + $class = new ReflectionClass( + $classes[count($classes)-1]->getName() + ); + } else { + $class = new ReflectionClass($classes[count($classes)-1]); + } + + $parent = $class->getParentClass(); + + if ($parent !== FALSE) { + if ($asReflectionObjects) { + $classes[] = $parent; + } else { + $classes[] = $parent->getName(); + } + } else { + $done = TRUE; + } + } + + return $classes; + } + + /** + * Returns the parameters of a function or method. + * + * @param ReflectionFunction|ReflectionMethod $method + * @param boolean $forCall + * @return string + * @since Method available since Release 3.2.0 + */ + public static function getMethodParameters($method, $forCall = FALSE) + { + $parameters = array(); + + foreach ($method->getParameters() as $i => $parameter) { + $name = '$' . $parameter->getName(); + + if ($name === '$') { + $name .= 'arg' . $i; + } + + $default = ''; + $typeHint = ''; + + if (!$forCall) { + if ($parameter->isArray()) { + $typeHint = 'array '; + } else { + try { + $class = $parameter->getClass(); + } + + catch (ReflectionException $e) { + $class = FALSE; + } + + if ($class) { + $typeHint = $class->getName() . ' '; + } + } + + if ($parameter->isDefaultValueAvailable()) { + $value = $parameter->getDefaultValue(); + $default = ' = ' . var_export($value, TRUE); + } + + else if ($parameter->isOptional()) { + $default = ' = null'; + } + } + + $ref = ''; + + if ($parameter->isPassedByReference()) { + $ref = '&'; + } + + $parameters[] = $typeHint . $ref . $name . $default; + } + + return join(', ', $parameters); + } + + /** + * Returns the package information of a user-defined class. + * + * @param string $className + * @param string $docComment + * @return array + */ + public static function getPackageInformation($className, $docComment) + { + $result = array( + 'namespace' => '', + 'fullPackage' => '', + 'category' => '', + 'package' => '', + 'subpackage' => '' + ); + + if (strpos($className, '\\') !== FALSE) { + $result['namespace'] = self::arrayToName( + explode('\\', $className) + ); + } + + if (preg_match('/@category[\s]+([\.\w]+)/', $docComment, $matches)) { + $result['category'] = $matches[1]; + } + + if (preg_match('/@package[\s]+([\.\w]+)/', $docComment, $matches)) { + $result['package'] = $matches[1]; + $result['fullPackage'] = $matches[1]; + } + + if (preg_match('/@subpackage[\s]+([\.\w]+)/', $docComment, $matches)) { + $result['subpackage'] = $matches[1]; + $result['fullPackage'] .= '.' . $matches[1]; + } + + if (empty($result['fullPackage'])) { + $result['fullPackage'] = self::arrayToName( + explode('_', str_replace('\\', '_', $className)), '.' + ); + } + + return $result; + } + + /** + * Returns the value of a static attribute. + * This also works for attributes that are declared protected or private. + * + * @param string $className + * @param string $attributeName + * @return mixed + * @throws InvalidArgumentException + * @since Method available since Release 3.4.0 + */ + public static function getStaticAttribute($className, $attributeName) + { + if (!is_string($className)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); + } + + if (!class_exists($className)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'class name'); + } + + if (!is_string($attributeName)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); + } + + $class = new ReflectionClass($className); + + while ($class) { + $attributes = $class->getStaticProperties(); + + if (array_key_exists($attributeName, $attributes)) { + return $attributes[$attributeName]; + } + + $class = $class->getParentClass(); + } + + throw new PHPUnit_Framework_Exception( + sprintf( + 'Attribute "%s" not found in class.', + + $attributeName + ) + ); + } + + /** + * Returns the value of an object's attribute. + * This also works for attributes that are declared protected or private. + * + * @param object $object + * @param string $attributeName + * @return mixed + * @throws InvalidArgumentException + * @since Method available since Release 3.4.0 + */ + public static function getObjectAttribute($object, $attributeName) + { + if (!is_object($object)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'object'); + } + + if (!is_string($attributeName)) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); + } + + try { + $attribute = new ReflectionProperty($object, $attributeName); + } + + catch (ReflectionException $e) { + $reflector = new ReflectionObject($object); + + while ($reflector = $reflector->getParentClass()) { + try { + $attribute = $reflector->getProperty($attributeName); + break; + } + + catch(ReflectionException $e) { + } + } + } + + if (isset($attribute)) { + if ($attribute == NULL || $attribute->isPublic()) { + return $object->$attributeName; + } else { + $array = (array)$object; + $protectedName = "\0*\0" . $attributeName; + + if (array_key_exists($protectedName, $array)) { + return $array[$protectedName]; + } else { + $classes = self::getHierarchy(get_class($object)); + + foreach ($classes as $class) { + $privateName = sprintf( + "\0%s\0%s", + + $class, + $attributeName + ); + + if (array_key_exists($privateName, $array)) { + return $array[$privateName]; + } + } + } + } + } + + throw new PHPUnit_Framework_Exception( + sprintf( + 'Attribute "%s" not found in object.', + + $attributeName + ) + ); + } + + /** + * + * + * @param string $className + * @return array + * @since Method available since Release 3.4.0 + */ + public static function parseFullyQualifiedClassName($className) + { + $result = array( + 'namespace' => '', + 'className' => $className, + 'fullyQualifiedClassName' => $className + ); + + if (strpos($className, '\\') !== FALSE) { + $tmp = explode('\\', $className); + $result['className'] = $tmp[count($tmp)-1]; + $result['namespace'] = self::arrayToName($tmp); + } + + return $result; + } + + /** + * Returns the package information of a user-defined class. + * + * @param array $parts + * @param string $join + * @return string + * @since Method available since Release 3.2.12 + */ + protected static function arrayToName(array $parts, $join = '\\') + { + $result = ''; + + if (count($parts) > 1) { + array_pop($parts); + + $result = join($join, $parts); + } + + return $result; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Configuration.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Configuration.php new file mode 100644 index 0000000..fbf16c7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Configuration.php @@ -0,0 +1,862 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.2.0 + */ + +/** + * Wrapper for the PHPUnit XML configuration file. + * + * Example XML configuration file: + * + * + * + * + * + * + * /path/to/files + * /path/to/MyTest.php + * + * + * + * + * + * name + * + * + * name + * + * + * + * + * + * /path/to/files + * /path/to/file + * + * /path/to/files + * /path/to/file + * + * + * + * /path/to/files + * /path/to/file + * + * /path/to/files + * /path/to/file + * + * + * + * + * + * + * + * + * + * Sebastian + * + * + * 22 + * April + * 19.78 + * + * + * MyRelativeFile.php + * MyRelativeDir + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * . + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.2.0 + */ +class PHPUnit_Util_Configuration +{ + private static $instances = array(); + + protected $document; + protected $xpath; + protected $filename; + + /** + * Loads a PHPUnit configuration file. + * + * @param string $filename + */ + protected function __construct($filename) + { + $this->filename = $filename; + $this->document = PHPUnit_Util_XML::loadFile($filename); + $this->xpath = new DOMXPath($this->document); + } + + /** + * @since Method available since Release 3.4.0 + */ + private final function __clone() + { + } + + /** + * Returns a PHPUnit configuration object. + * + * @param string $filename + * @return PHPUnit_Util_Configuration + * @since Method available since Release 3.4.0 + */ + public static function getInstance($filename) + { + $realpath = realpath($filename); + + if ($realpath === FALSE) { + throw new PHPUnit_Framework_Exception( + sprintf( + 'Could not read "%s".', + $filename + ) + ); + } + + if (!isset(self::$instances[$realpath])) { + self::$instances[$realpath] = new PHPUnit_Util_Configuration($realpath); + } + + return self::$instances[$realpath]; + } + + /** + * Returns the configuration for SUT filtering. + * + * @return array + * @since Method available since Release 3.2.1 + */ + public function getFilterConfiguration() + { + $addUncoveredFilesFromWhitelist = TRUE; + + $tmp = $this->xpath->query('filter/whitelist'); + + if ($tmp->length == 1 && + $tmp->item(0)->hasAttribute('addUncoveredFilesFromWhitelist')) { + $addUncoveredFilesFromWhitelist = $this->getBoolean( + (string)$tmp->item(0)->getAttribute('addUncoveredFilesFromWhitelist'), + TRUE + ); + } + + return array( + 'blacklist' => array( + 'include' => array( + 'directory' => $this->readFilterDirectories( + 'filter/blacklist/directory' + ), + 'file' => $this->readFilterFiles( + 'filter/blacklist/file' + ) + ), + 'exclude' => array( + 'directory' => $this->readFilterDirectories( + 'filter/blacklist/exclude/directory' + ), + 'file' => $this->readFilterFiles( + 'filter/blacklist/exclude/file' + ) + ) + ), + 'whitelist' => array( + 'addUncoveredFilesFromWhitelist' => $addUncoveredFilesFromWhitelist, + 'include' => array( + 'directory' => $this->readFilterDirectories( + 'filter/whitelist/directory' + ), + 'file' => $this->readFilterFiles( + 'filter/whitelist/file' + ) + ), + 'exclude' => array( + 'directory' => $this->readFilterDirectories( + 'filter/whitelist/exclude/directory' + ), + 'file' => $this->readFilterFiles( + 'filter/whitelist/exclude/file' + ) + ) + ) + ); + } + + /** + * Returns the configuration for groups. + * + * @return array + * @since Method available since Release 3.2.1 + */ + public function getGroupConfiguration() + { + $groups = array( + 'include' => array(), + 'exclude' => array() + ); + + foreach ($this->xpath->query('groups/include/group') as $group) { + $groups['include'][] = (string)$group->nodeValue; + } + + foreach ($this->xpath->query('groups/exclude/group') as $group) { + $groups['exclude'][] = (string)$group->nodeValue; + } + + return $groups; + } + + /** + * Returns the configuration for listeners. + * + * @return array + * @since Method available since Release 3.4.0 + */ + public function getListenerConfiguration() + { + $result = array(); + + foreach ($this->xpath->query('listeners/listener') as $listener) { + $class = (string)$listener->getAttribute('class'); + $file = ''; + $arguments = array(); + + if ($listener->hasAttribute('file')) { + $file = $this->toAbsolutePath((string)$listener->getAttribute('file')); + } + + if ($listener->childNodes->item(1) instanceof DOMElement && + $listener->childNodes->item(1)->tagName == 'arguments') { + foreach ($listener->childNodes->item(1)->childNodes as $argument) { + if ($argument instanceof DOMElement) { + if($argument->tagName == 'file' || $argument->tagName == 'directory') { + $arguments[] = $this->toAbsolutePath((string)$argument->nodeValue); + } else { + $arguments[] = PHPUnit_Util_XML::xmlToVariable($argument); + } + } + } + } + + $result[] = array( + 'class' => $class, + 'file' => $file, + 'arguments' => $arguments + ); + } + + return $result; + } + + /** + * Returns the logging configuration. + * + * @return array + */ + public function getLoggingConfiguration() + { + $result = array(); + + foreach ($this->xpath->query('logging/log') as $log) { + $type = (string)$log->getAttribute('type'); + $target = $this->toAbsolutePath((string)$log->getAttribute('target')); + + if ($type == 'coverage-html') { + if ($log->hasAttribute('title')) { + $result['title'] = (string)$log->getAttribute('title'); + } + + if ($log->hasAttribute('charset')) { + $result['charset'] = (string)$log->getAttribute('charset'); + } + + if ($log->hasAttribute('lowUpperBound')) { + $result['lowUpperBound'] = (string)$log->getAttribute('lowUpperBound'); + } + + if ($log->hasAttribute('highLowerBound')) { + $result['highLowerBound'] = (string)$log->getAttribute('highLowerBound'); + } + + if ($log->hasAttribute('yui')) { + $result['yui'] = $this->getBoolean( + (string)$log->getAttribute('yui'), + FALSE + ); + } + + if ($log->hasAttribute('highlight')) { + $result['highlight'] = $this->getBoolean( + (string)$log->getAttribute('highlight'), + FALSE + ); + } + } + + else if ($type == 'junit') { + if ($log->hasAttribute('logIncompleteSkipped')) { + $result['logIncompleteSkipped'] = $this->getBoolean( + (string)$log->getAttribute('logIncompleteSkipped'), + FALSE + ); + } + } + + $result[$type] = $target; + } + + return $result; + } + + /** + * Returns the PHP configuration. + * + * @return array + * @since Method available since Release 3.2.1 + */ + public function getPHPConfiguration() + { + $result = array( + 'include_path' => '', + 'ini' => array(), + 'const' => array(), + 'var' => array(), + 'env' => array(), + 'post' => array(), + 'get' => array(), + 'cookie' => array(), + 'server' => array(), + 'files' => array(), + 'request' => array() + ); + + $nl = $this->xpath->query('php/includePath'); + + if ($nl->length == 1) { + $result['include_path'] = $this->toAbsolutePath((string)$nl->item(0)->nodeValue); + } + + foreach ($this->xpath->query('php/ini') as $ini) { + $name = (string)$ini->getAttribute('name'); + $value = (string)$ini->getAttribute('value'); + + $result['ini'][$name] = $value; + } + + foreach ($this->xpath->query('php/const') as $const) { + $name = (string)$const->getAttribute('name'); + $value = (string)$const->getAttribute('value'); + + $result['const'][$name] = $this->getBoolean($value, $value); + } + + foreach (array('var', 'env', 'post', 'get', 'cookie', 'server', 'files', 'request') as $array) { + foreach ($this->xpath->query('php/' . $array) as $var) { + $name = (string)$var->getAttribute('name'); + $value = (string)$var->getAttribute('value'); + + $result[$array][$name] = $this->getBoolean($value, $value); + } + } + + return $result; + } + + /** + * Handles the PHP configuration. + * + * @since Method available since Release 3.2.20 + */ + public function handlePHPConfiguration() + { + $configuration = $this->getPHPConfiguration(); + + if ($configuration['include_path'] != '') { + ini_set( + 'include_path', + $configuration['include_path'] . PATH_SEPARATOR . + ini_get('include_path') + ); + } + + foreach ($configuration['ini'] as $name => $value) { + if (defined($value)) { + $value = constant($value); + } + + ini_set($name, $value); + } + + foreach ($configuration['const'] as $name => $value) { + if (!defined($name)) { + define($name, $value); + } + } + + foreach (array('var', 'env', 'post', 'get', 'cookie', 'server', 'files', 'request') as $array) { + if ($array == 'var') { + $target = &$GLOBALS; + } else { + $target = &$GLOBALS['_' . strtoupper($array)]; + } + + foreach ($configuration[$array] as $name => $value) { + $target[$name] = $value; + } + } + } + + /** + * Returns the PHPUnit configuration. + * + * @return array + * @since Method available since Release 3.2.14 + */ + public function getPHPUnitConfiguration() + { + $result = array(); + $root = $this->document->documentElement; + + if ($root->hasAttribute('colors')) { + $result['colors'] = $this->getBoolean( + (string)$root->getAttribute('colors'), FALSE + ); + } + + if ($root->hasAttribute('backupGlobals')) { + $result['backupGlobals'] = $this->getBoolean( + (string)$root->getAttribute('backupGlobals'), TRUE + ); + } + + if ($root->hasAttribute('backupStaticAttributes')) { + $result['backupStaticAttributes'] = $this->getBoolean( + (string)$root->getAttribute('backupStaticAttributes'), FALSE + ); + } + + if ($root->hasAttribute('bootstrap')) { + $result['bootstrap'] = $this->toAbsolutePath( + (string)$root->getAttribute('bootstrap') + ); + } + + if ($root->hasAttribute('convertErrorsToExceptions')) { + $result['convertErrorsToExceptions'] = $this->getBoolean( + (string)$root->getAttribute('convertErrorsToExceptions'), TRUE + ); + } + + if ($root->hasAttribute('convertNoticesToExceptions')) { + $result['convertNoticesToExceptions'] = $this->getBoolean( + (string)$root->getAttribute('convertNoticesToExceptions'), TRUE + ); + } + + if ($root->hasAttribute('convertWarningsToExceptions')) { + $result['convertWarningsToExceptions'] = $this->getBoolean( + (string)$root->getAttribute('convertWarningsToExceptions'), TRUE + ); + } + + if ($root->hasAttribute('forceCoversAnnotation')) { + $result['forceCoversAnnotation'] = $this->getBoolean( + (string)$root->getAttribute('forceCoversAnnotation'), FALSE + ); + } + + if ($root->hasAttribute('mapTestClassNameToCoveredClassName')) { + $result['mapTestClassNameToCoveredClassName'] = $this->getBoolean( + (string)$root->getAttribute('mapTestClassNameToCoveredClassName'), + FALSE + ); + } + + if ($root->hasAttribute('processIsolation')) { + $result['processIsolation'] = $this->getBoolean( + (string)$root->getAttribute('processIsolation'), FALSE + ); + } + + if ($root->hasAttribute('stopOnError')) { + $result['stopOnError'] = $this->getBoolean( + (string)$root->getAttribute('stopOnError'), FALSE + ); + } + + if ($root->hasAttribute('stopOnFailure')) { + $result['stopOnFailure'] = $this->getBoolean( + (string)$root->getAttribute('stopOnFailure'), FALSE + ); + } + + if ($root->hasAttribute('stopOnIncomplete')) { + $result['stopOnIncomplete'] = $this->getBoolean( + (string)$root->getAttribute('stopOnIncomplete'), FALSE + ); + } + + if ($root->hasAttribute('stopOnSkipped')) { + $result['stopOnSkipped'] = $this->getBoolean( + (string)$root->getAttribute('stopOnSkipped'), FALSE + ); + } + + if ($root->hasAttribute('syntaxCheck')) { + $result['syntaxCheck'] = $this->getBoolean( + (string)$root->getAttribute('syntaxCheck'), FALSE + ); + } + + if ($root->hasAttribute('testSuiteLoaderClass')) { + $result['testSuiteLoaderClass'] = (string)$root->getAttribute( + 'testSuiteLoaderClass' + ); + } + + if ($root->hasAttribute('testSuiteLoaderFile')) { + $result['testSuiteLoaderFile'] = (string)$root->getAttribute( + 'testSuiteLoaderFile' + ); + } + + if ($root->hasAttribute('strict')) { + $result['strict'] = $this->getBoolean( + (string)$root->getAttribute('strict'), FALSE + ); + } + + if ($root->hasAttribute('verbose')) { + $result['verbose'] = $this->getBoolean( + (string)$root->getAttribute('verbose'), FALSE + ); + } + + return $result; + } + + /** + * Returns the SeleniumTestCase browser configuration. + * + * @return array + * @since Method available since Release 3.2.9 + */ + public function getSeleniumBrowserConfiguration() + { + $result = array(); + + foreach ($this->xpath->query('selenium/browser') as $config) { + $name = (string)$config->getAttribute('name'); + $browser = (string)$config->getAttribute('browser'); + + if ($config->hasAttribute('host')) { + $host = (string)$config->getAttribute('host'); + } else { + $host = 'localhost'; + } + + if ($config->hasAttribute('port')) { + $port = (int)$config->getAttribute('port'); + } else { + $port = 4444; + } + + if ($config->hasAttribute('timeout')) { + $timeout = (int)$config->getAttribute('timeout'); + } else { + $timeout = 30000; + } + + $result[] = array( + 'name' => $name, + 'browser' => $browser, + 'host' => $host, + 'port' => $port, + 'timeout' => $timeout + ); + } + + return $result; + } + + /** + * Returns the test suite configuration. + * + * @param boolean $syntaxCheck + * @return PHPUnit_Framework_TestSuite + * @since Method available since Release 3.2.1 + */ + public function getTestSuiteConfiguration($syntaxCheck = FALSE) + { + $testSuiteNodes = $this->xpath->query('testsuites/testsuite'); + + if ($testSuiteNodes->length == 0) { + $testSuiteNodes = $this->xpath->query('testsuite'); + } + + if ($testSuiteNodes->length == 1) { + return $this->getTestSuite($testSuiteNodes->item(0), $syntaxCheck); + } + + if ($testSuiteNodes->length > 1) { + $suite = new PHPUnit_Framework_TestSuite; + + foreach ($testSuiteNodes as $testSuiteNode) { + $suite->addTestSuite( + $this->getTestSuite($testSuiteNode, $syntaxCheck) + ); + } + + return $suite; + } + } + + /** + * @param DOMElement $testSuiteNode + * @param boolean $syntaxCheck + * @return PHPUnit_Framework_TestSuite + * @since Method available since Release 3.4.0 + */ + protected function getTestSuite(DOMElement $testSuiteNode, $syntaxCheck) + { + if ($testSuiteNode->hasAttribute('name')) { + $suite = new PHPUnit_Framework_TestSuite( + (string)$testSuiteNode->getAttribute('name') + ); + } else { + $suite = new PHPUnit_Framework_TestSuite; + } + + foreach ($testSuiteNode->getElementsByTagName('directory') as $directoryNode) { + $directory = (string)$directoryNode->nodeValue; + + if (empty($directory)) { + continue; + } + + if ($directoryNode->hasAttribute('prefix')) { + $prefix = (string)$directoryNode->getAttribute('prefix'); + } else { + $prefix = ''; + } + + if ($directoryNode->hasAttribute('suffix')) { + $suffix = (string)$directoryNode->getAttribute('suffix'); + } else { + $suffix = 'Test.php'; + } + + $testCollector = new PHPUnit_Runner_IncludePathTestCollector( + array($this->toAbsolutePath($directory)), $suffix, $prefix + ); + + $suite->addTestFiles($testCollector->collectTests(), $syntaxCheck); + } + + foreach ($testSuiteNode->getElementsByTagName('file') as $fileNode) { + $file = (string)$fileNode->nodeValue; + + if (empty($file)) { + continue; + } + + $suite->addTestFile($file, $syntaxCheck); + } + + return $suite; + } + + /** + * @param string $value + * @param boolean $default + * @return boolean + * @since Method available since Release 3.2.3 + */ + protected function getBoolean($value, $default) + { + if (strtolower($value) == 'false') { + return FALSE; + } + + else if (strtolower($value) == 'true') { + return TRUE; + } + + return $default; + } + + /** + * @param string $query + * @return array + * @since Method available since Release 3.2.3 + */ + protected function readFilterDirectories($query) + { + $directories = array(); + + foreach ($this->xpath->query($query) as $directory) { + if ($directory->hasAttribute('prefix')) { + $prefix = (string)$directory->getAttribute('prefix'); + } else { + $prefix = ''; + } + + if ($directory->hasAttribute('suffix')) { + $suffix = (string)$directory->getAttribute('suffix'); + } else { + $suffix = '.php'; + } + + if ($directory->hasAttribute('group')) { + $group = (string)$directory->getAttribute('group'); + } else { + $group = 'DEFAULT'; + } + + $directories[] = array( + 'path' => $this->toAbsolutePath((string)$directory->nodeValue), + 'prefix' => $prefix, + 'suffix' => $suffix, + 'group' => $group + ); + } + + return $directories; + } + + /** + * @param string $query + * @return array + * @since Method available since Release 3.2.3 + */ + protected function readFilterFiles($query) + { + $files = array(); + + foreach ($this->xpath->query($query) as $file) { + $files[] = $this->toAbsolutePath((string)$file->nodeValue); + } + + return $files; + } + + /** + * @param string $path + * @return string + * @since Method available since Release 3.5.0 + */ + protected function toAbsolutePath($path) + { + // is the path already an absolute path? + if ($path[0] === '/' || $path[0] === '\\' || + (strlen($path) > 3 && ctype_alpha($path[0]) && + $path[1] === ':' && ($path[2] === '\\' || $path[2] === '/'))) { + return $path; + } + + return dirname($this->filename) . DIRECTORY_SEPARATOR . $path; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/DeprecatedFeature.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/DeprecatedFeature.php new file mode 100644 index 0000000..0b71c3f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/DeprecatedFeature.php @@ -0,0 +1,103 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Ralph Schindler + * @author Sebastian Bergmann + * @copyright 2002-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.5.7 + */ + +/** + * Class to hold the information about a deprecated feature that was used + * + * @package PHPUnit + * @subpackage Framework + * @author Ralph Schindler + * @author Sebastian Bergmann + * @copyright 2002-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Interface available since Release 3.5.7 + */ +class PHPUnit_Util_DeprecatedFeature +{ + /** + * @var array + */ + protected $traceInfo = array(); + + /** + * @var string + */ + protected $message = NULL; + + /** + * @param string $message + * @param array $traceInfo + */ + public function __construct($message, array $traceInfo = array()) + { + $this->message = $message; + $this->traceInfo = $traceInfo; + } + + /** + * Build a string representation of the deprecated feature that was raised + * + * @return string + */ + public function __toString() + { + $string = ''; + + if (isset($this->traceInfo['file'])) { + $string .= $this->traceInfo['file']; + + if (isset($this->traceInfo['line'])) { + $string .= ':' . $this->traceInfo['line'] . ' - '; + } + } + + $string .= $this->message; + + return $string; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/DeprecatedFeature/Logger.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/DeprecatedFeature/Logger.php new file mode 100644 index 0000000..dca3c4c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/DeprecatedFeature/Logger.php @@ -0,0 +1,202 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Framework + * @author Ralph Schindler + * @author Sebastian Bergmann + * @copyright 2002-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.5.7 + */ + +/** + * Test Listener that tracks the usage of deprecated features. + * + * @package PHPUnit + * @subpackage Framework + * @author Ralph Schindler + * @author Sebastian Bergmann + * @copyright 2002-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.5.7 + */ +class PHPUnit_Util_DeprecatedFeature_Logger implements PHPUnit_Framework_TestListener +{ + /** + * @var PHPUnit_Framework_TestCase + */ + protected static $currentTest = NULL; + + /** + * This is the publically accessible API for notifying the system that a + * deprecated feature has been used. + * + * If it is run via a TestRunner and the test extends + * PHPUnit_Framework_TestCase, then this will inject the result into the + * test runner for display, if not, it will throw the notice to STDERR. + * + * @param string $message + * @param int|bool $backtraceDepth + */ + public static function log($message, $backtraceDepth = 2) + { + if ($backtraceDepth !== FALSE) { + $trace = debug_backtrace(FALSE); + + if (is_int($backtraceDepth)) { + $traceItem = $trace[$backtraceDepth]; + } + + if (!isset($traceItem['file'])) { + $reflectionClass = new ReflectionClass($traceItem['class']); + $traceItem['file'] = $reflectionClass->getFileName(); + } + + if (!isset($traceItem['line']) && + isset($traceItem['class']) && + isset($traceItem['function'])) { + if (!isset($reflectionClass)) { + $reflectionClass = new ReflectionClass($traceItem['class']); + } + + $method = $reflectionClass->getMethod($traceItem['function']); + $traceItem['line'] = '(between ' . $method->getStartLine() . + ' and ' . $method->getEndLine() . ')'; + } + } + + $deprecatedFeature = new PHPUnit_Util_DeprecatedFeature( + $message, $traceItem + ); + + if (self::$currentTest instanceof PHPUnit_Framework_TestCase) { + $result = self::$currentTest->getTestResultObject(); + $result->addDeprecatedFeature($deprecatedFeature); + } else { + file_put_contents('php://stderr', $deprecatedFeature); + } + } + + /** + * An error occurred. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) + { + } + + /** + * A failure occurred. + * + * @param PHPUnit_Framework_Test $test + * @param PHPUnit_Framework_AssertionFailedError $e + * @param float $time + */ + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) + { + } + + /** + * Incomplete test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + } + + /** + * Skipped test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + * @since Method available since Release 3.0.0 + */ + public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + } + + /** + * A test suite started. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit_Framework_TestSuite $suite) + { + } + + /** + * A test suite ended. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit_Framework_TestSuite $suite) + { + } + + /** + * A test started. + * + * @param PHPUnit_Framework_Test $test + */ + public function startTest(PHPUnit_Framework_Test $test) + { + self::$currentTest = $test; + } + + /** + * A test ended. + * + * @param PHPUnit_Framework_Test $test + * @param float $time + */ + public function endTest(PHPUnit_Framework_Test $test, $time) + { + self::$currentTest = NULL; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Diff.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Diff.php new file mode 100644 index 0000000..338099c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Diff.php @@ -0,0 +1,261 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @author Kore Nordmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.4.0 + */ + +/** + * Diff implementation. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @author Kore Nordmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.4.0 + */ +class PHPUnit_Util_Diff +{ + /** + * Returns the diff between two arrays or strings. + * + * @param array|string $from + * @param array|string $to + * @return string + */ + public static function diff($from, $to) + { + if (is_string($from)) { + $from = preg_split('(\r\n|\r|\n)', $from); + } + + if (is_string($to)) { + $to = preg_split('(\r\n|\r|\n)', $to); + } + + $buffer = "--- Expected\n+++ Actual\n"; + $start = array(); + $end = array(); + $fromLength = count($from); + $toLength = count($to); + $length = min($fromLength, $toLength); + + for ($i = 0; $i < $length; ++$i) { + if ($from[$i] === $to[$i]) { + $start[] = $from[$i]; + unset($from[$i], $to[$i]); + } else { + break; + } + } + + $length -= $i; + + for ($i = 1; $i < $length; ++$i) { + if ($from[$fromLength - $i] === $to[$toLength - $i]) { + array_unshift($end, $from[$fromLength - $i]); + unset($from[$fromLength - $i], $to[$toLength - $i]); + } else { + break; + } + } + + $common = self::longestCommonSubsequence( + array_values($from), array_values($to) + ); + + $diff = array(); + $line = 0; + + foreach ($start as $token) { + $diff[] = array($token, 0 /* OLD */); + } + + reset($from); + reset($to); + + foreach ($common as $token) { + while ((($fromToken = reset($from)) !== $token)) { + $diff[] = array(array_shift($from), 2 /* REMOVED */); + } + + while ((($toToken = reset($to)) !== $token)) { + $diff[] = array(array_shift($to), 1 /* ADDED */); + } + + $diff[] = array($token, 0 /* OLD */); + + array_shift($from); + array_shift($to); + } + + while (($token = array_shift($from)) !== NULL) { + $diff[] = array($token, 2 /* REMOVED */); + } + + while (($token = array_shift($to)) !== NULL) { + $diff[] = array($token, 1 /* ADDED */); + } + + foreach ($end as $token) { + $diff[] = array($token, 0 /* OLD */); + } + + $inOld = FALSE; + $i = 0; + $old = array(); + + foreach ($diff as $line) { + if ($line[1] === 0 /* OLD */) { + if ($inOld === FALSE) { + $inOld = $i; + } + } + + else if ($inOld !== FALSE) { + if (($i - $inOld) > 5) { + $old[$inOld] = $i - 1; + } + + $inOld = FALSE; + } + + ++$i; + } + + $start = isset($old[0]) ? $old[0] : 0; + $end = count($diff); + $i = 0; + + if ($tmp = array_search($end, $old)) { + $end = $tmp; + } + + $newChunk = TRUE; + + for ($i = $start; $i < $end; $i++) { + if (isset($old[$i])) { + $buffer .= "\n"; + $newChunk = TRUE; + $i = $old[$i]; + } + + if ($newChunk) { + // TODO: Implement chunk range information. + $buffer .= "@@ @@\n"; + $newChunk = FALSE; + } + + if ($diff[$i][1] === 1 /* ADDED */) { + $buffer .= '+' . $diff[$i][0] . "\n"; + } + + else if ($diff[$i][1] === 2 /* REMOVED */) { + $buffer .= '-' . $diff[$i][0] . "\n"; + } + + else { + $buffer .= ' ' . $diff[$i][0] . "\n"; + } + } + + return $buffer; + } + + /** + * Calculates the longest common subsequence of two arrays. + * + * @param array $from + * @param array $to + * @return array + */ + protected static function longestCommonSubsequence(array $from, array $to) + { + $common = array(); + $matrix = array(); + $fromLength = count($from); + $toLength = count($to); + + for ($i = 0; $i <= $fromLength; ++$i) { + $matrix[$i][0] = 0; + } + + for ($j = 0; $j <= $toLength; ++$j) { + $matrix[0][$j] = 0; + } + + for ($i = 1; $i <= $fromLength; ++$i) { + for ($j = 1; $j <= $toLength; ++$j) { + $matrix[$i][$j] = max( + $matrix[$i-1][$j], + $matrix[$i][$j-1], + $from[$i-1] === $to[$j-1] ? $matrix[$i-1][$j-1] + 1 : 0 + ); + } + } + + $i = $fromLength; + $j = $toLength; + + while ($i > 0 && $j > 0) { + if ($from[$i-1] === $to[$j-1]) { + array_unshift($common, $from[$i-1]); + --$i; + --$j; + } + + else if ($matrix[$i][$j-1] > $matrix[$i-1][$j]) { + --$j; + } + + else { + --$i; + } + } + + return $common; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/ErrorHandler.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/ErrorHandler.php new file mode 100644 index 0000000..9342ff8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/ErrorHandler.php @@ -0,0 +1,124 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.3.0 + */ + +// Workaround for http://bugs.php.net/bug.php?id=47987, +// see https://github.com/sebastianbergmann/phpunit/issues#issue/125 for details +require_once 'PHPUnit/Framework/Error.php'; +require_once 'PHPUnit/Framework/Error/Notice.php'; +require_once 'PHPUnit/Framework/Error/Warning.php'; + +/** + * Error handler that converts PHP errors and warnings to exceptions. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Util_ErrorHandler +{ + protected static $errorStack = array(); + + /** + * Returns the error stack. + * + * @return array + */ + public static function getErrorStack() + { + return self::$errorStack; + } + + /** + * @param integer $errno + * @param string $errstr + * @param string $errfile + * @param integer $errline + * @throws PHPUnit_Framework_Error + */ + public static function handleError($errno, $errstr, $errfile, $errline) + { + if (!($errno & error_reporting())) { + return FALSE; + } + + self::$errorStack[] = array($errno, $errstr, $errfile, $errline); + + $trace = debug_backtrace(FALSE); + array_shift($trace); + + foreach ($trace as $frame) { + if ($frame['function'] == '__toString') { + return FALSE; + } + } + + if ($errno == E_NOTICE || $errno == E_USER_NOTICE || $errno == E_STRICT) { + if (PHPUnit_Framework_Error_Notice::$enabled !== TRUE) { + return FALSE; + } + + $exception = 'PHPUnit_Framework_Error_Notice'; + } + + else if ($errno == E_WARNING || $errno == E_USER_WARNING) { + if (PHPUnit_Framework_Error_Warning::$enabled !== TRUE) { + return FALSE; + } + + $exception = 'PHPUnit_Framework_Error_Warning'; + } + + else { + $exception = 'PHPUnit_Framework_Error'; + } + + throw new $exception($errstr, $errno, $errfile, $errline, $trace); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/File.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/File.php new file mode 100644 index 0000000..b4bf1b4 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/File.php @@ -0,0 +1,310 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.4.0 + */ + +if (!defined('T_NAMESPACE')) { + define('T_NAMESPACE', 377); +} + +/** + * File helpers. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.4.0 + */ +class PHPUnit_Util_File +{ + /** + * @var array + */ + protected static $cache = array(); + + /** + * Returns information on the classes declared in a sourcefile. + * + * @param string $filename + * @return array + */ + public static function getClassesInFile($filename) + { + if (!isset(self::$cache[$filename])) { + self::$cache[$filename] = self::parseFile($filename); + } + + return self::$cache[$filename]; + } + + /** + * Parses a file for class and method information. + * + * @param string $filename + * @return array + */ + protected static function parseFile($filename) + { + $result = array(); + + $tokens = token_get_all( + file_get_contents($filename) + ); + $numTokens = count($tokens); + $blocks = array(); + $line = 1; + $currentBlock = FALSE; + $currentNamespace = FALSE; + $currentClass = FALSE; + $currentFunction = FALSE; + $currentFunctionStartLine = FALSE; + $currentFunctionTokens = array(); + $currentDocComment = FALSE; + $currentSignature = FALSE; + $currentSignatureStartToken = FALSE; + + for ($i = 0; $i < $numTokens; $i++) { + if ($currentFunction !== FALSE) { + $currentFunctionTokens[] = $tokens[$i]; + } + + if (is_string($tokens[$i])) { + if ($tokens[$i] == '{') { + if ($currentBlock == T_CLASS) { + $block = $currentClass; + } + + else if ($currentBlock == T_FUNCTION) { + $currentSignature = ''; + + for ($j = $currentSignatureStartToken; $j < $i; $j++) { + if (is_string($tokens[$j])) { + $currentSignature .= $tokens[$j]; + } else { + $currentSignature .= $tokens[$j][1]; + } + } + + $currentSignature = trim($currentSignature); + + $block = $currentFunction; + $currentSignatureStartToken = FALSE; + } + + else { + $block = FALSE; + } + + array_push($blocks, $block); + + $currentBlock = FALSE; + } + + else if ($tokens[$i] == '}') { + $block = array_pop($blocks); + + if ($block !== FALSE && $block !== NULL) { + if ($block == $currentFunction) { + if ($currentDocComment !== FALSE) { + $docComment = $currentDocComment; + $currentDocComment = FALSE; + } else { + $docComment = ''; + } + + $tmp = array( + 'docComment' => $docComment, + 'signature' => $currentSignature, + 'startLine' => $currentFunctionStartLine, + 'endLine' => $line, + 'tokens' => $currentFunctionTokens + ); + + if ($currentClass !== FALSE) { + $result[$currentClass]['methods'][$currentFunction] = $tmp; + } + + $currentFunction = FALSE; + $currentFunctionStartLine = FALSE; + $currentFunctionTokens = array(); + $currentSignature = FALSE; + } + + else if ($block == $currentClass) { + $result[$currentClass]['endLine'] = $line; + + $currentClass = FALSE; + $currentClassStartLine = FALSE; + } + } + } + + continue; + } + + switch ($tokens[$i][0]) { + case T_HALT_COMPILER: { + return; + } + break; + + case T_NAMESPACE: { + $currentNamespace = $tokens[$i+2][1]; + + for ($j = $i+3; $j < $numTokens; $j += 2) { + if ($tokens[$j][0] == T_NS_SEPARATOR) { + $currentNamespace .= '\\' . $tokens[$j+1][1]; + } else { + break; + } + } + } + break; + + case T_CURLY_OPEN: { + $currentBlock = T_CURLY_OPEN; + array_push($blocks, $currentBlock); + } + break; + + case T_DOLLAR_OPEN_CURLY_BRACES: { + $currentBlock = T_DOLLAR_OPEN_CURLY_BRACES; + array_push($blocks, $currentBlock); + } + break; + + case T_CLASS: { + $currentBlock = T_CLASS; + + if ($currentNamespace === FALSE) { + $currentClass = $tokens[$i+2][1]; + } else { + $currentClass = $currentNamespace . '\\' . + $tokens[$i+2][1]; + } + + if ($currentDocComment !== FALSE) { + $docComment = $currentDocComment; + $currentDocComment = FALSE; + } else { + $docComment = ''; + } + + $result[$currentClass] = array( + 'methods' => array(), + 'docComment' => $docComment, + 'startLine' => $line + ); + } + break; + + case T_FUNCTION: { + if (!((is_array($tokens[$i+2]) && + $tokens[$i+2][0] == T_STRING) || + (is_string($tokens[$i+2]) && + $tokens[$i+2] == '&' && + is_array($tokens[$i+3]) && + $tokens[$i+3][0] == T_STRING))) { + continue; + } + + $currentBlock = T_FUNCTION; + $currentFunctionStartLine = $line; + + $done = FALSE; + $currentSignatureStartToken = $i - 1; + + do { + switch ($tokens[$currentSignatureStartToken][0]) { + case T_ABSTRACT: + case T_FINAL: + case T_PRIVATE: + case T_PUBLIC: + case T_PROTECTED: + case T_STATIC: + case T_WHITESPACE: { + $currentSignatureStartToken--; + } + break; + + default: { + $currentSignatureStartToken++; + $done = TRUE; + } + } + } + while (!$done); + + if (isset($tokens[$i+2][1])) { + $functionName = $tokens[$i+2][1]; + } + + else if (isset($tokens[$i+3][1])) { + $functionName = $tokens[$i+3][1]; + } + + if ($currentNamespace === FALSE) { + $currentFunction = $functionName; + } else { + $currentFunction = $currentNamespace . '\\' . + $functionName; + } + } + break; + + case T_DOC_COMMENT: { + $currentDocComment = $tokens[$i][1]; + } + break; + } + + $line += substr_count($tokens[$i][1], "\n"); + } + + return $result; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Fileloader.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Fileloader.php new file mode 100644 index 0000000..3bdaa6f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Fileloader.php @@ -0,0 +1,140 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.3.0 + */ + +/** + * Utility methods to load PHP sourcefiles. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.3.0 + */ +class PHPUnit_Util_Fileloader +{ + /** + * Checks if a PHP sourcefile is readable and is optionally checked for + * syntax errors through the syntaxCheck() method. The sourcefile is + * loaded through the load() method. + * + * @param string $filename + * @param boolean $syntaxCheck + * @return string + * @throws RuntimeException + */ + public static function checkAndLoad($filename, $syntaxCheck = FALSE) + { + $includePathFilename = PHPUnit_Util_Filesystem::fileExistsInIncludePath( + $filename + ); + + if (!$includePathFilename || !is_readable($includePathFilename)) { + throw new RuntimeException( + sprintf('Cannot open file "%s".' . "\n", $filename) + ); + } + + if ($syntaxCheck) { + self::syntaxCheck($includePathFilename); + } + + self::load($includePathFilename); + + return $includePathFilename; + } + + /** + * Loads a PHP sourcefile. + * + * @param string $filename + * @return mixed + * @since Method available since Release 3.0.0 + */ + public static function load($filename) + { + $oldVariableNames = array_keys(get_defined_vars()); + + include_once $filename; + + $newVariables = get_defined_vars(); + $newVariableNames = array_diff( + array_keys($newVariables), $oldVariableNames + ); + + foreach ($newVariableNames as $variableName) { + if ($variableName != 'oldVariableNames') { + $GLOBALS[$variableName] = $newVariables[$variableName]; + } + } + + return $filename; + } + + /** + * Uses a separate process to perform a syntax check on a PHP sourcefile. + * + * @param string $filename + * @throws RuntimeException + * @since Method available since Release 3.0.0 + */ + protected static function syntaxCheck($filename) + { + $command = PHPUnit_Util_PHP::getPhpBinary(); + + if (DIRECTORY_SEPARATOR == '\\') { + $command = escapeshellarg($command); + } + + $command .= ' -l ' . escapeshellarg($filename); + $output = shell_exec($command); + + if (strpos($output, 'Errors parsing') !== FALSE) { + throw new RuntimeException($output); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Filesystem.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Filesystem.php new file mode 100644 index 0000000..561626e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Filesystem.php @@ -0,0 +1,154 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Filesystem helpers. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Util_Filesystem +{ + /** + * @var array + */ + protected static $buffer = array(); + + /** + * Maps class names to source file names: + * - PEAR CS: Foo_Bar_Baz -> Foo/Bar/Baz.php + * - Namespace: Foo\Bar\Baz -> Foo/Bar/Baz.php + * + * @param string $className + * @return string + * @since Method available since Release 3.4.0 + */ + public static function classNameToFilename($className) + { + return str_replace( + array('_', '\\'), + DIRECTORY_SEPARATOR, + $className + ) . '.php'; + } + + /** + * Starts the collection of loaded files. + * + * @since Method available since Release 3.3.0 + */ + public static function collectStart() + { + self::$buffer = get_included_files(); + } + + /** + * Stops the collection of loaded files and + * returns the names of the loaded files. + * + * @return array + * @since Method available since Release 3.3.0 + */ + public static function collectEnd() + { + return array_values( + array_diff(get_included_files(), self::$buffer) + ); + } + + /** + * Stops the collection of loaded files and adds + * the names of the loaded files to the blacklist. + * + * @return array + * @since Method available since Release 3.4.6 + */ + public static function collectEndAndAddToBlacklist() + { + foreach (self::collectEnd() as $blacklistedFile) { + PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist( + $blacklistedFile, 'PHPUNIT' + ); + } + } + + /** + * Implementation of stream_resolve_include_path() in PHP + * for version before PHP 5.3.2. + * + * @param string $file + * @return mixed + * @author Mattis Stordalen Flister + * @since Method available since Release 3.2.9 + */ + public static function fileExistsInIncludePath($file) + { + if (function_exists('stream_resolve_include_path')) { + return stream_resolve_include_path($file); + } + + if (file_exists($file)) { + return realpath($file); + } + + $paths = explode(PATH_SEPARATOR, get_include_path()); + + foreach ($paths as $path) { + $fullpath = $path . DIRECTORY_SEPARATOR . $file; + + if (file_exists($fullpath)) { + return realpath($fullpath); + } + } + + return FALSE; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Filter.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Filter.php new file mode 100644 index 0000000..ab48ba8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Filter.php @@ -0,0 +1,138 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +require_once 'File/Iterator/Factory.php'; + +/** + * Utility class for code filtering. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +class PHPUnit_Util_Filter +{ + /** + * Filters stack frames from PHPUnit classes. + * + * @param Exception $e + * @param boolean $filterTests + * @param boolean $asString + * @return string + */ + public static function getFilteredStacktrace(Exception $e, $filterTests = TRUE, $asString = TRUE) + { + if ($asString === TRUE) { + $filteredStacktrace = ''; + } else { + $filteredStacktrace = array(); + } + + $groups = array('DEFAULT'); + + if (!defined('PHPUNIT_TESTSUITE')) { + $groups[] = 'PHPUNIT'; + } + + if ($filterTests) { + $groups[] = 'TESTS'; + } + + if ($e instanceof PHPUnit_Framework_SyntheticError) { + $eTrace = $e->getSyntheticTrace(); + } else { + $eTrace = $e->getTrace(); + } + + if (!self::frameExists($eTrace, $e->getFile(), $e->getLine())) { + array_unshift( + $eTrace, array('file' => $e->getFile(), 'line' => $e->getLine()) + ); + } + + foreach ($eTrace as $frame) { + if (isset($frame['file']) && is_file($frame['file']) && + !PHP_CodeCoverage::getInstance()->filter()->isFiltered( + $frame['file'], $groups, TRUE)) { + if ($asString === TRUE) { + $filteredStacktrace .= sprintf( + "%s:%s\n", + + $frame['file'], + isset($frame['line']) ? $frame['line'] : '?' + ); + } else { + $filteredStacktrace[] = $frame; + } + } + } + + return $filteredStacktrace; + } + + /** + * @param array $trace + * @param string $file + * @param int $line + * @return boolean + * @since Method available since Release 3.3.2 + */ + public static function frameExists(array $trace, $file, $line) + { + foreach ($trace as $frame) { + if (isset($frame['file']) && $frame['file'] == $file && + isset($frame['line']) && $frame['line'] == $line) { + return TRUE; + } + } + + return FALSE; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Getopt.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Getopt.php new file mode 100644 index 0000000..d04c888 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Getopt.php @@ -0,0 +1,208 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Command-line options parsing class. + * + * @package PHPUnit + * @subpackage Util + * @author Andrei Zmievski + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Util_Getopt +{ + public static function getopt(array $args, $short_options, $long_options = NULL) + { + if (empty($args)) { + return array(array(), array()); + } + + $opts = array(); + $non_opts = array(); + + if ($long_options) { + sort($long_options); + } + + if (isset($args[0][0]) && $args[0][0] != '-') { + array_shift($args); + } + + reset($args); + array_map('trim', $args); + + while (list($i, $arg) = each($args)) { + if ($arg == '') { + continue; + } + + if ($arg == '--') { + $non_opts = array_merge($non_opts, array_slice($args, $i + 1)); + break; + } + + if ($arg[0] != '-' || + (strlen($arg) > 1 && $arg[1] == '-' && !$long_options)) { + $non_opts = array_merge($non_opts, array_slice($args, $i)); + break; + } + + elseif (strlen($arg) > 1 && $arg[1] == '-') { + self::parseLongOption( + substr($arg, 2), $long_options, $opts, $args + ); + } + + else { + self::parseShortOption( + substr($arg, 1), $short_options, $opts, $args + ); + } + } + + return array($opts, $non_opts); + } + + protected static function parseShortOption($arg, $short_options, &$opts, &$args) + { + $argLen = strlen($arg); + + for ($i = 0; $i < $argLen; $i++) { + $opt = $arg[$i]; + $opt_arg = NULL; + + if (($spec = strstr($short_options, $opt)) === FALSE || + $arg[$i] == ':') { + throw new PHPUnit_Framework_Exception( + "unrecognized option -- $opt" + ); + } + + if (strlen($spec) > 1 && $spec[1] == ':') { + if (strlen($spec) > 2 && $spec[2] == ':') { + if ($i + 1 < $argLen) { + $opts[] = array($opt, substr($arg, $i + 1)); + break; + } + } else { + if ($i + 1 < $argLen) { + $opts[] = array($opt, substr($arg, $i + 1)); + break; + } + + else if (list(, $opt_arg) = each($args)) { + } + + else { + throw new PHPUnit_Framework_Exception( + "option requires an argument -- $opt" + ); + } + } + } + + $opts[] = array($opt, $opt_arg); + } + } + + protected static function parseLongOption($arg, $long_options, &$opts, &$args) + { + $count = count($long_options); + $list = explode('=', $arg); + $opt = $list[0]; + $opt_arg = NULL; + + if (count($list) > 1) { + $opt_arg = $list[1]; + } + + $opt_len = strlen($opt); + + for ($i = 0; $i < $count; $i++) { + $long_opt = $long_options[$i]; + $opt_start = substr($long_opt, 0, $opt_len); + + if ($opt_start != $opt) { + continue; + } + + $opt_rest = substr($long_opt, $opt_len); + + if ($opt_rest != '' && $opt[0] != '=' && $i + 1 < $count && + $opt == substr($long_options[$i+1], 0, $opt_len)) { + throw new PHPUnit_Framework_Exception( + "option --$opt is ambiguous" + ); + } + + if (substr($long_opt, -1) == '=') { + if (substr($long_opt, -2) != '==') { + if (!strlen($opt_arg) && + !(list(, $opt_arg) = each($args))) { + throw new PHPUnit_Framework_Exception( + "option --$opt requires an argument" + ); + } + } + } + + else if ($opt_arg) { + throw new PHPUnit_Framework_Exception( + "option --$opt doesn't allow an argument" + ); + } + + $opts[] = array('--' . $opt, $opt_arg); + return; + } + + throw new PHPUnit_Framework_Exception("unrecognized option --$opt"); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/GlobalState.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/GlobalState.php new file mode 100644 index 0000000..1cacc5a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/GlobalState.php @@ -0,0 +1,354 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.4.0 + */ + +/** + * + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.4.0 + */ +class PHPUnit_Util_GlobalState +{ + /** + * @var array + */ + protected static $globals = array(); + + /** + * @var array + */ + protected static $staticAttributes = array(); + + /** + * @var array + */ + protected static $superGlobalArrays = array( + '_ENV', + '_POST', + '_GET', + '_COOKIE', + '_SERVER', + '_FILES', + '_REQUEST' + ); + + /** + * @var array + */ + protected static $superGlobalArraysLong = array( + 'HTTP_ENV_VARS', + 'HTTP_POST_VARS', + 'HTTP_GET_VARS', + 'HTTP_COOKIE_VARS', + 'HTTP_SERVER_VARS', + 'HTTP_POST_FILES' + ); + + public static function backupGlobals(array $blacklist) + { + self::$globals = array(); + $superGlobalArrays = self::getSuperGlobalArrays(); + + foreach ($superGlobalArrays as $superGlobalArray) { + if (!in_array($superGlobalArray, $blacklist)) { + self::backupSuperGlobalArray($superGlobalArray); + } + } + + foreach (array_keys($GLOBALS) as $key) { + if ($key != 'GLOBALS' && + !in_array($key, $superGlobalArrays) && + !in_array($key, $blacklist)) { + self::$globals['GLOBALS'][$key] = serialize($GLOBALS[$key]); + } + } + } + + public static function restoreGlobals(array $blacklist) + { + if (ini_get('register_long_arrays') == '1') { + $superGlobalArrays = array_merge( + self::$superGlobalArrays, self::$superGlobalArraysLong + ); + } else { + $superGlobalArrays = self::$superGlobalArrays; + } + + foreach ($superGlobalArrays as $superGlobalArray) { + if (!in_array($superGlobalArray, $blacklist)) { + self::restoreSuperGlobalArray($superGlobalArray); + } + } + + foreach (array_keys($GLOBALS) as $key) { + if ($key != 'GLOBALS' && + !in_array($key, $superGlobalArrays) && + !in_array($key, $blacklist)) { + if (isset(self::$globals['GLOBALS'][$key])) { + $GLOBALS[$key] = unserialize( + self::$globals['GLOBALS'][$key] + ); + } else { + unset($GLOBALS[$key]); + } + } + } + + self::$globals = array(); + } + + protected static function backupSuperGlobalArray($superGlobalArray) + { + self::$globals[$superGlobalArray] = array(); + + if (isset($GLOBALS[$superGlobalArray]) && + is_array($GLOBALS[$superGlobalArray])) { + foreach ($GLOBALS[$superGlobalArray] as $key => $value) { + self::$globals[$superGlobalArray][$key] = serialize($value); + } + } + } + + protected static function restoreSuperGlobalArray($superGlobalArray) + { + if (isset($GLOBALS[$superGlobalArray]) && + is_array($GLOBALS[$superGlobalArray]) && + isset(self::$globals[$superGlobalArray])) { + $keys = array_keys( + array_merge( + $GLOBALS[$superGlobalArray], self::$globals[$superGlobalArray] + ) + ); + + foreach ($keys as $key) { + if (isset(self::$globals[$superGlobalArray][$key])) { + $GLOBALS[$superGlobalArray][$key] = unserialize( + self::$globals[$superGlobalArray][$key] + ); + } else { + unset($GLOBALS[$superGlobalArray][$key]); + } + } + } + + self::$globals[$superGlobalArray] = array(); + } + + public static function getIncludedFilesAsString() + { + $blacklist = PHP_CodeCoverage::getInstance()->filter()->getBlacklist(); + $blacklist = array_flip($blacklist['PHPUNIT']); + $files = get_included_files(); + $result = ''; + + for ($i = count($files) - 1; $i > 0; $i--) { + if (!isset($blacklist[$files[$i]]) && is_file($files[$i])) { + $result = 'require_once \'' . $files[$i] . "';\n" . $result; + } + } + + return $result; + } + + public static function getConstantsAsString() + { + $constants = get_defined_constants(TRUE); + $result = ''; + + if (isset($constants['user'])) { + foreach ($constants['user'] as $name => $value) { + $result .= sprintf( + 'if (!defined(\'%s\')) define(\'%s\', %s);' . "\n", + $name, + $name, + self::exportVariable($value) + ); + } + } + + return $result; + } + + public static function getGlobalsAsString() + { + $result = ''; + $superGlobalArrays = self::getSuperGlobalArrays(); + + foreach ($superGlobalArrays as $superGlobalArray) { + if (isset($GLOBALS[$superGlobalArray]) && + is_array($GLOBALS[$superGlobalArray])) { + foreach (array_keys($GLOBALS[$superGlobalArray]) as $key) { + $result .= sprintf( + '$GLOBALS[\'%s\'][\'%s\'] = %s;' . "\n", + $superGlobalArray, + $key, + self::exportVariable($GLOBALS[$superGlobalArray][$key]) + ); + } + } + } + + $blacklist = $superGlobalArrays; + $blacklist[] = 'GLOBALS'; + $blacklist[] = '_PEAR_Config_instance'; + + foreach (array_keys($GLOBALS) as $key) { + if (!in_array($key, $blacklist)) { + $result .= sprintf( + '$GLOBALS[\'%s\'] = %s;' . "\n", + $key, + self::exportVariable($GLOBALS[$key]) + ); + } + } + + return $result; + } + + protected static function getSuperGlobalArrays() + { + if (ini_get('register_long_arrays') == '1') { + return array_merge( + self::$superGlobalArrays, self::$superGlobalArraysLong + ); + } else { + return self::$superGlobalArrays; + } + } + + public static function backupStaticAttributes(array $blacklist) + { + self::$staticAttributes = array(); + $declaredClasses = get_declared_classes(); + $declaredClassesNum = count($declaredClasses); + + for ($i = $declaredClassesNum - 1; $i >= 0; $i--) { + if (strpos($declaredClasses[$i], 'PHPUnit') !== 0 && + strpos($declaredClasses[$i], 'File_Iterator') !== 0 && + strpos($declaredClasses[$i], 'PHP_CodeCoverage') !== 0 && + strpos($declaredClasses[$i], 'PHP_Timer') !== 0 && + strpos($declaredClasses[$i], 'PHP_TokenStream') !== 0 && + strpos($declaredClasses[$i], 'sfYaml') !== 0 && + strpos($declaredClasses[$i], 'Text_Template') !== 0 && + !$declaredClasses[$i] instanceof PHPUnit_Framework_Test) { + $class = new ReflectionClass($declaredClasses[$i]); + + if (!$class->isUserDefined()) { + break; + } + + $backup = array(); + + foreach ($class->getProperties() as $attribute) { + if ($attribute->isStatic()) { + $name = $attribute->getName(); + + if (!isset($blacklist[$declaredClasses[$i]]) || + !in_array($name, $blacklist[$declaredClasses[$i]])) { + $attribute->setAccessible(TRUE); + $backup[$name] = serialize($attribute->getValue()); + } + } + } + + if (!empty($backup)) { + self::$staticAttributes[$declaredClasses[$i]] = $backup; + } + } + } + } + + public static function restoreStaticAttributes() + { + foreach (self::$staticAttributes as $className => $staticAttributes) { + foreach ($staticAttributes as $name => $value) { + $reflector = new ReflectionProperty($className, $name); + $reflector->setAccessible(TRUE); + $reflector->setValue(unserialize($value)); + } + } + + self::$staticAttributes = array(); + } + + protected static function exportVariable($variable) + { + if (is_scalar($variable) || is_null($variable) || + (is_array($variable) && self::arrayOnlyContainsScalars($variable))) { + return var_export($variable, TRUE); + } + + return 'unserialize(\'' . + str_replace("'", "\'", serialize($variable)) . + '\')'; + } + + protected static function arrayOnlyContainsScalars(array $array) + { + $result = TRUE; + + foreach ($array as $element) { + if (is_array($element)) { + $result = self::arrayOnlyContainsScalars($element); + } + + else if (!is_scalar($element) && !is_null($element)) { + $result = FALSE; + } + + if ($result === FALSE) { + break; + } + } + + return $result; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/InvalidArgumentHelper.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/InvalidArgumentHelper.php new file mode 100644 index 0000000..1465f30 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/InvalidArgumentHelper.php @@ -0,0 +1,80 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.4.0 + */ + +/** + * Factory for InvalidArgumentException objects. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.4.0 + */ +class PHPUnit_Util_InvalidArgumentHelper +{ + /** + * @param integer $argument + * @param string $type + * @param mixed $value + */ + public static function factory($argument, $type, $value = NULL) + { + $stack = debug_backtrace(FALSE); + + return new InvalidArgumentException( + sprintf( + 'Argument #%d%sof %s::%s() must be a %s', + $argument, + $value !== NULL ? ' (' . $value . ')' : ' ', + $stack[1]['class'], + $stack[1]['function'], + $type + ) + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/DBUS.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/DBUS.php new file mode 100644 index 0000000..83464a7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/DBUS.php @@ -0,0 +1,236 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util_Log + * @author Benjamin Eberlei + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.5.0 + */ + +/** + * A TestListener that integrates with DBUS. + * + * @package PHPUnit + * @subpackage Util_Log + * @author Benjamin Eberlei + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.5.0 + */ +class PHPUnit_Util_Log_DBUS implements PHPUnit_Framework_TestListener +{ + /** + * @var integer + */ + protected $errors = 0; + + /** + * @var integer + */ + protected $failures = 0; + + /** + * @var integer + */ + protected $startTime = NULL; + + /** + * @var string + */ + protected $suiteName = ''; + + /** + * @var integer + */ + protected $tests = 0; + + /** + * @var integer + */ + protected $startedSuites = 0; + + /** + * @var integer + */ + protected $endedSuites = 0; + + /** + * + */ + public function __construct() + { + if (!extension_loaded('dbus')) { + throw new RuntimeException('ext/dbus is not available'); + } + } + + /** + * An error occurred. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) + { + $this->errors++; + } + + /** + * A failure occurred. + * + * @param PHPUnit_Framework_Test $test + * @param PHPUnit_Framework_AssertionFailedError $e + * @param float $time + */ + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) + { + $this->failures++; + } + + /** + * Incomplete test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + } + + /** + * Skipped test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + * @since Method available since Release 3.0.0 + */ + public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + } + + /** + * A test suite started. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit_Framework_TestSuite $suite) + { + if($this->startedSuites == 0) { + $this->startTime = time(); + $this->suiteName = $suite->getName(); + } + + $this->startedSuites++; + } + + /** + * A test suite ended. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit_Framework_TestSuite $suite) + { + $this->endedSuites++; + + if($this->startedSuites <= $this->endedSuites) { + $this->notify(); + } + } + + /** + * A test started. + * + * @param PHPUnit_Framework_Test $test + */ + public function startTest(PHPUnit_Framework_Test $test) + { + $this->tests++; + } + + /** + * A test ended. + * + * @param PHPUnit_Framework_Test $test + * @param float $time + */ + public function endTest(PHPUnit_Framework_Test $test, $time) + { + } + + /** + * + */ + protected function notify() + { + $d = new Dbus(Dbus::BUS_SESSION); + + $n = $d->createProxy( + 'org.freedesktop.Notifications', + '/org/freedesktop/Notifications', + 'org.freedesktop.Notifications' + ); + + $n->Notify( + 'PHPUnit_Util_Log_DBUS', + new DBusUInt32(0), + 'phpunit', + 'PHPUnit Test Report', + sprintf( + "Suite: %s\n%d tests run in %s minutes.\n%d errors, %d failures", + $this->suiteName, + $this->tests, + (date('i:s', time() - $this->startTime)), + $this->errors, + $this->failures + ), + new DBusArray(DBus::STRING, array()), + new DBusDict(DBus::VARIANT, array()), + 1000 + ); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/JSON.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/JSON.php new file mode 100644 index 0000000..ba21be5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/JSON.php @@ -0,0 +1,240 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util_Log + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * A TestListener that generates JSON messages. + * + * @package PHPUnit + * @subpackage Util_Log + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Util_Log_JSON extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener +{ + /** + * @var string + */ + protected $currentTestSuiteName = ''; + + /** + * @var string + */ + protected $currentTestName = ''; + + /** + * @var boolean + * @access private + */ + protected $currentTestPass = TRUE; + + /** + * An error occurred. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) + { + $this->writeCase( + 'error', + $time, + PHPUnit_Util_Filter::getFilteredStacktrace( + $e, + TRUE, + FALSE + ), + $e->getMessage() + ); + + $this->currentTestPass = FALSE; + } + + /** + * A failure occurred. + * + * @param PHPUnit_Framework_Test $test + * @param PHPUnit_Framework_AssertionFailedError $e + * @param float $time + */ + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) + { + $this->writeCase( + 'fail', + $time, + PHPUnit_Util_Filter::getFilteredStacktrace( + $e, + TRUE, + FALSE + ), + $e->getMessage() + ); + + $this->currentTestPass = FALSE; + } + + /** + * Incomplete test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + $this->writeCase('error', $time, array(), 'Incomplete Test'); + + $this->currentTestPass = FALSE; + } + + /** + * Skipped test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + $this->writeCase('error', $time, array(), 'Skipped Test'); + + $this->currentTestPass = FALSE; + } + + /** + * A testsuite started. + * + * @param PHPUnit_Framework_TestSuite $suite + */ + public function startTestSuite(PHPUnit_Framework_TestSuite $suite) + { + $this->currentTestSuiteName = $suite->getName(); + $this->currentTestName = ''; + + $this->write( + array( + 'event' => 'suiteStart', + 'suite' => $this->currentTestSuiteName, + 'tests' => count($suite) + ) + ); + } + + /** + * A testsuite ended. + * + * @param PHPUnit_Framework_TestSuite $suite + */ + public function endTestSuite(PHPUnit_Framework_TestSuite $suite) + { + $this->currentTestSuiteName = ''; + $this->currentTestName = ''; + } + + /** + * A test started. + * + * @param PHPUnit_Framework_Test $test + */ + public function startTest(PHPUnit_Framework_Test $test) + { + $this->currentTestName = PHPUnit_Util_Test::describe($test); + $this->currentTestPass = TRUE; + + $this->write( + array( + 'event' => 'testStart', + 'suite' => $this->currentTestSuiteName, + 'test' => $this->currentTestName + ) + ); + } + + /** + * A test ended. + * + * @param PHPUnit_Framework_Test $test + * @param float $time + */ + public function endTest(PHPUnit_Framework_Test $test, $time) + { + if ($this->currentTestPass) { + $this->writeCase('pass', $time); + } + } + + /** + * @param string $status + * @param float $time + * @param array $trace + * @param string $message + */ + protected function writeCase($status, $time, array $trace = array(), $message = '') + { + $this->write( + array( + 'event' => 'test', + 'suite' => $this->currentTestSuiteName, + 'test' => $this->currentTestName, + 'status' => $status, + 'time' => $time, + 'trace' => $trace, + 'message' => $message + ) + ); + } + + /** + * @param string $buffer + */ + public function write($buffer) + { + parent::write(json_encode($buffer)); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/JUnit.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/JUnit.php new file mode 100644 index 0000000..b56f475 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/JUnit.php @@ -0,0 +1,485 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util_Log + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.3.0 + */ + +/** + * A TestListener that generates a logfile of the test execution in XML markup. + * + * The XML markup used is the same as the one that is used by the JUnit Ant task. + * + * @package PHPUnit + * @subpackage Util_Log + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.1.0 + */ +class PHPUnit_Util_Log_JUnit extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener +{ + /** + * @var DOMDocument + */ + protected $document; + + /** + * @var DOMElement + */ + protected $root; + + /** + * @var boolean + */ + protected $logIncompleteSkipped = FALSE; + + /** + * @var boolean + */ + protected $writeDocument = TRUE; + + /** + * @var DOMElement[] + */ + protected $testSuites = array(); + + /** + * @var integer[] + */ + protected $testSuiteTests = array(0); + + /** + * @var integer[] + */ + protected $testSuiteAssertions = array(0); + + /** + * @var integer[] + */ + protected $testSuiteErrors = array(0); + + /** + * @var integer[] + */ + protected $testSuiteFailures = array(0); + + /** + * @var integer[] + */ + protected $testSuiteTimes = array(0); + + /** + * @var integer + */ + protected $testSuiteLevel = 0; + + /** + * @var DOMElement + */ + protected $currentTestCase = NULL; + + /** + * @var boolean + */ + protected $attachCurrentTestCase = TRUE; + + /** + * Constructor. + * + * @param mixed $out + * @param boolean $logIncompleteSkipped + */ + public function __construct($out = NULL, $logIncompleteSkipped = FALSE) + { + $this->document = new DOMDocument('1.0', 'UTF-8'); + $this->document->formatOutput = TRUE; + + $this->root = $this->document->createElement('testsuites'); + $this->document->appendChild($this->root); + + parent::__construct($out); + + $this->logIncompleteSkipped = $logIncompleteSkipped; + } + + /** + * Flush buffer and close output. + * + */ + public function flush() + { + if ($this->writeDocument === TRUE) { + $this->write($this->getXML()); + } + + parent::flush(); + } + + /** + * An error occurred. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) + { + if ($this->currentTestCase !== NULL) { + if ($test instanceof PHPUnit_Framework_SelfDescribing) { + $buffer = $test->toString() . "\n"; + } else { + $buffer = ''; + } + + $buffer .= PHPUnit_Framework_TestFailure::exceptionToString($e) . + "\n" . + PHPUnit_Util_Filter::getFilteredStacktrace($e, FALSE); + + $error = $this->document->createElement( + 'error', PHPUnit_Util_XML::prepareString($buffer) + ); + + $error->setAttribute('type', get_class($e)); + + $this->currentTestCase->appendChild($error); + + $this->testSuiteErrors[$this->testSuiteLevel]++; + } + } + + /** + * A failure occurred. + * + * @param PHPUnit_Framework_Test $test + * @param PHPUnit_Framework_AssertionFailedError $e + * @param float $time + */ + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) + { + if ($this->currentTestCase !== NULL) { + if (!$test instanceof PHPUnit_Framework_Warning) { + if ($test instanceof PHPUnit_Framework_SelfDescribing) { + $buffer = $test->toString() . "\n"; + } else { + $buffer = ''; + } + + $buffer .= PHPUnit_Framework_TestFailure::exceptionToString($e). + "\n" . + PHPUnit_Util_Filter::getFilteredStacktrace( + $e, FALSE + ); + + $failure = $this->document->createElement( + 'failure', PHPUnit_Util_XML::prepareString($buffer) + ); + + $failure->setAttribute('type', get_class($e)); + + $this->currentTestCase->appendChild($failure); + + $this->testSuiteFailures[$this->testSuiteLevel]++; + } + } + } + + /** + * Incomplete test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + if ($this->logIncompleteSkipped && $this->currentTestCase !== NULL) { + $error = $this->document->createElement( + 'error', + PHPUnit_Util_XML::prepareString( + "Incomplete Test\n" . + PHPUnit_Util_Filter::getFilteredStacktrace($e, FALSE) + ) + ); + + $error->setAttribute('type', get_class($e)); + + $this->currentTestCase->appendChild($error); + + $this->testSuiteErrors[$this->testSuiteLevel]++; + } else { + $this->attachCurrentTestCase = FALSE; + } + } + + /** + * Skipped test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + * @since Method available since Release 3.0.0 + */ + public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + if ($this->logIncompleteSkipped && $this->currentTestCase !== NULL) { + $error = $this->document->createElement( + 'error', + PHPUnit_Util_XML::prepareString( + "Skipped Test\n" . + PHPUnit_Util_Filter::getFilteredStacktrace($e, FALSE) + ) + ); + + $error->setAttribute('type', get_class($e)); + + $this->currentTestCase->appendChild($error); + + $this->testSuiteErrors[$this->testSuiteLevel]++; + } else { + $this->attachCurrentTestCase = FALSE; + } + } + + /** + * A testsuite started. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit_Framework_TestSuite $suite) + { + $testSuite = $this->document->createElement('testsuite'); + $testSuite->setAttribute('name', $suite->getName()); + + if (class_exists($suite->getName(), FALSE)) { + try { + $class = new ReflectionClass($suite->getName()); + + $testSuite->setAttribute('file', $class->getFileName()); + + $packageInformation = PHPUnit_Util_Class::getPackageInformation( + $suite->getName(), $class->getDocComment() + ); + + if (!empty($packageInformation['namespace'])) { + $testSuite->setAttribute( + 'namespace', $packageInformation['namespace'] + ); + } + + if (!empty($packageInformation['fullPackage'])) { + $testSuite->setAttribute( + 'fullPackage', $packageInformation['fullPackage'] + ); + } + + if (!empty($packageInformation['category'])) { + $testSuite->setAttribute( + 'category', $packageInformation['category'] + ); + } + + if (!empty($packageInformation['package'])) { + $testSuite->setAttribute( + 'package', $packageInformation['package'] + ); + } + + if (!empty($packageInformation['subpackage'])) { + $testSuite->setAttribute( + 'subpackage', $packageInformation['subpackage'] + ); + } + } + + catch (ReflectionException $e) { + } + } + + if ($this->testSuiteLevel > 0) { + $this->testSuites[$this->testSuiteLevel]->appendChild($testSuite); + } else { + $this->root->appendChild($testSuite); + } + + $this->testSuiteLevel++; + $this->testSuites[$this->testSuiteLevel] = $testSuite; + $this->testSuiteTests[$this->testSuiteLevel] = 0; + $this->testSuiteAssertions[$this->testSuiteLevel] = 0; + $this->testSuiteErrors[$this->testSuiteLevel] = 0; + $this->testSuiteFailures[$this->testSuiteLevel] = 0; + $this->testSuiteTimes[$this->testSuiteLevel] = 0; + } + + /** + * A testsuite ended. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit_Framework_TestSuite $suite) + { + $this->testSuites[$this->testSuiteLevel]->setAttribute( + 'tests', $this->testSuiteTests[$this->testSuiteLevel] + ); + + $this->testSuites[$this->testSuiteLevel]->setAttribute( + 'assertions', $this->testSuiteAssertions[$this->testSuiteLevel] + ); + + $this->testSuites[$this->testSuiteLevel]->setAttribute( + 'failures', $this->testSuiteFailures[$this->testSuiteLevel] + ); + + $this->testSuites[$this->testSuiteLevel]->setAttribute( + 'errors', $this->testSuiteErrors[$this->testSuiteLevel] + ); + + $this->testSuites[$this->testSuiteLevel]->setAttribute( + 'time', sprintf('%F', $this->testSuiteTimes[$this->testSuiteLevel]) + ); + + if ($this->testSuiteLevel > 1) { + $this->testSuiteTests[$this->testSuiteLevel - 1] += $this->testSuiteTests[$this->testSuiteLevel]; + $this->testSuiteAssertions[$this->testSuiteLevel - 1] += $this->testSuiteAssertions[$this->testSuiteLevel]; + $this->testSuiteErrors[$this->testSuiteLevel - 1] += $this->testSuiteErrors[$this->testSuiteLevel]; + $this->testSuiteFailures[$this->testSuiteLevel - 1] += $this->testSuiteFailures[$this->testSuiteLevel]; + $this->testSuiteTimes[$this->testSuiteLevel - 1] += $this->testSuiteTimes[$this->testSuiteLevel]; + } + + $this->testSuiteLevel--; + } + + /** + * A test started. + * + * @param PHPUnit_Framework_Test $test + */ + public function startTest(PHPUnit_Framework_Test $test) + { + if (!$test instanceof PHPUnit_Framework_Warning) { + $testCase = $this->document->createElement('testcase'); + $testCase->setAttribute('name', $test->getName()); + + if ($test instanceof PHPUnit_Framework_TestCase) { + $class = new ReflectionClass($test); + $methodName = $test->getName(); + + if ($class->hasMethod($methodName)) { + $method = $class->getMethod($test->getName()); + + $testCase->setAttribute('class', $class->getName()); + $testCase->setAttribute('file', $class->getFileName()); + $testCase->setAttribute('line', $method->getStartLine()); + } + } + + $this->currentTestCase = $testCase; + } + } + + /** + * A test ended. + * + * @param PHPUnit_Framework_Test $test + * @param float $time + */ + public function endTest(PHPUnit_Framework_Test $test, $time) + { + if (!$test instanceof PHPUnit_Framework_Warning) { + if ($this->attachCurrentTestCase) { + if ($test instanceof PHPUnit_Framework_TestCase) { + $numAssertions = $test->getNumAssertions(); + $this->testSuiteAssertions[$this->testSuiteLevel] += $numAssertions; + + $this->currentTestCase->setAttribute( + 'assertions', $numAssertions + ); + } + + $this->currentTestCase->setAttribute( + 'time', sprintf('%F', $time) + ); + + $this->testSuites[$this->testSuiteLevel]->appendChild( + $this->currentTestCase + ); + + $this->testSuiteTests[$this->testSuiteLevel]++; + $this->testSuiteTimes[$this->testSuiteLevel] += $time; + } + } + + $this->attachCurrentTestCase = TRUE; + $this->currentTestCase = NULL; + } + + /** + * Returns the XML as a string. + * + * @return string + * @since Method available since Release 2.2.0 + */ + public function getXML() + { + return $this->document->saveXML(); + } + + /** + * Enables or disables the writing of the document + * in flush(). + * + * This is a "hack" needed for the integration of + * PHPUnit with Phing. + * + * @return string + * @since Method available since Release 2.2.0 + */ + public function setWriteDocument($flag) + { + if (is_bool($flag)) { + $this->writeDocument = $flag; + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/TAP.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/TAP.php new file mode 100644 index 0000000..1796b26 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/TAP.php @@ -0,0 +1,253 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util_Log + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +require_once 'SymfonyComponents/YAML/sfYamlDumper.php'; + +/** + * A TestListener that generates a logfile of the + * test execution using the Test Anything Protocol (TAP). + * + * @package PHPUnit + * @subpackage Util_Log + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Util_Log_TAP extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener +{ + /** + * @var integer + */ + protected $testNumber = 0; + + /** + * @var integer + */ + protected $testSuiteLevel = 0; + + /** + * @var boolean + */ + protected $testSuccessful = TRUE; + + /** + * Constructor. + * + * @param mixed $out + * @throws InvalidArgumentException + * @since Method available since Release 3.3.4 + */ + public function __construct($out = NULL) + { + parent::__construct($out); + $this->write("TAP version 13\n"); + } + + /** + * An error occurred. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) + { + $this->writeNotOk($test, 'Error'); + } + + /** + * A failure occurred. + * + * @param PHPUnit_Framework_Test $test + * @param PHPUnit_Framework_AssertionFailedError $e + * @param float $time + */ + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) + { + $this->writeNotOk($test, 'Failure'); + + $message = explode( + "\n", PHPUnit_Framework_TestFailure::exceptionToString($e) + ); + + $diagnostic = array( + 'message' => $message[0], + 'severity' => 'fail' + ); + + if ($e instanceof PHPUnit_Framework_ExpectationFailedException) { + $cf = $e->getComparisonFailure(); + + if ($cf !== NULL) { + $diagnostic['data'] = array( + 'got' => $cf->getActual(), + 'expected' => $cf->getExpected() + ); + } + } + + $yaml = new sfYamlDumper(); + + $this->write( + sprintf( + " ---\n%s ...\n", + $yaml->dump($diagnostic, 2, 2) + ) + ); + } + + /** + * Incomplete test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + $this->writeNotOk($test, '', 'TODO Incomplete Test'); + } + + /** + * Skipped test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + * @since Method available since Release 3.0.0 + */ + public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + $this->write( + sprintf( + "ok %d - # SKIP%s\n", + + $this->testNumber, + $e->getMessage() != '' ? ' ' . $e->getMessage() : '' + ) + ); + + $this->testSuccessful = FALSE; + } + + /** + * A testsuite started. + * + * @param PHPUnit_Framework_TestSuite $suite + */ + public function startTestSuite(PHPUnit_Framework_TestSuite $suite) + { + $this->testSuiteLevel++; + } + + /** + * A testsuite ended. + * + * @param PHPUnit_Framework_TestSuite $suite + */ + public function endTestSuite(PHPUnit_Framework_TestSuite $suite) + { + $this->testSuiteLevel--; + + if ($this->testSuiteLevel == 0) { + $this->write(sprintf("1..%d\n", $this->testNumber)); + } + } + + /** + * A test started. + * + * @param PHPUnit_Framework_Test $test + */ + public function startTest(PHPUnit_Framework_Test $test) + { + $this->testNumber++; + $this->testSuccessful = TRUE; + } + + /** + * A test ended. + * + * @param PHPUnit_Framework_Test $test + * @param float $time + */ + public function endTest(PHPUnit_Framework_Test $test, $time) + { + if ($this->testSuccessful === TRUE) { + $this->write( + sprintf( + "ok %d - %s\n", + + $this->testNumber, + PHPUnit_Util_Test::describe($test) + ) + ); + } + } + + /** + * @param PHPUnit_Framework_Test $test + * @param string $prefix + * @param string $directive + */ + protected function writeNotOk(PHPUnit_Framework_Test $test, $prefix = '', $directive = '') + { + $this->write( + sprintf( + "not ok %d - %s%s%s\n", + + $this->testNumber, + $prefix != '' ? $prefix . ': ' : '', + PHPUnit_Util_Test::describe($test), + $directive != '' ? ' # ' . $directive : '' + ) + ); + + $this->testSuccessful = FALSE; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/XHProf.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/XHProf.php new file mode 100644 index 0000000..0e6084b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Log/XHProf.php @@ -0,0 +1,252 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util_Log + * @author Benjamin Eberlei + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.5.0 + */ + +/** + * A TestListener that integrates with XHProf. + * + * Here is an example XML configuration for activating this listener: + * + * + * + * + * + * + * + * /var/www/xhprof_lib/utils/xhprof_lib.php + * + * + * /var/www/xhprof_lib/utils/xhprof_runs.php + * + * + * http://localhost/xhprof_html/index.php + * + * + * Doctrine2 + * + * + * XHPROF_FLAGS_CPU,XHPROF_FLAGS_MEMORY + * + * + * + * + * + * + * + * @package PHPUnit + * @subpackage Util_Log + * @author Benjamin Eberlei + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.5.0 + */ +class PHPUnit_Util_Log_XHProf implements PHPUnit_Framework_TestListener +{ + /** + * @var array + */ + protected $runs = array(); + + /** + * @var array + */ + protected $options = array(); + + /** + * @var integer + */ + protected $suites = 0; + + /** + * Constructor. + * + * @param array $options + */ + public function __construct(array $options = array()) + { + if (!extension_loaded('xhprof')) { + throw new RuntimeException( + 'The XHProf extension is required for this listener to work.' + ); + } + + if (!isset($options['appNamespace'])) { + throw new InvalidArgumentException( + 'The "appNamespace" option is not set.' + ); + } + + if (!isset($options['xhprofLibFile']) || + !file_exists($options['xhprofLibFile'])) { + throw new InvalidArgumentException( + 'The "xhprofLibFile" option is not set or the configured file does not exist' + ); + } + + if (!isset($options['xhprofRunsFile']) || + !file_exists($options['xhprofRunsFile'])) { + throw new InvalidArgumentException( + 'The "xhprofRunsFile" option is not set or the configured file does not exist' + ); + } + + require_once $options['xhprofLibFile']; + require_once $options['xhprofRunsFile']; + + $this->options = $options; + } + + /** + * An error occurred. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) + { + } + + /** + * A failure occurred. + * + * @param PHPUnit_Framework_Test $test + * @param PHPUnit_Framework_AssertionFailedError $e + * @param float $time + */ + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) + { + } + + /** + * Incomplete test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + } + + /** + * Skipped test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + } + + /** + * A test started. + * + * @param PHPUnit_Framework_Test $test + */ + public function startTest(PHPUnit_Framework_Test $test) + { + if (!isset($this->options['xhprofFlags'])) { + $flags = XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY; + } else { + $flags = 0; + + foreach (explode(',', $this->options['xhprofFlags']) as $flag) { + $flags += constant($flag); + } + } + + xhprof_enable($flags); + } + + /** + * A test ended. + * + * @param PHPUnit_Framework_Test $test + * @param float $time + */ + public function endTest(PHPUnit_Framework_Test $test, $time) + { + $data = xhprof_disable(); + $runs = new XHProfRuns_Default; + $run = $runs->save_run($data, $this->options['appNamespace']); + $this->runs[] = $this->options['xhprofWeb'] . '?run=' . $run . + '&source=' . $this->options['appNamespace']; + } + + /** + * A test suite started. + * + * @param PHPUnit_Framework_TestSuite $suite + */ + public function startTestSuite(PHPUnit_Framework_TestSuite $suite) + { + $this->suites++; + } + + /** + * A test suite ended. + * + * @param PHPUnit_Framework_TestSuite $suite + */ + public function endTestSuite(PHPUnit_Framework_TestSuite $suite) + { + $this->suites--; + + if ($this->suites == 0) { + print "\n\nXHProf runs: " . count($this->runs) . "\n"; + + foreach ($this->runs as $run) { + print ' * ' . $run . "\n"; + } + + print "\n"; + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/PHP.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/PHP.php new file mode 100644 index 0000000..b50db20 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/PHP.php @@ -0,0 +1,277 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.4.0 + */ + +/** + * Utility methods for PHP sub-processes. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.4.0 + */ +abstract class PHPUnit_Util_PHP +{ + /** + * Path to the PHP interpreter that is to be used. + * + * @var string $phpBinary + */ + protected static $phpBinary = NULL; + + /** + * Returns the path to a PHP interpreter. + * + * PHPUnit_Util_PHP::$phpBinary contains the path to the PHP + * interpreter. + * + * When not set, the following assumptions will be made: + * + * 1. When the PHP CLI/CGI binary configured with the PEAR Installer + * (php_bin configuration value) is readable, it will be used. + * + * 2. When PHPUnit is run using the CLI SAPI and the $_SERVER['_'] + * variable does not contain the string "PHPUnit", $_SERVER['_'] + * is assumed to contain the path to the current PHP interpreter + * and that will be used. + * + * 3. When PHPUnit is run using the CLI SAPI and the $_SERVER['_'] + * variable contains the string "PHPUnit", the file that $_SERVER['_'] + * points to is assumed to be the PHPUnit TextUI CLI wrapper script + * "phpunit" and the binary set up using #! on that file's first + * line of code is assumed to contain the path to the current PHP + * interpreter and that will be used. + * + * 4. The current PHP interpreter is assumed to be in the $PATH and + * to be invokable through "php". + * + * @return string + */ + public static function getPhpBinary() + { + if (self::$phpBinary === NULL) { + if (is_readable('/usr/bin/php')) { + self::$phpBinary = '/usr/bin/php'; + } + + else if (PHP_SAPI == 'cli' && isset($_SERVER['_']) && + strpos($_SERVER['_'], 'phpunit') !== FALSE) { + $file = file($_SERVER['_']); + $tmp = explode(' ', $file[0]); + self::$phpBinary = trim($tmp[1]); + } + + if (!is_readable(self::$phpBinary)) { + self::$phpBinary = 'php'; + } else { + self::$phpBinary = escapeshellarg(self::$phpBinary); + } + } + + return self::$phpBinary; + } + + /** + * @return PHPUnit_Util_PHP + * @since Method available since Release 3.5.12 + */ + public static function factory() + { + if (DIRECTORY_SEPARATOR == '\\') { + return new PHPUnit_Util_PHP_Windows; + } + + return new PHPUnit_Util_PHP_Default; + } + + /** + * Runs a single job (PHP code) using a separate PHP process. + * + * @param string $job + * @param PHPUnit_Framework_TestCase $test + * @param PHPUnit_Framework_TestResult $result + * @return array|null + * @throws PHPUnit_Framework_Exception + */ + public function runJob($job, PHPUnit_Framework_Test $test = NULL, PHPUnit_Framework_TestResult $result = NULL) + { + $process = proc_open( + self::getPhpBinary(), + array( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w') + ), + $pipes + ); + + if (!is_resource($process)) { + throw new PHPUnit_Framework_Exception( + 'Unable to create process for process isolation.' + ); + } + + if ($result !== NULL) { + $result->startTest($test); + } + + $this->process($pipes[0], $job); + fclose($pipes[0]); + + $stdout = stream_get_contents($pipes[1]); + fclose($pipes[1]); + + $stderr = stream_get_contents($pipes[2]); + fclose($pipes[2]); + + proc_close($process); + $this->cleanup(); + + if ($result !== NULL) { + $this->processChildResult($test, $result, $stdout, $stderr); + } else { + return array('stdout' => $stdout, 'stderr' => $stderr); + } + } + + /** + * @param resource $pipe + * @param string $job + * @since Method available since Release 3.5.12 + */ + abstract protected function process($pipe, $job); + + /** + * @since Method available since Release 3.5.12 + */ + protected function cleanup() + { + } + + /** + * Processes the TestResult object from an isolated process. + * + * @param PHPUnit_Framework_TestCase $test + * @param PHPUnit_Framework_TestResult $result + * @param string $stdout + * @param string $stderr + * @since Method available since Release 3.5.0 + */ + protected function processChildResult(PHPUnit_Framework_Test $test, PHPUnit_Framework_TestResult $result, $stdout, $stderr) + { + if (!empty($stderr)) { + $time = 0; + $result->addError( + $test, + new RuntimeException(trim($stderr)), $time + ); + } else { + $childResult = @unserialize($stdout); + + if ($childResult !== FALSE) { + if (!empty($childResult['output'])) { + print $childResult['output']; + } + + $test->setResult($childResult['testResult']); + $test->addToAssertionCount($childResult['numAssertions']); + + $childResult = $childResult['result']; + + if ($result->getCollectCodeCoverageInformation()) { + $codeCoverageInformation = $childResult->getRawCodeCoverageInformation(); + + if (isset($codeCoverageInformation[0]) && + is_array($codeCoverageInformation[0])) { + $result->getCodeCoverage()->append( + $codeCoverageInformation[0], $test + ); + } + } + + $time = $childResult->time(); + $notImplemented = $childResult->notImplemented(); + $skipped = $childResult->skipped(); + $errors = $childResult->errors(); + $failures = $childResult->failures(); + + if (!empty($notImplemented)) { + $result->addError( + $test, $notImplemented[0]->thrownException(), $time + ); + } + + else if (!empty($skipped)) { + $result->addError( + $test, $skipped[0]->thrownException(), $time + ); + } + + else if (!empty($errors)) { + $result->addError( + $test, $errors[0]->thrownException(), $time + ); + } + + else if (!empty($failures)) { + $result->addFailure( + $test, $failures[0]->thrownException(), $time + ); + } + } else { + $time = 0; + + $result->addError( + $test, new RuntimeException(trim($stdout)), $time + ); + } + } + + $result->endTest($test, $time); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/PHP/Default.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/PHP/Default.php new file mode 100644 index 0000000..f0d99a7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/PHP/Default.php @@ -0,0 +1,68 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.5.12 + */ + +/** + * Default utility for PHP sub-processes. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.5.12 + */ +class PHPUnit_Util_PHP_Default extends PHPUnit_Util_PHP +{ + /** + * @param resource $pipe + * @since Method available since Release 3.5.12 + */ + protected function process($pipe, $job) + { + fwrite($pipe, $job); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/PHP/Windows.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/PHP/Windows.php new file mode 100644 index 0000000..3a3e0cf --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/PHP/Windows.php @@ -0,0 +1,91 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.5.12 + */ + +/** + * Windows utility for PHP sub-processes. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.5.12 + */ +class PHPUnit_Util_PHP_Windows extends PHPUnit_Util_PHP +{ + /** + * @var string + */ + protected $tempFile; + + /** + * @param resource $pipe + * @since Method available since Release 3.5.12 + */ + protected function process($pipe, $job) + { + if (!($this->tempFile = tempnam(sys_get_temp_dir(), 'PHPUnit')) || + file_put_contents($this->tempFile, $job) === FALSE) { + throw new PHPUnit_Framework_Exception( + 'Unable to write temporary files for process isolation.' + ); + } + + fwrite( + $pipe, + "tempFile, "'") . "'; ?>" + ); + } + + /** + * @since Method available since Release 3.5.12 + */ + protected function cleanup() + { + unlink($this->tempFile); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Printer.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Printer.php new file mode 100644 index 0000000..da0567c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Printer.php @@ -0,0 +1,209 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.0.0 + */ + +/** + * Utility class that can print to STDOUT or write to a file. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.0.0 + */ +abstract class PHPUnit_Util_Printer +{ + /** + * If TRUE, flush output after every write. + * + * @var boolean + */ + protected $autoFlush = FALSE; + + /** + * @var resource + */ + protected $out; + + /** + * @var string + */ + protected $outTarget; + + /** + * @var boolean + */ + protected $printsHTML = FALSE; + + /** + * Constructor. + * + * @param mixed $out + * @throws InvalidArgumentException + */ + public function __construct($out = NULL) + { + if ($out !== NULL) { + if (is_string($out)) { + if (strpos($out, 'socket://') === 0) { + $out = explode(':', str_replace('socket://', '', $out)); + + if (sizeof($out) != 2) { + throw new InvalidArgumentException; + } + + $this->out = fsockopen($out[0], $out[1]); + } else { + if (strpos($out, 'php://') === FALSE && + !is_dir(dirname($out))) { + mkdir(dirname($out), 0777, TRUE); + } + + $this->out = fopen($out, 'wt'); + } + + $this->outTarget = $out; + } else { + $this->out = $out; + } + } + } + + /** + * Flush buffer, optionally tidy up HTML, and close output. + */ + public function flush() + { + if ($this->out && $this->outTarget !== 'php://stderr') { + fclose($this->out); + } + + if ($this->printsHTML === TRUE && + $this->outTarget !== NULL && + strpos($this->outTarget, 'php://') !== 0 && + strpos($this->outTarget, 'socket://') !== 0 && + extension_loaded('tidy')) { + file_put_contents( + $this->outTarget, + tidy_repair_file( + $this->outTarget, array('indent' => TRUE, 'wrap' => 0), 'utf8' + ) + ); + } + } + + /** + * Performs a safe, incremental flush. + * + * Do not confuse this function with the flush() function of this class, + * since the flush() function may close the file being written to, rendering + * the current object no longer usable. + * + * @since Method available since Release 3.3.0 + */ + public function incrementalFlush() + { + if ($this->out) { + fflush($this->out); + } else { + flush(); + } + } + + /** + * @param string $buffer + */ + public function write($buffer) + { + if ($this->out) { + fwrite($this->out, $buffer); + + if ($this->autoFlush) { + $this->incrementalFlush(); + } + } else { + if (PHP_SAPI != 'cli') { + $buffer = htmlspecialchars($buffer); + } + + print $buffer; + + if ($this->autoFlush) { + $this->incrementalFlush(); + } + } + } + + /** + * Check auto-flush mode. + * + * @return boolean + * @since Method available since Release 3.3.0 + */ + public function getAutoFlush() + { + return $this->autoFlush; + } + + /** + * Set auto-flushing mode. + * + * If set, *incremental* flushes will be done after each write. This should + * not be confused with the different effects of this class' flush() method. + * + * @param boolean $autoFlush + * @since Method available since Release 3.3.0 + */ + public function setAutoFlush($autoFlush) + { + if (is_bool($autoFlush)) { + $this->autoFlush = $autoFlush; + } else { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton.php new file mode 100644 index 0000000..ed9e848 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton.php @@ -0,0 +1,146 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.1.0 + */ + +/** + * Generator for skeletons. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.1.0 + */ +abstract class PHPUnit_Util_Skeleton +{ + /** + * @var array + */ + protected $inClassName; + + /** + * @var string + */ + protected $inSourceFile; + + /** + * @var array + */ + protected $outClassName; + + /** + * @var string + */ + protected $outSourceFile; + + /** + * Constructor. + * + * @param string $inClassName + * @param string $inSourceFile + * @param string $outClassName + * @param string $outSourceFile + * @since Method available since Release 3.4.0 + */ + public function __construct($inClassName, $inSourceFile = '', $outClassName = '', $outSourceFile = '') + { + $this->inClassName = PHPUnit_Util_Class::parseFullyQualifiedClassName( + $inClassName + ); + + $this->outClassName = PHPUnit_Util_Class::parseFullyQualifiedClassName( + $outClassName + ); + + $this->inSourceFile = str_replace( + $this->inClassName['fullyQualifiedClassName'], + $this->inClassName['className'], + $inSourceFile + ); + + $this->outSourceFile = str_replace( + $this->outClassName['fullyQualifiedClassName'], + $this->outClassName['className'], + $outSourceFile + ); + } + + /** + * @return string + */ + public function getOutClassName() + { + return $this->outClassName['fullyQualifiedClassName']; + } + + /** + * @return string + */ + public function getOutSourceFile() + { + return $this->outSourceFile; + } + + /** + * Generates the code and writes it to a source file. + * + * @param string $file + */ + public function write($file = '') + { + if ($file == '') { + $file = $this->outSourceFile; + } + + if ($fp = @fopen($file, 'wt')) { + @fwrite($fp, $this->generate()); + @fclose($fp); + } + } + + abstract public function generate(); +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Class.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Class.php new file mode 100644 index 0000000..1360e22 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Class.php @@ -0,0 +1,327 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util_Skeleton + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +require_once 'Text/Template.php'; + +/** + * Generator for class skeletons from test classes. + * + * @package PHPUnit + * @subpackage Util_Skeleton + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Util_Skeleton_Class extends PHPUnit_Util_Skeleton +{ + /** + * Constructor. + * + * @param string $inClassName + * @param string $inSourceFile + * @param string $outClassName + * @param string $outSourceFile + * @throws RuntimeException + */ + public function __construct($inClassName, $inSourceFile = '', $outClassName = '', $outSourceFile = '') + { + if (empty($inSourceFile)) { + $inSourceFile = $inClassName . '.php'; + } + + if (!is_file($inSourceFile)) { + throw new PHPUnit_Framework_Exception( + sprintf( + '"%s" could not be opened.', + + $inSourceFile + ) + ); + } + + if (empty($outClassName)) { + $outClassName = substr($inClassName, 0, strlen($inClassName) - 4); + } + + if (empty($outSourceFile)) { + $outSourceFile = dirname($inSourceFile) . DIRECTORY_SEPARATOR . + $outClassName . '.php'; + } + + parent::__construct( + $inClassName, $inSourceFile, $outClassName, $outSourceFile + ); + } + + /** + * Generates the class' source. + * + * @return mixed + */ + public function generate() + { + $methods = ''; + + foreach ($this->findTestedMethods() as $method) { + $methodTemplate = new Text_Template( + sprintf( + '%s%sTemplate%sMethod.tpl', + + dirname(__FILE__), + DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR + ) + ); + + $methodTemplate->setVar( + array( + 'methodName' => $method, + ) + ); + + $methods .= $methodTemplate->render(); + } + + $classTemplate = new Text_Template( + sprintf( + '%s%sTemplate%sClass.tpl', + + dirname(__FILE__), + DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR + ) + ); + + $classTemplate->setVar( + array( + 'className' => $this->outClassName['fullyQualifiedClassName'], + 'methods' => $methods, + 'date' => date('Y-m-d'), + 'time' => date('H:i:s') + ) + ); + + return $classTemplate->render(); + } + + /** + * Returns the methods of the class under test + * that are called from the test methods. + * + * @return array + */ + protected function findTestedMethods() + { + $setUpVariables = array(); + $testedMethods = array(); + $classes = PHPUnit_Util_File::getClassesInFile( + $this->inSourceFile + ); + $testMethods = $classes[$this->inClassName['fullyQualifiedClassName']]['methods']; + unset($classes); + + foreach ($testMethods as $name => $testMethod) { + if (strtolower($name) == 'setup') { + $setUpVariables = $this->findVariablesThatReferenceClass( + $testMethod['tokens'] + ); + + break; + } + } + + foreach ($testMethods as $name => $testMethod) { + $argVariables = array(); + + if (strtolower($name) == 'setup') { + continue; + } + + $start = strpos($testMethod['signature'], '(') + 1; + $end = strlen($testMethod['signature']) - $start - 1; + $args = substr($testMethod['signature'], $start, $end); + + foreach (explode(',', $args) as $arg) { + $arg = explode(' ', trim($arg)); + + if (count($arg) == 2) { + $type = $arg[0]; + $var = $arg[1]; + } else { + $type = NULL; + $var = $arg[0]; + } + + if ($type == $this->outClassName['fullyQualifiedClassName']) { + $argVariables[] = $var; + } + } + + $variables = array_unique( + array_merge( + $setUpVariables, + $argVariables, + $this->findVariablesThatReferenceClass($testMethod['tokens']) + ) + ); + + foreach ($testMethod['tokens'] as $i => $token) { + // Class::method() + if (is_array($token) && $token[0] == T_DOUBLE_COLON && + is_array($testMethod['tokens'][$i-1]) && + $testMethod['tokens'][$i-1][0] == T_STRING && + $testMethod['tokens'][$i-1][1] == $this->outClassName['fullyQualifiedClassName'] && + is_array($testMethod['tokens'][$i+1]) && + $testMethod['tokens'][$i+1][0] == T_STRING && + $testMethod['tokens'][$i+2] == '(') { + $testedMethods[] = $testMethod['tokens'][$i+1][1]; + } + + // $this->object->method() + else if (is_array($token) && $token[0] == T_OBJECT_OPERATOR && + in_array($this->findVariableName($testMethod['tokens'], $i), $variables) && + is_array($testMethod['tokens'][$i+2]) && + $testMethod['tokens'][$i+2][0] == T_OBJECT_OPERATOR && + is_array($testMethod['tokens'][$i+3]) && + $testMethod['tokens'][$i+3][0] == T_STRING && + $testMethod['tokens'][$i+4] == '(') { + $testedMethods[] = $testMethod['tokens'][$i+3][1]; + } + + // $object->method() + else if (is_array($token) && $token[0] == T_OBJECT_OPERATOR && + in_array($this->findVariableName($testMethod['tokens'], $i), $variables) && + is_array($testMethod['tokens'][$i+1]) && + $testMethod['tokens'][$i+1][0] == T_STRING && + $testMethod['tokens'][$i+2] == '(') { + $testedMethods[] = $testMethod['tokens'][$i+1][1]; + } + } + } + + $testedMethods = array_unique($testedMethods); + sort($testedMethods); + + return $testedMethods; + } + + /** + * Returns the variables used in test methods + * that reference the class under test. + * + * @param array $tokens + * @return array + */ + protected function findVariablesThatReferenceClass(array $tokens) + { + $inNew = FALSE; + $variables = array(); + + foreach ($tokens as $i => $token) { + if (is_string($token)) { + if (trim($token) == ';') { + $inNew = FALSE; + } + + continue; + } + + list ($token, $value) = $token; + + switch ($token) { + case T_NEW: { + $inNew = TRUE; + } + break; + + case T_STRING: { + if ($inNew) { + if ($value == $this->outClassName['fullyQualifiedClassName']) { + $variables[] = $this->findVariableName( + $tokens, $i + ); + } + } + + $inNew = FALSE; + } + break; + } + } + + return $variables; + } + + /** + * Finds the variable name of the object for the method call + * that is currently being processed. + * + * @param array $tokens + * @param integer $start + * @return mixed + */ + protected function findVariableName(array $tokens, $start) + { + for ($i = $start - 1; $i >= 0; $i--) { + if (is_array($tokens[$i]) && $tokens[$i][0] == T_VARIABLE) { + $variable = $tokens[$i][1]; + + if (is_array($tokens[$i+1]) && + $tokens[$i+1][0] == T_OBJECT_OPERATOR && + $tokens[$i+2] != '(' && + $tokens[$i+3] != '(') { + $variable .= '->' . $tokens[$i+2][1]; + } + + return $variable; + } + } + + return FALSE; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/Class.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/Class.tpl.dist new file mode 100644 index 0000000..2a29e5e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/Class.tpl.dist @@ -0,0 +1,7 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/IncompleteTestMethod.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/IncompleteTestMethod.tpl.dist new file mode 100644 index 0000000..d89f90e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/IncompleteTestMethod.tpl.dist @@ -0,0 +1,11 @@ + + /** + * @todo Implement test{methodName}(). + */ + public function test{methodName}() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/Method.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/Method.tpl.dist new file mode 100644 index 0000000..dd3b044 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/Method.tpl.dist @@ -0,0 +1,9 @@ + + /** + * @todo Implement {methodName}(). + */ + public function {methodName}() + { + // Remove the following line when you implement this method. + throw new RuntimeException('Not yet implemented.'); + } diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestClass.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestClass.tpl.dist new file mode 100644 index 0000000..68e10e3 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestClass.tpl.dist @@ -0,0 +1,31 @@ +object = new {className}; + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } +{methods}} +?> diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethod.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethod.tpl.dist new file mode 100644 index 0000000..68acf2b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethod.tpl.dist @@ -0,0 +1,11 @@ + + /** + * Generated from @assert {annotation}. + */ + public function test{methodName}() + { + $this->assert{assertion}( + {expected}, + $this->object->{origMethodName}({arguments}) + ); + } diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodBool.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodBool.tpl.dist new file mode 100644 index 0000000..483a272 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodBool.tpl.dist @@ -0,0 +1,10 @@ + + /** + * Generated from @assert {annotation}. + */ + public function test{methodName}() + { + $this->assert{assertion}( + $this->object->{origMethodName}({arguments}) + ); + } diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodBoolStatic.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodBoolStatic.tpl.dist new file mode 100644 index 0000000..f46d84d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodBoolStatic.tpl.dist @@ -0,0 +1,10 @@ + + /** + * Generated from @assert {annotation}. + */ + public function test{methodName}() + { + $this->assert{assertion}( + {className}::{origMethodName}({arguments}) + ); + } diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodException.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodException.tpl.dist new file mode 100644 index 0000000..75c02b0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodException.tpl.dist @@ -0,0 +1,9 @@ + + /** + * Generated from @assert {annotation}. + * @expectedException {expected} + */ + public function test{methodName}() + { + $this->object->{origMethodName}({arguments}); + } diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodExceptionStatic.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodExceptionStatic.tpl.dist new file mode 100644 index 0000000..5f27729 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodExceptionStatic.tpl.dist @@ -0,0 +1,9 @@ + + /** + * Generated from @assert {annotation}. + * @expectedException {expected} + */ + public function test{methodName}() + { + {className}::{origMethodName}({arguments}); + } diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodStatic.tpl.dist b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodStatic.tpl.dist new file mode 100644 index 0000000..b4fe571 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Template/TestMethodStatic.tpl.dist @@ -0,0 +1,11 @@ + + /** + * Generated from @assert {annotation}. + */ + public function test{methodName}() + { + $this->assert{assertion}( + {expected}, + {className}::{origMethodName}({arguments}) + ); + } diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Test.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Test.php new file mode 100644 index 0000000..cc221ca --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Skeleton/Test.php @@ -0,0 +1,379 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util_Skeleton + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.3.0 + */ + +require_once 'Text/Template.php'; + +/** + * Generator for test class skeletons from classes. + * + * @package PHPUnit + * @subpackage Util_Skeleton + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.3.0 + */ +class PHPUnit_Util_Skeleton_Test extends PHPUnit_Util_Skeleton +{ + /** + * @var array + */ + protected $methodNameCounter = array(); + + /** + * Constructor. + * + * @param string $inClassName + * @param string $inSourceFile + * @param string $outClassName + * @param string $outSourceFile + * @throws RuntimeException + */ + public function __construct($inClassName, $inSourceFile = '', $outClassName = '', $outSourceFile = '') + { + if (class_exists($inClassName)) { + $reflector = new ReflectionClass($inClassName); + $inSourceFile = $reflector->getFileName(); + + if ($inSourceFile === FALSE) { + $inSourceFile = ''; + } + + unset($reflector); + } else { + if (empty($inSourceFile)) { + $possibleFilenames = array( + $inClassName . '.php', + PHPUnit_Util_Filesystem::classNameToFilename($inClassName) + ); + + foreach ($possibleFilenames as $possibleFilename) { + if (is_file($possibleFilename)) { + $inSourceFile = $possibleFilename; + } + } + } + + if (empty($inSourceFile)) { + throw new PHPUnit_Framework_Exception( + sprintf( + 'Neither "%s" nor "%s" could be opened.', + $possibleFilenames[0], + $possibleFilenames[1] + ) + ); + } + + if (!is_file($inSourceFile)) { + throw new PHPUnit_Framework_Exception( + sprintf( + '"%s" could not be opened.', + + $inSourceFile + ) + ); + } + + $inSourceFile = realpath($inSourceFile); + include_once $inSourceFile; + + if (!class_exists($inClassName)) { + throw new PHPUnit_Framework_Exception( + sprintf( + 'Could not find class "%s" in "%s".', + + $inClassName, + $inSourceFile + ) + ); + } + } + + if (empty($outClassName)) { + $outClassName = $inClassName . 'Test'; + } + + if (empty($outSourceFile)) { + $outSourceFile = dirname($inSourceFile) . DIRECTORY_SEPARATOR . $outClassName . '.php'; + } + + parent::__construct( + $inClassName, $inSourceFile, $outClassName, $outSourceFile + ); + } + + /** + * Generates the test class' source. + * + * @param boolean $verbose + * @return mixed + */ + public function generate($verbose = FALSE) + { + $class = new ReflectionClass( + $this->inClassName['fullyQualifiedClassName'] + ); + $methods = ''; + $incompleteMethods = ''; + + foreach ($class->getMethods() as $method) { + if (!$method->isConstructor() && + !$method->isAbstract() && + $method->isPublic() && + $method->getDeclaringClass()->getName() == $this->inClassName['fullyQualifiedClassName']) { + $assertAnnotationFound = FALSE; + + if (preg_match_all('/@assert(.*)$/Um', $method->getDocComment(), $annotations)) { + foreach ($annotations[1] as $annotation) { + if (preg_match('/\((.*)\)\s+([^\s]*)\s+(.*)/', $annotation, $matches)) { + switch ($matches[2]) { + case '==': { + $assertion = 'Equals'; + } + break; + + case '!=': { + $assertion = 'NotEquals'; + } + break; + + case '===': { + $assertion = 'Same'; + } + break; + + case '!==': { + $assertion = 'NotSame'; + } + break; + + case '>': { + $assertion = 'GreaterThan'; + } + break; + + case '>=': { + $assertion = 'GreaterThanOrEqual'; + } + break; + + case '<': { + $assertion = 'LessThan'; + } + break; + + case '<=': { + $assertion = 'LessThanOrEqual'; + } + break; + + case 'throws': { + $assertion = 'exception'; + } + break; + + default: { + throw new PHPUnit_Framework_Exception( + sprintf( + 'Token "%s" could not be parsed in @assert annotation.', + $matches[2] + ) + ); + } + } + + if ($assertion == 'exception') { + $template = 'TestMethodException'; + } + + else if ($assertion == 'Equals' && + strtolower($matches[3]) == 'true') { + $assertion = 'True'; + $template = 'TestMethodBool'; + } + + else if ($assertion == 'NotEquals' && + strtolower($matches[3]) == 'true') { + $assertion = 'False'; + $template = 'TestMethodBool'; + } + + else if ($assertion == 'Equals' && + strtolower($matches[3]) == 'false') { + $assertion = 'False'; + $template = 'TestMethodBool'; + } + + else if ($assertion == 'NotEquals' && + strtolower($matches[3]) == 'false') { + $assertion = 'True'; + $template = 'TestMethodBool'; + } + + else { + $template = 'TestMethod'; + } + + if ($method->isStatic()) { + $template .= 'Static'; + } + + $methodTemplate = new Text_Template( + sprintf( + '%s%sTemplate%s%s.tpl', + + dirname(__FILE__), + DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR, + $template + ) + ); + + $origMethodName = $method->getName(); + $methodName = ucfirst($origMethodName); + + if (isset($this->methodNameCounter[$methodName])) { + $this->methodNameCounter[$methodName]++; + } else { + $this->methodNameCounter[$methodName] = 1; + } + + if ($this->methodNameCounter[$methodName] > 1) { + $methodName .= $this->methodNameCounter[$methodName]; + } + + $methodTemplate->setVar( + array( + 'annotation' => trim($annotation), + 'arguments' => $matches[1], + 'assertion' => isset($assertion) ? $assertion : '', + 'expected' => $matches[3], + 'origMethodName' => $origMethodName, + 'className' => $this->inClassName['fullyQualifiedClassName'], + 'methodName' => $methodName + ) + ); + + $methods .= $methodTemplate->render(); + + $assertAnnotationFound = TRUE; + } + } + } + + if (!$assertAnnotationFound) { + $methodTemplate = new Text_Template( + sprintf( + '%s%sTemplate%sIncompleteTestMethod.tpl', + + dirname(__FILE__), + DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR + ) + ); + + $methodTemplate->setVar( + array( + 'methodName' => ucfirst($method->getName()) + ) + ); + + $incompleteMethods .= $methodTemplate->render(); + } + } + } + + $classTemplate = new Text_Template( + sprintf( + '%s%sTemplate%sTestClass.tpl', + + dirname(__FILE__), + DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR + ) + ); + + if ($this->inSourceFile != '') { + $requireClassFile = sprintf( + "\n\nrequire_once '%s';", + + $this->inSourceFile + ); + } else { + $requireClassFile = ''; + } + + if ($this->outClassName['namespace'] != '') { + $namespace = "\nnamespace " . + $this->outClassName['namespace'] . ";\n"; + } else { + $namespace = ''; + } + + $classTemplate->setVar( + array( + 'namespace' => $namespace, + 'namespaceSeparator' => !empty($namespace) ? '\\' : '', + 'className' => $this->inClassName['className'], + 'testClassName' => $this->outClassName['className'], + 'requireClassFile' => $requireClassFile, + 'methods' => $methods . $incompleteMethods, + 'date' => date('Y-m-d'), + 'time' => date('H:i:s') + ) + ); + + if (!$verbose) { + return $classTemplate->render(); + } else { + return array( + 'code' => $classTemplate->render(), + 'incomplete' => empty($methods) + ); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Test.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Test.php new file mode 100644 index 0000000..52fae1f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Test.php @@ -0,0 +1,473 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Test helpers. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Util_Test +{ + const REGEX_DATA_PROVIDER = '/@dataProvider\s+([a-zA-Z0-9._:-\\\\x7f-\xff]+)/'; + const REGEX_EXPECTED_EXCEPTION = '(@expectedException\s+([:.\w\\\\x7f-\xff]+)(?:[\t ]+(\S*))?(?:[\t ]+(\S*))?\s*$)m'; + + private static $annotationCache = array(); + + protected static $templateMethods = array( + 'setUp', 'assertPreConditions', 'assertPostConditions', 'tearDown' + ); + + /** + * @param PHPUnit_Framework_Test $test + * @param boolean $asString + * @return mixed + */ + public static function describe(PHPUnit_Framework_Test $test, $asString = TRUE) + { + if ($asString) { + if ($test instanceof PHPUnit_Framework_SelfDescribing) { + return $test->toString(); + } else { + return get_class($test); + } + } else { + if ($test instanceof PHPUnit_Framework_TestCase) { + return array( + get_class($test), $test->getName() + ); + } + + else if ($test instanceof PHPUnit_Framework_SelfDescribing) { + return array('', $test->toString()); + } + + else { + return array('', get_class($test)); + } + } + } + + /** + * Returns the expected exception for a test. + * + * @param string $className + * @param string $methodName + * @return array + * @since Method available since Release 3.3.6 + */ + public static function getExpectedException($className, $methodName) + { + $reflector = new ReflectionMethod($className, $methodName); + $docComment = $reflector->getDocComment(); + + if (preg_match(self::REGEX_EXPECTED_EXCEPTION, $docComment, $matches)) { + $annotations = self::parseTestMethodAnnotations( + $className, $methodName + ); + + $class = $matches[1]; + $code = 0; + $message = ''; + + if (isset($matches[2])) { + $message = trim($matches[2]); + } + + else if (isset($annotations['method']['expectedExceptionMessage'])) { + $message = $annotations['method']['expectedExceptionMessage'][0]; + } + + if (isset($matches[3])) { + $code = (int)$matches[3]; + } + + else if (isset($annotations['method']['expectedExceptionCode'])) { + $code = (int)$annotations['method']['expectedExceptionCode'][0]; + } + + return array( + 'class' => $class, 'code' => $code, 'message' => $message + ); + } + + return FALSE; + } + + /** + * Returns the provided data for a method. + * + * @param string $className + * @param string $methodName + * @param string $docComment + * @return mixed array|Iterator when a data provider is specified and exists + * false when a data provider is specified and does not exist + * null when no data provider is specified + * @since Method available since Release 3.2.0 + */ + public static function getProvidedData($className, $methodName) + { + $reflector = new ReflectionMethod($className, $methodName); + $docComment = $reflector->getDocComment(); + $data = NULL; + + if (preg_match(self::REGEX_DATA_PROVIDER, $docComment, $matches)) { + $dataProviderMethodNameNamespace = explode('\\', $matches[1]); + $leaf = explode('::', array_pop($dataProviderMethodNameNamespace)); + $dataProviderMethodName = array_pop($leaf); + + if (!empty($dataProviderMethodNameNamespace)) { + $dataProviderMethodNameNamespace = join('\\', $dataProviderMethodNameNamespace) . '\\'; + } else { + $dataProviderMethodNameNamespace = ''; + } + + if (!empty($leaf)) { + $dataProviderClassName = $dataProviderMethodNameNamespace . array_pop($leaf); + } else { + $dataProviderClassName = $className; + } + + $dataProviderClass = new ReflectionClass($dataProviderClassName); + $dataProviderMethod = $dataProviderClass->getMethod( + $dataProviderMethodName + ); + + if ($dataProviderMethod->isStatic()) { + $object = NULL; + } else { + $object = $dataProviderClass->newInstance(); + } + + if ($dataProviderMethod->getNumberOfParameters() == 0) { + $data = $dataProviderMethod->invoke($object); + } else { + $data = $dataProviderMethod->invoke($object, $methodName); + } + } + + if ($data !== NULL) { + foreach ($data as $key => $value) { + if (!is_array($value)) { + throw new InvalidArgumentException( + sprintf( + 'Data set %s is invalid.', + is_int($key) ? '#' . $key : '"' . $key . '"' + ) + ); + } + } + } + + return $data; + } + + /** + * @param string $className + * @param string $methodName + * @return array + * @throws ReflectionException + * @since Method available since Release 3.4.0 + */ + public static function parseTestMethodAnnotations($className, $methodName = '') + { + if (!isset(self::$annotationCache[$className])) { + $class = new ReflectionClass($className); + self::$annotationCache[$className] = self::parseAnnotations($class->getDocComment()); + } + + if (!empty($methodName) && !isset(self::$annotationCache[$className . '::' . $methodName])) { + $method = new ReflectionMethod($className, $methodName); + self::$annotationCache[$className . '::' . $methodName] = self::parseAnnotations($method->getDocComment()); + } + + return array( + 'class' => self::$annotationCache[$className], + 'method' => !empty($methodName) ? self::$annotationCache[$className . '::' . $methodName] : array() + ); + } + + /** + * @param string $docblock + * @return array + * @since Method available since Release 3.4.0 + */ + private static function parseAnnotations($docblock) + { + $annotations = array(); + + if (preg_match_all('/@(?P[A-Za-z_-]+)(?:[ \t]+(?P.*?))?[ \t]*\r?$/m', $docblock, $matches)) { + $numMatches = count($matches[0]); + + for ($i = 0; $i < $numMatches; ++$i) { + $annotations[$matches['name'][$i]][] = $matches['value'][$i]; + } + } + + return $annotations; + } + + /** + * Returns the backup settings for a test. + * + * @param string $className + * @param string $methodName + * @return array + * @since Method available since Release 3.4.0 + */ + public static function getBackupSettings($className, $methodName) + { + return array( + 'backupGlobals' => self::getBooleanAnnotationSetting( + $className, $methodName, 'backupGlobals' + ), + 'backupStaticAttributes' => self::getBooleanAnnotationSetting( + $className, $methodName, 'backupStaticAttributes' + ) + ); + } + + /** + * Returns the dependencies for a test class or method. + * + * @param string $className + * @param string $methodName + * @return array + * @since Method available since Release 3.4.0 + */ + public static function getDependencies($className, $methodName) + { + $annotations = self::parseTestMethodAnnotations( + $className, $methodName + ); + + $dependencies = array(); + + if (isset($annotations['class']['depends'])) { + $dependencies = $annotations['class']['depends']; + } + + if (isset($annotations['method']['depends'])) { + $dependencies = array_merge( + $dependencies, $annotations['method']['depends'] + ); + } + + return array_unique($dependencies); + } + + /** + * Returns the error handler settings for a test. + * + * @param string $className + * @param string $methodName + * @return boolean + * @since Method available since Release 3.4.0 + */ + public static function getErrorHandlerSettings($className, $methodName) + { + return self::getBooleanAnnotationSetting( + $className, $methodName, 'errorHandler' + ); + } + + /** + * Returns the groups for a test class or method. + * + * @param string $className + * @param string $methodName + * @return array + * @since Method available since Release 3.2.0 + */ + public static function getGroups($className, $methodName = '') + { + $annotations = self::parseTestMethodAnnotations( + $className, $methodName + ); + + $groups = array(); + + if (isset($annotations['method']['author'])) { + $groups = $annotations['method']['author']; + } + + else if (isset($annotations['class']['author'])) { + $groups = $annotations['class']['author']; + } + + if (isset($annotations['class']['group'])) { + $groups = array_merge($groups, $annotations['class']['group']); + } + + if (isset($annotations['method']['group'])) { + $groups = array_merge($groups, $annotations['method']['group']); + } + + return array_unique($groups); + } + + /** + * Returns the tickets for a test class or method. + * + * @param string $className + * @param string $methodName + * @return array + * @since Method available since Release 3.4.0 + */ + public static function getTickets($className, $methodName) + { + $annotations = self::parseTestMethodAnnotations( + $className, $methodName + ); + + $tickets = array(); + + if (isset($annotations['class']['ticket'])) { + $tickets = $annotations['class']['ticket']; + } + + if (isset($annotations['method']['ticket'])) { + $tickets = array_merge($tickets, $annotations['method']['ticket']); + } + + return array_unique($tickets); + } + + /** + * Returns the output buffering settings for a test. + * + * @param string $className + * @param string $methodName + * @return boolean + * @since Method available since Release 3.4.0 + */ + public static function getOutputBufferingSettings($className, $methodName) + { + return self::getBooleanAnnotationSetting( + $className, $methodName, 'outputBuffering' + ); + } + + /** + * Returns the process isolation settings for a test. + * + * @param string $className + * @param string $methodName + * @return boolean + * @since Method available since Release 3.4.1 + */ + public static function getProcessIsolationSettings($className, $methodName) + { + $annotations = self::parseTestMethodAnnotations( + $className, $methodName + ); + + if (isset($annotations['class']['runTestsInSeparateProcesses']) || + isset($annotations['method']['runInSeparateProcess'])) { + return TRUE; + } else { + return FALSE; + } + } + + /** + * Returns the preserve global state settings for a test. + * + * @param string $className + * @param string $methodName + * @return boolean + * @since Method available since Release 3.4.0 + */ + public static function getPreserveGlobalStateSettings($className, $methodName) + { + return self::getBooleanAnnotationSetting( + $className, $methodName, 'preserveGlobalState' + ); + } + + /** + * @param string $className + * @param string $methodName + * @param string $settingName + * @return boolean + * @since Method available since Release 3.4.0 + */ + private static function getBooleanAnnotationSetting($className, $methodName, $settingName) + { + $annotations = self::parseTestMethodAnnotations( + $className, $methodName + ); + + $result = NULL; + + if (isset($annotations['class'][$settingName])) { + if ($annotations['class'][$settingName][0] == 'enabled') { + $result = TRUE; + } + + else if ($annotations['class'][$settingName][0] == 'disabled') { + $result = FALSE; + } + } + + if (isset($annotations['method'][$settingName])) { + if ($annotations['method'][$settingName][0] == 'enabled') { + $result = TRUE; + } + + else if ($annotations['method'][$settingName][0] == 'disabled') { + $result = FALSE; + } + } + + return $result; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/NamePrettifier.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/NamePrettifier.php new file mode 100644 index 0000000..1d85659 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/NamePrettifier.php @@ -0,0 +1,178 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util_TestDox + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.3.0 + */ + +/** + * Prettifies class and method names for use in TestDox documentation. + * + * @package PHPUnit + * @subpackage Util_TestDox + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.1.0 + */ +class PHPUnit_Util_TestDox_NamePrettifier +{ + /** + * @var string + */ + protected $prefix = 'Test'; + + /** + * @var string + */ + protected $suffix = 'Test'; + + /** + * @var array + */ + protected $strings = array(); + + /** + * Prettifies the name of a test class. + * + * @param string $name + * @return string + */ + public function prettifyTestClass($name) + { + $title = $name; + + if ($this->suffix !== NULL && + $this->suffix == substr($name, -1 * strlen($this->suffix))) { + $title = substr($title, 0, strripos($title, $this->suffix)); + } + + if ($this->prefix !== NULL && + $this->prefix == substr($name, 0, strlen($this->prefix))) { + $title = substr($title, strlen($this->prefix)); + } + + return $title; + } + + /** + * Prettifies the name of a test method. + * + * @param string $name + * @return string + */ + public function prettifyTestMethod($name) + { + $buffer = ''; + + if (!is_string($name) || strlen($name) == 0) { + return $buffer; + } + + $string = preg_replace('#\d+$#', '', $name, -1, $count); + + if (in_array($string, $this->strings)) { + $name = $string; + } else if ($count == 0) { + $this->strings[] = $string; + } + + if (strpos($name, '_') !== FALSE) { + return str_replace('_', ' ', $name); + } + + $max = strlen($name); + + if (substr($name, 0, 4) == 'test') { + $offset = 4; + } else { + $offset = 0; + $name[0] = strtoupper($name[0]); + } + + $wasNumeric = FALSE; + + for ($i = $offset; $i < $max; $i++) { + if ($i > $offset && + ord($name[$i]) >= 65 && + ord($name[$i]) <= 90) { + $buffer .= ' ' . strtolower($name[$i]); + } else { + $isNumeric = is_numeric($name[$i]); + + if (!$wasNumeric && $isNumeric) { + $buffer .= ' '; + $wasNumeric = TRUE; + } + + if ($wasNumeric && !$isNumeric) { + $wasNumeric = FALSE; + } + + $buffer .= $name[$i]; + } + } + + return $buffer; + } + + /** + * Sets the prefix of test names. + * + * @param string $prefix + */ + public function setPrefix($prefix) + { + $this->prefix = $prefix; + } + + /** + * Sets the suffix of test names. + * + * @param string $prefix + */ + public function setSuffix($suffix) + { + $this->suffix = $suffix; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/ResultPrinter.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/ResultPrinter.php new file mode 100644 index 0000000..85d25d5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/ResultPrinter.php @@ -0,0 +1,348 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util_TestDox + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.3.0 + */ + +/** + * Base class for printers of TestDox documentation. + * + * @package PHPUnit + * @subpackage Util_TestDox + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.1.0 + */ +abstract class PHPUnit_Util_TestDox_ResultPrinter extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener +{ + /** + * @var PHPUnit_Util_TestDox_NamePrettifier + */ + protected $prettifier; + + /** + * @var string + */ + protected $testClass = ''; + + /** + * @var integer + */ + protected $testStatus = FALSE; + + /** + * @var array + */ + protected $tests = array(); + + /** + * @var integer + */ + protected $successful = 0; + + /** + * @var integer + */ + protected $failed = 0; + + /** + * @var integer + */ + protected $skipped = 0; + + /** + * @var integer + */ + protected $incomplete = 0; + + /** + * @var string + */ + protected $testTypeOfInterest = 'PHPUnit_Framework_TestCase'; + + /** + * @var string + */ + protected $currentTestClassPrettified; + + /** + * @var string + */ + protected $currentTestMethodPrettified; + + /** + * Constructor. + * + * @param resource $out + */ + public function __construct($out = NULL) + { + parent::__construct($out); + + $this->prettifier = new PHPUnit_Util_TestDox_NamePrettifier; + $this->startRun(); + } + + /** + * Flush buffer and close output. + * + */ + public function flush() + { + $this->doEndClass(); + $this->endRun(); + + parent::flush(); + } + + /** + * An error occurred. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) + { + if ($test instanceof $this->testTypeOfInterest) { + $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_ERROR; + $this->failed++; + } + } + + /** + * A failure occurred. + * + * @param PHPUnit_Framework_Test $test + * @param PHPUnit_Framework_AssertionFailedError $e + * @param float $time + */ + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) + { + if ($test instanceof $this->testTypeOfInterest) { + $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE; + $this->failed++; + } + } + + /** + * Incomplete test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + if ($test instanceof $this->testTypeOfInterest) { + $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE; + $this->incomplete++; + } + } + + /** + * Skipped test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + * @since Method available since Release 3.0.0 + */ + public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + if ($test instanceof $this->testTypeOfInterest) { + $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED; + $this->skipped++; + } + } + + /** + * A testsuite started. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit_Framework_TestSuite $suite) + { + } + + /** + * A testsuite ended. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit_Framework_TestSuite $suite) + { + } + + /** + * A test started. + * + * @param PHPUnit_Framework_Test $test + */ + public function startTest(PHPUnit_Framework_Test $test) + { + if ($test instanceof $this->testTypeOfInterest) { + $class = get_class($test); + + if ($this->testClass != $class) { + if ($this->testClass != '') { + $this->doEndClass(); + } + + $this->currentTestClassPrettified = $this->prettifier->prettifyTestClass($class); + $this->startClass($class); + + $this->testClass = $class; + $this->tests = array(); + } + + $prettified = FALSE; + + if ($test instanceof PHPUnit_Framework_TestCase && + !$test instanceof PHPUnit_Framework_Warning) { + $annotations = $test->getAnnotations(); + + if (isset($annotations['method']['testdox'][0])) { + $this->currentTestMethodPrettified = $annotations['method']['testdox'][0]; + $prettified = TRUE; + } + } + + if (!$prettified) { + $this->currentTestMethodPrettified = $this->prettifier->prettifyTestMethod($test->getName(FALSE)); + } + + $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_PASSED; + } + } + + /** + * A test ended. + * + * @param PHPUnit_Framework_Test $test + * @param float $time + */ + public function endTest(PHPUnit_Framework_Test $test, $time) + { + if ($test instanceof $this->testTypeOfInterest) { + if (!isset($this->tests[$this->currentTestMethodPrettified])) { + if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) { + $this->tests[$this->currentTestMethodPrettified]['success'] = 1; + $this->tests[$this->currentTestMethodPrettified]['failure'] = 0; + } else { + $this->tests[$this->currentTestMethodPrettified]['success'] = 0; + $this->tests[$this->currentTestMethodPrettified]['failure'] = 1; + } + } else { + if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) { + $this->tests[$this->currentTestMethodPrettified]['success']++; + } else { + $this->tests[$this->currentTestMethodPrettified]['failure']++; + } + } + + $this->currentTestClassPrettified = NULL; + $this->currentTestMethodPrettified = NULL; + } + } + + /** + * @since Method available since Release 2.3.0 + */ + protected function doEndClass() + { + foreach ($this->tests as $name => $data) { + $this->onTest($name, $data['failure'] == 0); + } + + $this->endClass($this->testClass); + } + + /** + * Handler for 'start run' event. + * + */ + protected function startRun() + { + } + + /** + * Handler for 'start class' event. + * + * @param string $name + */ + protected function startClass($name) + { + } + + /** + * Handler for 'on test' event. + * + * @param string $name + * @param boolean $success + */ + protected function onTest($name, $success = TRUE) + { + } + + /** + * Handler for 'end class' event. + * + * @param string $name + */ + protected function endClass($name) + { + } + + /** + * Handler for 'end run' event. + * + */ + protected function endRun() + { + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/ResultPrinter/HTML.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/ResultPrinter/HTML.php new file mode 100644 index 0000000..a9bd606 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/ResultPrinter/HTML.php @@ -0,0 +1,124 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util_TestDox + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.3.0 + */ + +/** + * Prints TestDox documentation in HTML format. + * + * @package PHPUnit + * @subpackage Util_TestDox + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.1.0 + */ +class PHPUnit_Util_TestDox_ResultPrinter_HTML extends PHPUnit_Util_TestDox_ResultPrinter +{ + /** + * @var boolean + */ + protected $printsHTML = TRUE; + + /** + * Handler for 'start run' event. + * + */ + protected function startRun() + { + $this->write(''); + } + + /** + * Handler for 'start class' event. + * + * @param string $name + */ + protected function startClass($name) + { + $this->write( + '

    ' . $this->currentTestClassPrettified . + '

      ' + ); + } + + /** + * Handler for 'on test' event. + * + * @param string $name + * @param boolean $success + */ + protected function onTest($name, $success = TRUE) + { + if (!$success) { + $strikeOpen = ''; + $strikeClose = ''; + } else { + $strikeOpen = ''; + $strikeClose = ''; + } + + $this->write('
    • ' . $strikeOpen . $name . $strikeClose . '
    • '); + } + + /** + * Handler for 'end class' event. + * + * @param string $name + */ + protected function endClass($name) + { + $this->write('
    '); + } + + /** + * Handler for 'end run' event. + * + */ + protected function endRun() + { + $this->write(''); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/ResultPrinter/Text.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/ResultPrinter/Text.php new file mode 100644 index 0000000..65958a3 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestDox/ResultPrinter/Text.php @@ -0,0 +1,96 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util_TestDox + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 2.3.0 + */ + +/** + * Prints TestDox documentation in text format. + * + * @package PHPUnit + * @subpackage Util_TestDox + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 2.1.0 + */ +class PHPUnit_Util_TestDox_ResultPrinter_Text extends PHPUnit_Util_TestDox_ResultPrinter +{ + /** + * Handler for 'start class' event. + * + * @param string $name + */ + protected function startClass($name) + { + $this->write($this->currentTestClassPrettified . "\n"); + } + + /** + * Handler for 'on test' event. + * + * @param string $name + * @param boolean $success + */ + protected function onTest($name, $success = TRUE) + { + if ($success) { + $this->write(' [x] '); + } else { + $this->write(' [ ] '); + } + + $this->write($name . "\n"); + } + + /** + * Handler for 'end class' event. + * + * @param string $name + */ + protected function endClass($name) + { + $this->write("\n"); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestSuiteIterator.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestSuiteIterator.php new file mode 100644 index 0000000..25bcbab --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/TestSuiteIterator.php @@ -0,0 +1,149 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.1.0 + */ + +/** + * Iterator for test suites. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.1.0 + */ +class PHPUnit_Util_TestSuiteIterator implements RecursiveIterator +{ + /** + * @var integer + */ + protected $position; + + /** + * @var PHPUnit_Framework_Test[] + */ + protected $tests; + + /** + * Constructor. + * + * @param PHPUnit_Framework_TestSuite $suite + */ + public function __construct(PHPUnit_Framework_TestSuite $testSuite) + { + $this->tests = $testSuite->tests(); + } + + /** + * Rewinds the Iterator to the first element. + * + */ + public function rewind() + { + $this->position = 0; + } + + /** + * Checks if there is a current element after calls to rewind() or next(). + * + * @return boolean + */ + public function valid() + { + return $this->position < count($this->tests); + } + + /** + * Returns the key of the current element. + * + * @return integer + */ + public function key() + { + return $this->position; + } + + /** + * Returns the current element. + * + * @return PHPUnit_Framework_Test + */ + public function current() + { + return $this->valid() ? $this->tests[$this->position] : NULL; + } + + /** + * Moves forward to next element. + * + */ + public function next() + { + $this->position++; + } + + /** + * Returns the sub iterator for the current element. + * + * @return PHPUnit_Util_TestSuiteIterator + */ + public function getChildren() + { + return new PHPUnit_Util_TestSuiteIterator( + $this->tests[$this->position] + ); + } + + /** + * Checks whether the current element has children. + * + * @return boolean + */ + public function hasChildren() + { + return $this->tests[$this->position] instanceof PHPUnit_Framework_TestSuite; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Type.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Type.php new file mode 100644 index 0000000..ca43122 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/Type.php @@ -0,0 +1,192 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.0.0 + */ + +/** + * Utility class for textual type (and value) representation. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.0.0 + */ +class PHPUnit_Util_Type +{ + public static function isType($type) + { + return in_array( + $type, + array( + 'numeric', + 'integer', + 'int', + 'float', + 'string', + 'boolean', + 'bool', + 'null', + 'array', + 'object', + 'resource', + 'scalar' + ) + ); + } + + public static function shortenedExport($value) + { + if (is_string($value)) { + return self::shortenedString($value); + } + + elseif (is_array($value)) { + if (count($value) == 0) { + return 'array()'; + } + + $a1 = array_slice($value, 0, 1, TRUE); + $k1 = key($a1); + $v1 = $a1[$k1]; + + if (is_string($v1)) { + $v1 = self::shortenedString($v1); + } + + elseif (is_array($v1)) { + $v1 = 'array(...)'; + } else { + $v1 = self::toString($v1); + } + + $a2 = FALSE; + + if (count($value) > 1) { + $a2 = array_slice($value, -1, 1, TRUE); + $k2 = key($a2); + $v2 = $a2[$k2]; + + if (is_string($v2)) { + $v2 = self::shortenedString($v2); + } + + elseif (is_array($v2)) { + $v2 = 'array(...)'; + } else { + $v2 = self::toString($v2); + } + } + + $text = 'array( ' . self::toString($k1) . ' => ' . $v1; + + if ($a2 !== FALSE) { + $text .= ', ..., ' . self::toString($k2) . ' => ' . $v2 . ' )'; + } else { + $text .= ' )'; + } + + return $text; + } + + elseif (is_object($value)) { + return get_class($value) . '(...)'; + } + + return self::toString($value); + } + + public static function shortenedString($string) + { + $string = preg_replace('#\n|\r\n|\r#', ' ', $string); + + if (strlen($string) > 14) { + return PHPUnit_Util_Type::toString( + substr($string, 0, 7) . '...' . substr($string, -7) + ); + } else { + return PHPUnit_Util_Type::toString($string); + } + } + + public static function toString($value, $short = FALSE) + { + if (is_array($value) || is_object($value)) { + if (!$short) { + return "\n" . print_r($value, TRUE); + } else { + if (is_array($value)) { + return ''; + } else { + return '<' . get_class($value) . '>'; + } + } + } + + if (is_string($value) && strpos($value, "\n") !== FALSE) { + return ''; + } + + if (!is_null($value)) { + $type = gettype($value) . ':'; + } else { + $type = ''; + $value = 'null'; + } + + if (is_bool($value)) { + if ($value === TRUE) { + $value = 'true'; + } + + else if ($value === FALSE) { + $value = 'false'; + } + } + + return '<' . $type . $value . '>'; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/XML.php b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/XML.php new file mode 100644 index 0000000..b8d48f9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/PHPUnit/Util/XML.php @@ -0,0 +1,957 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 3.2.0 + */ + +/** + * XML helpers. + * + * @package PHPUnit + * @subpackage Util + * @author Sebastian Bergmann + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 3.5.14 + * @link http://www.phpunit.de/ + * @since Class available since Release 3.2.0 + */ +class PHPUnit_Util_XML +{ + /** + * @param string $string + * @return string + * @author Kore Nordmann + * @since Method available since Release 3.4.6 + */ + public static function prepareString($string) + { + return preg_replace( + '([\\x00-\\x04\\x0b\\x0c\\x0e-\\x1f\\x7f])e', + 'sprintf( "&#x%02x;", ord( "\\1" ) )', + htmlspecialchars( + self::convertToUtf8($string), ENT_COMPAT, 'UTF-8' + ) + ); + } + + /** + * Converts a string to UTF-8 encoding. + * + * @param string $string + * @return string + * @since Method available since Release 3.2.19 + */ + protected static function convertToUtf8($string) + { + if (!self::isUtf8($string)) { + if (function_exists('mb_convert_encoding')) { + $string = mb_convert_encoding($string, 'UTF-8'); + } else { + $string = utf8_encode($string); + } + } + + return $string; + } + + /** + * Checks a string for UTF-8 encoding. + * + * @param string $string + * @return boolean + * @since Method available since Release 3.3.0 + */ + protected static function isUtf8($string) + { + $length = strlen($string); + + for ($i = 0; $i < $length; $i++) { + if (ord($string[$i]) < 0x80) { + $n = 0; + } + + else if ((ord($string[$i]) & 0xE0) == 0xC0) { + $n = 1; + } + + else if ((ord($string[$i]) & 0xF0) == 0xE0) { + $n = 2; + } + + else if ((ord($string[$i]) & 0xF0) == 0xF0) { + $n = 3; + } + + else { + return FALSE; + } + + for ($j = 0; $j < $n; $j++) { + if ((++$i == $length) || ((ord($string[$i]) & 0xC0) != 0x80)) { + return FALSE; + } + } + } + + return TRUE; + } + + /** + * Loads an XML (or HTML) file into a DOMDocument object. + * + * @param string $filename + * @param boolean $isHtml + * @return DOMDocument + * @since Method available since Release 3.3.0 + */ + public static function loadFile($filename, $isHtml = FALSE) + { + $reporting = error_reporting(0); + $contents = file_get_contents($filename); + error_reporting($reporting); + + if ($contents === FALSE) { + throw new PHPUnit_Framework_Exception( + sprintf( + 'Could not read "%s".', + $filename + ) + ); + } + + return self::load($contents, $isHtml, $filename); + } + + /** + * Load an $actual document into a DOMDocument. This is called + * from the selector assertions. + * + * If $actual is already a DOMDocument, it is returned with + * no changes. Otherwise, $actual is loaded into a new DOMDocument + * as either HTML or XML, depending on the value of $isHtml. + * + * Note: prior to PHPUnit 3.3.0, this method loaded a file and + * not a string as it currently does. To load a file into a + * DOMDocument, use loadFile() instead. + * + * @param string|DOMDocument $actual + * @param boolean $isHtml + * @param string $filename + * @return DOMDocument + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + */ + public static function load($actual, $isHtml = FALSE, $filename = '') + { + if ($actual instanceof DOMDocument) { + return $actual; + } + + $document = new DOMDocument; + $internal = libxml_use_internal_errors(TRUE); + $message = ''; + $reporting = error_reporting(0); + + if ($isHtml) { + $loaded = $document->loadHTML($actual); + } else { + $loaded = $document->loadXML($actual); + } + + foreach (libxml_get_errors() as $error) { + $message .= $error->message; + } + + libxml_use_internal_errors($internal); + error_reporting($reporting); + + if ($loaded === FALSE) { + if ($filename != '') { + throw new PHPUnit_Framework_Exception( + sprintf( + 'Could not load "%s".%s', + + $filename, + $message != '' ? "\n" . $message : '' + ) + ); + } else { + throw new PHPUnit_Framework_Exception($message); + } + } + + return $document; + } + + /** + * + * + * @param DOMNode $node + * @return string + * @since Method available since Release 3.4.0 + */ + public static function nodeToText(DOMNode $node) + { + if ($node->childNodes->length == 1) { + return $node->nodeValue; + } + + $result = ''; + + foreach ($node->childNodes as $childNode) { + $result .= $node->ownerDocument->saveXML($childNode); + } + + return $result; + } + + /** + * + * + * @param DOMNode $node + * @since Method available since Release 3.3.0 + * @author Mattis Stordalen Flister + */ + public static function removeCharacterDataNodes(DOMNode $node) + { + if ($node->hasChildNodes()) { + for ($i = $node->childNodes->length - 1; $i >= 0; $i--) { + if (($child = $node->childNodes->item($i)) instanceof DOMCharacterData) { + $node->removeChild($child); + } + } + } + } + + /** + * "Convert" a DOMElement object into a PHP variable. + * + * @param DOMElement $element + * @return mixed + * @since Method available since Release 3.4.0 + */ + public static function xmlToVariable(DOMElement $element) + { + $variable = NULL; + + switch ($element->tagName) { + case 'array': { + $variable = array(); + + foreach ($element->getElementsByTagName('element') as $element) { + $value = self::xmlToVariable($element->childNodes->item(1)); + + if ($element->hasAttribute('key')) { + $variable[(string)$element->getAttribute('key')] = $value; + } else { + $variable[] = $value; + } + } + } + break; + + case 'object': { + $className = $element->getAttribute('class'); + + if ($element->hasChildNodes()) { + $arguments = $element->childNodes->item(1)->childNodes; + $constructorArgs = array(); + + foreach ($arguments as $argument) { + if ($argument instanceof DOMElement) { + $constructorArgs[] = self::xmlToVariable($argument); + } + } + + $class = new ReflectionClass($className); + $variable = $class->newInstanceArgs($constructorArgs); + } else { + $variable = new $className; + } + } + break; + + case 'boolean': { + $variable = $element->nodeValue == 'true' ? TRUE : FALSE; + } + break; + + case 'integer': + case 'double': + case 'string': { + $variable = $element->nodeValue; + + settype($variable, $element->tagName); + } + break; + } + + return $variable; + } + + /** + * Validate list of keys in the associative array. + * + * @param array $hash + * @param array $validKeys + * @return array + * @throws InvalidArgumentException + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + */ + public static function assertValidKeys(array $hash, array $validKeys) + { + $valids = array(); + + // Normalize validation keys so that we can use both indexed and + // associative arrays. + foreach ($validKeys as $key => $val) { + is_int($key) ? $valids[$val] = NULL : $valids[$key] = $val; + } + + $validKeys = array_keys($valids); + + // Check for invalid keys. + foreach ($hash as $key => $value) { + if (!in_array($key, $validKeys)) { + $unknown[] = $key; + } + } + + if (!empty($unknown)) { + throw new InvalidArgumentException( + 'Unknown key(s): ' . implode(', ', $unknown) + ); + } + + // Add default values for any valid keys that are empty. + foreach ($valids as $key => $value) { + if (!isset($hash[$key])) { + $hash[$key] = $value; + } + } + + return $hash; + } + + /** + * Parse a CSS selector into an associative array suitable for + * use with findNodes(). + * + * @param string $selector + * @param mixed $content + * @return array + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + */ + public static function convertSelectToTag($selector, $content = TRUE) + { + $selector = trim(preg_replace("/\s+/", " ", $selector)); + + // substitute spaces within attribute value + while (preg_match('/\[[^\]]+"[^"]+\s[^"]+"\]/', $selector)) { + $selector = preg_replace( + '/(\[[^\]]+"[^"]+)\s([^"]+"\])/', "$1__SPACE__$2", $selector + ); + } + + if (strstr($selector, ' ')) { + $elements = explode(' ', $selector); + } else { + $elements = array($selector); + } + + $previousTag = array(); + + foreach (array_reverse($elements) as $element) { + $element = str_replace('__SPACE__', ' ', $element); + + // child selector + if ($element == '>') { + $previousTag = array('child' => $previousTag['descendant']); + continue; + } + + $tag = array(); + + // match element tag + preg_match("/^([^\.#\[]*)/", $element, $eltMatches); + + if (!empty($eltMatches[1])) { + $tag['tag'] = $eltMatches[1]; + } + + // match attributes (\[[^\]]*\]*), ids (#[^\.#\[]*), + // and classes (\.[^\.#\[]*)) + preg_match_all( + "/(\[[^\]]*\]*|#[^\.#\[]*|\.[^\.#\[]*)/", $element, $matches + ); + + if (!empty($matches[1])) { + $classes = array(); + $attrs = array(); + + foreach ($matches[1] as $match) { + // id matched + if (substr($match, 0, 1) == '#') { + $tag['id'] = substr($match, 1); + } + + // class matched + else if (substr($match, 0, 1) == '.') { + $classes[] = substr($match, 1); + } + + // attribute matched + else if (substr($match, 0, 1) == '[' && + substr($match, -1, 1) == ']') { + $attribute = substr($match, 1, strlen($match) - 2); + $attribute = str_replace('"', '', $attribute); + + // match single word + if (strstr($attribute, '~=')) { + list($key, $value) = explode('~=', $attribute); + $value = "regexp:/.*\b$value\b.*/"; + } + + // match substring + else if (strstr($attribute, '*=')) { + list($key, $value) = explode('*=', $attribute); + $value = "regexp:/.*$value.*/"; + } + + // exact match + else { + list($key, $value) = explode('=', $attribute); + } + + $attrs[$key] = $value; + } + } + + if ($classes) { + $tag['class'] = join(' ', $classes); + } + + if ($attrs) { + $tag['attributes'] = $attrs; + } + } + + // tag content + if (is_string($content)) { + $tag['content'] = $content; + } + + // determine previous child/descendants + if (!empty($previousTag['descendant'])) { + $tag['descendant'] = $previousTag['descendant']; + } + + else if (!empty($previousTag['child'])) { + $tag['child'] = $previousTag['child']; + } + + $previousTag = array('descendant' => $tag); + } + + return $tag; + } + + /** + * Parse an $actual document and return an array of DOMNodes + * matching the CSS $selector. If an error occurs, it will + * return FALSE. + * + * To only return nodes containing a certain content, give + * the $content to match as a string. Otherwise, setting + * $content to TRUE will return all nodes matching $selector. + * + * The $actual document may be a DOMDocument or a string + * containing XML or HTML, identified by $isHtml. + * + * @param array $selector + * @param string $content + * @param mixed $actual + * @param boolean $isHtml + * @return false|array + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + * @author Tobias Schlitt + */ + public static function cssSelect($selector, $content, $actual, $isHtml = TRUE) + { + $matcher = self::convertSelectToTag($selector, $content); + $dom = self::load($actual, $isHtml); + $tags = self::findNodes($dom, $matcher, $isHtml); + + return $tags; + } + + /** + * Parse out the options from the tag using DOM object tree. + * + * @param DOMDocument $dom + * @param array $options + * @param boolean $isHtml + * @return array + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + * @author Tobias Schlitt + */ + public static function findNodes(DOMDocument $dom, array $options, $isHtml = TRUE) + { + $valid = array( + 'id', 'class', 'tag', 'content', 'attributes', 'parent', + 'child', 'ancestor', 'descendant', 'children' + ); + + $filtered = array(); + $options = self::assertValidKeys($options, $valid); + + // find the element by id + if ($options['id']) { + $options['attributes']['id'] = $options['id']; + } + + if ($options['class']) { + $options['attributes']['class'] = $options['class']; + } + + // find the element by a tag type + if ($options['tag']) { + if ($isHtml) { + $elements = self::getElementsByCaseInsensitiveTagName( + $dom, $options['tag'] + ); + } else { + $elements = $dom->getElementsByTagName($options['tag']); + } + + foreach ($elements as $element) { + $nodes[] = $element; + } + + if (empty($nodes)) { + return FALSE; + } + } + + // no tag selected, get them all + else { + $tags = array( + 'a', 'abbr', 'acronym', 'address', 'area', 'b', 'base', 'bdo', + 'big', 'blockquote', 'body', 'br', 'button', 'caption', 'cite', + 'code', 'col', 'colgroup', 'dd', 'del', 'div', 'dfn', 'dl', + 'dt', 'em', 'fieldset', 'form', 'frame', 'frameset', 'h1', 'h2', + 'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'html', 'i', 'iframe', + 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'link', + 'map', 'meta', 'noframes', 'noscript', 'object', 'ol', 'optgroup', + 'option', 'p', 'param', 'pre', 'q', 'samp', 'script', 'select', + 'small', 'span', 'strong', 'style', 'sub', 'sup', 'table', + 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'title', + 'tr', 'tt', 'ul', 'var' + ); + + foreach ($tags as $tag) { + if ($isHtml) { + $elements = self::getElementsByCaseInsensitiveTagName( + $dom, $tag + ); + } else { + $elements = $dom->getElementsByTagName($tag); + } + + foreach ($elements as $element) { + $nodes[] = $element; + } + } + + if (empty($nodes)) { + return FALSE; + } + } + + // filter by attributes + if ($options['attributes']) { + foreach ($nodes as $node) { + $invalid = FALSE; + + foreach ($options['attributes'] as $name => $value) { + // match by regexp if like "regexp:/foo/i" + if (preg_match('/^regexp\s*:\s*(.*)/i', $value, $matches)) { + if (!preg_match($matches[1], $node->getAttribute($name))) { + $invalid = TRUE; + } + } + + // class can match only a part + else if ($name == 'class') { + // split to individual classes + $findClasses = explode( + ' ', preg_replace("/\s+/", " ", $value) + ); + + $allClasses = explode( + ' ', + preg_replace("/\s+/", " ", $node->getAttribute($name)) + ); + + // make sure each class given is in the actual node + foreach ($findClasses as $findClass) { + if (!in_array($findClass, $allClasses)) { + $invalid = TRUE; + } + } + } + + // match by exact string + else { + if ($node->getAttribute($name) != $value) { + $invalid = TRUE; + } + } + } + + // if every attribute given matched + if (!$invalid) { + $filtered[] = $node; + } + } + + $nodes = $filtered; + $filtered = array(); + + if (empty($nodes)) { + return FALSE; + } + } + + // filter by content + if ($options['content'] !== NULL) { + foreach ($nodes as $node) { + $invalid = FALSE; + + // match by regexp if like "regexp:/foo/i" + if (preg_match('/^regexp\s*:\s*(.*)/i', $options['content'], $matches)) { + if (!preg_match($matches[1], self::getNodeText($node))) { + $invalid = TRUE; + } + } + + // match by exact string + else if (strstr(self::getNodeText($node), $options['content']) === FALSE) { + $invalid = TRUE; + } + + if (!$invalid) { + $filtered[] = $node; + } + } + + $nodes = $filtered; + $filtered = array(); + + if (empty($nodes)) { + return FALSE; + } + } + + // filter by parent node + if ($options['parent']) { + $parentNodes = self::findNodes($dom, $options['parent'], $isHtml); + $parentNode = isset($parentNodes[0]) ? $parentNodes[0] : NULL; + + foreach ($nodes as $node) { + if ($parentNode !== $node->parentNode) { + break; + } + + $filtered[] = $node; + } + + $nodes = $filtered; + $filtered = array(); + + if (empty($nodes)) { + return FALSE; + } + } + + // filter by child node + if ($options['child']) { + $childNodes = self::findNodes($dom, $options['child'], $isHtml); + $childNodes = !empty($childNodes) ? $childNodes : array(); + + foreach ($nodes as $node) { + foreach ($node->childNodes as $child) { + foreach ($childNodes as $childNode) { + if ($childNode === $child) { + $filtered[] = $node; + } + } + } + } + + $nodes = $filtered; + $filtered = array(); + + if (empty($nodes)) { + return FALSE; + } + } + + // filter by ancestor + if ($options['ancestor']) { + $ancestorNodes = self::findNodes($dom, $options['ancestor'], $isHtml); + $ancestorNode = isset($ancestorNodes[0]) ? $ancestorNodes[0] : NULL; + + foreach ($nodes as $node) { + $parent = $node->parentNode; + + while ($parent->nodeType != XML_HTML_DOCUMENT_NODE) { + if ($parent === $ancestorNode) { + $filtered[] = $node; + } + + $parent = $parent->parentNode; + } + } + + $nodes = $filtered; + $filtered = array(); + + if (empty($nodes)) { + return FALSE; + } + } + + // filter by descendant + if ($options['descendant']) { + $descendantNodes = self::findNodes($dom, $options['descendant'], $isHtml); + $descendantNodes = !empty($descendantNodes) ? $descendantNodes : array(); + + foreach ($nodes as $node) { + foreach (self::getDescendants($node) as $descendant) { + foreach ($descendantNodes as $descendantNode) { + if ($descendantNode === $descendant) { + $filtered[] = $node; + } + } + } + } + + $nodes = $filtered; + $filtered = array(); + + if (empty($nodes)) { + return FALSE; + } + } + + // filter by children + if ($options['children']) { + $validChild = array('count', 'greater_than', 'less_than', 'only'); + $childOptions = self::assertValidKeys( + $options['children'], $validChild + ); + + foreach ($nodes as $node) { + $childNodes = $node->childNodes; + + foreach ($childNodes as $childNode) { + if ($childNode->nodeType !== XML_CDATA_SECTION_NODE && + $childNode->nodeType !== XML_TEXT_NODE) { + $children[] = $childNode; + } + } + + // we must have children to pass this filter + if (!empty($children)) { + // exact count of children + if ($childOptions['count'] !== NULL) { + if (count($children) !== $childOptions['count']) { + break; + } + } + + // range count of children + else if ($childOptions['less_than'] !== NULL && + $childOptions['greater_than'] !== NULL) { + if (count($children) >= $childOptions['less_than'] || + count($children) <= $childOptions['greater_than']) { + break; + } + } + + // less than a given count + else if ($childOptions['less_than'] !== NULL) { + if (count($children) >= $childOptions['less_than']) { + break; + } + } + + // more than a given count + else if ($childOptions['greater_than'] !== NULL) { + if (count($children) <= $childOptions['greater_than']) { + break; + } + } + + // match each child against a specific tag + if ($childOptions['only']) { + $onlyNodes = self::findNodes( + $dom, $childOptions['only'], $isHtml + ); + + // try to match each child to one of the 'only' nodes + foreach ($children as $child) { + $matched = FALSE; + + foreach ($onlyNodes as $onlyNode) { + if ($onlyNode === $child) { + $matched = TRUE; + } + } + + if (!$matched) { + break(2); + } + } + } + + $filtered[] = $node; + } + } + + $nodes = $filtered; + $filtered = array(); + + if (empty($nodes)) { + return; + } + } + + // return the first node that matches all criteria + return !empty($nodes) ? $nodes : array(); + } + + /** + * Recursively get flat array of all descendants of this node. + * + * @param DOMNode $node + * @return array + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + */ + protected static function getDescendants(DOMNode $node) + { + $allChildren = array(); + $childNodes = $node->childNodes ? $node->childNodes : array(); + + foreach ($childNodes as $child) { + if ($child->nodeType === XML_CDATA_SECTION_NODE || + $child->nodeType === XML_TEXT_NODE) { + continue; + } + + $children = self::getDescendants($child); + $allChildren = array_merge($allChildren, $children, array($child)); + } + + return isset($allChildren) ? $allChildren : array(); + } + + /** + * Gets elements by case insensitive tagname. + * + * @param DOMDocument $dom + * @param string $tag + * @return DOMNodeList + * @since Method available since Release 3.4.0 + */ + protected static function getElementsByCaseInsensitiveTagName(DOMDocument $dom, $tag) + { + $elements = $dom->getElementsByTagName(strtolower($tag)); + + if ($elements->length == 0) { + $elements = $dom->getElementsByTagName(strtoupper($tag)); + } + + return $elements; + } + + /** + * Get the text value of this node's child text node. + * + * @param DOMNode $node + * @return string + * @since Method available since Release 3.3.0 + * @author Mike Naberezny + * @author Derek DeVries + */ + protected static function getNodeText(DOMNode $node) + { + if (!$node->childNodes instanceof DOMNodeList) { + return ''; + } + + $result = ''; + + foreach ($node->childNodes as $childNode) { + if ($childNode->nodeType === XML_TEXT_NODE) { + $result .= trim($childNode->data) . ' '; + } else { + $result .= self::getNodeText($childNode); + } + } + + return str_replace(' ', ' ', $result); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/Structures/Graph.php b/typo3conf/ext/phpunit/PEAR/Structures/Graph.php new file mode 100644 index 0000000..3757f15 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/Structures/Graph.php @@ -0,0 +1,154 @@ + | +// +-----------------------------------------------------------------------------+ +// +/** + * The Graph.php file contains the definition of the Structures_Graph class + * + * @see Structures_Graph + * @package Structures_Graph + */ + +/* dependencies {{{ */ +/** PEAR base classes */ +require_once 'PEAR.php'; +/** Graph Node */ +require_once 'Structures/Graph/Node.php'; +/* }}} */ + +define('STRUCTURES_GRAPH_ERROR_GENERIC', 100); + +/* class Structures_Graph {{{ */ +/** + * The Structures_Graph class represents a graph data structure. + * + * A Graph is a data structure composed by a set of nodes, connected by arcs. + * Graphs may either be directed or undirected. In a directed graph, arcs are + * directional, and can be traveled only one way. In an undirected graph, arcs + * are bidirectional, and can be traveled both ways. + * + * @author Sérgio Carvalho + * @copyright (c) 2004 by Sérgio Carvalho + * @package Structures_Graph + */ +/* }}} */ +class Structures_Graph { + /* fields {{{ */ + /** + * @access private + */ + var $_nodes = array(); + /** + * @access private + */ + var $_directed = false; + /* }}} */ + + /* Constructor {{{ */ + /** + * + * Constructor + * + * @param boolean Set to true if the graph is directed. Set to false if it is not directed. (Optional, defaults to true) + * @access public + */ + function Structures_Graph($directed = true) { + $this->_directed = $directed; + } + /* }}} */ + + /* isDirected {{{ */ + /** + * + * Return true if a graph is directed + * + * @return boolean true if the graph is directed + * @access public + */ + function isDirected() { + return (boolean) $this->_directed; + } + /* }}} */ + + /* addNode {{{ */ + /** + * + * Add a Node to the Graph + * + * @param Structures_Graph_Node The node to be added. + * @access public + */ + function addNode(&$newNode) { + // We only add nodes + if (!is_a($newNode, 'Structures_Graph_Node')) return Pear::raiseError('Structures_Graph::addNode received an object that is not a Structures_Graph_Node', STRUCTURES_GRAPH_ERROR_GENERIC); + // Graphs are node *sets*, so duplicates are forbidden. We allow nodes that are exactly equal, but disallow equal references. + foreach($this->_nodes as $key => $node) { + /* + ZE1 equality operators choke on the recursive cycle introduced by the _graph field in the Node object. + So, we'll check references the hard way (change $this->_nodes[$key] and check if the change reflects in + $node) + */ + $savedData = $this->_nodes[$key]; + $referenceIsEqualFlag = false; + $this->_nodes[$key] = true; + if ($node === true) { + $this->_nodes[$key] = false; + if ($node === false) $referenceIsEqualFlag = true; + } + $this->_nodes[$key] = $savedData; + if ($referenceIsEqualFlag) return Pear::raiseError('Structures_Graph::addNode received an object that is a duplicate for this dataset', STRUCTURES_GRAPH_ERROR_GENERIC); + } + $this->_nodes[] =& $newNode; + $newNode->setGraph($this); + } + /* }}} */ + + /* removeNode (unimplemented) {{{ */ + /** + * + * Remove a Node from the Graph + * + * @todo This is unimplemented + * @param Structures_Graph_Node The node to be removed from the graph + * @access public + */ + function removeNode(&$node) { + } + /* }}} */ + + /* getNodes {{{ */ + /** + * + * Return the node set, in no particular order. For ordered node sets, use a Graph Manipulator insted. + * + * @access public + * @see Structures_Graph_Manipulator_TopologicalSorter + * @return array The set of nodes in this graph + */ + function &getNodes() { + return $this->_nodes; + } + /* }}} */ +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/Structures/Graph/Manipulator/AcyclicTest.php b/typo3conf/ext/phpunit/PEAR/Structures/Graph/Manipulator/AcyclicTest.php new file mode 100644 index 0000000..fc1ba92 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/Structures/Graph/Manipulator/AcyclicTest.php @@ -0,0 +1,136 @@ + | +// +-----------------------------------------------------------------------------+ +// +/** + * This file contains the definition of the Structures_Graph_Manipulator_AcyclicTest graph manipulator. + * + * @see Structures_Graph_Manipulator_AcyclicTest + * @package Structures_Graph + */ + +/* dependencies {{{ */ +/** */ +require_once 'PEAR.php'; +/** */ +require_once 'Structures/Graph.php'; +/** */ +require_once 'Structures/Graph/Node.php'; +/* }}} */ + +/* class Structures_Graph_Manipulator_AcyclicTest {{{ */ +/** + * The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator + * which tests whether a graph contains a cycle. + * + * The definition of an acyclic graph used in this manipulator is that of a + * DAG. The graph must be directed, or else it is considered cyclic, even when + * there are no arcs. + * + * @author Sérgio Carvalho + * @copyright (c) 2004 by Sérgio Carvalho + * @package Structures_Graph + */ +class Structures_Graph_Manipulator_AcyclicTest { + /* _nonVisitedInDegree {{{ */ + /** + * + * This is a variant of Structures_Graph::inDegree which does + * not count nodes marked as visited. + * + * @access private + * @return integer Number of non-visited nodes that link to this one + */ + function _nonVisitedInDegree(&$node) { + $result = 0; + $graphNodes =& $node->_graph->getNodes(); + foreach (array_keys($graphNodes) as $key) { + if ((!$graphNodes[$key]->getMetadata('acyclic-test-visited')) && $graphNodes[$key]->connectsTo($node)) $result++; + } + return $result; + + } + /* }}} */ + + /* _isAcyclic {{{ */ + /** + * @access private + */ + function _isAcyclic(&$graph) { + // Mark every node as not visited + $nodes =& $graph->getNodes(); + $nodeKeys = array_keys($nodes); + $refGenerator = array(); + foreach($nodeKeys as $key) { + $refGenerator[] = false; + $nodes[$key]->setMetadata('acyclic-test-visited', $refGenerator[sizeof($refGenerator) - 1]); + } + + // Iteratively peel off leaf nodes + do { + // Find out which nodes are leafs (excluding visited nodes) + $leafNodes = array(); + foreach($nodeKeys as $key) { + if ((!$nodes[$key]->getMetadata('acyclic-test-visited')) && Structures_Graph_Manipulator_AcyclicTest::_nonVisitedInDegree($nodes[$key]) == 0) { + $leafNodes[] =& $nodes[$key]; + } + } + // Mark leafs as visited + for ($i=sizeof($leafNodes) - 1; $i>=0; $i--) { + $visited =& $leafNodes[$i]->getMetadata('acyclic-test-visited'); + $visited = true; + $leafNodes[$i]->setMetadata('acyclic-test-visited', $visited); + } + } while (sizeof($leafNodes) > 0); + + // If graph is a DAG, there should be no non-visited nodes. Let's try to prove otherwise + $result = true; + foreach($nodeKeys as $key) if (!$nodes[$key]->getMetadata('acyclic-test-visited')) $result = false; + + // Cleanup visited marks + foreach($nodeKeys as $key) $nodes[$key]->unsetMetadata('acyclic-test-visited'); + + return $result; + } + /* }}} */ + + /* isAcyclic {{{ */ + /** + * + * isAcyclic returns true if a graph contains no cycles, false otherwise. + * + * @return boolean true iff graph is acyclic + * @access public + */ + function isAcyclic(&$graph) { + // We only test graphs + if (!is_a($graph, 'Structures_Graph')) return Pear::raiseError('Structures_Graph_Manipulator_AcyclicTest::isAcyclic received an object that is not a Structures_Graph', STRUCTURES_GRAPH_ERROR_GENERIC); + if (!$graph->isDirected()) return false; // Only directed graphs may be acyclic + + return Structures_Graph_Manipulator_AcyclicTest::_isAcyclic($graph); + } + /* }}} */ +} +/* }}} */ +?> diff --git a/typo3conf/ext/phpunit/PEAR/Structures/Graph/Manipulator/TopologicalSorter.php b/typo3conf/ext/phpunit/PEAR/Structures/Graph/Manipulator/TopologicalSorter.php new file mode 100644 index 0000000..98a9fa0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/Structures/Graph/Manipulator/TopologicalSorter.php @@ -0,0 +1,153 @@ + | +// +-----------------------------------------------------------------------------+ +// +/** + * This file contains the definition of the Structures_Graph_Manipulator_TopologicalSorter class. + * + * @see Structures_Graph_Manipulator_TopologicalSorter + * @package Structures_Graph + */ + +/* dependencies {{{ */ +/** */ +require_once 'PEAR.php'; +/** */ +require_once 'Structures/Graph.php'; +/** */ +require_once 'Structures/Graph/Node.php'; +/** */ +require_once 'Structures/Graph/Manipulator/AcyclicTest.php'; +/* }}} */ + +/* class Structures_Graph_Manipulator_TopologicalSorter {{{ */ +/** + * The Structures_Graph_Manipulator_TopologicalSorter is a manipulator + * which is able to return the set of nodes in a graph, sorted by topological + * order. + * + * A graph may only be sorted topologically iff it's a DAG. You can test it + * with the Structures_Graph_Manipulator_AcyclicTest. + * + * @author Sérgio Carvalho + * @copyright (c) 2004 by Sérgio Carvalho + * @see Structures_Graph_Manipulator_AcyclicTest + * @package Structures_Graph + */ +class Structures_Graph_Manipulator_TopologicalSorter { + /* _nonVisitedInDegree {{{ */ + /** + * + * This is a variant of Structures_Graph::inDegree which does + * not count nodes marked as visited. + * + * @access private + * @return integer Number of non-visited nodes that link to this one + */ + function _nonVisitedInDegree(&$node) { + $result = 0; + $graphNodes =& $node->_graph->getNodes(); + foreach (array_keys($graphNodes) as $key) { + if ((!$graphNodes[$key]->getMetadata('topological-sort-visited')) && $graphNodes[$key]->connectsTo($node)) $result++; + } + return $result; + + } + /* }}} */ + + /* _sort {{{ */ + /** + * @access private + */ + function _sort(&$graph) { + // Mark every node as not visited + $nodes =& $graph->getNodes(); + $nodeKeys = array_keys($nodes); + $refGenerator = array(); + foreach($nodeKeys as $key) { + $refGenerator[] = false; + $nodes[$key]->setMetadata('topological-sort-visited', $refGenerator[sizeof($refGenerator) - 1]); + } + + // Iteratively peel off leaf nodes + $topologicalLevel = 0; + do { + // Find out which nodes are leafs (excluding visited nodes) + $leafNodes = array(); + foreach($nodeKeys as $key) { + if ((!$nodes[$key]->getMetadata('topological-sort-visited')) && Structures_Graph_Manipulator_TopologicalSorter::_nonVisitedInDegree($nodes[$key]) == 0) { + $leafNodes[] =& $nodes[$key]; + } + } + // Mark leafs as visited + $refGenerator[] = $topologicalLevel; + for ($i=sizeof($leafNodes) - 1; $i>=0; $i--) { + $visited =& $leafNodes[$i]->getMetadata('topological-sort-visited'); + $visited = true; + $leafNodes[$i]->setMetadata('topological-sort-visited', $visited); + $leafNodes[$i]->setMetadata('topological-sort-level', $refGenerator[sizeof($refGenerator) - 1]); + } + $topologicalLevel++; + } while (sizeof($leafNodes) > 0); + + // Cleanup visited marks + foreach($nodeKeys as $key) $nodes[$key]->unsetMetadata('topological-sort-visited'); + } + /* }}} */ + + /* sort {{{ */ + /** + * + * sort returns the graph's nodes, sorted by topological order. + * + * The result is an array with + * as many entries as topological levels. Each entry in this array is an array of nodes within + * the given topological level. + * + * @return array The graph's nodes, sorted by topological order. + * @access public + */ + function sort(&$graph) { + // We only sort graphs + if (!is_a($graph, 'Structures_Graph')) return Pear::raiseError('Structures_Graph_Manipulator_TopologicalSorter::sort received an object that is not a Structures_Graph', STRUCTURES_GRAPH_ERROR_GENERIC); + if (!Structures_Graph_Manipulator_AcyclicTest::isAcyclic($graph)) return Pear::raiseError('Structures_Graph_Manipulator_TopologicalSorter::sort received an graph that has cycles', STRUCTURES_GRAPH_ERROR_GENERIC); + + Structures_Graph_Manipulator_TopologicalSorter::_sort($graph); + $result = array(); + + // Fill out result array + $nodes =& $graph->getNodes(); + $nodeKeys = array_keys($nodes); + foreach($nodeKeys as $key) { + if (!array_key_exists($nodes[$key]->getMetadata('topological-sort-level'), $result)) $result[$nodes[$key]->getMetadata('topological-sort-level')] = array(); + $result[$nodes[$key]->getMetadata('topological-sort-level')][] =& $nodes[$key]; + $nodes[$key]->unsetMetadata('topological-sort-level'); + } + + return $result; + } + /* }}} */ +} +/* }}} */ +?> diff --git a/typo3conf/ext/phpunit/PEAR/Structures/Graph/Node.php b/typo3conf/ext/phpunit/PEAR/Structures/Graph/Node.php new file mode 100644 index 0000000..95afa2b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/Structures/Graph/Node.php @@ -0,0 +1,342 @@ + | +// +-----------------------------------------------------------------------------+ +// +/** + * This file contains the definition of the Structures_Graph_Node class + * + * @see Structures_Graph_Node + * @package Structures_Graph + */ + +/* dependencies {{{ */ +/** */ +require_once 'PEAR.php'; +/** */ +require_once 'Structures/Graph.php'; +/* }}} */ + +/* class Structures_Graph_Node {{{ */ +/** + * The Structures_Graph_Node class represents a Node that can be member of a + * graph node set. + * + * A graph node can contain data. Under this API, the node contains default data, + * and key index data. It behaves, thus, both as a regular data node, and as a + * dictionary (or associative array) node. + * + * Regular data is accessed via getData and setData. Key indexed data is accessed + * via getMetadata and setMetadata. + * + * @author Sérgio Carvalho + * @copyright (c) 2004 by Sérgio Carvalho + * @package Structures_Graph + */ +/* }}} */ +class Structures_Graph_Node { + /* fields {{{ */ + /** + * @access private + */ + var $_data = null; + /** @access private */ + var $_metadata = array(); + /** @access private */ + var $_arcs = array(); + /** @access private */ + var $_graph = null; + /* }}} */ + + /* Constructor {{{ */ + /** + * + * Constructor + * + * @access public + */ + function Structures_Graph_Node() { + } + /* }}} */ + + /* getGraph {{{ */ + /** + * + * Node graph getter + * + * @return Structures_Graph Graph where node is stored + * @access public + */ + function &getGraph() { + return $this->_graph; + } + /* }}} */ + + /* setGraph {{{ */ + /** + * + * Node graph setter. This method should not be called directly. Use Graph::addNode instead. + * + * @param Structures_Graph Set the graph for this node. + * @see Structures_Graph::addNode() + * @access public + */ + function setGraph(&$graph) { + $this->_graph =& $graph; + } + /* }}} */ + + /* getData {{{ */ + /** + * + * Node data getter. + * + * Each graph node can contain a reference to one variable. This is the getter for that reference. + * + * @return mixed Data stored in node + * @access public + */ + function &getData() { + return $this->_data; + } + /* }}} */ + + /* setData {{{ */ + /** + * + * Node data setter + * + * Each graph node can contain a reference to one variable. This is the setter for that reference. + * + * @return mixed Data to store in node + * @access public + */ + function setData($data) { + $this->_data =& $data; + } + /* }}} */ + + /* metadataKeyExists {{{ */ + /** + * + * Test for existence of metadata under a given key. + * + * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an + * associative array or in a dictionary. This method tests whether a given metadata key exists for this node. + * + * @param string Key to test + * @return boolean + * @access public + */ + function metadataKeyExists($key) { + return array_key_exists($key, $this->_metadata); + } + /* }}} */ + + /* getMetadata {{{ */ + /** + * + * Node metadata getter + * + * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an + * associative array or in a dictionary. This method gets the data under the given key. If the key does + * not exist, an error will be thrown, so testing using metadataKeyExists might be needed. + * + * @param string Key + * @param boolean nullIfNonexistent (defaults to false). + * @return mixed Metadata Data stored in node under given key + * @see metadataKeyExists + * @access public + */ + function &getMetadata($key, $nullIfNonexistent = false) { + if (array_key_exists($key, $this->_metadata)) { + return $this->_metadata[$key]; + } else { + if ($nullIfNonexistent) { + $a = null; + return $a; + } else { + $a = Pear::raiseError('Structures_Graph_Node::getMetadata: Requested key does not exist', STRUCTURES_GRAPH_ERROR_GENERIC); + return $a; + } + } + } + /* }}} */ + + /* unsetMetadata {{{ */ + /** + * + * Delete metadata by key + * + * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an + * associative array or in a dictionary. This method removes any data that might be stored under the provided key. + * If the key does not exist, no error is thrown, so it is safe using this method without testing for key existence. + * + * @param string Key + * @access public + */ + function unsetMetadata($key) { + if (array_key_exists($key, $this->_metadata)) unset($this->_metadata[$key]); + } + /* }}} */ + + /* setMetadata {{{ */ + /** + * + * Node metadata setter + * + * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an + * associative array or in a dictionary. This method stores data under the given key. If the key already exists, + * previously stored data is discarded. + * + * @param string Key + * @param mixed Data + * @access public + */ + function setMetadata($key, $data) { + $this->_metadata[$key] =& $data; + } + /* }}} */ + + /* _connectTo {{{ */ + /** @access private */ + function _connectTo(&$destinationNode) { + $this->_arcs[] =& $destinationNode; + } + /* }}} */ + + /* connectTo {{{ */ + /** + * + * Connect this node to another one. + * + * If the graph is not directed, the reverse arc, connecting $destinationNode to $this is also created. + * + * @param Structures_Graph_Node Node to connect to + * @access public + */ + function connectTo(&$destinationNode) { + // We only connect to nodes + if (!is_a($destinationNode, 'Structures_Graph_Node')) return Pear::raiseError('Structures_Graph_Node::connectTo received an object that is not a Structures_Graph_Node', STRUCTURES_GRAPH_ERROR_GENERIC); + // Nodes must already be in graphs to be connected + if ($this->_graph == null) return Pear::raiseError('Structures_Graph_Node::connectTo Tried to connect a node that is not in a graph', STRUCTURES_GRAPH_ERROR_GENERIC); + if ($destinationNode->getGraph() == null) return Pear::raiseError('Structures_Graph_Node::connectTo Tried to connect to a node that is not in a graph', STRUCTURES_GRAPH_ERROR_GENERIC); + // Connect here + $this->_connectTo($destinationNode); + // If graph is undirected, connect back + if (!$this->_graph->isDirected()) { + $destinationNode->_connectTo($this); + } + } + /* }}} */ + + /* getNeighbours {{{ */ + /** + * + * Return nodes connected to this one. + * + * @return array Array of nodes + * @access public + */ + function getNeighbours() { + return $this->_arcs; + } + /* }}} */ + + /* connectsTo {{{ */ + /** + * + * Test wether this node has an arc to the target node + * + * @return boolean True if the two nodes are connected + * @access public + */ + function connectsTo(&$target) { + if (version_compare(PHP_VERSION, '5.0.0') >= 0) { + return in_array($target, $this->getNeighbours(), true); + } + + $copy = $target; + $arcKeys = array_keys($this->_arcs); + foreach($arcKeys as $key) { + /* ZE1 chokes on this expression: + if ($target === $arc) return true; + so, we'll use more convoluted stuff + */ + $arc =& $this->_arcs[$key]; + $target = true; + if ($arc === true) { + $target = false; + if ($arc === false) { + $target = $copy; + return true; + } + } + } + $target = $copy; + return false; + } + /* }}} */ + + /* inDegree {{{ */ + /** + * + * Calculate the in degree of the node. + * + * The indegree for a node is the number of arcs entering the node. For non directed graphs, + * the indegree is equal to the outdegree. + * + * @return integer In degree of the node + * @access public + */ + function inDegree() { + if ($this->_graph == null) return 0; + if (!$this->_graph->isDirected()) return $this->outDegree(); + $result = 0; + $graphNodes =& $this->_graph->getNodes(); + foreach (array_keys($graphNodes) as $key) { + if ($graphNodes[$key]->connectsTo($this)) $result++; + } + return $result; + + } + /* }}} */ + + /* outDegree {{{ */ + /** + * + * Calculate the out degree of the node. + * + * The outdegree for a node is the number of arcs exiting the node. For non directed graphs, + * the outdegree is always equal to the indegree. + * + * @return integer Out degree of the node + * @access public + */ + function outDegree() { + if ($this->_graph == null) return 0; + return sizeof($this->_arcs); + } + /* }}} */ +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYaml.php b/typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYaml.php new file mode 100644 index 0000000..2a53cbc --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYaml.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfYaml offers convenience methods to load and dump YAML. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + * @version SVN: $Id: sfYaml.php 78660 2011-05-25 14:01:08Z dkd-kahler $ + */ +class sfYaml +{ + static protected + $spec = '1.2'; + + /** + * Sets the YAML specification version to use. + * + * @param string $version The YAML specification version + */ + static public function setSpecVersion($version) + { + if (!in_array($version, array('1.1', '1.2'))) + { + throw new InvalidArgumentException(sprintf('Version %s of the YAML specifications is not supported', $version)); + } + + self::$spec = $version; + } + + /** + * Gets the YAML specification version to use. + * + * @return string The YAML specification version + */ + static public function getSpecVersion() + { + return self::$spec; + } + + /** + * Loads YAML into a PHP array. + * + * The load method, when supplied with a YAML stream (string or file), + * will do its best to convert YAML in a file into a PHP array. + * + * Usage: + * + * $array = sfYaml::load('config.yml'); + * print_r($array); + * + * + * @param string $input Path of YAML file or string containing YAML + * + * @return array The YAML converted to a PHP array + * + * @throws InvalidArgumentException If the YAML is not valid + */ + public static function load($input) + { + $file = ''; + + // if input is a file, process it + if (strpos($input, "\n") === false && is_file($input)) + { + $file = $input; + + ob_start(); + $retval = include($input); + $content = ob_get_clean(); + + // if an array is returned by the config file assume it's in plain php form else in YAML + $input = is_array($retval) ? $retval : $content; + } + + // if an array is returned by the config file assume it's in plain php form else in YAML + if (is_array($input)) + { + return $input; + } + + require_once dirname(__FILE__).'/sfYamlParser.php'; + + $yaml = new sfYamlParser(); + + try + { + $ret = $yaml->parse($input); + } + catch (Exception $e) + { + throw new InvalidArgumentException(sprintf('Unable to parse %s: %s', $file ? sprintf('file "%s"', $file) : 'string', $e->getMessage())); + } + + return $ret; + } + + /** + * Dumps a PHP array to a YAML string. + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. + * + * @param array $array PHP array + * @param integer $inline The level where you switch to inline YAML + * + * @return string A YAML string representing the original PHP array + */ + public static function dump($array, $inline = 2) + { + require_once dirname(__FILE__).'/sfYamlDumper.php'; + + $yaml = new sfYamlDumper(); + + return $yaml->dump($array, $inline); + } +} + +/** + * Wraps echo to automatically provide a newline. + * + * @param string $string The string to echo with new line + */ +function echoln($string) +{ + echo $string."\n"; +} diff --git a/typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYamlDumper.php b/typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYamlDumper.php new file mode 100644 index 0000000..dd11f2b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYamlDumper.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +require_once(dirname(__FILE__).'/sfYamlInline.php'); + +/** + * sfYamlDumper dumps PHP variables to YAML strings. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + * @version SVN: $Id: sfYamlDumper.php 78660 2011-05-25 14:01:08Z dkd-kahler $ + */ +class sfYamlDumper +{ + /** + * Dumps a PHP value to YAML. + * + * @param mixed $input The PHP value + * @param integer $inline The level where you switch to inline YAML + * @param integer $indent The level o indentation indentation (used internally) + * + * @return string The YAML representation of the PHP value + */ + public function dump($input, $inline = 0, $indent = 0) + { + $output = ''; + $prefix = $indent ? str_repeat(' ', $indent) : ''; + + if ($inline <= 0 || !is_array($input) || empty($input)) + { + $output .= $prefix.sfYamlInline::dump($input); + } + else + { + $isAHash = array_keys($input) !== range(0, count($input) - 1); + + foreach ($input as $key => $value) + { + $willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value); + + $output .= sprintf('%s%s%s%s', + $prefix, + $isAHash ? sfYamlInline::dump($key).':' : '-', + $willBeInlined ? ' ' : "\n", + $this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + 2) + ).($willBeInlined ? "\n" : ''); + } + } + + return $output; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYamlInline.php b/typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYamlInline.php new file mode 100644 index 0000000..8491ed0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYamlInline.php @@ -0,0 +1,442 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +require_once dirname(__FILE__).'/sfYaml.php'; + +/** + * sfYamlInline implements a YAML parser/dumper for the YAML inline syntax. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + * @version SVN: $Id: sfYamlInline.php 78660 2011-05-25 14:01:08Z dkd-kahler $ + */ +class sfYamlInline +{ + const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')'; + + /** + * Convert a YAML string to a PHP array. + * + * @param string $value A YAML string + * + * @return array A PHP array representing the YAML string + */ + static public function load($value) + { + $value = trim($value); + + if (0 == strlen($value)) + { + return ''; + } + + if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) + { + $mbEncoding = mb_internal_encoding(); + mb_internal_encoding('ASCII'); + } + + switch ($value[0]) + { + case '[': + $result = self::parseSequence($value); + break; + case '{': + $result = self::parseMapping($value); + break; + default: + $result = self::parseScalar($value); + } + + if (isset($mbEncoding)) + { + mb_internal_encoding($mbEncoding); + } + + return $result; + } + + /** + * Dumps a given PHP variable to a YAML string. + * + * @param mixed $value The PHP variable to convert + * + * @return string The YAML string representing the PHP array + */ + static public function dump($value) + { + if ('1.1' === sfYaml::getSpecVersion()) + { + $trueValues = array('true', 'on', '+', 'yes', 'y'); + $falseValues = array('false', 'off', '-', 'no', 'n'); + } + else + { + $trueValues = array('true'); + $falseValues = array('false'); + } + + switch (true) + { + case is_resource($value): + throw new InvalidArgumentException('Unable to dump PHP resources in a YAML file.'); + case is_object($value): + return '!!php/object:'.serialize($value); + case is_array($value): + return self::dumpArray($value); + case null === $value: + return 'null'; + case true === $value: + return 'true'; + case false === $value: + return 'false'; + case ctype_digit($value): + return is_string($value) ? "'$value'" : (int) $value; + case is_numeric($value): + return is_infinite($value) ? str_ireplace('INF', '.Inf', strval($value)) : (is_string($value) ? "'$value'" : $value); + case false !== strpos($value, "\n") || false !== strpos($value, "\r"): + return sprintf('"%s"', str_replace(array('"', "\n", "\r"), array('\\"', '\n', '\r'), $value)); + case preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ - ? | < > = ! % @ ` ]/x', $value): + return sprintf("'%s'", str_replace('\'', '\'\'', $value)); + case '' == $value: + return "''"; + case preg_match(self::getTimestampRegex(), $value): + return "'$value'"; + case in_array(strtolower($value), $trueValues): + return "'$value'"; + case in_array(strtolower($value), $falseValues): + return "'$value'"; + case in_array(strtolower($value), array('null', '~')): + return "'$value'"; + default: + return $value; + } + } + + /** + * Dumps a PHP array to a YAML string. + * + * @param array $value The PHP array to dump + * + * @return string The YAML string representing the PHP array + */ + static protected function dumpArray($value) + { + // array + $keys = array_keys($value); + if ( + (1 == count($keys) && '0' == $keys[0]) + || + (count($keys) > 1 && array_reduce($keys, create_function('$v,$w', 'return (integer) $v + $w;'), 0) == count($keys) * (count($keys) - 1) / 2)) + { + $output = array(); + foreach ($value as $val) + { + $output[] = self::dump($val); + } + + return sprintf('[%s]', implode(', ', $output)); + } + + // mapping + $output = array(); + foreach ($value as $key => $val) + { + $output[] = sprintf('%s: %s', self::dump($key), self::dump($val)); + } + + return sprintf('{ %s }', implode(', ', $output)); + } + + /** + * Parses a scalar to a YAML string. + * + * @param scalar $scalar + * @param string $delimiters + * @param array $stringDelimiter + * @param integer $i + * @param boolean $evaluate + * + * @return string A YAML string + */ + static public function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true) + { + if (in_array($scalar[$i], $stringDelimiters)) + { + // quoted scalar + $output = self::parseQuotedScalar($scalar, $i); + } + else + { + // "normal" string + if (!$delimiters) + { + $output = substr($scalar, $i); + $i += strlen($output); + + // remove comments + if (false !== $strpos = strpos($output, ' #')) + { + $output = rtrim(substr($output, 0, $strpos)); + } + } + else if (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) + { + $output = $match[1]; + $i += strlen($output); + } + else + { + throw new InvalidArgumentException(sprintf('Malformed inline YAML string (%s).', $scalar)); + } + + $output = $evaluate ? self::evaluateScalar($output) : $output; + } + + return $output; + } + + /** + * Parses a quoted scalar to YAML. + * + * @param string $scalar + * @param integer $i + * + * @return string A YAML string + */ + static protected function parseQuotedScalar($scalar, &$i) + { + if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) + { + throw new InvalidArgumentException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i))); + } + + $output = substr($match[0], 1, strlen($match[0]) - 2); + + if ('"' == $scalar[$i]) + { + // evaluate the string + $output = str_replace(array('\\"', '\\n', '\\r'), array('"', "\n", "\r"), $output); + } + else + { + // unescape ' + $output = str_replace('\'\'', '\'', $output); + } + + $i += strlen($match[0]); + + return $output; + } + + /** + * Parses a sequence to a YAML string. + * + * @param string $sequence + * @param integer $i + * + * @return string A YAML string + */ + static protected function parseSequence($sequence, &$i = 0) + { + $output = array(); + $len = strlen($sequence); + $i += 1; + + // [foo, bar, ...] + while ($i < $len) + { + switch ($sequence[$i]) + { + case '[': + // nested sequence + $output[] = self::parseSequence($sequence, $i); + break; + case '{': + // nested mapping + $output[] = self::parseMapping($sequence, $i); + break; + case ']': + return $output; + case ',': + case ' ': + break; + default: + $isQuoted = in_array($sequence[$i], array('"', "'")); + $value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i); + + if (!$isQuoted && false !== strpos($value, ': ')) + { + // embedded mapping? + try + { + $value = self::parseMapping('{'.$value.'}'); + } + catch (InvalidArgumentException $e) + { + // no, it's not + } + } + + $output[] = $value; + + --$i; + } + + ++$i; + } + + throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $sequence)); + } + + /** + * Parses a mapping to a YAML string. + * + * @param string $mapping + * @param integer $i + * + * @return string A YAML string + */ + static protected function parseMapping($mapping, &$i = 0) + { + $output = array(); + $len = strlen($mapping); + $i += 1; + + // {foo: bar, bar:foo, ...} + while ($i < $len) + { + switch ($mapping[$i]) + { + case ' ': + case ',': + ++$i; + continue 2; + case '}': + return $output; + } + + // key + $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false); + + // value + $done = false; + while ($i < $len) + { + switch ($mapping[$i]) + { + case '[': + // nested sequence + $output[$key] = self::parseSequence($mapping, $i); + $done = true; + break; + case '{': + // nested mapping + $output[$key] = self::parseMapping($mapping, $i); + $done = true; + break; + case ':': + case ' ': + break; + default: + $output[$key] = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i); + $done = true; + --$i; + } + + ++$i; + + if ($done) + { + continue 2; + } + } + } + + throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $mapping)); + } + + /** + * Evaluates scalars and replaces magic values. + * + * @param string $scalar + * + * @return string A YAML string + */ + static protected function evaluateScalar($scalar) + { + $scalar = trim($scalar); + + if ('1.1' === sfYaml::getSpecVersion()) + { + $trueValues = array('true', 'on', '+', 'yes', 'y'); + $falseValues = array('false', 'off', '-', 'no', 'n'); + } + else + { + $trueValues = array('true'); + $falseValues = array('false'); + } + + switch (true) + { + case 'null' == strtolower($scalar): + case '' == $scalar: + case '~' == $scalar: + return null; + case 0 === strpos($scalar, '!str'): + return (string) substr($scalar, 5); + case 0 === strpos($scalar, '! '): + return intval(self::parseScalar(substr($scalar, 2))); + case 0 === strpos($scalar, '!!php/object:'): + return unserialize(substr($scalar, 13)); + case ctype_digit($scalar): + $raw = $scalar; + $cast = intval($scalar); + return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw); + case in_array(strtolower($scalar), $trueValues): + return true; + case in_array(strtolower($scalar), $falseValues): + return false; + case is_numeric($scalar): + return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar); + case 0 == strcasecmp($scalar, '.inf'): + case 0 == strcasecmp($scalar, '.NaN'): + return -log(0); + case 0 == strcasecmp($scalar, '-.inf'): + return log(0); + case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar): + return floatval(str_replace(',', '', $scalar)); + case preg_match(self::getTimestampRegex(), $scalar): + return strtotime($scalar); + default: + return (string) $scalar; + } + } + + static protected function getTimestampRegex() + { + return <<[0-9][0-9][0-9][0-9]) + -(?P[0-9][0-9]?) + -(?P[0-9][0-9]?) + (?:(?:[Tt]|[ \t]+) + (?P[0-9][0-9]?) + :(?P[0-9][0-9]) + :(?P[0-9][0-9]) + (?:\.(?P[0-9]*))? + (?:[ \t]*(?PZ|(?P[-+])(?P[0-9][0-9]?) + (?::(?P[0-9][0-9]))?))?)? + $~x +EOF; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYamlParser.php b/typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYamlParser.php new file mode 100644 index 0000000..c367708 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/SymfonyComponents/YAML/sfYamlParser.php @@ -0,0 +1,600 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +require_once(dirname(__FILE__).'/sfYamlInline.php'); + +if (!defined('PREG_BAD_UTF8_OFFSET_ERROR')) +{ + define('PREG_BAD_UTF8_OFFSET_ERROR', 5); +} + +/** + * sfYamlParser parses YAML strings to convert them to PHP arrays. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + * @version SVN: $Id: sfYamlParser.php 78660 2011-05-25 14:01:08Z dkd-kahler $ + */ +class sfYamlParser +{ + protected + $offset = 0, + $lines = array(), + $currentLineNb = -1, + $currentLine = '', + $refs = array(); + + /** + * Constructor + * + * @param integer $offset The offset of YAML document (used for line numbers in error messages) + */ + public function __construct($offset = 0) + { + $this->offset = $offset; + } + + /** + * Parses a YAML string to a PHP value. + * + * @param string $value A YAML string + * + * @return mixed A PHP value + * + * @throws InvalidArgumentException If the YAML is not valid + */ + public function parse($value) + { + $this->currentLineNb = -1; + $this->currentLine = ''; + $this->lines = explode("\n", $this->cleanup($value)); + + if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) + { + $mbEncoding = mb_internal_encoding(); + mb_internal_encoding('UTF-8'); + } + + $data = array(); + while ($this->moveToNextLine()) + { + if ($this->isCurrentLineEmpty()) + { + continue; + } + + // tab? + if (preg_match('#^\t+#', $this->currentLine)) + { + throw new InvalidArgumentException(sprintf('A YAML file cannot contain tabs as indentation at line %d (%s).', $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + + $isRef = $isInPlace = $isProcessed = false; + if (preg_match('#^\-(\s+(?P.+?))?\s*$#u', $this->currentLine, $values)) + { + if (isset($values['value']) && preg_match('#^&(?P[^ ]+) *(?P.*)#u', $values['value'], $matches)) + { + $isRef = $matches['ref']; + $values['value'] = $matches['value']; + } + + // array + if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) + { + $c = $this->getRealCurrentLineNb() + 1; + $parser = new sfYamlParser($c); + $parser->refs =& $this->refs; + $data[] = $parser->parse($this->getNextEmbedBlock()); + } + else + { + if (preg_match('/^([^ ]+)\: +({.*?)$/u', $values['value'], $matches)) + { + $data[] = array($matches[1] => sfYamlInline::load($matches[2])); + } + else + { + $data[] = $this->parseValue($values['value']); + } + } + } + else if (preg_match('#^(?P'.sfYamlInline::REGEX_QUOTED_STRING.'|[^ \{\[].*?) *\:(\s+(?P.+?))?\s*$#u', $this->currentLine, $values)) + { + $key = sfYamlInline::parseScalar($values['key']); + + if ('<<' === $key) + { + if (isset($values['value']) && '*' === substr($values['value'], 0, 1)) + { + $isInPlace = substr($values['value'], 1); + if (!array_key_exists($isInPlace, $this->refs)) + { + throw new InvalidArgumentException(sprintf('Reference "%s" does not exist at line %s (%s).', $isInPlace, $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + } + else + { + if (isset($values['value']) && $values['value'] !== '') + { + $value = $values['value']; + } + else + { + $value = $this->getNextEmbedBlock(); + } + $c = $this->getRealCurrentLineNb() + 1; + $parser = new sfYamlParser($c); + $parser->refs =& $this->refs; + $parsed = $parser->parse($value); + + $merged = array(); + if (!is_array($parsed)) + { + throw new InvalidArgumentException(sprintf("YAML merge keys used with a scalar value instead of an array at line %s (%s)", $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + else if (isset($parsed[0])) + { + // Numeric array, merge individual elements + foreach (array_reverse($parsed) as $parsedItem) + { + if (!is_array($parsedItem)) + { + throw new InvalidArgumentException(sprintf("Merge items must be arrays at line %s (%s).", $this->getRealCurrentLineNb() + 1, $parsedItem)); + } + $merged = array_merge($parsedItem, $merged); + } + } + else + { + // Associative array, merge + $merged = array_merge($merge, $parsed); + } + + $isProcessed = $merged; + } + } + else if (isset($values['value']) && preg_match('#^&(?P[^ ]+) *(?P.*)#u', $values['value'], $matches)) + { + $isRef = $matches['ref']; + $values['value'] = $matches['value']; + } + + if ($isProcessed) + { + // Merge keys + $data = $isProcessed; + } + // hash + else if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) + { + // if next line is less indented or equal, then it means that the current value is null + if ($this->isNextLineIndented()) + { + $data[$key] = null; + } + else + { + $c = $this->getRealCurrentLineNb() + 1; + $parser = new sfYamlParser($c); + $parser->refs =& $this->refs; + $data[$key] = $parser->parse($this->getNextEmbedBlock()); + } + } + else + { + if ($isInPlace) + { + $data = $this->refs[$isInPlace]; + } + else + { + $data[$key] = $this->parseValue($values['value']); + } + } + } + else + { + // 1-liner followed by newline + if (2 == count($this->lines) && empty($this->lines[1])) + { + $value = sfYamlInline::load($this->lines[0]); + if (is_array($value)) + { + $first = reset($value); + if ('*' === substr($first, 0, 1)) + { + $data = array(); + foreach ($value as $alias) + { + $data[] = $this->refs[substr($alias, 1)]; + } + $value = $data; + } + } + + if (isset($mbEncoding)) + { + mb_internal_encoding($mbEncoding); + } + + return $value; + } + + switch (preg_last_error()) + { + case PREG_INTERNAL_ERROR: + $error = 'Internal PCRE error on line'; + break; + case PREG_BACKTRACK_LIMIT_ERROR: + $error = 'pcre.backtrack_limit reached on line'; + break; + case PREG_RECURSION_LIMIT_ERROR: + $error = 'pcre.recursion_limit reached on line'; + break; + case PREG_BAD_UTF8_ERROR: + $error = 'Malformed UTF-8 data on line'; + break; + case PREG_BAD_UTF8_OFFSET_ERROR: + $error = 'Offset doesn\'t correspond to the begin of a valid UTF-8 code point on line'; + break; + default: + $error = 'Unable to parse line'; + } + + throw new InvalidArgumentException(sprintf('%s %d (%s).', $error, $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + + if ($isRef) + { + $this->refs[$isRef] = end($data); + } + } + + if (isset($mbEncoding)) + { + mb_internal_encoding($mbEncoding); + } + + return empty($data) ? null : $data; + } + + /** + * Returns the current line number (takes the offset into account). + * + * @return integer The current line number + */ + protected function getRealCurrentLineNb() + { + return $this->currentLineNb + $this->offset; + } + + /** + * Returns the current line indentation. + * + * @return integer The current line indentation + */ + protected function getCurrentLineIndentation() + { + return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' ')); + } + + /** + * Returns the next embed block of YAML. + * + * @return string A YAML string + */ + protected function getNextEmbedBlock() + { + $this->moveToNextLine(); + + $newIndent = $this->getCurrentLineIndentation(); + + if (!$this->isCurrentLineEmpty() && 0 == $newIndent) + { + throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + + $data = array(substr($this->currentLine, $newIndent)); + + while ($this->moveToNextLine()) + { + if ($this->isCurrentLineEmpty()) + { + if ($this->isCurrentLineBlank()) + { + $data[] = substr($this->currentLine, $newIndent); + } + + continue; + } + + $indent = $this->getCurrentLineIndentation(); + + if (preg_match('#^(?P *)$#', $this->currentLine, $match)) + { + // empty line + $data[] = $match['text']; + } + else if ($indent >= $newIndent) + { + $data[] = substr($this->currentLine, $newIndent); + } + else if (0 == $indent) + { + $this->moveToPreviousLine(); + + break; + } + else + { + throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + } + + return implode("\n", $data); + } + + /** + * Moves the parser to the next line. + */ + protected function moveToNextLine() + { + if ($this->currentLineNb >= count($this->lines) - 1) + { + return false; + } + + $this->currentLine = $this->lines[++$this->currentLineNb]; + + return true; + } + + /** + * Moves the parser to the previous line. + */ + protected function moveToPreviousLine() + { + $this->currentLine = $this->lines[--$this->currentLineNb]; + } + + /** + * Parses a YAML value. + * + * @param string $value A YAML value + * + * @return mixed A PHP value + */ + protected function parseValue($value) + { + if ('*' === substr($value, 0, 1)) + { + if (false !== $pos = strpos($value, '#')) + { + $value = substr($value, 1, $pos - 2); + } + else + { + $value = substr($value, 1); + } + + if (!array_key_exists($value, $this->refs)) + { + throw new InvalidArgumentException(sprintf('Reference "%s" does not exist (%s).', $value, $this->currentLine)); + } + return $this->refs[$value]; + } + + if (preg_match('/^(?P\||>)(?P\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P +#.*)?$/', $value, $matches)) + { + $modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : ''; + + return $this->parseFoldedScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), intval(abs($modifiers))); + } + else + { + return sfYamlInline::load($value); + } + } + + /** + * Parses a folded scalar. + * + * @param string $separator The separator that was used to begin this folded scalar (| or >) + * @param string $indicator The indicator that was used to begin this folded scalar (+ or -) + * @param integer $indentation The indentation that was used to begin this folded scalar + * + * @return string The text value + */ + protected function parseFoldedScalar($separator, $indicator = '', $indentation = 0) + { + $separator = '|' == $separator ? "\n" : ' '; + $text = ''; + + $notEOF = $this->moveToNextLine(); + + while ($notEOF && $this->isCurrentLineBlank()) + { + $text .= "\n"; + + $notEOF = $this->moveToNextLine(); + } + + if (!$notEOF) + { + return ''; + } + + if (!preg_match('#^(?P'.($indentation ? str_repeat(' ', $indentation) : ' +').')(?P.*)$#u', $this->currentLine, $matches)) + { + $this->moveToPreviousLine(); + + return ''; + } + + $textIndent = $matches['indent']; + $previousIndent = 0; + + $text .= $matches['text'].$separator; + while ($this->currentLineNb + 1 < count($this->lines)) + { + $this->moveToNextLine(); + + if (preg_match('#^(?P {'.strlen($textIndent).',})(?P.+)$#u', $this->currentLine, $matches)) + { + if (' ' == $separator && $previousIndent != $matches['indent']) + { + $text = substr($text, 0, -1)."\n"; + } + $previousIndent = $matches['indent']; + + $text .= str_repeat(' ', $diff = strlen($matches['indent']) - strlen($textIndent)).$matches['text'].($diff ? "\n" : $separator); + } + else if (preg_match('#^(?P *)$#', $this->currentLine, $matches)) + { + $text .= preg_replace('#^ {1,'.strlen($textIndent).'}#', '', $matches['text'])."\n"; + } + else + { + $this->moveToPreviousLine(); + + break; + } + } + + if (' ' == $separator) + { + // replace last separator by a newline + $text = preg_replace('/ (\n*)$/', "\n$1", $text); + } + + switch ($indicator) + { + case '': + $text = preg_replace('#\n+$#s', "\n", $text); + break; + case '+': + break; + case '-': + $text = preg_replace('#\n+$#s', '', $text); + break; + } + + return $text; + } + + /** + * Returns true if the next line is indented. + * + * @return Boolean Returns true if the next line is indented, false otherwise + */ + protected function isNextLineIndented() + { + $currentIndentation = $this->getCurrentLineIndentation(); + $notEOF = $this->moveToNextLine(); + + while ($notEOF && $this->isCurrentLineEmpty()) + { + $notEOF = $this->moveToNextLine(); + } + + if (false === $notEOF) + { + return false; + } + + $ret = false; + if ($this->getCurrentLineIndentation() <= $currentIndentation) + { + $ret = true; + } + + $this->moveToPreviousLine(); + + return $ret; + } + + /** + * Returns true if the current line is blank or if it is a comment line. + * + * @return Boolean Returns true if the current line is empty or if it is a comment line, false otherwise + */ + protected function isCurrentLineEmpty() + { + return $this->isCurrentLineBlank() || $this->isCurrentLineComment(); + } + + /** + * Returns true if the current line is blank. + * + * @return Boolean Returns true if the current line is blank, false otherwise + */ + protected function isCurrentLineBlank() + { + return '' == trim($this->currentLine, ' '); + } + + /** + * Returns true if the current line is a comment line. + * + * @return Boolean Returns true if the current line is a comment line, false otherwise + */ + protected function isCurrentLineComment() + { + //checking explicitly the first char of the trim is faster than loops or strpos + $ltrimmedLine = ltrim($this->currentLine, ' '); + return $ltrimmedLine[0] === '#'; + } + + /** + * Cleanups a YAML string to be parsed. + * + * @param string $value The input YAML string + * + * @return string A cleaned up YAML string + */ + protected function cleanup($value) + { + $value = str_replace(array("\r\n", "\r"), "\n", $value); + + if (!preg_match("#\n$#", $value)) + { + $value .= "\n"; + } + + // strip YAML header + $count = 0; + $value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#su', '', $value, -1, $count); + $this->offset += $count; + + // remove leading comments + $trimmedValue = preg_replace('#^(\#.*?\n)+#s', '', $value, -1, $count); + if ($count == 1) + { + // items have been removed, update the offset + $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n"); + $value = $trimmedValue; + } + + // remove start of the document marker (---) + $trimmedValue = preg_replace('#^\-\-\-.*?\n#s', '', $value, -1, $count); + if ($count == 1) + { + // items have been removed, update the offset + $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n"); + $value = $trimmedValue; + + // remove end of the document marker (...) + $value = preg_replace('#\.\.\.\s*$#s', '', $value); + } + + return $value; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/System.php b/typo3conf/ext/phpunit/PEAR/System.php new file mode 100644 index 0000000..9b08443 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/System.php @@ -0,0 +1,621 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: System.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR.php'; +require_once 'Console/Getopt.php'; + +$GLOBALS['_System_temp_files'] = array(); + +/** +* System offers cross plattform compatible system functions +* +* Static functions for different operations. Should work under +* Unix and Windows. The names and usage has been taken from its respectively +* GNU commands. The functions will return (bool) false on error and will +* trigger the error with the PHP trigger_error() function (you can silence +* the error by prefixing a '@' sign after the function call, but this +* is not recommended practice. Instead use an error handler with +* {@link set_error_handler()}). +* +* Documentation on this class you can find in: +* http://pear.php.net/manual/ +* +* Example usage: +* if (!@System::rm('-r file1 dir1')) { +* print "could not delete file1 or dir1"; +* } +* +* In case you need to to pass file names with spaces, +* pass the params as an array: +* +* System::rm(array('-r', $file1, $dir1)); +* +* @category pear +* @package System +* @author Tomas V.V. Cox +* @copyright 1997-2006 The PHP Group +* @license http://opensource.org/licenses/bsd-license.php New BSD License +* @version Release: 1.9.3 +* @link http://pear.php.net/package/PEAR +* @since Class available since Release 0.1 +* @static +*/ +class System +{ + /** + * returns the commandline arguments of a function + * + * @param string $argv the commandline + * @param string $short_options the allowed option short-tags + * @param string $long_options the allowed option long-tags + * @return array the given options and there values + * @static + * @access private + */ + function _parseArgs($argv, $short_options, $long_options = null) + { + if (!is_array($argv) && $argv !== null) { + $argv = preg_split('/\s+/', $argv, -1, PREG_SPLIT_NO_EMPTY); + } + return Console_Getopt::getopt2($argv, $short_options); + } + + /** + * Output errors with PHP trigger_error(). You can silence the errors + * with prefixing a "@" sign to the function call: @System::mkdir(..); + * + * @param mixed $error a PEAR error or a string with the error message + * @return bool false + * @static + * @access private + */ + function raiseError($error) + { + if (PEAR::isError($error)) { + $error = $error->getMessage(); + } + trigger_error($error, E_USER_WARNING); + return false; + } + + /** + * Creates a nested array representing the structure of a directory + * + * System::_dirToStruct('dir1', 0) => + * Array + * ( + * [dirs] => Array + * ( + * [0] => dir1 + * ) + * + * [files] => Array + * ( + * [0] => dir1/file2 + * [1] => dir1/file3 + * ) + * ) + * @param string $sPath Name of the directory + * @param integer $maxinst max. deep of the lookup + * @param integer $aktinst starting deep of the lookup + * @param bool $silent if true, do not emit errors. + * @return array the structure of the dir + * @static + * @access private + */ + function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false) + { + $struct = array('dirs' => array(), 'files' => array()); + if (($dir = @opendir($sPath)) === false) { + if (!$silent) { + System::raiseError("Could not open dir $sPath"); + } + return $struct; // XXX could not open error + } + + $struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ? + $list = array(); + while (false !== ($file = readdir($dir))) { + if ($file != '.' && $file != '..') { + $list[] = $file; + } + } + + closedir($dir); + natsort($list); + if ($aktinst < $maxinst || $maxinst == 0) { + foreach ($list as $val) { + $path = $sPath . DIRECTORY_SEPARATOR . $val; + if (is_dir($path) && !is_link($path)) { + $tmp = System::_dirToStruct($path, $maxinst, $aktinst+1, $silent); + $struct = array_merge_recursive($struct, $tmp); + } else { + $struct['files'][] = $path; + } + } + } + + return $struct; + } + + /** + * Creates a nested array representing the structure of a directory and files + * + * @param array $files Array listing files and dirs + * @return array + * @static + * @see System::_dirToStruct() + */ + function _multipleToStruct($files) + { + $struct = array('dirs' => array(), 'files' => array()); + settype($files, 'array'); + foreach ($files as $file) { + if (is_dir($file) && !is_link($file)) { + $tmp = System::_dirToStruct($file, 0); + $struct = array_merge_recursive($tmp, $struct); + } else { + if (!in_array($file, $struct['files'])) { + $struct['files'][] = $file; + } + } + } + return $struct; + } + + /** + * The rm command for removing files. + * Supports multiple files and dirs and also recursive deletes + * + * @param string $args the arguments for rm + * @return mixed PEAR_Error or true for success + * @static + * @access public + */ + function rm($args) + { + $opts = System::_parseArgs($args, 'rf'); // "f" does nothing but I like it :-) + if (PEAR::isError($opts)) { + return System::raiseError($opts); + } + foreach ($opts[0] as $opt) { + if ($opt[0] == 'r') { + $do_recursive = true; + } + } + $ret = true; + if (isset($do_recursive)) { + $struct = System::_multipleToStruct($opts[1]); + foreach ($struct['files'] as $file) { + if (!@unlink($file)) { + $ret = false; + } + } + + rsort($struct['dirs']); + foreach ($struct['dirs'] as $dir) { + if (!@rmdir($dir)) { + $ret = false; + } + } + } else { + foreach ($opts[1] as $file) { + $delete = (is_dir($file)) ? 'rmdir' : 'unlink'; + if (!@$delete($file)) { + $ret = false; + } + } + } + return $ret; + } + + /** + * Make directories. + * + * The -p option will create parent directories + * @param string $args the name of the director(y|ies) to create + * @return bool True for success + * @static + * @access public + */ + function mkDir($args) + { + $opts = System::_parseArgs($args, 'pm:'); + if (PEAR::isError($opts)) { + return System::raiseError($opts); + } + + $mode = 0777; // default mode + foreach ($opts[0] as $opt) { + if ($opt[0] == 'p') { + $create_parents = true; + } elseif ($opt[0] == 'm') { + // if the mode is clearly an octal number (starts with 0) + // convert it to decimal + if (strlen($opt[1]) && $opt[1]{0} == '0') { + $opt[1] = octdec($opt[1]); + } else { + // convert to int + $opt[1] += 0; + } + $mode = $opt[1]; + } + } + + $ret = true; + if (isset($create_parents)) { + foreach ($opts[1] as $dir) { + $dirstack = array(); + while ((!file_exists($dir) || !is_dir($dir)) && + $dir != DIRECTORY_SEPARATOR) { + array_unshift($dirstack, $dir); + $dir = dirname($dir); + } + + while ($newdir = array_shift($dirstack)) { + if (!is_writeable(dirname($newdir))) { + $ret = false; + break; + } + + if (!mkdir($newdir, $mode)) { + $ret = false; + } + } + } + } else { + foreach($opts[1] as $dir) { + if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) { + $ret = false; + } + } + } + + return $ret; + } + + /** + * Concatenate files + * + * Usage: + * 1) $var = System::cat('sample.txt test.txt'); + * 2) System::cat('sample.txt test.txt > final.txt'); + * 3) System::cat('sample.txt test.txt >> final.txt'); + * + * Note: as the class use fopen, urls should work also (test that) + * + * @param string $args the arguments + * @return boolean true on success + * @static + * @access public + */ + function &cat($args) + { + $ret = null; + $files = array(); + if (!is_array($args)) { + $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); + } + + $count_args = count($args); + for ($i = 0; $i < $count_args; $i++) { + if ($args[$i] == '>') { + $mode = 'wb'; + $outputfile = $args[$i+1]; + break; + } elseif ($args[$i] == '>>') { + $mode = 'ab+'; + $outputfile = $args[$i+1]; + break; + } else { + $files[] = $args[$i]; + } + } + $outputfd = false; + if (isset($mode)) { + if (!$outputfd = fopen($outputfile, $mode)) { + $err = System::raiseError("Could not open $outputfile"); + return $err; + } + $ret = true; + } + foreach ($files as $file) { + if (!$fd = fopen($file, 'r')) { + System::raiseError("Could not open $file"); + continue; + } + while ($cont = fread($fd, 2048)) { + if (is_resource($outputfd)) { + fwrite($outputfd, $cont); + } else { + $ret .= $cont; + } + } + fclose($fd); + } + if (is_resource($outputfd)) { + fclose($outputfd); + } + return $ret; + } + + /** + * Creates temporary files or directories. This function will remove + * the created files when the scripts finish its execution. + * + * Usage: + * 1) $tempfile = System::mktemp("prefix"); + * 2) $tempdir = System::mktemp("-d prefix"); + * 3) $tempfile = System::mktemp(); + * 4) $tempfile = System::mktemp("-t /var/tmp prefix"); + * + * prefix -> The string that will be prepended to the temp name + * (defaults to "tmp"). + * -d -> A temporary dir will be created instead of a file. + * -t -> The target dir where the temporary (file|dir) will be created. If + * this param is missing by default the env vars TMP on Windows or + * TMPDIR in Unix will be used. If these vars are also missing + * c:\windows\temp or /tmp will be used. + * + * @param string $args The arguments + * @return mixed the full path of the created (file|dir) or false + * @see System::tmpdir() + * @static + * @access public + */ + function mktemp($args = null) + { + static $first_time = true; + $opts = System::_parseArgs($args, 't:d'); + if (PEAR::isError($opts)) { + return System::raiseError($opts); + } + + foreach ($opts[0] as $opt) { + if ($opt[0] == 'd') { + $tmp_is_dir = true; + } elseif ($opt[0] == 't') { + $tmpdir = $opt[1]; + } + } + + $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp'; + if (!isset($tmpdir)) { + $tmpdir = System::tmpdir(); + } + + if (!System::mkDir(array('-p', $tmpdir))) { + return false; + } + + $tmp = tempnam($tmpdir, $prefix); + if (isset($tmp_is_dir)) { + unlink($tmp); // be careful possible race condition here + if (!mkdir($tmp, 0700)) { + return System::raiseError("Unable to create temporary directory $tmpdir"); + } + } + + $GLOBALS['_System_temp_files'][] = $tmp; + if (isset($tmp_is_dir)) { + //$GLOBALS['_System_temp_files'][] = dirname($tmp); + } + + if ($first_time) { + PEAR::registerShutdownFunc(array('System', '_removeTmpFiles')); + $first_time = false; + } + + return $tmp; + } + + /** + * Remove temporary files created my mkTemp. This function is executed + * at script shutdown time + * + * @static + * @access private + */ + function _removeTmpFiles() + { + if (count($GLOBALS['_System_temp_files'])) { + $delete = $GLOBALS['_System_temp_files']; + array_unshift($delete, '-r'); + System::rm($delete); + $GLOBALS['_System_temp_files'] = array(); + } + } + + /** + * Get the path of the temporal directory set in the system + * by looking in its environments variables. + * Note: php.ini-recommended removes the "E" from the variables_order setting, + * making unavaible the $_ENV array, that s why we do tests with _ENV + * + * @static + * @return string The temporary directory on the system + */ + function tmpdir() + { + if (OS_WINDOWS) { + if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) { + return $var; + } + if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) { + return $var; + } + if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE')) { + return $var; + } + if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) { + return $var; + } + return getenv('SystemRoot') . '\temp'; + } + if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) { + return $var; + } + return realpath('/tmp'); + } + + /** + * The "which" command (show the full path of a command) + * + * @param string $program The command to search for + * @param mixed $fallback Value to return if $program is not found + * + * @return mixed A string with the full path or false if not found + * @static + * @author Stig Bakken + */ + function which($program, $fallback = false) + { + // enforce API + if (!is_string($program) || '' == $program) { + return $fallback; + } + + // full path given + if (basename($program) != $program) { + $path_elements[] = dirname($program); + $program = basename($program); + } else { + // Honor safe mode + if (!ini_get('safe_mode') || !$path = ini_get('safe_mode_exec_dir')) { + $path = getenv('PATH'); + if (!$path) { + $path = getenv('Path'); // some OSes are just stupid enough to do this + } + } + $path_elements = explode(PATH_SEPARATOR, $path); + } + + if (OS_WINDOWS) { + $exe_suffixes = getenv('PATHEXT') + ? explode(PATH_SEPARATOR, getenv('PATHEXT')) + : array('.exe','.bat','.cmd','.com'); + // allow passing a command.exe param + if (strpos($program, '.') !== false) { + array_unshift($exe_suffixes, ''); + } + // is_executable() is not available on windows for PHP4 + $pear_is_executable = (function_exists('is_executable')) ? 'is_executable' : 'is_file'; + } else { + $exe_suffixes = array(''); + $pear_is_executable = 'is_executable'; + } + + foreach ($exe_suffixes as $suff) { + foreach ($path_elements as $dir) { + $file = $dir . DIRECTORY_SEPARATOR . $program . $suff; + if (@$pear_is_executable($file)) { + return $file; + } + } + } + return $fallback; + } + + /** + * The "find" command + * + * Usage: + * + * System::find($dir); + * System::find("$dir -type d"); + * System::find("$dir -type f"); + * System::find("$dir -name *.php"); + * System::find("$dir -name *.php -name *.htm*"); + * System::find("$dir -maxdepth 1"); + * + * Params implmented: + * $dir -> Start the search at this directory + * -type d -> return only directories + * -type f -> return only files + * -maxdepth -> max depth of recursion + * -name -> search pattern (bash style). Multiple -name param allowed + * + * @param mixed Either array or string with the command line + * @return array Array of found files + * @static + * + */ + function find($args) + { + if (!is_array($args)) { + $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); + } + $dir = realpath(array_shift($args)); + if (!$dir) { + return array(); + } + $patterns = array(); + $depth = 0; + $do_files = $do_dirs = true; + $args_count = count($args); + for ($i = 0; $i < $args_count; $i++) { + switch ($args[$i]) { + case '-type': + if (in_array($args[$i+1], array('d', 'f'))) { + if ($args[$i+1] == 'd') { + $do_files = false; + } else { + $do_dirs = false; + } + } + $i++; + break; + case '-name': + $name = preg_quote($args[$i+1], '#'); + // our magic characters ? and * have just been escaped, + // so now we change the escaped versions to PCRE operators + $name = strtr($name, array('\?' => '.', '\*' => '.*')); + $patterns[] = '('.$name.')'; + $i++; + break; + case '-maxdepth': + $depth = $args[$i+1]; + break; + } + } + $path = System::_dirToStruct($dir, $depth, 0, true); + if ($do_files && $do_dirs) { + $files = array_merge($path['files'], $path['dirs']); + } elseif ($do_dirs) { + $files = $path['dirs']; + } else { + $files = $path['files']; + } + if (count($patterns)) { + $dsq = preg_quote(DIRECTORY_SEPARATOR, '#'); + $pattern = '#(^|'.$dsq.')'.implode('|', $patterns).'($|'.$dsq.')#'; + $ret = array(); + $files_count = count($files); + for ($i = 0; $i < $files_count; $i++) { + // only search in the part of the file below the current directory + $filepart = basename($files[$i]); + if (preg_match($pattern, $filepart)) { + $ret[] = $files[$i]; + } + } + return $ret; + } + return $files; + } +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/Text/Template.php b/typo3conf/ext/phpunit/PEAR/Text/Template.php new file mode 100644 index 0000000..f47b243 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/Text/Template.php @@ -0,0 +1,153 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Text + * @package Template + * @author Sebastian Bergmann + * @copyright 2009-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/php-text-template + * @since File available since Release 1.0.0 + */ + +/** + * A simple template engine. + * + * @category Text + * @package Template + * @author Sebastian Bergmann + * @copyright 2009-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.1.0 + * @link http://github.com/sebastianbergmann/php-text-template + * @since Class available since Release 1.0.0 + */ +class Text_Template +{ + /** + * @var string + */ + protected $template = ''; + + /** + * @var array + */ + protected $values = array(); + + /** + * Constructor. + * + * @param string $file + * @throws InvalidArgumentException + */ + public function __construct($file = '') + { + $this->setFile($file); + } + + /** + * Sets the template file. + * + * @param string $file + * @throws InvalidArgumentException + */ + public function setFile($file) + { + $distFile = $file . '.dist'; + + if (file_exists($file)) { + $this->template = file_get_contents($file); + } + + else if (file_exists($distFile)) { + $this->template = file_get_contents($distFile); + } + + else { + throw new InvalidArgumentException( + 'Template file could not be loaded.' + ); + } + } + + /** + * Sets one or more template variables. + * + * @param array $values + * @param boolean $merge + */ + public function setVar(array $values, $merge = TRUE) + { + if (!$merge || empty($this->values)) { + $this->values = $values; + } else { + $this->values = array_merge($this->values, $values); + } + } + + /** + * Renders the template and returns the result. + * + * @return string + */ + public function render() + { + $keys = array(); + + foreach ($this->values as $key => $value) { + $keys[] = '{' . $key . '}'; + } + + return str_replace($keys, $this->values, $this->template); + } + + /** + * Renders the template and writes the result to a file. + * + * @param string $target + */ + public function renderTo($target) + { + $fp = @fopen($target, 'wt'); + + if ($fp) { + fwrite($fp, $this->render()); + fclose($fp); + } else { + throw new RuntimeException('Could not write to ' . $target . '.'); + } + } +} diff --git a/typo3conf/ext/phpunit/PEAR/Text/Template/Autoload.php b/typo3conf/ext/phpunit/PEAR/Text/Template/Autoload.php new file mode 100644 index 0000000..19776de --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/Text/Template/Autoload.php @@ -0,0 +1,65 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Text + * @package Template + * @author Sebastian Bergmann + * @copyright 2009-2010 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://github.com/sebastianbergmann/php-text-template + * @since File available since Release 1.1.0 + */ + +function text_template_autoload($class) { + static $classes = NULL; + static $path = NULL; + + if ($classes === NULL) { + $classes = array( + 'text_template' => '/Template.php' + ); + + $path = dirname(dirname(__FILE__)); + } + + $cn = strtolower($class); + + if (isset($classes[$cn])) { + require $path . $classes[$cn]; + } +} + +spl_autoload_register('text_template_autoload'); diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend.php new file mode 100644 index 0000000..a7dc0a7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend.php @@ -0,0 +1,191 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Backend.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'PEAR.php'; +// }}} + +/** + * XML_RPC Backend class. The backend is responsible for the actual execution of + * a request, as well as payload encoding and decoding. + * + * The only external usage of this class is when explicitely setting the backend, as in + * + * XML_RPC2_Backend::setBackend('php'); + * // or + * XML_RPC2_Backend::setBackend('xmlrpcext'); + * + * Note that if you do not explicitely set the backend, it will be selected automatically. + * + * Internally, this class provides methods to obtain the relevant backend classes: + * - The server class + * - The client class + * - The value class + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +abstract class XML_RPC2_Backend +{ + + // {{{ properties + + /** + * current backend + * + * @var string + */ + protected static $currentBackend; + + // }}} + // {{{ setBackend() + + /** + * Backend setter. + * + * Currently, two backends exist: 'php' and 'XMLRPCext'. + * The PHP backend has no external dependencies, while the xmlrpcext + * requires the xmlrpc extension. + * + * The XMLRPCext backend is quite faster, and will be automatically + * selected when no explicit backend has been set and the extension + * is available. + * + * @param string The backend to select. Either 'php' or 'XMLRPCext'. + */ + public static function setBackend($backend) + { + $backend = ucfirst(strtolower($backend)); + if ( + $backend != 'Php' && + $backend != 'Xmlrpcext' + ) { + throw new XML_RPC2_Exception(sprintf('Backend %s does not exist', $backend)); + } + if ( + $backend == 'Xmlrpcext' && + !function_exists('xmlrpc_server_create') && + !( PEAR::loadExtension('php_xmlrpc') ) + ) { + throw new XML_RPC2_Exception('Unable to load xmlrpc extension.'); + } + self::$currentBackend = $backend; + } + + // }}} + // {{{ getBackend() + + /** + * Backend getter. + * + * Return the current backend name. If no backend was previously selected + * select one and set it. + * + * The xmlrpcext backend is preferred, and will be automatically + * selected when no explicit backend has been set and the xmlrpc + * extension exists. If it does not exist, then the php backend is + * selected. + * + * @return string The current backend + */ + protected static function getBackend() + { + if (!isset(self::$currentBackend)) { + try { + self::setBackend('XMLRPCext'); // We prefer this one + } catch (XML_RPC2_Exception $e) { + // TODO According to PEAR CG logging should occur here + self::setBackend('php'); // But will settle with this one in case of error + } + } + return self::$currentBackend; + } + + // }}} + // {{{ getServerClassname() + + /** + * Include the relevant php files for the server class, and return the backend server + * class name. + * + * @return string The Server class name + */ + public static function getServerClassname() { + require_once(sprintf('XML/RPC2/Backend/%s/Server.php', self::getBackend())); + return sprintf('XML_RPC2_Backend_%s_Server', self::getBackend()); + } + + // }}} + // {{{ getClientClassname() + + /** + * Include the relevant php files for the client class, and return the backend client + * class name. + * + * @return string The Client class name + */ + public static function getClientClassname() { + require_once(sprintf('XML/RPC2/Backend/%s/Client.php', self::getBackend())); + return sprintf('XML_RPC2_Backend_%s_Client', self::getBackend()); + } + + // }}} + // {{{ getValueClassname() + + /** + * Include the relevant php files for the value class, and return the backend value + * class name. + * + * @return string The Value class name + */ + public static function getValueClassname() { + require_once(sprintf('XML/RPC2/Backend/%s/Value.php', self::getBackend())); + return sprintf('XML_RPC2_Backend_%s_Value', self::getBackend()); + } + + // }}} + +} diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Client.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Client.php new file mode 100644 index 0000000..1838153 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Client.php @@ -0,0 +1,143 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Client.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Util/HTTPRequest.php'; +require_once 'XML/RPC2/Value.php'; +require_once 'XML/RPC2/Client.php'; +require_once 'XML/RPC2/Backend/Php/Request.php'; +require_once 'XML/RPC2/Backend/Php/Response.php'; +// }}} + +/** + * XML_RPC client backend class. This is the default, all-php XML_RPC client backend. + * + * This backend does not require the xmlrpc extension to be compiled in. It implements + * XML_RPC based on the always present DOM and SimpleXML PHP5 extensions. + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Php_Client extends XML_RPC2_Client +{ + + // {{{ constructor + + /** + * Construct a new XML_RPC2_Client PHP Backend. + * + * To create a new XML_RPC2_Client, a URI must be provided (e.g. http://xmlrpc.example.com/1.0/). + * Optionally, some options may be set + * + * @param string URI for the XML-RPC server + * @param array (optional) Associative array of options + */ + public function __construct($uri, $options = array()) + { + parent::__construct($uri, $options); + if ($this->encoding != 'utf-8') throw new XML_RPC2_Exception('XML_RPC2_Backend_Php does not support any encoding other than utf-8, due to a simplexml limitation'); + } + + // }}} + // {{{ __call() + + /** + * __call Catchall. This method catches remote method calls and provides for remote forwarding. + * + * If the parameters are native types, this method will use XML_RPC_Value::createFromNative to + * convert it into an XML-RPC type. Whenever a parameter is already an instance of XML_RPC_Value + * it will be used as provided. It follows that, in situations when XML_RPC_Value::createFromNative + * proves inacurate -- as when encoding DateTime values -- you should present an instance of + * XML_RPC_Value in lieu of the native parameter. + * + * @param string Method name + * @param array Parameters + * @return mixed The call result, already decoded into native types + */ + public function __call($methodName, $parameters) + { + $request = new XML_RPC2_Backend_Php_Request($this->prefix . $methodName, $this->encoding); + $request->setParameters($parameters); + $request = $request->encode(); + $uri = $this->uri; + $options = array( + 'encoding' => $this->encoding, + 'proxy' => $this->proxy, + 'sslverify' => $this->sslverify, + 'connectionTimeout' => $this->connectionTimeout + ); + if (isset($this->httpRequest)) $options['httpRequest'] = $this->httpRequest; + $httpRequest = new XML_RPC2_Util_HTTPRequest($uri, $options); + $httpRequest->setPostData($request); + $httpRequest->sendRequest(); + $body = $httpRequest->getBody(); + if ($this->debug) { + XML_RPC2_ClientHelper::printPreParseDebugInfo($request, $body); + } + try { + $document = new SimpleXMLElement($body); + $result = XML_RPC2_Backend_Php_Response::decode($document); + } catch (XML_RPC2_Exception $e) { + if ($this->debug) { + if (get_class($e)=='XML_RPC2_FaultException') { + print "XML_RPC2_FaultException #" . $e->getFaultCode() . " : " . $e->getMessage(); + } else { + print get_class($e) . " : " . $e->getMessage(); + } + } + throw $e; + } + if ($this->debug) { + XML_RPC2_ClientHelper::printPostRequestDebugInformation($result); + } + return $result; + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Request.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Request.php new file mode 100644 index 0000000..3c2f9d4 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Request.php @@ -0,0 +1,205 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Request.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend/Php/Value.php'; +// }}} + +/** + * XML_RPC request backend class. This class represents an XML_RPC request, exposing the methods + * needed to encode/decode a request. + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Php_Request +{ + // {{{ properties + + /** + * Name of requested method + * + * @var mixed + */ + private $_methodName = ''; + + /** + * request parameters + * + * @var array + */ + private $_parameters = null; + + /** + * encoding of the request + * + * @var string + */ + private $_encoding = 'utf-8'; + + // }}} + // {{{ setParameters() + + /** + * parameters property setter + * + * @param mixed value The new parameters + */ + public function setParameters($value) + { + $this->_parameters = $value; + } + + // }}} + // {{{ addParameter() + + /** + * parameters property appender + * + * @param mixed value The new parameter + */ + public function addParameter($value) + { + $this->_parameters[] = $value; + } + + // }}} + // {{{ getParameters() + + /** + * parameters property getter + * + * @return mixed The current parameters + */ + public function getParameters() + { + return $this->_parameters; + } + + // }}} + // {{{ getMethodName() + + /** + * method name getter + * + * @return string method name + */ + public function getMethodName() + { + return $this->_methodName; + } + + // }}} + // {{{ constructor + + /** + * Create a new xml-rpc request with the provided methodname + * + * @param string Name of method targeted by this xml-rpc request + * @param string encoding of the request + */ + function __construct($methodName, $encoding = 'utf-8') + { + $this->_methodName = $methodName; + $this->setParameters(array()); + $this->_encoding = $encoding; + } + + // }}} + // {{{ encode() + + /** + * Encode the request for transmission. + * + * @return string XML-encoded request (a full XML document) + */ + public function encode() + { + $methodName = $this->_methodName; + $parameters = $this->getParameters(); + + $result = '_encoding . '"?>'; + $result .= ''; + $result .= "${methodName}"; + $result .= ''; + foreach($parameters as $parameter) { + $result .= ''; + $result .= ($parameter instanceof XML_RPC2_Backend_Php_Value) ? $parameter->encode() : XML_RPC2_Backend_Php_Value::createFromNative($parameter)->encode(); + $result .= ''; + } + $result .= ''; + $result .= ''; + return $result; + } + + // }}} + // {{{ createFromDecode() + + /** + * Decode a request from XML and construct a request object with the createFromDecoded values + * + * @param SimpleXMLElement The encoded XML-RPC request. + * @return XML_RPC2_Backend_Php_Request The xml-rpc request, represented as an object instance + */ + public static function createFromDecode($simpleXML) + { + $methodName = (string) $simpleXML->methodName; + $params = array(); + foreach ($simpleXML->params->param as $param) { + foreach ($param->value as $value) { + $params[] = XML_RPC2_Backend_Php_Value::createFromDecode($value)->getNativeValue(); + } + } + $result = new XML_RPC2_Backend_Php_Request($methodName); + $result->setParameters($params); + return $result; + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Response.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Response.php new file mode 100644 index 0000000..49f909d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Response.php @@ -0,0 +1,142 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Response.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend/Php/Value.php'; +require_once 'XML/RPC2/Backend/Php/Value/Struct.php'; +// }}} + +/** + * XML-RPC response backend class. + * + * This class represents an XML_RPC request, exposing the methods + * needed to encode/decode an xml-rpc response. + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Php_Response +{ + + // {{{ encode() + + /** + * Encode a normal XML-RPC response, containing the provided value + * + * You may supply a php-native value, or an XML_RPC2_Backend_Php_Value instance, to be returned. Usually providing a native value + * is more convenient. However, for some types, XML_RPC2_Backend_Php_Value::createFromNative can't properly choose the xml-rpc + * type. In these cases, constructing an XML_RPC2_Backend_Php_Value and using it as param here is the only way to return the desired + * type. + * + * @see http://www.xmlrpc.com/spec + * @see XML_RPC2_Backend_Php_Value::createFromNative + * @param mixed $param The result value which the response will envelop + * @param string $encoding encoding + * @return string The XML payload + */ + public static function encode($param, $encoding = 'utf-8') + { + if (!$param instanceof XML_RPC2_Backend_Php_Value) { + $param = XML_RPC2_Backend_Php_Value::createFromNative($param); + } + $result = ''; + $result .= '' . $param->encode() . ''; + return $result; + } + + // }}} + // {{{ encodeFault() + + /** + * Encode a fault XML-RPC response, containing the provided code and message + * + * @see http://www.xmlrpc.com/spec + * @param int $code Response code + * @param string $message Response message + * @param string $encoding encoding + * @return string The XML payload + */ + public static function encodeFault($code, $message, $encoding = 'utf-8') + { + $value = new XML_RPC2_Backend_Php_Value_Struct(array('faultCode' => (int) $code, 'faultString' => (string) $message)); + $result = ''; + $result .= '' . $value->encode() . ''; + return $result; + } + + // }}} + // {{{ decode() + + /** + * Parse a response and either return the native PHP result. + * + * This method receives an XML-RPC response document, in SimpleXML format, decodes it and returns the payload value. + * + * @param SimpleXmlElement $xml The Transport XML + * @return mixed The response payload + * + * @see http://www.xmlrpc.com/spec + * @throws XML_RPC2_FaultException Signals the decoded response was an XML-RPC fault + * @throws XML_RPC2_DecodeException Signals an ill formed payload response section + */ + public static function decode(SimpleXMLElement $xml) + { + $faultNode = $xml->xpath('/methodResponse/fault'); + if (count($faultNode) == 1) { + throw XML_RPC2_FaultException::createFromDecode($faultNode[0]); + } + $paramValueNode = $xml->xpath('/methodResponse/params/param/value'); + if (count($paramValueNode) == 1) { + return XML_RPC2_Backend_Php_Value::createFromDecode($paramValueNode[0])->getNativeValue(); + } + throw new XML_RPC2_DecodeException('Unable to decode xml-rpc response. No fault nor params/param elements found'); + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Server.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Server.php new file mode 100644 index 0000000..f8f3712 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Server.php @@ -0,0 +1,142 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Server.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Backend/Php/Request.php'; +require_once 'XML/RPC2/Backend/Php/Response.php'; +require_once 'XML/RPC2/Exception.php'; +// }}} + +/** + * XML_RPC server class PHP-only backend. + * + * The XML_RPC2_Server does the work of decoding and encoding xml-rpc request and response. The actual + * method execution is delegated to the call handler instance. + * + * The XML_RPC server is responsible for decoding the request and calling the appropriate method in the + * call handler class. It then encodes the result into an XML-RPC response and returns it to the client. + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Php_Server extends XML_RPC2_Server +{ + + // {{{ constructor + + /** + * Create a new XML-RPC Server. + * + * The constructor receives a mandatory parameter: the Call Handler. The call handler executes the actual + * method call. XML_RPC2 server acts as a protocol decoder/encoder between the call handler and the client + * + * @param object $callHandler + * @param array $options associative array of options + * @access public + */ + function __construct($callHandler, $options = array()) + { + parent::__construct($callHandler, $options); + if ($this->encoding != 'utf-8') throw new XML_RPC2_Exception('XML_RPC2_Backend_Php does not support any encoding other than utf-8, due to a simplexml limitation'); + } + + // }}} + // {{{ handleCall() + + /** + * Receive the XML-RPC request, decode the HTTP payload, delegate execution to the call handler, and output the encoded call handler response. + * + */ + public function handleCall() + { + if ($this->autoDocument && $this->input->isEmpty()) { + $this->autoDocument(); + } else { + $response = $this->getResponse(); + header('Content-type: text/xml; charset=' . $this->encoding); + header('Content-length: ' . $this->getContentLength($response)); + print $response; + } + } + + // }}} + // {{{ getResponse() + + /** + * Get the XML response of the XMLRPC server + * + * @return string XML response + */ + public function getResponse() + { + try { + set_error_handler(array('XML_RPC2_Backend_Php_Server', 'errorToException')); + $request = @simplexml_load_string($this->input->readRequest()); + // TODO : do not use exception but a XMLRPC error ! + if (!is_object($request)) throw new XML_RPC2_FaultException('Unable to parse request XML', 0); + $request = XML_RPC2_Backend_Php_Request::createFromDecode($request); + $methodName = $request->getMethodName(); + $arguments = $request->getParameters(); + if ($this->signatureChecking) { + $method = $this->callHandler->getMethod($methodName); + if (!($method)) { + // see http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php for standard error codes + return (XML_RPC2_Backend_Php_Response::encodeFault(-32601, 'server error. requested method not found')); + } + if (!($method->matchesSignature($methodName, $arguments))) { + return (XML_RPC2_Backend_Php_Response::encodeFault(-32602, 'server error. invalid method parameters')); + } + } + restore_error_handler(); + return (XML_RPC2_Backend_Php_Response::encode(call_user_func_array(array($this->callHandler, $methodName), $arguments), $this->encoding)); + } catch (XML_RPC2_FaultException $e) { + return (XML_RPC2_Backend_Php_Response::encodeFault($e->getFaultCode(), $e->getMessage(), $this->encoding)); + } catch (Exception $e) { + return (XML_RPC2_Backend_Php_Response::encodeFault(1, 'Unhandled ' . get_class($e) . ' exception:' . $e->getMessage() . $e->getTraceAsString(), $this->encoding)); + } + } + +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value.php new file mode 100644 index 0000000..a60889d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value.php @@ -0,0 +1,302 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2005 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Value.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Value.php'; +// }}} + +/** + * XML_RPC value abstract class. All XML_RPC value classes inherit from XML_RPC2_Value + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2005 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +abstract class XML_RPC2_Backend_Php_Value extends XML_RPC2_Value +{ + // {{{ properties + + /** + * native value + * + * @var mixed + */ + private $_nativeValue = null; + + // }}} + // {{{ getNativeValue() + + /** + * nativeValue property getter + * + * @return mixed The current nativeValue + */ + public function getNativeValue() + { + return $this->_nativeValue; + } + + // }}} + // {{{ setNativeValue() + + /** + * nativeValue setter + * + * @param mixed $value + */ + protected function setNativeValue($value) + { + $this->_nativeValue = $value; + } + + // }}} + // {{{ createFromNative() + + /** + * Choose a XML_RPC2_Value subclass appropriate for the + * given value and create it. + * + * This method tries to find the most adequate XML-RPC datatype to hold + * a given PHP native type. Note that distinguishing some datatypes may be + * difficult: + * - Timestamps are represented by PHP integers, so an XML_RPC2_Value_Datetime is never returned + * - Indexed arrays and associative arrays are the same native PHP type. In this case: + * a) The array's indexes start at 0 or 1 and increase monotonically with step 1, or + * b) they do not + * in the first case, an XML_RPC2_Value_Array is returned. In the second, a XML_RPC2_Value_Struct is returned. + * - PHP Objects are serialized and represented in an XML_RPC2_Value_Base64 + * - Integers fitting in a 32bit integer are encoded as regular xml-rpc integers + * - Integers larger than 32bit are encoded using the i8 xml-rpc extension + * + * Whenever native object automatic detection proves inaccurate, use XML_RPC2_Value::createFromNative providing + * a valid explicit type as second argument + * + * the appropriate XML_RPC2_Value child class instead. + * + * @param mixed The native value + * @param string The xml-rpc target encoding type, as per the xmlrpc spec (optional) + * @throws XML_RPC2_InvalidTypeEncodeException When the native value has a type that can't be translated to XML_RPC + * @return A new XML_RPC2_Value instance + * @see XML_RPC_Client::__call + * @see XML_RPC_Server + */ + public static function createFromNative($nativeValue, $explicitType = null) + { + if (is_null($explicitType)) { + switch (gettype($nativeValue)) { + case 'boolean': + $explicitType = 'boolean'; + break; + case 'integer': + $explicitType = 'int'; + break; + case 'double': + $explicitType = 'double'; + break; + case 'string': + $explicitType = 'string'; + break; + case 'array': + $explicitType = 'array'; + $keys = array_keys($nativeValue); + if (count($keys) > 0) { + if ($keys[0] !== 0 && ($keys[0] !== 1)) $explicitType = 'struct'; + $i=0; + do { + $previous = $keys[$i]; + $i++; + if (array_key_exists($i, $keys) && ($keys[$i] !== $keys[$i - 1] + 1)) $explicitType = 'struct'; + } while (array_key_exists($i, $keys) && $explicitType == 'array'); + } + break; + case 'object': + if ((strtolower(get_class($nativeValue)) == 'stdclass') && (isset($nativeValue->xmlrpc_type))) { + // In this case, we have a "stdclass native value" (emulate xmlrpcext) + // the type 'base64' or 'datetime' is given by xmlrpc_type public property + $explicitType = $nativeValue->xmlrpc_type; + } else { + $nativeValue = serialize($nativeValue); + $explicitType = 'base64'; + } + break; + case 'resource': + case 'NULL': + case 'unknown type': + throw new XML_RPC2_InvalidTypeEncodeException(sprintf('Impossible to encode value \'%s\' from type \'%s\'. No analogous type in XML_RPC.', + (string) $nativeValue, + gettype($nativeValue))); + default: + throw new XML_RPC2_InvalidTypeEncodeException(sprintf('Unexpected PHP native type returned by gettype: \'%s\', for value \'%s\'', + gettype($nativeValue), + (string) $nativeValue)); + } + } + $explicitType = ucfirst(strtolower($explicitType)); + switch ($explicitType) { + case 'I8': + require_once 'XML/RPC2/Backend/Php/Value/Scalar.php'; + return XML_RPC2_Backend_Php_Value_Scalar::createFromNative($nativeValue, 'Integer64'); + break; + case 'I4': + case 'Int': + case 'Boolean': + case 'Double': + case 'String': + case 'Nil': + require_once 'XML/RPC2/Backend/Php/Value/Scalar.php'; + return XML_RPC2_Backend_Php_Value_Scalar::createFromNative($nativeValue); + break; + case 'Datetime.iso8601': + case 'Datetime': + require_once 'XML/RPC2/Backend/Php/Value/Datetime.php'; + return new XML_RPC2_Backend_Php_Value_Datetime($nativeValue); + break; + case 'Base64': + require_once 'XML/RPC2/Backend/Php/Value/Base64.php'; + return new XML_RPC2_Backend_Php_Value_Base64($nativeValue); + break; + case 'Array': + require_once 'XML/RPC2/Backend/Php/Value/Array.php'; + return new XML_RPC2_Backend_Php_Value_Array($nativeValue); + break; + case 'Struct': + require_once 'XML/RPC2/Backend/Php/Value/Struct.php'; + return new XML_RPC2_Backend_Php_Value_Struct($nativeValue); + break; + default: + throw new XML_RPC2_InvalidTypeEncodeException(sprintf('Unexpected explicit encoding type \'%s\'', $explicitType)); + } + } + + // }}} + // {{{ createFromDecode() + + /** + * Decode an encoded value and build the applicable XML_RPC2_Value subclass + * + * @param SimpleXMLElement The encoded XML-RPC value + * @return mixed the corresponding XML_RPC2_Value object + */ + public static function createFromDecode($simpleXML) + { + // TODO Remove reparsing of XML fragment, when SimpleXML proves more solid. Currently it segfaults when + // xpath is used both in an element and in one of its children + $simpleXML = simplexml_load_string($simpleXML->asXML()); + + $valueType = $simpleXML->xpath('./*'); + if (count($valueType) == 1) { // Usually we must check the node name + $nodename = dom_import_simplexml($valueType[0])->nodeName; + switch ($nodename) { + case 'i8': + $nativeType = 'Integer64'; + break; + case 'i4': + case 'int': + $nativeType = 'Integer'; + break; + case 'boolean': + $nativeType = 'Boolean'; + break; + case 'double': + $nativeType = 'Double'; + break; + case 'string': + $nativeType = 'String'; + break; + case 'dateTime.iso8601': + $nativeType = 'Datetime'; + break; + case 'base64': + $nativeType = 'Base64'; + break; + case 'array': + $nativeType = 'Array'; + break; + case 'struct': + $nativeType = 'Struct'; + break; + case 'nil': + $nativeType = 'Nil'; + break; + default: + throw new XML_RPC2_DecodeException(sprintf('Unable to decode XML-RPC value. Value type is not recognized \'%s\'', $nodename)); + } + } elseif (count($valueType) == 0) { // Default type is string + $nodename = null; + $nativeType = 'String'; + } else { + throw new XML_RPC2_DecodeException(sprintf('Unable to decode XML-RPC value. Value presented %s type nodes: %s.', count($valueType), $simpleXML->asXML())); + } + require_once(sprintf('XML/RPC2/Backend/Php/Value/%s.php', $nativeType)); + $nativeType = 'XML_RPC2_Backend_Php_Value_' . $nativeType; + return self::createFromNative(@call_user_func(array($nativeType, 'decode'), $simpleXML), $nodename); + } + + // }}} + // {{{ encode() + + /** + * Encode the instance into XML, for transport + * + * @return string The encoded XML-RPC value, + */ + // Declaration commented because of: http://pear.php.net/bugs/bug.php?id=8499 +// public abstract function encode(); + + // }}} + // {{{ decode() + + /** + * decode. Decode transport XML and set the instance value accordingly + * + * @param mixed The encoded XML-RPC value, + */ + // Declaration commented because of: http://pear.php.net/bugs/bug.php?id=8499 +// public static abstract function decode($xml); + + // }}} +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Array.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Array.php new file mode 100644 index 0000000..1860001 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Array.php @@ -0,0 +1,131 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Array.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend/Php/Value.php'; +// }}} + +/** + * XML_RPC array value class. Represents values of type array + * + * @author Sergio Carvalho + * @package XML_RPC2 + */ +class XML_RPC2_Backend_Php_Value_Array extends XML_RPC2_Backend_Php_Value +{ + + // {{{ setNativeValue() + + /** + * nativeValue property setter + * + * @param mixed value the new nativeValue + */ + protected function setNativeValue($value) + { + if (!is_array($value)) { + throw new XML_RPC2_InvalidTypeException(sprintf('Cannot create XML_RPC2_Value_Array from type \'%s\'.', gettype($nativeValue))); + } + parent::setNativeValue($value); + } + + // }}} + // {{{ constructor + + /** + * Constructor. Will build a new XML_RPC2_Backend_Php_Value_Array with the given nativeValue + * + * @param mixed nativeValue + */ + public function __construct($nativeValue) + { + $this->setNativeValue($nativeValue); + } + + // }}} + // {{{ encode() + + /** + * Encode the instance into XML, for transport + * + * @return string The encoded XML-RPC value, + */ + public function encode() + { + $result = ''; + foreach($this->getNativeValue() as $element) { + $result .= ''; + $result .= ($element instanceof XML_RPC2_Backend_Php_Value) ? + $element->encode() : + XML_RPC2_Backend_Php_Value::createFromNative($element)->encode(); + $result .= ''; + } + $result .= ''; + return $result; + } + + // }}} + // {{{ decode() + + /** + * Decode transport XML and set the instance value accordingly + * + * @param mixed The encoded XML-RPC value, + */ + public static function decode($xml) + { + // TODO Remove reparsing of XML fragment, when SimpleXML proves more solid. Currently it segfaults when + // xpath is used both in an element and in one of its children + $xml = simplexml_load_string($xml->asXML()); + $values = $xml->xpath('/value/array/data/value'); + $result = array(); + foreach (array_keys($values) as $i) { + $result[] = XML_RPC2_Backend_Php_Value::createFromDecode($values[$i])->getNativeValue(); + } + return $result; + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Base64.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Base64.php new file mode 100644 index 0000000..bc69d78 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Base64.php @@ -0,0 +1,135 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Base64.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend/Php/Value/Scalar.php'; +// }}} + +/** + * XML_RPC base64 value class. Instances of this class represent base64-encoded string scalars in XML_RPC + * + * To work on a compatible way with the xmlrpcext backend, we introduce a particular "nativeValue" which is + * a standard class (stdclass) with two public properties : + * scalar => the string (non encoded) + * xmlrpc_type => 'base64' + * + * The constructor can be called with a "classic" string or with a such object + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Php_Value_Base64 extends XML_RPC2_Backend_Php_Value +{ + + // {{{ constructor + + /** + * Constructor. Will build a new XML_RPC2_Backend_Php_Value_Base64 with the given value + * + * This class handles encoding-decoding internally. Do not provide the + * native string base64-encoded + * + * @param mixed String $nativeValue to be transmited base64-encoded or "stdclass native value" + */ + public function __construct($nativeValue) + { + if ((is_object($nativeValue)) &&(strtolower(get_class($nativeValue)) == 'stdclass') && (isset($nativeValue->xmlrpc_type))) { + $scalar = $nativeValue->scalar; + } else { + if (!is_string($nativeValue)) { + throw new XML_RPC2_InvalidTypeException(sprintf('Cannot create XML_RPC2_Backend_Php_Value_Base64 from type \'%s\'.', gettype($nativeValue))); + } + $scalar = $nativeValue; + } + $tmp = new stdclass(); + $tmp->scalar = $scalar; + $tmp->xmlrpc_type = 'base64'; + $this->setNativeValue($tmp); + } + + // }}} + // {{{ encode() + + /** + * Encode the instance into XML, for transport + * + * @return string The encoded XML-RPC value, + */ + public function encode() + { + $native = $this->getNativeValue(); + return '' . base64_encode($native->scalar) . ''; + } + + // }}} + // {{{ decode() + + /** + * Decode transport XML and set the instance value accordingly + * + * @param mixed $xml The encoded XML-RPC value, + */ + public static function decode($xml) + { + // TODO Remove reparsing of XML fragment, when SimpleXML proves more solid. Currently it segfaults when + // xpath is used both in an element and in one of its children + $xml = simplexml_load_string($xml->asXML()); + $value = $xml->xpath('/value/base64/text()'); + if (!array_key_exists(0, $value)) { + $value = $xml->xpath('/value/text()'); + } + // Emulate xmlrpcext results (to be able to switch from a backend to another) + $result = new stdclass(); + $result->scalar = base64_decode($value[0]); + $result->xmlrpc_type = 'base64'; + return $result; + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Boolean.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Boolean.php new file mode 100644 index 0000000..13efd5f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Boolean.php @@ -0,0 +1,108 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Boolean.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend/Php/Value/Scalar.php'; +// }}} + +/** + * XML_RPC boolean value class. Instances of this class represent boolean scalars in XML_RPC + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Php_Value_Boolean extends XML_RPC2_Backend_Php_Value_Scalar +{ + + // {{{ constructor + + /** + * Constructor. Will build a new XML_RPC2_Value_Boolean with the given value + * + * @param mixed value + */ + public function __construct($nativeValue) + { + parent::__construct('boolean', $nativeValue); + } + + // }}} + // {{{ encode() + + /** + * Encode the instance into XML, for transport + * + * @return string The encoded XML-RPC value, + */ + public function encode() + { + return '' . ($this->getNativeValue() ? 1 : 0). ''; + } + + // }}} + // {{{ decode() + + /** + * decode. Decode transport XML and set the instance value accordingly + * + * @param mixed The encoded XML-RPC value, + */ + public static function decode($xml) + { + // TODO Remove reparsing of XML fragment, when SimpleXML proves more solid. Currently it segfaults when + // xpath is used both in an element and in one of its children + $xml = simplexml_load_string($xml->asXML()); + $value = $xml->xpath('/value/boolean/text()'); + + // Double cast explanation: http://pear.php.net/bugs/bug.php?id=8644 + return (boolean) ((string) $value[0]); + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Datetime.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Datetime.php new file mode 100644 index 0000000..9555b6f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Datetime.php @@ -0,0 +1,209 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Datetime.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend/Php/Value/Scalar.php'; +// }}} + +/** + * XML_RPC datetime value class. Instances of this class represent datetime scalars in XML_RPC + * + * To work on a compatible way with the xmlrpcext backend, we introduce a particular "nativeValue" which is + * a standard class (stdclass) with three public properties : + * scalar => the iso8601 date string + * timestamp => the corresponding timestamp (int) + * xmlrpc_type => 'datetime' + * + * The constructor can be called with a iso8601 string, with a timestamp or with a such object + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Php_Value_Datetime extends XML_RPC2_Backend_Php_Value +{ + + // {{{ constructor + + /** + * Constructor. Will build a new XML_RPC2_Backend_Php_Value_Datetime with the given value + * + * The provided value can be an int, which will be interpreted as a Unix timestamp, or + * a string in iso8601 format, or a "stdclass native value" + * + * @param mixed $nativeValue a timestamp, an iso8601 date or a "stdclass native value" + * @see http://www.w3.org/TR/NOTE-datetime + */ + public function __construct($nativeValue) + { + if ((!is_int($nativeValue)) and (!is_float($nativeValue)) and (!is_string($nativeValue)) and (!is_object($nativeValue))) { + throw new XML_RPC2_InvalidTypeException(sprintf('Cannot create XML_RPC2_Backend_Php_Value_Datetime from type \'%s\'.', gettype($nativeValue))); + } + if ((is_object($nativeValue)) &&(strtolower(get_class($nativeValue)) == 'stdclass') && (isset($nativeValue->xmlrpc_type))) { + $scalar = $nativeValue->scalar; + $timestamp = $nativeValue->timestamp; + } else { + if ((is_int($nativeValue)) or (is_float($nativeValue))) { + $scalar = XML_RPC2_Backend_Php_Value_Datetime::_timestampToIso8601($nativeValue); + $timestamp = (int) $nativeValue; + } elseif (is_string($nativeValue)) { + $scalar= $nativeValue; + $timestamp = (int) XML_RPC2_Backend_Php_Value_Datetime::_iso8601ToTimestamp($nativeValue); + } else { + throw new XML_RPC2_InvalidTypeException(sprintf('Cannot create XML_RPC2_Backend_Php_Value_Datetime from type \'%s\'.', gettype($nativeValue))); + } + } + $tmp = new stdclass(); + $tmp->scalar = $scalar; + $tmp->timestamp = $timestamp; + $tmp->xmlrpc_type = 'datetime'; + $this->setNativeValue($tmp); + } + + // }}} + // {{{ _iso8601ToTimestamp() + + /** + * Convert a iso8601 datetime string into timestamp + * + * @param string $datetime iso8601 datetime + * @return int corresponding timestamp + */ + private static function _iso8601ToTimestamp($datetime) + { + if (!preg_match('/([0-9]{4})(-?([0-9]{2})(-?([0-9]{2})(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?/', $datetime, $matches)) { + throw new XML_RPC2_InvalidDateFormatException(sprintf('Provided date \'%s\' is not ISO-8601.', $datetime)); + } + $year = $matches[1]; + $month = array_key_exists(3, $matches) ? $matches[3] : 1; + $day = array_key_exists(5, $matches) ? $matches[5] : 1; + $hour = array_key_exists(7, $matches) ? $matches[7] : 0; + $minutes = array_key_exists(8, $matches) ? $matches[8] : 0; + $seconds = array_key_exists(10, $matches) ? $matches[10] : 0; + $milliseconds = array_key_exists(12, $matches) ? ((double) ('0.' . $matches[12])) : 0; + if (array_key_exists(13, $matches)) { + if ($matches[13] == 'Z') { + $tzSeconds = 0; + } else { + $tmp = ($matches[15] == '-') ? -1 : 1; + $tzSeconds = $tmp * (((int) $matches[16]) * 3600 + ((int) $matches[17]) * 60); + } + } else { + $tzSeconds = 0; + } + if (class_exists('DateTime')) { + $result = new DateTime(); + $result->setDate($year, $month, $day); + $result->setTime($hour, $minutes, $seconds); + $result = $result->getTimestamp(); + if ($milliseconds==0) return $result; + return ((float) $result) + $milliseconds/1000; + } else { + $result = ((double) @mktime($hour, $minutes, $seconds, $month, $day, $year, 0)) + + ((double) $milliseconds) - + ((double) $tzSeconds); + if ($milliseconds==0) return ((int) $result); + return $result; + } + } + + // }}} + // {{{ _timestampToIso8601() + + /** + * Convert a timestamp into an iso8601 datetime + * + * @param int $timestamp timestamp + * @return string iso8601 datetim + */ + private static function _timestampToIso8601($timestamp) + { + return strftime('%Y%m%dT%H:%M:%S', (int) $timestamp); + } + + // }}} + // {{{ decode() + + /** + * Decode transport XML and set the instance value accordingly + * + * @param mixed The encoded XML-RPC value, + */ + public static function decode($xml) + { + // TODO Remove reparsing of XML fragment, when SimpleXML proves more solid. Currently it segfaults when + // xpath is used both in an element and in one of its children + $xml = simplexml_load_string($xml->asXML()); + $value = $xml->xpath('/value/dateTime.iso8601/text()'); + if (!array_key_exists(0, $value)) { + $value = $xml->xpath('/value/text()'); + } + // Emulate xmlrpcext results (to be able to switch from a backend to another) + $result = new stdclass(); + $result->scalar = (string) $value[0]; + $result->timestamp = (int) XML_RPC2_Backend_Php_Value_Datetime::_iso8601ToTimestamp((string) $value[0]); + $result->xmlrpc_type = 'datetime'; + return $result; + } + + // }}} + // {{{ encode() + + /** + * Encode the instance into XML, for transport + * + * @return string The encoded XML-RPC value, + */ + public function encode() + { + $native = $this->getNativeValue(); + return '' . $native->scalar . ''; + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Double.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Double.php new file mode 100644 index 0000000..6193da0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Double.php @@ -0,0 +1,96 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Double.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend/Php/Value/Scalar.php'; +// }}} + +/** + * XML_RPC double value class. Instances of this class represent int scalars in XML_RPC + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Php_Value_Double extends XML_RPC2_Backend_Php_Value_Scalar +{ + + // {{{ constructor + + /** + * Constructor. Will build a new XML_RPC2_Backend_Php_Value_Double with the given value + * + * @param mixed value + */ + public function __construct($nativeValue) + { + $this->setScalarType('double'); + $this->setNativeValue($nativeValue); + } + + // }}} + // {{{ decode() + + /** + * decode. Decode transport XML and set the instance value accordingly + * + * @param mixed The encoded XML-RPC value, + */ + public static function decode($xml) + { + // TODO Remove reparsing of XML fragment, when SimpleXML proves more solid. Currently it segfaults when + // xpath is used both in an element and in one of its children + $xml = simplexml_load_string($xml->asXML()); + $value = $xml->xpath('/value/double/text()'); + + // Double cast explanation: http://pear.php.net/bugs/bug.php?id=8644 + return (double) ((string) $value[0]); + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Integer.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Integer.php new file mode 100644 index 0000000..576d3b2 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Integer.php @@ -0,0 +1,96 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Integer.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend/Php/Value/Scalar.php'; +// }}} + +/** + * XML_RPC integer value class. Instances of this class represent int scalars in XML_RPC + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Php_Value_Integer extends XML_RPC2_Backend_Php_Value_Scalar +{ + + // {{{ constructor + + /** + * Constructor. Will build a new XML_RPC2_Backend_Php_Value_Integer with the given value + * + * @param mixed value + */ + public function __construct($nativeValue) + { + $this->setScalarType('int'); + $this->setNativeValue($nativeValue); + } + + // }}} + // {{{ decode() + + /** + * decode. Decode transport XML and set the instance value accordingly + * + * @param mixed The decoded XML-RPC value, + */ + public static function decode($xml) + { + // TODO Remove reparsing of XML fragment, when SimpleXML proves more solid. Currently it segfaults when + // xpath is used both in an element and in one of its children + $xml = simplexml_load_string($xml->asXML()); + $value = $xml->xpath('/value/int/text()|/value/i4/text()'); + + // Double cast explanation: http://pear.php.net/bugs/bug.php?id=8644 + return (int) ((string) $value[0]); + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Integer64.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Integer64.php new file mode 100644 index 0000000..3561b59 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Integer64.php @@ -0,0 +1,97 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Integer64.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend/Php/Value/Scalar.php'; +// }}} + +/** + * XML_RPC integer value class. Instances of this class represent int scalars in XML_RPC + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Php_Value_Integer64 extends XML_RPC2_Backend_Php_Value_Scalar +{ + + // {{{ constructor + + /** + * Constructor. Will build a new XML_RPC2_Backend_Php_Value_Integer64 with the given value + * + * @param mixed value + */ + public function __construct($nativeValue) + { + if (PHP_INT_SIZE < 8) throw new XML_RPC2_ConfigException('i8 XML-RPC extension can only be used with 64 bit (or larger) architectures'); + $this->setScalarType('i8'); + $this->setNativeValue($nativeValue); + } + + // }}} + // {{{ decode() + + /** + * decode. Decode transport XML and set the instance value accordingly + * + * @param mixed The decoded XML-RPC value, + */ + public static function decode($xml) + { + // TODO Remove reparsing of XML fragment, when SimpleXML proves more solid. Currently it segfaults when + // xpath is used both in an element and in one of its children + $xml = simplexml_load_string($xml->asXML()); + $value = $xml->xpath('/value/i8/text()'); + + // Double cast explanation: http://pear.php.net/bugs/bug.php?id=8644 + return (int) ((string) $value[0]); + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Nil.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Nil.php new file mode 100644 index 0000000..d138c2c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Nil.php @@ -0,0 +1,90 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Nil.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend/Php/Value/Scalar.php'; +// }}} + +/** + * XML_RPC null value class. Instances of this class represent null scalars in XML_RPC + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Php_Value_Nil extends XML_RPC2_Backend_Php_Value_Scalar +{ + + // {{{ constructor + + /** + * Constructor. Will build a new XML_RPC2_Backend_Php_Value_Nil with the given value + * + * @param mixed value + */ + public function __construct() + { + $this->setScalarType('nil'); + $this->setNativeValue(null); + } + + // }}} + // {{{ decode() + + /** + * decode. Decode transport XML and set the instance value accordingly + * + * @param mixed The decoded XML-RPC value, + */ + public static function decode($xml) + { + return null; + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Scalar.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Scalar.php new file mode 100644 index 0000000..628593f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Scalar.php @@ -0,0 +1,179 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Scalar.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend/Php/Value.php'; +// }}} + +/** + * XML_RPC scalar value abstract class. All XML_RPC value classes representing scalar types inherit from XML_RPC2_Value_Scalar + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +abstract class XML_RPC2_Backend_Php_Value_Scalar extends XML_RPC2_Backend_Php_Value +{ + + // {{{ properties + + /** + * scalar type + * + * @var string + */ + private $_scalarType = null; + + // }}} + // {{{ setScalarType() + + /** + * scalarType property setter + * + * @param mixed value The new scalarType + */ + protected function setScalarType($value) + { + switch ($value) { + case 'nil': + case 'int': + case 'i8': + case 'i4': + case 'boolean': + case 'string': + case 'double': + case 'dateTime.iso8601': + case 'base64': + $this->_scalarType = $value; + break; + default: + throw new XML_RPC2_InvalidTypeException(sprintf('Type \'%s\' is not an XML-RPC scalar type', $value)); + } + } + + // }}} + // {{{ getScalarType() + + /** + * scalarType property getter + * + * @return mixed The current scalarType + */ + public function getScalarType() + { + return $this->_scalarType; + } + + // }}} + // {{{ constructor + + /** + * Constructor. Will build a new XML_RPC2_Value_Scalar with the given nativeValue + * + * @param mixed nativeValue + */ + public function __construct($scalarType, $nativeValue) + { + $this->setScalarType($scalarType); + $this->setNativeValue($nativeValue); + } + + // }}} + // {{{ createFromNative() + + /** + * Choose a XML_RPC2_Value subclass appropriate for the + * given value and create it. + * + * @param string The native value + * @param string Optinally, the scalar type to use + * @throws XML_RPC2_InvalidTypeEncodeException When native value's type is not a native type + * @return XML_RPC2_Value The newly created value + */ + public static function createFromNative($nativeValue, $explicitType = null) + { + if (is_null($explicitType)) { + switch (gettype($nativeValue)) { + case 'integer': + $explicitType = $nativeValue <= 2147483647 /* PHP_INT_MAX on 32 bit systems */ ? gettype($nativeValue) : 'Integer64'; + break; + case 'NULL': + $explicitType = 'Nil'; + break; + case 'boolean': + case 'double': + case 'string': + $explicitType = gettype($nativeValue); + break; + default: + throw new XML_RPC2_InvalidTypeEncodeException(sprintf('Impossible to encode scalar value \'%s\' from type \'%s\'. Native type is not a scalar XML_RPC type (boolean, integer, double, string)', + (string) $nativeValue, + gettype($nativeValue))); + } + } + $explicitType = ucfirst(strtolower($explicitType)); + require_once(sprintf('XML/RPC2/Backend/Php/Value/%s.php', $explicitType)); + $explicitType = sprintf('XML_RPC2_Backend_Php_Value_%s', $explicitType); + return new $explicitType($nativeValue); + } + + // }}} + // {{{ encode() + + /** + * Encode the instance into XML, for transport + * + * @return string The encoded XML-RPC value, + */ + public function encode() + { + return '<' . $this->getScalarType() . '>' . $this->getNativeValue() . 'getScalarType() . '>'; + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/String.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/String.php new file mode 100644 index 0000000..4defaaf --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/String.php @@ -0,0 +1,110 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: String.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend/Php/Value/Scalar.php'; +// }}} + +/** + * XML_RPC string value class. Instances of this class represent string scalars in XML_RPC + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Php_Value_String extends XML_RPC2_Backend_Php_Value_Scalar +{ + + // {{{ constructor + + /** + * Constructor. Will build a new XML_RPC2_Backend_Php_Value_String with the given value + * + * @param mixed value + */ + public function __construct($nativeValue) + { + $this->setScalarType('string'); + $this->setNativeValue($nativeValue); + } + + // }}} + // {{{ encode() + + /** + * Encode the instance into XML, for transport + * + * @return string The encoded XML-RPC value, + */ + public function encode() + { + return '' . strtr($this->getNativeValue(),array('&' => '&', '<' => '<' , '>' => '>')) . ''; + } + + // }}} + // {{{ decode() + + /** + * Decode transport XML and set the instance value accordingly + * + * @param mixed The encoded XML-RPC value, + */ + public static function decode($xml) + { + /* Stupid way of testing for the presence of string element. I don't know another one. + At least got rid of the xpath and consequent reparsing of the XML + */ + if ($xml->string->asXML() === FALSE) { + return (string) $xml; + } else { + return (string) $xml->string; + } + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Struct.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Struct.php new file mode 100644 index 0000000..9fa3d63 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Php/Value/Struct.php @@ -0,0 +1,140 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Struct.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend/Php/Value.php'; +// }}} + +/** + * XML_RPC struct value class. Represents values of type struct (associative struct) + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Php_Value_Struct extends XML_RPC2_Backend_Php_Value +{ + + // {{{ setNativeValue() + + /** + * nativeValue property setter + * + * @param mixed value the new nativeValue + */ + protected function setNativeValue($value) + { + if (!is_array($value)) { + throw new XML_RPC2_InvalidTypeException(sprintf('Cannot create XML_RPC2_Backend_Php_Value_Struct from type \'%s\'.', gettype($nativeValue))); + } + parent::setNativeValue($value); + } + + // }}} + // {{{ constructor + + /** + * Constructor. Will build a new XML_RPC2_Backend_Php_Value_Scalar with the given nativeValue + * + * @param mixed nativeValue + */ + public function __construct($nativeValue) + { + $this->setNativeValue($nativeValue); + } + + // }}} + // {{{ encode() + + /** + * Encode the instance into XML, for transport + * + * @return string The encoded XML-RPC value, + */ + public function encode() + { + $result = ''; + foreach($this->getNativeValue() as $name => $element) { + $result .= ''; + $result .= ''; + $result .= strtr($name, array('&' => '&', '<' => '<', '>' => '>')); + $result .= ''; + $result .= ''; + $result .= ($element instanceof XML_RPC2_Backend_Php_Value) ? + $element->encode() : + XML_RPC2_Backend_Php_Value::createFromNative($element)->encode(); + $result .= ''; + $result .= ''; + } + $result .= ''; + return $result; + } + + // }}} + // {{{ decode() + + /** + * Decode transport XML and set the instance value accordingly + * + * @param mixed The encoded XML-RPC value, + */ + public static function decode($xml) + { + // TODO Remove reparsing of XML fragment, when SimpleXML proves more solid. Currently it segfaults when + // xpath is used both in an element and in one of its children + $xml = simplexml_load_string($xml->asXML()); + $values = $xml->xpath('/value/struct/member'); + $result = array(); + foreach (array_keys($values) as $i) { + $result[(string) $values[$i]->name] = XML_RPC2_Backend_Php_Value::createFromDecode($values[$i]->value)->getNativeValue(); + } + return $result; + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Xmlrpcext/Client.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Xmlrpcext/Client.php new file mode 100644 index 0000000..6ed997f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Xmlrpcext/Client.php @@ -0,0 +1,143 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Client.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Client.php'; +require_once 'XML/RPC2/Util/HTTPRequest.php'; +//}}} + +/** + * XML_RPC client backend class. This backend class uses the XMLRPCext extension to execute the call. + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Xmlrpcext_Client extends XML_RPC2_Client +{ + + // {{{ constructor + + /** + * Construct a new XML_RPC2_Client PHP Backend. + * + * A URI must be provided (e.g. http://xmlrpc.example.com/1.0/). + * Optionally, some options may be set. + * + * @param string URI for the XML-RPC server + * @param array (optional) Associative array of options + */ + public function __construct($uri, $options = array()) + { + parent::__construct($uri, $options); + } + + // }}} + // {{{ __call() + + /** + * __call Catchall. This method catches remote method calls and provides for remote forwarding. + * + * If the parameters are native types, this method will use XML_RPC_Value::createFromNative to + * convert it into an XML-RPC type. Whenever a parameter is already an instance of XML_RPC_Value + * it will be used as provided. It follows that, in situations when XML_RPC_Value::createFromNative + * proves inacurate -- as when encoding DateTime values -- you should present an instance of + * XML_RPC_Value in lieu of the native parameter. + * + * @param string Method name + * @param array Parameters + * @return mixed The call result, already decoded into native types + */ + public function __call($methodName, $parameters) + { + $tmp = xmlrpc_encode_request($this->prefix . $methodName, $parameters, array('escaping' => $this->escaping, 'encoding' => $this->encoding)); + if ($this->uglyStructHack) { + // ugly hack because of http://bugs.php.net/bug.php?id=21949 + // see XML_RPC2_Backend_Xmlrpcext_Value::createFromNative() from more infos + $request = preg_replace('~xml_rpc2_ugly_struct_hack_(.*)~', '\1', $tmp); + } else { + $request = $tmp; + } + $uri = $this->uri; + $options = array( + 'encoding' => $this->encoding, + 'proxy' => $this->proxy, + 'sslverify' => $this->sslverify, + 'connectionTimeout' => $this->connectionTimeout + ); + if (isset($this->httpRequest)) $options['httpRequest'] = $this->httpRequest; + $httpRequest = new XML_RPC2_Util_HTTPRequest($uri, $options); + $httpRequest->setPostData($request); + $httpRequest->sendRequest(); + $body = $httpRequest->getBody(); + if ($this->debug) { + XML_RPC2_ClientHelper::printPreParseDebugInfo($request, $body); + } + $result = xmlrpc_decode($body, $this->encoding); + /* Commented due to change in behaviour from xmlrpc_decode. It does not return faults now + if ($result === false || is_null($result)) { + if ($this->debug) { + print "XML_RPC2_Exception : unable to decode response !"; + } + throw new XML_RPC2_Exception('Unable to decode response'); + } + */ + if (is_array($result) && xmlrpc_is_fault($result)) { + if ($this->debug) { + print "XML_RPC2_FaultException(${result['faultString']}, ${result['faultCode']})"; + } + throw new XML_RPC2_FaultException($result['faultString'], $result['faultCode']); + } + if ($this->debug) { + XML_RPC2_ClientHelper::printPostRequestDebugInformation($result); + } + return $result; + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Xmlrpcext/Server.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Xmlrpcext/Server.php new file mode 100644 index 0000000..2f71f9f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Xmlrpcext/Server.php @@ -0,0 +1,175 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Server.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Backend/Php/Request.php'; +require_once 'XML/RPC2/Backend/Php/Response.php'; +require_once 'XML/RPC2/Exception.php'; +// }}} + +/** + * XML_RPC server class XMLRPCext extension-based backend + * + * The XML_RPC2_Server does the work of decoding and encoding xml-rpc request and response. The actual + * method execution is delegated to the call handler instance. + * + * The XML_RPC server is responsible for decoding the request and calling the appropriate method in the + * call handler class. It then encodes the result into an XML-RPC response and returns it to the client. + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Xmlrpcext_Server extends XML_RPC2_Server +{ + // {{{ properties + + /** + * xmlrpcext server + * + * @var resource + */ + private $_xmlrpcextServer; + + // }}} + // {{{ constructor + + /** + * Create a new XML-RPC Server. + * + * The constructor receives a mandatory parameter: the Call Handler. The call handler executes the actual + * method call. XML_RPC2 server acts as a protocol decoder/encoder between the call handler and the client + * + * @param object $callHandler + * @param array $options associative array of options + */ + function __construct($callHandler, $options = array()) + { + parent::__construct($callHandler, $options); + $this->_xmlrpcextServer = xmlrpc_server_create(); + foreach ($callHandler->getMethods() as $method) { + if (xmlrpc_server_register_method($this->_xmlrpcextServer, + $method->getName(), + array($this, 'epiFunctionHandlerAdapter')) !== true) { + throw new XML_RPC2_Exception('Unable to setup XMLRPCext server. xmlrpc_server_register_method returned non-true.'); + } + } + } + + // }}} + // {{{ epiFunctionHandlerAdapter() + + /** + * This is an adapter between XML_RPC2_CallHandler::__call and xmlrpc_server_register_method callback interface + * + * @param string Method name + * @param array Parameters + * @param array Application data (ignored) + */ + protected function epiFunctionHandlerAdapter($method_name, $params, $app_data) { + return @call_user_func_array(array($this->callHandler, $method_name), $params); + } + + // }}} + // {{{ handleCall() + + /** + * Respond to the XML-RPC request. + * + * handleCall reads the XML-RPC request from the raw HTTP body and decodes it. It then calls the + * corresponding method in the call handler class, returning the encoded result to the client. + */ + public function handleCall() + { + if ($this->autoDocument && $this->input->isEmpty()) { + $this->autoDocument(); + } else { + $response = $this->getResponse(); + header('Content-type: text/xml; charset=' . $this->encoding); + header('Content-length: ' . $this->getContentLength($response)); + print $response; + } + } + + // }}} + // {{{ getResponse() + + /** + * get the XML response of the XMLRPC server + * + * @return string the XML response + */ + public function getResponse() + { + try { + if ($this->signatureChecking) { + $tmp = xmlrpc_parse_method_descriptions($this->input->readRequest()); + $methodName = $tmp['methodName']; + $parameters = xmlrpc_decode($this->input->readRequest(), $this->encoding); + $method = $this->callHandler->getMethod($methodName); + if (!($method)) { + // see http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php for standard error codes + return (XML_RPC2_Backend_Php_Response::encodeFault(-32601, 'server error. requested method not found')); + } + if (!($method->matchesSignature($methodName, $parameters))) { + return (XML_RPC2_Backend_Php_Response::encodeFault(-32602, 'server error. invalid method parameters')); + } + } + set_error_handler(array('XML_RPC2_Backend_Xmlrpcext_Server', 'errorToException')); + $response = @xmlrpc_server_call_method($this->_xmlrpcextServer, + $this->input->readRequest(), + null, + array('output_type' => 'xml', 'encoding' => $this->encoding)); + restore_error_handler(); + return $response; + } catch (XML_RPC2_FaultException $e) { + return (XML_RPC2_Backend_Php_Response::encodeFault($e->getFaultCode(), $e->getMessage())); + } catch (Exception $e) { + return (XML_RPC2_Backend_Php_Response::encodeFault(1, 'Unhandled ' . get_class($e) . ' exception:' . $e->getMessage())); + } + } + // }}} +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Xmlrpcext/Value.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Xmlrpcext/Value.php new file mode 100644 index 0000000..fb62f67 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Backend/Xmlrpcext/Value.php @@ -0,0 +1,101 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Value.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend.php'; +// }}} + +/** + * XML_RPC value class for the XMLRPCext backend. + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Backend_Xmlrpcext_Value +{ + + // {{{ createFromNative() + + /** + * Factory method that constructs the appropriate XML-RPC encoded type value + * + * @param mixed Value to be encode + * @param string Explicit XML-RPC type as enumerated in the XML-RPC spec (defaults to automatically selected type) + * @return mixed The encoded value + */ + public static function createFromNative($value, $explicitType) + { + $type = strtolower($explicitType); + $availableTypes = array('datetime', 'base64', 'struct'); + if (in_array($type, $availableTypes)) { + if ($type=='struct') { + if (!(is_array($value))) { + throw new XML_RPC2_Exception('With struct type, value has to be an array'); + } + // Because of http://bugs.php.net/bug.php?id=21949 + // is some cases (structs with numeric indexes), we need to be able to force the "struct" type + // (xmlrpc_set_type doesn't help for this, so we need this ugly hack) + $new = array(); + while (list($k, $v) = each($value)) { + $new["xml_rpc2_ugly_struct_hack_$k"] = $v; + // with this "string" prefix, we are sure that the array will be seen as a "struct" + } + return $new; + } + $value2 = (string) $value; + if (!xmlrpc_set_type($value2, $type)) { + throw new XML_RPC2_Exception('Error returned from xmlrpc_set_type'); + } + return $value2; + } + return $value; + } + + // }}} + +} + +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/CachedClient.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/CachedClient.php new file mode 100644 index 0000000..6d9e75c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/CachedClient.php @@ -0,0 +1,361 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Fabien MARTY +* @copyright 2005-2006 Fabien MARTY +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: CachedClient.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once('Cache/Lite.php'); +require_once('XML/RPC2/Exception.php'); +// }}} + +/** + * XML_RPC "cached client" class. + * + * @category XML + * @package XML_RPC2 + * @author Fabien MARTY + * @copyright 2005-2006 Fabien MARTY + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_CachedClient { + + // {{{ properties + + /** + * Associative array of options for XML_RPC2_Client + * + * @var array + */ + private $_options; + + /** + * uri Field (holds the uri for the XML_RPC server) + * + * @var array + */ + private $_uri; + + /** + * Holds the debug flag + * + * @var boolean + */ + private $_debug = false; + + /** + * Cache_Lite options array + * + * @var array + */ + private $_cacheOptions = array(); + + /** + * Cached methods array (usefull only if cache is off by default) + * + * example1 : array('method1ToCache', 'method2ToCache', ...) + * example2 (with specific cache lifetime) : + * array('method1ToCache' => 3600, 'method2ToCache' => 60, ...) + * NB : a lifetime value of -1 means "no cache for this method" + * + * @var array + */ + private $_cachedMethods = array(); + + /** + * Non-Cached methods array (usefull only if cache is on by default) + * + * example : array('method1ToCache', 'method2ToCache', ...) + * + * @var array + */ + private $_notCachedMethods = array(); + + /** + * cache by default + * + * @var boolean + */ + private $_cacheByDefault = true; + + /** + * Cache_Lite object + * + * @var object + */ + private $_cacheObject = null; + + /** + * XML_RPC2_Client object (if needed, dynamically built) + * + * @var object + */ + private $_clientObject = null; + + /** + * Default cache group for XML_RPC client caching + * + * @var string + */ + private $_defaultCacheGroup = 'xml_rpc2_client'; + + /** + * "cache debug" flag (for debugging the caching process) + * + * @var boolean + */ + private $_cacheDebug = false; + + // }}} + // {{{ constructor + + /** + * Constructor + * + * TODO : documentations about cache options + * + * @param string URI for the XML-RPC server + * @param array (optional) Associative array of options + */ + protected function __construct($uri, $options = array()) + { + if (isset($options['cacheOptions'])) { + $array = $options['cacheOptions']; + if (isset($array['defaultCacheGroup'])) { + $this->_defaultCacheGroup = $array['defaultCacheGroup']; + unset($array['defaultCacheGroup']); // this is a "non standard" option for Cache_Lite + } + if (isset($array['cachedMethods'])) { + $this->_cachedMethods = $array['cachedMethods']; + unset($array['cachedMethods']); // this is a "non standard" option for Cache_Lite + } + if (isset($array['notCachedMethods'])) { + $this->_notCachedMethods = $array['notCachedMethods']; + unset($array['notCachedMethods']); // this is a "non standard" option for Cache_Lite + } + if (isset($array['cacheByDefault'])) { + $this->_cacheByDefault = $array['cacheByDefault']; + unset($array['CacheByDefault']); // this is a "non standard" option for Cache_Lite + } + $array['automaticSerialization'] = false; // datas are already serialized in this class + if (!isset($array['lifetime'])) { + $array['lifetime'] = 3600; // we need a default lifetime + } + unset($options['cacheOptions']); // this is a "non standard" option for XML/RPC2/Client + } else { // no cache options ? + $array = array( + 'lifetime' => 3600, // we need a default lifetime + 'automaticSerialization' => false // datas are already serialized in this class + ); + } + if (isset($options['cacheDebug'])) { + $this->_cacheDebug = $options['cacheDebug']; + unset($options['cacheDebug']); // this a "non standard" option for XML/RPC2/Client + } + $this->_cacheOptions = $array; + $this->_cacheObject = new Cache_Lite($this->_cacheOptions); + $this->_options = $options; + $this->_uri = $uri; + } + + // }}} + // {{{ create() + + /** + * "Emulated Factory" method to get the same API than XML_RPC2_Client class + * + * Here, simply returns a new instance of XML_RPC2_CachedClient class + * + * @param string URI for the XML-RPC server + * @param string (optional) Prefix to prepend on all called functions (defaults to '') + * @param string (optional) Proxy server URI (defaults to no proxy) + * + */ + public static function create($uri, $options = array()) + { + return new XML_RPC2_CachedClient($uri, $options); + } + + // }}} + // {{{ __call() + + /** + * __call Catchall + * + * Encapsulate all the class logic : + * - determine if the cache has to be used (or not) for the called method + * - see if a cache is available for this call + * - if no cache available, really do the call and store the result for next time + * + * @param string Method name + * @param array Parameters + * @return mixed The call result, already decoded into native types + */ + public function __call($methodName, $parameters) + { + if (!isset($this->_cacheObject)) { + $this->_cacheObject = new Cache_Lite($this->_cacheOptions); + } + if (in_array($methodName, $this->_notCachedMethods)) { + // if the called method is listed in _notCachedMethods => no cache + if ($this->_cacheDebug) { + print "CACHE DEBUG : the called method is listed in _notCachedMethods => no cache !\n"; + } + return $this->_workWithoutCache___($methodName, $parameters); + } + if (!($this->_cacheByDefault)) { + if ((!(isset($this->_cachedMethods[$methodName]))) and (!(in_array($methodName, $this->_cachedMethods)))) { + // if cache is not on by default and if the called method is not described in _cachedMethods array + // => no cache + if ($this->_cacheDebug) { + print "CACHE DEBUG : cache is not on by default and the called method is not listed in _cachedMethods => no cache !\n"; + } + return $this->_workWithoutCache___($methodName, $parameters); + } + } + if (isset($this->_cachedMethods[$methodName])) { + if ($this->_cachedMethods[$methodName] == -1) { + // if a method is described with a lifetime value of -1 => no cache + if ($this->_cacheDebug) { + print "CACHE DEBUG : called method has a -1 lifetime value => no cache !\n"; + } + return $this->_workWithoutCache___($methodName, $parameters); + } + // if a method is described with a specific (and <> -1) lifetime + // => we fix this new lifetime + $this->_cacheObject->setLifetime($this->_cachedMethods[$methodName]); + } else { + // there is no specific lifetime, let's use the default one + $this->_cacheObject->setLifetime($this->_cacheOptions['lifetime']); + } + $cacheId = $this->_makeCacheId___($methodName, $parameters); + $data = $this->_cacheObject->get($cacheId, $this->_defaultCacheGroup); + if (is_string($data)) { + // cache is hit ! + if ($this->_cacheDebug) { + print "CACHE DEBUG : cache is hit !\n"; + } + return unserialize($data); + } + // the cache is not hit, let's call the "real" XML_RPC client + if ($this->_cacheDebug) { + print "CACHE DEBUG : cache is not hit !\n"; + } + $result = $this->_workWithoutCache___($methodName, $parameters); + $this->_cacheObject->save(serialize($result)); // save in cache for next time... + return $result; + } + + // }}} + // {{{ _workWithoutCache___() + + /** + * Do the real call if no cache available + * + * NB : The '___' at the end of the method name is to avoid collisions with + * XMLRPC __call() + * + * @param string Method name + * @param array Parameters + * @return mixed The call result, already decoded into native types + */ + private function _workWithoutCache___($methodName, $parameters) + { + if (!(isset($this->_clientObject))) { + // If the XML_RPC2_Client object is not available, let's build it + require_once('XML/RPC2/Client.php'); + $this->_clientObject = XML_RPC2_Client::create($this->_uri, $this->_options); + } + // the real function call... + return call_user_func_array(array($this->_clientObject, $methodName), $parameters); + } + + // }}} + // {{{ _makeCacheId___() + + /** + * make a cache id depending on method called (and corresponding parameters) but depending on "environnement" setting too + * + * NB : The '___' at the end of the method name is to avoid collisions with + * XMLRPC __call() + * + * @param string $methodName called method + * @param array $parameters parameters of the called method + * @return string cache id + */ + private function _makeCacheId___($methodName, $parameters) + { + return md5($methodName . serialize($parameters) . serialize($this->_uri) . serialize($this->_options)); + } + + // }}} + // {{{ dropCacheFile___() + + /** + * Drop the cache file corresponding to the given method call + * + * NB : The '___' at the end of the method name is to avoid collisions with + * XMLRPC __call() + * + * @param string $methodName called method + * @param array $parameters parameters of the called method + */ + public function dropCacheFile___($methodName, $parameters) + { + $id = $this->_makeCacheId___($methodName, $parameters); + $this->_cacheObject->remove($id, $this->_defaultCacheGroup); + } + + // }}} + // {{{ clean___() + + /** + * Clean all the cache + * + * NB : The '___' at the end of the method name is to avoid collisions with + * XMLRPC __call() + */ + public function clean___() + { + $this->_cacheObject->clean($this->_defaultCacheGroup, 'ingroup'); + } + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/CachedServer.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/CachedServer.php new file mode 100644 index 0000000..e465c00 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/CachedServer.php @@ -0,0 +1,416 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Fabien MARTY +* @copyright 2005-2006 Fabien MARTY +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: CachedServer.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once('Cache/Lite.php'); +// }}} + +/** + * XML_RPC "cached server" class. + * + * @category XML + * @package XML_RPC2 + * @author Fabien MARTY + * @copyright 2005-2006 Fabien MARTY + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_CachedServer { + + // {{{ properties + + /** + * cache by default + * + * @var boolean + */ + private $_cacheByDefault = true; + + /** + * Cache_Lite object + * + * @var object + */ + private $_cacheObject = null; + + /** + * XML_RPC2_Server object (if needed, dynamically built) + * + * @var object + */ + private $_serverObject = null; + + /** + * Default cache group for XML_RPC server caching + * + * @var string + */ + private $_defaultCacheGroup = 'xml_rpc2_server'; + + /** + * callHandler field + * + * The call handler is responsible for executing the server exported methods + * + * @var mixed + */ + private $_callHandler = null; + + /** + * either a class name or an object instance + * + * @var mixed + */ + private $_callTarget = ''; + + /** + * methods prefix + * + * @var string + */ + private $_prefix = ''; + + /** + * XML_RPC2_Server options + * + * @var array + */ + private $_options = array(); + + /** + * "cache debug" flag (for debugging the caching process) + * + * @var boolean + */ + private $_cacheDebug = false; + + /** + * encoding + * + * @var string + */ + private $_encoding = 'utf-8'; + + // }}} + // {{{ setCacheOptions() + + /** + * Set options for the caching process + * + * See Cache_Lite constructor for options + * Specific options are 'cachedMethods', 'notCachedMethods', 'cacheByDefault', 'defaultCacheGroup' + * See corresponding properties for more informations + * + * @param array $array + */ + private function _setCacheOptions($array) + { + if (isset($array['defaultCacheGroup'])) { + $this->_defaultCacheGroup = $array['defaultCacheGroup']; + unset($array['defaultCacheGroup']); // this is a "non standard" option for Cache_Lite + } + if (isset($array['cacheByDefault'])) { + $this->_cacheByDefault = $array['cacheByDefault']; + unset($array['CacheByDefault']); // this is a "non standard" option for Cache_Lite + } + $array['automaticSerialization'] = false; // datas are already serialized in this class + if (!isset($array['lifetime'])) { + $array['lifetime'] = 3600; // we need a default lifetime + } + $this->_cacheOptions = $array; + $this->_cacheObject = new Cache_Lite($this->_cacheOptions); + } + + // }}} + // {{{ constructor + + /** + * Constructor + * + * @param object $callHandler the call handler will receive a method call for each remote call received. + */ + protected function __construct($callTarget, $options = array()) + { + if (isset($options['cacheOptions'])) { + $cacheOptions = $options['cacheOptions']; + $this->_setCacheOptions($cacheOptions); + unset($options['cacheOptions']); + } + if (isset($options['cacheDebug'])) { + $this->_cacheDebug = $options['cacheDebug']; + unset($options['cacheDebug']); // 'cacheDebug' is not a standard option for XML/RPC2/Server + } + $this->_options = $options; + $this->_callTarget = $callTarget; + if (isset($this->_options['encoding'])) { + $this->_encoding = $this->_options['encoding']; + } + if (isset($this->_options['prefix'])) { + $this->_prefix = $this->_options['prefix']; + } + } + + // }}} + // {{{ create() + + /** + * "Emulated Factory" method to get the same API than XML_RPC2_Server class + * + * Here, simply returns a new instance of XML_RPC2_CachedServer class + * + * @param mixed $callTarget either a class name or an object instance. + * @param array $options associative array of options + * @return object a server class instance + */ + public static function create($callTarget, $options = array()) + { + return new XML_RPC2_CachedServer($callTarget, $options); + } + + // }}} + // {{{ handleCall() + + /** + * handle XML_RPC calls + * + */ + public function handleCall() + { + $response = $this->getResponse(); + $encoding = 'utf-8'; + if (isset($this->_options['encoding'])) { + $encoding = $this->_options['encoding']; + } + header('Content-type: text/xml; charset=' . $encoding); + header('Content-length: ' . $this->getContentLength($response)); + print $response; + } + + /** + * get the XML response of the XMLRPC server + * + * @return string the XML response + */ + public function getResponse() + { + if (isset($GLOBALS['HTTP_RAW_POST_DATA'])) { + $methodName = $this->_parseMethodName($GLOBALS['HTTP_RAW_POST_DATA']); + } else { + $methodName = null; + } + $weCache = $this->_cacheByDefault; + $lifetime = $this->_cacheOptions['lifetime']; + if ($this->_cacheDebug) { + if ($weCache) { + print "CACHE DEBUG : default values => weCache=true, lifetime=$lifetime\n"; + } else { + print "CACHE DEBUG : default values => weCache=false, lifetime=$lifetime\n"; + } + } + if ($methodName) { + // work on reflection API to search for @xmlrpc.caching tags into PHPDOC comments + list($weCache, $lifetime) = $this->_reflectionWork($methodName); + if ($this->_cacheDebug) { + if ($weCache) { + print "CACHE DEBUG : phpdoc comments => weCache=true, lifetime=$lifetime\n"; + } else { + print "CACHE DEBUG : phpdoc comments => weCache=false, lifetime=$lifetime\n"; + } + } + } + if (($weCache) and ($lifetime!=-1)) { + if (isset($GLOBALS['HTTP_RAW_POST_DATA'])) { + $cacheId = $this->_makeCacheId($GLOBALS['HTTP_RAW_POST_DATA']); + } else { + $cacheId = 'norawpostdata'; + } + $this->_cacheObject = new Cache_Lite($this->_cacheOptions); + $this->_cacheObject->setLifetime($lifetime); + if ($data = $this->_cacheObject->get($cacheId, $this->_defaultCacheGroup)) { + // cache id hit + if ($this->_cacheDebug) { + print "CACHE DEBUG : cache is hit !\n"; + } + } else { + // cache is not hit + if ($this->_cacheDebug) { + print "CACHE DEBUG : cache is not hit !\n"; + } + $data = $this->_workWithoutCache(); + $this->_cacheObject->save($data); + } + } else { + if ($this->_cacheDebug) { + print "CACHE DEBUG : we don't cache !\n"; + } + $data = $this->_workWithoutCache(); + } + return $data; + } + + // }}} + // {{{ _reflectionWork() + + /** + * Work on reflection API to search for @xmlrpc.caching tags into PHPDOC comments + * + * @param string $methodName method name + * @return array array((boolean) weCache, (int) lifetime) => parameters to use for caching + */ + private function _reflectionWork($methodName) { + $weCache = $this->_cacheByDefault; + $lifetime = $this->_cacheOptions['lifetime']; + if (is_string($this->_callTarget)) { + $className = strtolower($this->_callTarget); + } else { + $className = get_class($this->_callTarget); + } + $class = new ReflectionClass($className); + $method = $class->getMethod($methodName); + $docs = explode("\n", $method->getDocComment()); + foreach ($docs as $i => $doc) { + $doc = trim($doc, " \r\t/*"); + $res = preg_match('/@xmlrpc.caching ([+-]{0,1}[a-zA-Z0-9]*)/', $doc, $results); // TODO : better/faster regexp ? + if ($res>0) { + $value = $results[1]; + if (($value=='yes') or ($value=='true') or ($value=='on')) { + $weCache = true; + } else if (($value=='no') or ($value=='false') or ($value=='off')) { + $weCache = false; + } else { + $lifetime = (int) $value; + if ($lifetime==-1) { + $weCache = false; + } else { + $weCache = true; + } + } + } + } + return array($weCache, $lifetime); + } + + // }}} + // {{{ _parseMethodName() + + /** + * Parse the method name from the raw XMLRPC client request + * + * NB : the prefix is removed from the method name + * + * @param string $request raw XMLRPC client request + * @return string method name + */ + private function _parseMethodName($request) + { + // TODO : change for "simplexml" + $res = preg_match('/' . $this->_prefix . '([a-zA-Z0-9\.,\/]*)<\/methodName>/', $request, $results); + if ($res>0) { + return $results[1]; + } + return false; + } + + // }}} + // {{{ _workWithoutCache() + + /** + * Do the real stuff if no cache available + * + * @return string the response of the real XML/RPC2 server + */ + private function _workWithoutCache() + { + require_once('XML/RPC2/Server.php'); + $this->_serverObject = XML_RPC2_Server::create($this->_callTarget, $this->_options); + return $this->_serverObject->getResponse(); + } + + // }}} + // {{{ _makeCacheId() + + /** + * make a cache id depending on the raw xmlrpc client request but depending on "environnement" setting too + * + * @param string $raw_request + * @return string cache id + */ + private function _makeCacheId($raw_request) + { + return md5($raw_request . serialize($this->_options)); + } + + // }}} + // {{{ clean() + + /** + * Clean all the cache + */ + public function clean() + { + $this->_cacheObject->clean($this->_defaultCacheGroup, 'ingroup'); + } + + // }}} + // {{{ getContentLength() + + /** + * Gets the content legth of a serialized XML-RPC message in bytes + * + * @param string $content the serialized XML-RPC message. + * + * @return integer the content length in bytes. + */ + protected function getContentLength($content) + { + if (extension_loaded('mbstring') && (ini_get('mbstring.func_overload') & 2) == 2) { + $length = mb_strlen($content, '8bit'); + } else { + $length = strlen((binary)$content); + } + + return $length; + } + + // }}} +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Client.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Client.php new file mode 100644 index 0000000..c5667c7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Client.php @@ -0,0 +1,261 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Client.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend.php'; +require_once 'XML/RPC2/ClientHelper.php'; +// }}} + +/** + * XML_RPC client class. Use this class to access remote methods. + * + * To use this class, construct it providing the server URL and method prefix. + * Then, call remote methods on the new instance as if they were local. + * + * Example: + * + * require_once 'XML_RPC2/Client.php'; + * + * $client = XML_RPC2_Client('http://xmlrpc.example.com/1.0/', 'example.'); + * $result = $client->hello('Sergio'); + * print($result); + * + * + * The above example will call the example.hello method on the xmlrpc.example.com + * server, under the /1.0/ URI. + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +abstract class XML_RPC2_Client +{ + // {{{ properties + + /** + * uri Field (holds the uri for the XML_RPC server) + * + * @var string + */ + protected $uri = null; + + /** + * proxy Field (holds the proxy server data) + * + * @var string + */ + protected $proxy = null; + + /** + * Holds the prefix to prepend to method names + * + * @var string + */ + protected $prefix = null; + + /** + * Holds the debug flag + * + * @var boolean + */ + protected $debug = false; + + /** + * Hold the encoding of the client request + * + * @var string + */ + protected $encoding = 'utf-8'; + + /** + * Holds the escaping method(s) of the client request + * + * @var string + */ + protected $escaping = array('non-ascii', 'non-print', 'markup'); + + /** + * Holds the SSL verify flag + * + * @var boolean + */ + protected $sslverify = true; + + /** + * Holds the connection timeout in milliseconds of the client request. + * + * @var integer + */ + protected $connectionTimeout = null; + + /** + * ugly hack flag to avoid http://bugs.php.net/bug.php?id=21949 + * + * see XML_RPC2_Backend_Xmlrpcext_Value::createFromNative() from more infos + */ + protected $uglyStructHack = true; + + /** + * Preconfigured HTTP_Request2 provided by the user + * + * @var HTTP_Request2 + */ + protected $httpRequest; + // }}} + + // {{{ constructor + + /** + * Construct a new XML_RPC2_Client. + * + * To create a new XML_RPC2_Client, a URI must be provided (e.g. http://xmlrpc.example.com/1.0/). + * Optionally, some options may be set as an associative array. Accepted keys are : + * 'prefix', 'proxy', 'debug' => see correspondant property to get more informations + * 'encoding' => The XML encoding for the requests (optional, defaults to utf-8) + * 'sslverify' => boolean, true iff SSL certificates are to be verified against local cert database (optional, default false) + * 'connectionTimeout' => Timeout, in seconds, for the XML-RPC HTTP request (optional, default is no timeout) + * 'httpRequest' => Preconfigured HTTP_Request2 instance to be used in executing the XML-RPC calls (optional) + * + * @param string URI for the XML-RPC server + * @param array (optional) Associative array of options + */ + protected function __construct($uri, $options = array()) + { + if (!$uriParse = parse_url($uri)) { + throw new XML_RPC2_InvalidUriException(sprintf('Client URI \'%s\' is not valid', $uri)); + } + $this->uri = $uri; + if (isset($options['prefix'])) { + if (!(XML_RPC2_ClientHelper::testMethodName($options['prefix']))) { + throw new XML_RPC2_InvalidPrefixException(sprintf('Prefix \'%s\' is not valid', $options['prefix'])); + } + $this->prefix = $options['prefix']; + } + if (isset($options['proxy'])) { + if (!$proxyParse = parse_url($options['proxy'])) { + throw new XML_RPC2_InvalidProxyException(sprintf('Proxy URI \'%s\' is not valid', $options['proxy'])); + } + $this->proxy = $options['proxy']; + } + if (isset($options['debug'])) { + if (!(is_bool($options['debug']))) { + throw new XML_RPC2_InvalidDebugException(sprintf('Debug \'%s\' is not valid', $options['debug'])); + } + $this->debug = $options['debug']; + } + if (isset($options['encoding'])) { + // TODO : control & exception + $this->encoding = $options['encoding']; + } + if (isset($options['escaping'])) { + // TODO : control & exception + $this->escaping = $options['escaping']; + } + if (isset($options['uglyStructHack'])) { + $this->uglyStructHack = $options['uglyStructHack']; + } + if (isset($options['sslverify'])) { + if (!(is_bool($options['sslverify']))) { + throw new XML_RPC2_InvalidSslverifyException(sprintf('SSL verify \'%s\' is not valid', $options['sslverify'])); + } + $this->sslverify = $options['sslverify']; + } + if (isset($options['connectionTimeout'])) { + if (!(is_int($options['connectionTimeout']))) { + throw new XML_RPC2_InvalidConnectionTimeoutException(sprintf('Connection timeout \'%s\' is not valid', $options['connectionTimeout'])); + } + $this->connectionTimeout = $options['connectionTimeout']; + } + if (isset($options['httpRequest'])) { + $this->httpRequest = $options['httpRequest']; + } + } + + // }}} + // {{{ create() + + /** + * Factory method to select, create and return a XML_RPC2_Client backend + * + * To create a new XML_RPC2_Client, a URI must be provided (e.g. http://xmlrpc.example.com/1.0/). + * + * Optionally, some options may be set. + * + * @param string URI for the XML-RPC server + * @param array (optional) associative array of options (see constructor) + */ + public static function create($uri, $options = array()) + { + if (isset($this)) { // Method called non-statically forward to remote call() as RPC + $this->__call('create', func_get_args()); + } + if (isset($options['backend'])) { + XML_RPC2_Backend::setBackend($options['backend']); + } + $backend = XML_RPC2_Backend::getClientClassname(); + return new $backend($uri, $options); + } + + // }}} + // {{{ __call() + + /** + * __call Catchall. This method catches remote method calls and provides for remote forwarding. + * + * If the parameters are native types, this method will use XML_RPC_Value::createFromNative to + * convert it into an XML-RPC type. Whenever a parameter is already an instance of XML_RPC_Value + * it will be used as provided. It follows that, in situations when XML_RPC_Value::createFromNative + * proves inacurate -- as when encoding DateTime values -- you should present an instance of + * XML_RPC_Value in lieu of the native parameter. + * + * @param string Method name + * @param array Parameters + * @return mixed The call result, already decoded into native types + */ + public abstract function __call($methodName, $parameters); + + // }}} +} + diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/ClientHelper.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/ClientHelper.php new file mode 100644 index 0000000..b1e78f9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/ClientHelper.php @@ -0,0 +1,118 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: ClientHelper.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend.php'; +// }}} + +/** + * XML_RPC2 client helper class. + * + * XML_RPC2_Client must maintain a function namespace as clean as possible. As such + * whenever possible, methods that may be usefull to subclasses but shouldn't be defined + * in XML_RPC2 because of namespace pollution are defined here. + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_ClientHelper +{ + // {{{ printPreParseDebugInfo() + + /** + * Display debug informations + * + * @param string $request XML client request + * @param string $body XML server response + */ + public static function printPreParseDebugInfo($request, $body) + { + print '
    ';
    +        print "***** Request *****\n";
    +        print htmlspecialchars($request);
    +        print "***** End Of request *****\n\n";
    +        print "***** Server response *****\n";
    +        print htmlspecialchars($body);
    +        print "\n***** End of server response *****\n\n";
    +    }
    +    
    +    // }}}
    +    // {{{ printPostRequestDebugInformation()
    +    
    +    /**
    +     * Display debug informations (part 2)
    +     *
    +     * @param mixed $result decoded server response
    +     */
    +    public static function printPostRequestDebugInformation($result)
    +    {
    +        print "***** Decoded result *****\n";
    +        print_r($result);
    +        print "\n***** End of decoded result *****";
    +        print '
    '; + } + + // }}} + // {{{ testMethodName___() + + /** + * Return true is the given method name is ok with XML/RPC spec. + * + * NB : The '___' at the end of the method name is to avoid collisions with + * XMLRPC __call() + * + * @param string $methodName method name + * @return boolean true if ok + */ + public static function testMethodName($methodName) + { + return (preg_match('~^[a-zA-Z0-9_.:/]*$~', $methodName)); + } + + // }}} + +} + diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Exception.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Exception.php new file mode 100644 index 0000000..22057e5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Exception.php @@ -0,0 +1,360 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Exception.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +/** + * XML_RPC2 base exception class. All XML_RPC2 originated exceptions inherit from XML_RPC2_Exception + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Exception extends Exception +{ +} + +/* Encoding and decoding values exceptions {{{ +/** + * XML_RPC2_InvalidTypeException is thrown whenever an invalid XML_RPC type is used in an operation + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_InvalidTypeException extends XML_RPC2_Exception +{ +} + +/** + * XML_RPC2_InvalidTypeException is thrown when creating DateTime value objects from invalid string datetime representations + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_InvalidDateFormatException extends XML_RPC2_Exception +{ +} + +/** + * XML_RPC2_EncodeException is thrown whenever a class is asked to encode itself in XML with invalid or not enough data. + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_EncodeException extends XML_RPC2_Exception +{ +} + +/** + * XML_RPC2_DecodeException is thrown whenever there is a problem decoding transport XML + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_DecodeException extends XML_RPC2_Exception +{ +} + +/** + * XML_RPC2_InvalidTypeEncodeException is thrown whenever a class is asked to encode itself and provided a PHP type + * that can't be translated to XML_RPC + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_InvalidTypeEncodeException extends XML_RPC2_Exception +{ +} +/* }}} */ + +/** + * XML_RPC2_InvalidUriException is thrown whenever the XML_RPC2 client is asked to use an invalid uri + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_InvalidUriException extends XML_RPC2_Exception +{ +} + +/** + * XML_RPC2_InvalidPrefixException is thrown whenever the XML_RPC2 client is asked to use an invalid XML/RPC prefix + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_InvalidPrefixException extends XML_RPC2_Exception +{ +} + +/** + * XML_RPC2_InvalidPrefixException is thrown whenever the XML_RPC2 client is asked to use an invalid XML/RPC debug flag + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_InvalidDebugException extends XML_RPC2_Exception +{ +} + +/** + * XML_RPC2_InvalidSslverifyException is thrown whenever the XML_RPC2 client is asked to use an invalid XML/RPC SSL verify flag + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_InvalidSslverifyException extends XML_RPC2_Exception +{ +} + +/** + * XML_RPC2_InvalidConnectionTimeoutException is thrown whenever the XML_RPC2 + * client is asked to use an invalid XML/RPC connection timeout value + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_InvalidConnectionTimeoutException extends XML_RPC2_Exception +{ +} + +/** + * XML_RPC2_FaultException signals a XML-RPC response that contains a fault element instead of a regular params element. + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_FaultException extends XML_RPC2_Exception +{ + + // {{{ properties + + /** + * Fault code (in the response body) + * + * @var string + */ + protected $faultCode = null; + + // }}} + // {{{ constructor + + /** Construct a new XML_RPC2_FaultException with a given message string and fault code + * + * @param string The message string, corresponding to the faultString present in the response body + * @param string The fault code, corresponding to the faultCode in the response body + */ + function __construct($messageString, $faultCode) + { + parent::__construct($messageString); + $this->faultCode = $faultCode; + } + + // }}} + // {{{ getFaultCode() + + /** + * FaultCode getter + * + * @return string fault code + */ + public function getFaultCode() + { + return $this->faultCode; + } + + // }}} + // {{{ getFaultString() + + /** + * FaultString getter + * + * This is an alias to getMessage() in order to respect XML-RPC nomenclature for faults + * + * @return string fault code + */ + public function getFaultString() + { + return $this->getMessage(); + } + + // }}} + // {{{ createFromDecode() + + /** + * Create a XML_RPC2_FaultException by decoding the corresponding xml string + * + * @param string $xml + * @return object a XML_RPC2_FaultException + */ + public static function createFromDecode($xml) { + require_once 'XML/RPC2/Backend/Php/Value.php'; + + // This is the only way I know of creating a new Document rooted in the provided simpleXMLFragment (needed for the xpath expressions that does not segfault sometimes + $xml = simplexml_load_string($xml->asXML()); + $struct = XML_RPC2_Backend_Php_Value::createFromDecode($xml->value)->getNativeValue(); + if (!(is_array($struct) && + array_key_exists('faultString', $struct) && + array_key_exists('faultCode', $struct))) throw new XML_RPC2_DecodeException('Unable to decode XML-RPC fault payload'); + + return new XML_RPC2_FaultException( $struct['faultString'], $struct['faultCode'] ); + } + + // }}} + +} + +/** + * XML_RPC2_UnknownMethodException is thrown when a non-existent method is remote-called + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_UnknownMethodException extends XML_RPC2_Exception +{ +} + +/** + * XML_RPC2_TransportException signal transport level exceptions that stop requests from reaching the server + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_TransportException extends XML_RPC2_Exception +{ +} + +/** + * XML_RPC2_ReceivedInvalidStatusCodeExceptionextends is thrown whenever the XML_RPC2 response to a request does not return a 200 http status code. + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_ReceivedInvalidStatusCodeException extends XML_RPC2_TransportException +{ +} + +/** + * XML_RPC2_CurlException is thrown whenever an error is reported by the low level HTTP cURL library + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_CurlException extends XML_RPC2_TransportException +{ +} + +/** + * XML_RPC2_ConfigException is thrown whenever PHP config clashes with XML_RPC2 requirements or config + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_ConfigException extends XML_RPC2_Exception +{ +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server.php new file mode 100644 index 0000000..febd05e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server.php @@ -0,0 +1,355 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Server.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend.php'; +require_once 'XML/RPC2/Server/Input.php'; +// }}} + + +/** + * XML_RPC2_Server is the frontend class for exposing PHP functions via XML-RPC. + * + * Exporting a programatic interface via XML-RPC using XML_RPC2 is exceedingly easy: + * + * The first step is to assemble all methods you wish to export into a class. You may either + * create a (abstract) class with exportable methods as static, or use an existing instance + * of an object. + * + * You'll then need to document the methods using PHPDocumentor tags. XML_RPC2 will use the + * documentation for server introspection. You'll get something like this: + * + * + * class ExampleServer { + * /** + * * hello says hello + * * + * * @param string Name + * * @return string Greetings + * {@*} + * public static function hello($name) + { + * return "Hello $name"; + * } + * } + * + * + * Now, instantiate the server, using the Factory method to select a backend and a call handler for you: + * + * require_once 'XML/RPC2/Server.php'; + * $server = XML_RPC2_Server::create('ExampleServer'); + * $server->handleCall(); + * + * + * This will create a server exporting all of the 'ExampleServer' class' methods. If you wish to export + * instance methods as well, pass an object instance to the factory instead: + * + * require_once 'XML/RPC2/Server.php'; + * $server = XML_RPC2_Server::create(new ExampleServer()); + * $server->handleCall(); + * + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +abstract class XML_RPC2_Server +{ + + // {{{ properties + + /** + * callHandler field + * + * The call handler is responsible for executing the server exported methods + * + * @var mixed + */ + protected $callHandler = null; + + /** + * prefix field + * + * @var string + */ + protected $prefix = ''; + + /** + * encoding field + * + * TODO : work on encoding for this backend + * + * @var string + */ + protected $encoding = 'utf-8'; + + /** + * display html documentation of xmlrpc exported methods when there is no post datas + * + * @var boolean + */ + protected $autoDocument = true; + + /** + * display external links at the end of autodocumented page + * + * @var boolean + */ + protected $autoDocumentExternalLinks = true; + + /** + * signature checking flag + * + * if set to true, the server will check the method signature before + * calling the corresponding php method + * + * @var boolean + */ + protected $signatureChecking = true; + + /** + * input handler + * + * Implementation of XML_RPC2_Server_Input that feeds this server with input + * + * @var XML_RPC2_Server_Input + */ + protected $input; + + // }}} + // {{{ constructor + + /** + * Create a new XML-RPC Server. + * + * @param object $callHandler the call handler will receive a method call for each remote call received. + * @param array associative array of options + */ + protected function __construct($callHandler, $options = array()) + { + $this->callHandler = $callHandler; + if ((isset($options['prefix'])) && (is_string($options['prefix']))) { + $this->prefix = $options['prefix']; + } + if ((isset($options['encoding'])) && (is_string($options['encoding']))) { + $this->encoding = $options['encoding']; + } + if ((isset($options['autoDocument'])) && (is_bool($options['autoDocument']))) { + $this->autoDocument = $options['autoDocument']; + } + if ((isset($options['autoDocumentExternalLinks'])) && (is_bool($options['autoDocumentExternalLinks']))) { + $this->autoDocumentExternalLinks = $options['autoDocumentExternalLinks']; + } + if ((isset($options['signatureChecking'])) && (is_bool($options['signatureChecking']))) { + $this->signatureChecking = $options['signatureChecking']; + } + if (!isset($options['input'])) $options['input'] = 'XML_RPC2_Server_Input_RawPostData'; + if (is_string($options['input'])) { + $inputDir = strtr($options['input'], array('_' => DIRECTORY_SEPARATOR)) . '.php'; + require_once($inputDir); + $inputClass = $options['input']; + + $options['input'] = new $inputClass(); + } + if ($options['input'] instanceof XML_RPC2_Server_Input) { + $this->input = $options['input']; + } else { + throw new XML_RPC2_ConfigException('Invalid value for "input" option. It must be either a XML_RPC2_Server_Input subclass name or XML_RPC2_Server_Input subclass instance'); + } + } + + // }}} + // {{{ create() + + /** + * Factory method to select a backend and return a new XML_RPC2_Server based on the backend + * + * @param mixed $callTarget either a class name or an object instance. + * @param array associative array of options + * @return object a server class instance + */ + public static function create($callTarget, $options = array()) + { + if (isset($options['backend'])) { + XML_RPC2_Backend::setBackend($options['backend']); + } + if (isset($options['prefix'])) { + $prefix = $options['prefix']; + } else { + $prefix = ''; + } + $backend = XML_RPC2_Backend::getServerClassname(); + // Find callHandler class + if (!isset($options['callHandler'])) { + if (is_object($callTarget)) { // Delegate calls to instance methods + require_once 'XML/RPC2/Server/CallHandler/Instance.php'; + $callHandler = new XML_RPC2_Server_CallHandler_Instance($callTarget, $prefix); + } else { // Delegate calls to static class methods + require_once 'XML/RPC2/Server/CallHandler/Class.php'; + $callHandler = new XML_RPC2_Server_CallHandler_Class($callTarget, $prefix); + } + } else { + $callHandler = $options['callHandler']; + } + return new $backend($callHandler, $options); + } + + // }}} + // {{{ handleCall() + + /** + * Receive the XML-RPC request, decode the HTTP payload, delegate execution to the call handler, and output the encoded call handler response. + * + */ + public abstract function handleCall(); + + // }}} + // {{{ errorToException() + + /** + * Transform an error into an exception + * + * @param int $errno error number + * @param string $errstr error string + * @param string $errfile error file + * @param int $errline error line + */ + public static function errorToException($errno, $errstr, $errfile, $errline) + { + switch ($errno) { + case E_WARNING: + case E_NOTICE: + case E_USER_WARNING: + case E_USER_NOTICE: + case E_STRICT: + // Silence warnings + // TODO Logging should occur here + break; + default: + throw new Exception('Classic error reported "' . $errstr . '" on ' . $errfile . ':' . $errline); + } + } + + // }}} + // {{{ autoDocument() + /* autoDocument {{{ */ + /** + * autoDocument. Produce an HTML page from the result of server introspection + * + * @return string HTML document describing this server + */ + public function autoDocument() + /* }}} */ + { + print "\n"; + print "\n"; + print " \n"; + print " \n"; + print " Available XMLRPC methods for this server\n"; + print " \n"; + print " \n"; + print " \n"; + print "

    Available XMLRPC methods for this server

    \n"; + print "

    Index

    \n"; + print "
      \n"; + foreach ($this->callHandler->getMethods() as $method) { + $name = $method->getName(); + $id = md5($name); + $signature = $method->getHTMLSignature(); + print "
    • $name()
    • \n"; + } + print "
    \n"; + print "

    Details

    \n"; + foreach ($this->callHandler->getMethods() as $method) { + print "
    \n"; + $method->autoDocument(); + print "

    (return to index)

    \n"; + print "
    \n"; + } + if (!($this->autoDocumentExternalLinks)) { + print '

    Powered by PEAR/XML_RPC2       Valid XHTML 1.0 Strict       Valid CSS!

    ' . "\n"; + } + print " \n"; + print "\n"; + } + // }}} + // {{{ getContentLength() + + /** + * Gets the content legth of a serialized XML-RPC message in bytes + * + * @param string $content the serialized XML-RPC message. + * + * @return integer the content length in bytes. + */ + protected function getContentLength($content) + { + if (extension_loaded('mbstring') && (ini_get('mbstring.func_overload') & 2) == 2) { + $length = mb_strlen($content, '8bit'); + } else { + $length = strlen((binary)$content); + } + + return $length; + } + + // }}} +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/CallHandler.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/CallHandler.php new file mode 100644 index 0000000..0abb159 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/CallHandler.php @@ -0,0 +1,129 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: CallHandler.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +// }}} + +/** + * A CallHandler is responsible for actually calling the server-exported methods from the exported class. + * + * This class is abstract and not meant to be used directly by XML_RPC2 users. + * + * XML_RPC2_Server_CallHandler provides the basic code for a call handler class. An XML_RPC2 Call Handler + * operates in tandem with an XML_RPC2 server to export a classe's methods. While XML_RPC2 Server + * is responsible for request decoding and response encoding, the Call Handler is responsible for + * delegating the actual method call to the intended target. + * + * Different server behaviours can be obtained by plugging different Call Handlers into the XML_RPC2_Server. + * Namely, there are two call handlers available: + * - XML_RPC2_Server_Callhandler_Class: Which exports a classe's public static methods + * - XML_RPC2_Server_Callhandler_Instance: Which exports an object's pubilc methods + * + * @see XML_RPC2_Server_Callhandler_Class + * @see XML_RPC2_Server_Callhandler_Instance + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +abstract class XML_RPC2_Server_CallHandler +{ + + // {{{ properties + + /** + * methods Field : holds server methods + * + * @var array + */ + protected $methods = array(); + + // }}} + // {{{ getMethods() + + /** + * methods getter + * + * @return array Array of XML_RPC2_Server_Method instances + */ + public function getMethods() + { + return $this->methods; + } + + // }}} + // {{{ addMethod() + + /** + * method appender + * + * @param XML_RPC2_Server_Method Method to append to methods + */ + protected function addMethod(XML_RPC2_Server_Method $method) + { + $this->methods[$method->getName()] = $method; + } + + // }}} + // {{{ getMethod() + + /** + * method getter + * + * @param string Name of method to return + * @param XML_RPC2_Server_Method Method named $name + */ + public function getMethod($name) + { + if (isset($this->methods[$name])) { + return $this->methods[$name]; + } + return false; + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/CallHandler/Class.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/CallHandler/Class.php new file mode 100644 index 0000000..f7ad3da --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/CallHandler/Class.php @@ -0,0 +1,150 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Class.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Server/Method.php'; +require_once 'XML/RPC2/Server/CallHandler.php'; +// }}} + +/** + * This class is a server call handler which exposes a classe's static public methods. + * + * XML_RPC2_Server_Callhandler_Class is the preferred call handler to use when you are + * designing your XML-RPC server from the ground up. Usage is quite simple: + * - Create a class holding all of the XML-RPC server's exported procedures as public static methods (the interface class). + * - PhpDoc the classes' methods, including at least method signature (params and return types) and short description. + * - Use the XML_RPC2 factory method to create a server based on the interface class. + * A simple example: + * + * /** + * * echoecho echoes the message received + * * + * * @param string Message + * * @return string The echo + * {@*} + * class EchoServer { + * public static function echoecho($string) + * { + * return $string; + * } + * } + * + * require_once 'XML/RPC2/Server.php'; + * $server = XML_RPC2_Server::create('EchoServer'); + * $server->handleCall(); + * + * + * Use this call handler if you have designed your xml-rpc external interface as a set of + * public class methods on a given class. If, on the other hand, you intend to export an + * already existing class, it may be that not all of the methods you want to export are static. + * In that case, it is probably best to use XML_RPC2_Server_Callhandler_Instance instead. + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + * @see XML_RPC2_Server::create + * @see XML_RPC2_Server_Callhandler_Instance + */ +class XML_RPC2_Server_Callhandler_Class extends XML_RPC2_Server_CallHandler +{ + + // {{{ properties + + /** + * name of target class + * + * @var string + */ + private $_className; + + // }}} + // {{{ constructor + + /** + * XML_RPC2_Server_Callhandler_Class Constructor. Creates a new call handler exporting the give static class' methods + * + * Before using this constructor, take a look at XML_RPC2_Server::create. The factory + * method is usually a quicker way of instantiating the server and its call handler. + * + * @see XML_RPC2_Server::create() + * @param string The Target class. Calls will be made on this class + * @param string Default prefix to prepend to all exported methods (defaults to '') + */ + public function __construct($className, $defaultPrefix) + { + $this->_className = $className; + $reflection = new ReflectionClass($className); + foreach ($reflection->getMethods() as $method) { + if ($method->isStatic() && $method->isPublic() && !$method->isAbstract() && !$method->isConstructor()) + { + $candidate = new XML_RPC2_Server_Method($method, $defaultPrefix); + if (!$candidate->isHidden()) $this->addMethod($candidate); + } + } + } + + // }}} + // {{{ __call() + + /** + * __call catchall. Delegate the method call to the target class, and return its result + * + * @param string Name of method to call + * @param array Array of parameters for call + * @return mixed Whatever the target method returned + */ + public function __call($methodName, $parameters) + { + if (!array_key_exists($methodName, $this->getMethods())) { + throw new XML_RPC2_UnknownMethodException("Method $methodName is not exported by this server"); + } + return call_user_func_array(array($this->_className, $this->getMethod($methodName)->getInternalMethod()), $parameters); + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/CallHandler/Instance.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/CallHandler/Instance.php new file mode 100644 index 0000000..8c284a9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/CallHandler/Instance.php @@ -0,0 +1,148 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Instance.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Server/Method.php'; +require_once 'XML/RPC2/Server/CallHandler.php'; +// }}} + +/** + * This class is a server call handler which exposes an instance's public methods. + * + * XML_RPC2_Server_Callhandler_Instance is the preferred call handler to use when + * you just need to quickly expose an already existing object. If designing a remote + * API from the ground up, it's best to use XML_RPC2_Server_Callhandler_Class instead. + * + * Usage is simple: + * - PhpDoc the methods, including at least method signature (params and return types) and short description. + * - Use the XML_RPC2 factory method to create a server based on the interface class. + * A simple example: + * + * class EchoServer { + * /** + * * Echo the message + * * + * * @param string The string to echo + * * @return string The echo + * {@*} + * public function echoecho($string) + * { + * return $string; + * } + * } + * + * require_once 'XML/RPC2/Server.php'; + * $someInstance = new EchoServer(); + * $server = XML_RPC2_Server::create($someInstance); + * $server->handleCall(); + * + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + * @see XML_RPC2_Server::create + * @see XML_RPC2_Server_Callhandler_Class + */ +class XML_RPC2_Server_Callhandler_Instance extends XML_RPC2_Server_CallHandler +{ + + // {{{ properties + + /** + * instance of target object + * + * @var mixed + */ + private $_instance; + + // }}} + // {{{ constructor + + /** + * XML_RPC2_Server_Callhandler_Class Constructor. Creates a new call handler exporting the given object methods + * + * Before using this constructor, take a look at XML_RPC2_Server::create. The factory + * method is usually a quicker way of instantiating the server and its call handler. + * + * @see XML_RPC2_Server::create() + * @param object The Target object. Calls will be made on this instance + * @param string Default prefix to prepend to all exported methods (defaults to '') + */ + public function __construct($instance, $defaultPrefix) + { + $this->_instance = $instance; + $reflection = new ReflectionClass(get_class($instance)); + foreach ($reflection->getMethods() as $method) { + if (!$method->isStatic() && $method->isPublic() && !$method->isConstructor()) + { + $candidate = new XML_RPC2_Server_Method($method, $defaultPrefix); + if (!$candidate->isHidden()) $this->addMethod($candidate); + } + } + } + + // }}} + // {{{ __call() + + /** + * __call catchall. Delegate the method call to the target object, and return its result + * + * @param string Name of method to call + * @param array Array of parameters for call + * @return mixed Whatever the target method returned + */ + public function __call($methodName, $parameters) + { + if (!array_key_exists($methodName, $this->getMethods())) { + throw new XML_RPC2_UnknownMethodException("Method $methodName is not exported by this server"); + } + return call_user_func_array(array($this->_instance, $this->getMethod($methodName)->getInternalMethod()), $parameters); + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Input.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Input.php new file mode 100644 index 0000000..a697a7c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Input.php @@ -0,0 +1,68 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Input.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +/** + * Interface for feeding input to an XML_RPC2_Server + * + * Classes to be used as input readers for XML_RPC2_Server instances + * should implement this interface + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2011 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +interface XML_RPC2_Server_Input +{ + /** + * Return true if there is no input (input is empty) + * + * @return boolean True iff there is no input + */ + public function isEmpty(); + /** + * Return the input as a string + * + * @return string The Input + */ + public function readRequest(); +} diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Input/PhpInput.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Input/PhpInput.php new file mode 100644 index 0000000..99f9944 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Input/PhpInput.php @@ -0,0 +1,79 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: PhpInput.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// Dependencies {{{ +require_once('XML/RPC2/Server/Input.php'); +// }}} + +/** + * Class that feeds XML_RPC2 with input originating from php://input + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2011 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Server_Input_PhpInput implements XML_RPC2_Server_Input +{ + protected $input; + /** + * Return true if there is no input (input is empty) + * + * @return boolean True iff there is no input + */ + public function isEmpty() + { + if (!isset($this->input)) $this->readRequest; + return empty($this->readRequest); + } + /** + * Return the input as a string + * + * @return string The Input + */ + public function readRequest() + { + if (!isset($this->input)) $this->input = file_get_contents('php://input'); + return $this->input; + } +} + diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Input/RawPostData.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Input/RawPostData.php new file mode 100644 index 0000000..183d695 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Input/RawPostData.php @@ -0,0 +1,82 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: RawPostData.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// Dependencies {{{ +require_once('XML/RPC2/Server/Input.php'); +require_once('XML/RPC2/Exception.php'); +// }}} + +/** + * Class that feeds XML_RPC2 with input originating from + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2011 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Server_Input_RawPostData implements XML_RPC2_Server_Input +{ + protected $input; + /** + * Return true if there is no input (input is empty) + * + * @return boolean True iff there is no input + */ + public function isEmpty() + { + if (!isset($this->input)) $this->readRequest(); + $result = empty($this->input); + return $result; + } + /** + * Return the input as a string + * + * @return string The Input + */ + public function readRequest() + { + if (!isset($this->input) && !isset($GLOBALS['HTTP_RAW_POST_DATA'])) throw new XML_RPC2_ConfigException('XML_RPC2_Server_Input_RawPostData requested but PHP config does not show GLOBALS[\'HTTP_RAW_POST_DATA\'] as available'); + if (!isset($this->input)) $this->input = $GLOBALS['HTTP_RAW_POST_DATA']; + + return $this->input; + } +} diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Method.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Method.php new file mode 100644 index 0000000..8a320ec --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Server/Method.php @@ -0,0 +1,391 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Method.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +// }}} + +/** + * Class representing an XML-RPC exported method. + * + * This class is used internally by XML_RPC2_Server. External users of the + * package should not need to ever instantiate XML_RPC2_Server_Method + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Server_Method +{ + // {{{ properties + + /** + * Method signature parameters + * + * @var array + */ + private $_parameters; + + /** + * Method signature return type + * + * @var string + */ + private $_returns ; + + /** + * Method help, for introspection + * + * @var string + */ + private $_help; + + /** + * internalMethod field : method name in PHP-land + * + * @var string + */ + private $_internalMethod; + + /** + * hidden field : true if the method is hidden + * + * @var boolean + */ + private $_hidden; + + /** + * name Field : external method name + * + * @var string + */ + private $_name; + + /** + * Number of required parameters + * + * @var int + */ + private $_numberOfRequiredParameters; + + // }}} + // {{{ getInternalMethod() + + /** + * internalMethod getter + * + * @return string internalMethod + */ + public function getInternalMethod() + { + return $this->_internalMethod; + } + + // }}} + // {{{ isHidden() + + /** + * hidden getter + * + * @return boolean hidden value + */ + public function isHidden() + { + return $this->_hidden; + } + + // }}} + // {{{ getName() + + /** + * name getter + * + * @return string name + */ + public function getName() + { + return $this->_name; + } + + // }}} + // {{{ constructor + + /** + * Create a new XML-RPC method by introspecting a PHP method + * + * @param ReflectionMethod The PHP method to introspect + * @param string default prefix + */ + public function __construct(ReflectionMethod $method, $defaultPrefix) + { + $hidden = false; + $docs = $method->getDocComment(); + if (!$docs) { + $hidden = true; + } + $docs = explode("\n", $docs); + + $parameters = array(); + $methodname = null; + $returns = 'mixed'; + $shortdesc = ''; + $paramcount = -1; + $prefix = $defaultPrefix; + + // Extract info from Docblock + $paramDocs = array(); + foreach ($docs as $i => $doc) { + $doc = trim($doc, " \r\t/*"); + if (strlen($doc) && strpos($doc, '@') !== 0) { + if ($shortdesc) { + $shortdesc .= "\n"; + } + $shortdesc .= $doc; + continue; + } + if (strpos($doc, '@xmlrpc.hidden') === 0) { + $hidden = true; + } + if ((strpos($doc, '@xmlrpc.prefix') === 0) && preg_match('/@xmlrpc.prefix( )*(.*)/', $doc, $matches)) { + $prefix = $matches[2]; + } + if ((strpos($doc, '@xmlrpc.methodname') === 0) && preg_match('/@xmlrpc.methodname( )*(.*)/', $doc, $matches)) { + $methodname = $matches[2]; + } + if (strpos($doc, '@param') === 0) { // Save doctag for usage later when filling parameters + $paramDocs[] = $doc; + } + + if (strpos($doc, '@return') === 0) { + $param = preg_split("/\s+/", $doc); + if (isset($param[1])) { + $param = $param[1]; + $returns = $param; + } + } + } + $this->_numberOfRequiredParameters = $method->getNumberOfRequiredParameters(); // we don't use isOptional() because of bugs in the reflection API + // Fill in info for each method parameter + foreach ($method->getParameters() as $parameterIndex => $parameter) { + // Parameter defaults + $newParameter = array('type' => 'mixed'); + + // Attempt to extract type and doc from docblock + if (array_key_exists($parameterIndex, $paramDocs) && + preg_match('/@param\s+(\S+)(\s+(.+))/', $paramDocs[$parameterIndex], $matches)) { + if (strpos($matches[1], '|')) { + $newParameter['type'] = XML_RPC2_Server_Method::_limitPHPType(explode('|', $matches[1])); + } else { + $newParameter['type'] = XML_RPC2_Server_Method::_limitPHPType($matches[1]); + } + $tmp = '$' . $parameter->getName() . ' '; + if (strpos($matches[3], '$' . $tmp) === 0) { + $newParameter['doc'] = $matches[3]; + } else { + // The phpdoc comment is something like "@param string $param description of param" + // Let's keep only "description of param" as documentation (remove $param) + $newParameter['doc'] = substr($matches[3], strlen($tmp)); + } + $newParameter['doc'] = preg_replace('_^\s*_', '', $newParameter['doc']); + } + + $parameters[$parameter->getName()] = $newParameter; + } + + if (is_null($methodname)) { + $methodname = $prefix . $method->getName(); + } + + $this->_internalMethod = $method->getName(); + $this->_parameters = $parameters; + $this->_returns = $returns; + $this->_help = $shortdesc; + $this->_name = $methodname; + $this->_hidden = $hidden; + } + + // }}} + // {{{ matchesSignature() + + /** + * Check if method matches provided call signature + * + * Compare the provided call signature with this methods' signature and + * return true iff they match. + * + * @param string Signature to compare method name + * @param array Array of parameter values for method call. + * @return boolean True if call matches signature, false otherwise + */ + public function matchesSignature($methodName, $callParams) + { + if ($methodName != $this->_name) return false; + if (count($callParams) < $this->_numberOfRequiredParameters) return false; + if (count($callParams) > $this->_parameters) return false; + $paramIndex = 0; + foreach($this->_parameters as $param) { + $paramIndex++; + if ($paramIndex <= $this->_numberOfRequiredParameters) { + // the parameter is not optional + $callParamType = XML_RPC2_Server_Method::_limitPHPType(gettype($callParams[$paramIndex-1])); + if ((!($param['type'] == 'mixed')) and ($param['type'] != $callParamType)) { + return false; + } + } + } + return true; + } + + // }}} + // {{{ getHTMLSignature() + + /** + * Return a HTML signature of the method + * + * @return string HTML signature + */ + public function getHTMLSignature() + { + $name = $this->_name; + $returnType = $this->_returns; + $result = "($returnType) "; + $result .= "$name"; + $result .= "("; + $first = true; + $nbr = 0; + while (list($name, $parameter) = each($this->_parameters)) { + $nbr++; + if ($nbr == $this->_numberOfRequiredParameters + 1) { + $result .= " [ "; + } + if ($first) { + $first = false; + } else { + $result .= ', '; + } + $type = $parameter['type']; + $result .= "($type) "; + $result .= "$name"; + } + reset($this->_parameters); + if ($nbr > $this->_numberOfRequiredParameters) { + $result .= " ] "; + } + $result .= ")"; + return $result; + } + + // }}} + // {{{ autoDocument() + /** + * Print a complete HTML description of the method + */ + public function autoDocument() + { + $name = $this->getName(); + $signature = $this->getHTMLSignature(); + $id = md5($name); + $help = nl2br(htmlentities($this->_help)); + print "

    $signature

    \n"; + print "

    Description :

    \n"; + print "
    \n"; + print " $help\n"; + print "
    \n"; + if (count($this->_parameters)>0) { + print "

    Parameters :

    \n"; + if (count($this->_parameters)>0) { + print " \n"; + print " \n"; + while (list($name, $parameter) = each($this->_parameters)) { + $type = $parameter['type']; + $doc = isset($parameter['doc']) ? htmlentities($parameter['doc']) : 'Method is not documented. No PHPDoc block was found associated with the method in the source code.'; + print " \n"; + } + reset($this->_parameters); + print "
    TypeNameDocumentation
    $type$name$doc
    \n"; + } + } + } + + // }}} + // {{{ _limitPHPType() + /** + * standardise type names between gettype php function and phpdoc comments (and limit to xmlrpc available types) + * + * @var string $type + * @return string standardised type + */ + private static function _limitPHPType($type) + { + $tmp = strtolower($type); + $convertArray = array( + 'int' => 'integer', + 'i4' => 'integer', + 'integer' => 'integer', + 'string' => 'string', + 'str' => 'string', + 'char' => 'string', + 'bool' => 'boolean', + 'boolean' => 'boolean', + 'array' => 'array', + 'float' => 'double', + 'double' => 'double', + 'array' => 'array', + 'struct' => 'array', + 'assoc' => 'array', + 'structure' => 'array', + 'datetime' => 'mixed', + 'datetime.iso8601' => 'mixed', + 'iso8601' => 'mixed', + 'base64' => 'string' + ); + if (isset($convertArray[$tmp])) { + return $convertArray[$tmp]; + } + return 'mixed'; + } + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Util/HTTPRequest.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Util/HTTPRequest.php new file mode 100644 index 0000000..e9f1a9e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Util/HTTPRequest.php @@ -0,0 +1,248 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: HTTPRequest.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Client.php'; +require_once 'HTTP/Request2.php'; +// }}} + +/** + * XML_RPC utility HTTP request class. This class mimics a subset of PEAR's HTTP_Request + * and is to be refactored out of the package once HTTP_Request releases an E_STRICT version. + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2011 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +class XML_RPC2_Util_HTTPRequest +{ + + // {{{ properties + + /** + * proxy field + * + * @var string + */ + private $_proxy = null; + + /** + * proxyauth field + * + * @var string + */ + private $_proxyAuth = null; + + /** + * postData field + * + * @var string + */ + private $_postData; + + /** + * uri field + * + * @var array + */ + private $_uri; + + /** + * encoding for the request + * + * @var string + */ + private $_encoding='utf-8'; + + /** + * SSL verify flag + * + * @var boolean + */ + private $_sslverify=true; + + /** + * HTTP timeout length in seconds. + * + * @var integer + */ + private $_connectionTimeout = null; + + /** + * HTTP_Request2 backend + * + * @var integer + */ + private $_httpRequest = null; + + // }}} + // {{{ getBody() + + /** + * body field getter + * + * @return string body value + */ + public function getBody() + { + return $this->_body; + } + + // }}} + // {{{ setPostData() + + /** + * postData field setter + * + * @param string postData value + */ + public function setPostData($value) + { + $this->_postData = $value; + } + + // }}} + // {{{ constructor + + /** + * Constructor + * + * Sets up the object + * @param string The uri to fetch/access + * @param array Associative array of parameters which can have the following keys: + *
      + *
    • proxy - Proxy (string)
    • + *
    • encoding - The request encoding (string)
    • + *
    • sslverify
    • - The SSL verify flag (boolean) + *
    • connectionTimeout
    • - The connection timeout in milliseconds (integer) + *
    • httpRequest
    • - Preconfigured instance of HTTP_Request2 (optional) + *
    + * @access public + */ + public function __construct($uri = '', $params = array()) + { + if (!preg_match('/(https?:\/\/)(.*)/', $uri)) throw new XML_RPC2_Exception('Unable to parse URI'); + $this->_uri = $uri; + if (isset($params['encoding'])) { + $this->_encoding = $params['encoding']; + } + if (isset($params['proxy'])) { + $proxy = $params['proxy']; + $elements = parse_url($proxy); + if (is_array($elements)) { + if ((isset($elements['scheme'])) and (isset($elements['host']))) { + $this->_proxy = $elements['scheme'] . '://' . $elements['host']; + } + if (isset($elements['port'])) { + $this->_proxy = $this->_proxy . ':' . $elements['port']; + } + if ((isset($elements['user'])) and (isset($elements['pass']))) { + $this->_proxyAuth = $elements['user'] . ':' . $elements['pass']; + } + } + } + if (isset($params['sslverify'])) { + $this->_sslverify = $params['sslverify']; + } + if (isset($params['connectionTimeout'])) { + $this->_connectionTimeout = $params['connectionTimeout']; + } + if (isset($params['httpRequest']) && $params['httpRequest'] instanceof HTTP_Request2) { + $this->_httpRequest = $params['httpRequest']; + } + } + + // }}} + // {{{ sendRequest() + + /** + * Sends the request + * + * @access public + * @return mixed PEAR error on error, true otherwise + */ + public function sendRequest() + { + if (is_null($this->_httpRequest)) $this->_httpRequest = new HTTP_Request2($this->_uri, HTTP_Request2::METHOD_POST); + $request = $this->_httpRequest; + $request->setUrl($this->_uri); + $request->setMethod(HTTP_Request2::METHOD_POST); + if (isset($params['proxy'])) { + $elements = parse_url($params['proxy']); + if (is_array($elements)) { + if ((isset($elements['scheme'])) and (isset($elements['host']))) { + $request->setConfig('proxy_host', $elements['host']); + } + if (isset($elements['port'])) { + $request->setConfig('proxy_port', $elements['port']); + } + if ((isset($elements['user'])) and (isset($elements['pass']))) { + $request->setConfig('proxy_user', $elements['user']); + $request->setConfig('proxy_password', $elements['pass']); + } + } + } + $request->setConfig('ssl_verify_peer', $this->_sslverify); + $request->setConfig('ssl_verify_host', $this->_sslverify); + $request->setHeader('Content-type: text/xml; charset='.$this->_encoding); + $request->setHeader('User-Agent: PEAR::XML_RPC2/@package_version@'); + $request->setBody($this->_postData); + if (isset($this->_connectionTimeout)) $request->setConfig('timeout', (int) ($this->_connectionTimeout / 1000)); + try { + $result = $request->send(); + if ($result->getStatus() != 200) throw new XML_RPC2_ReceivedInvalidStatusCodeException('Received non-200 HTTP Code: ' . $request->getStatus() . '. Response body:' . $result->getBody()); + + } catch (HTTP_Request2_Exception $e) { + throw new XML_RPC2_CurlException($e); + } + $this->_body = $result->getBody(); + return $result->getBody(); + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/RPC2/Value.php b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Value.php new file mode 100644 index 0000000..96ae88d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/RPC2/Value.php @@ -0,0 +1,81 @@ + | +* +-----------------------------------------------------------------------------+ +* +* @category XML +* @package XML_RPC2 +* @author Sergio Carvalho +* @copyright 2004-2006 Sergio Carvalho +* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 +* @version CVS: $Id: Value.php 79708 2011-06-28 07:50:21Z dkd-webler $ +* @link http://pear.php.net/package/XML_RPC2 +*/ + +// }}} + +// dependencies {{{ +require_once 'XML/RPC2/Exception.php'; +require_once 'XML/RPC2/Backend.php'; +// }}} + +/** + * XML_RPC value abstract class. All XML_RPC value classes inherit from XML_RPC2_Value + * + * @category XML + * @package XML_RPC2 + * @author Sergio Carvalho + * @copyright 2004-2006 Sergio Carvalho + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/XML_RPC2 + */ +abstract class XML_RPC2_Value +{ + // {{{ createFromNative() + + /** + * Factory method that constructs the appropriate XML-RPC encoded type value + * + * @param mixed Value to be encode + * @param string (optional) Explicit XML-RPC type as enumerated in the XML-RPC spec (defaults to automatically selected type) + * @return mixed The encoded value + */ + public static function createFromNative($value, $explicitType = null) + { + $xmlrpcTypes = array('int', 'boolean', 'string', 'double', 'datetime', 'base64', 'struct', 'array'); + if (in_array($explicitType, $xmlrpcTypes)) { + return @call_user_func(array(XML_RPC2_Backend::getValueClassname(), 'createFromNative'), $value, $explicitType); + } + return $value; + } + + // }}} + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/XML/Util.php b/typo3conf/ext/phpunit/PEAR/XML/Util.php new file mode 100644 index 0000000..eb6c4e8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/XML/Util.php @@ -0,0 +1,911 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category XML + * @package XML_Util + * @author Stephan Schmidt + * @copyright 2003-2008 Stephan Schmidt + * @license http://opensource.org/licenses/bsd-license New BSD License + * @version CVS: $Id: Util.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/XML_Util + */ + +/** + * error code for invalid chars in XML name + */ +define('XML_UTIL_ERROR_INVALID_CHARS', 51); + +/** + * error code for invalid chars in XML name + */ +define('XML_UTIL_ERROR_INVALID_START', 52); + +/** + * error code for non-scalar tag content + */ +define('XML_UTIL_ERROR_NON_SCALAR_CONTENT', 60); + +/** + * error code for missing tag name + */ +define('XML_UTIL_ERROR_NO_TAG_NAME', 61); + +/** + * replace XML entities + */ +define('XML_UTIL_REPLACE_ENTITIES', 1); + +/** + * embedd content in a CData Section + */ +define('XML_UTIL_CDATA_SECTION', 5); + +/** + * do not replace entitites + */ +define('XML_UTIL_ENTITIES_NONE', 0); + +/** + * replace all XML entitites + * This setting will replace <, >, ", ' and & + */ +define('XML_UTIL_ENTITIES_XML', 1); + +/** + * replace only required XML entitites + * This setting will replace <, " and & + */ +define('XML_UTIL_ENTITIES_XML_REQUIRED', 2); + +/** + * replace HTML entitites + * @link http://www.php.net/htmlentities + */ +define('XML_UTIL_ENTITIES_HTML', 3); + +/** + * Collapse all empty tags. + */ +define('XML_UTIL_COLLAPSE_ALL', 1); + +/** + * Collapse only empty XHTML tags that have no end tag. + */ +define('XML_UTIL_COLLAPSE_XHTML_ONLY', 2); + +/** + * utility class for working with XML documents + * + + * @category XML + * @package XML_Util + * @author Stephan Schmidt + * @copyright 2003-2008 Stephan Schmidt + * @license http://opensource.org/licenses/bsd-license New BSD License + * @version Release: 1.2.1 + * @link http://pear.php.net/package/XML_Util + */ +class XML_Util +{ + /** + * return API version + * + * @return string $version API version + * @access public + * @static + */ + function apiVersion() + { + return '1.1'; + } + + /** + * replace XML entities + * + * With the optional second parameter, you may select, which + * entities should be replaced. + * + * + * require_once 'XML/Util.php'; + * + * // replace XML entites: + * $string = XML_Util::replaceEntities('This string contains < & >.'); + * + * + * With the optional third parameter, you may pass the character encoding + * + * require_once 'XML/Util.php'; + * + * // replace XML entites in UTF-8: + * $string = XML_Util::replaceEntities( + * 'This string contains < & > as well as ä, ö, ß, à and ê', + * XML_UTIL_ENTITIES_HTML, + * 'UTF-8' + * ); + * + * + * @param string $string string where XML special chars + * should be replaced + * @param int $replaceEntities setting for entities in attribute values + * (one of XML_UTIL_ENTITIES_XML, + * XML_UTIL_ENTITIES_XML_REQUIRED, + * XML_UTIL_ENTITIES_HTML) + * @param string $encoding encoding value (if any)... + * must be a valid encoding as determined + * by the htmlentities() function + * + * @return string string with replaced chars + * @access public + * @static + * @see reverseEntities() + */ + function replaceEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML, + $encoding = 'ISO-8859-1') + { + switch ($replaceEntities) { + case XML_UTIL_ENTITIES_XML: + return strtr($string, array( + '&' => '&', + '>' => '>', + '<' => '<', + '"' => '"', + '\'' => ''' )); + break; + case XML_UTIL_ENTITIES_XML_REQUIRED: + return strtr($string, array( + '&' => '&', + '<' => '<', + '"' => '"' )); + break; + case XML_UTIL_ENTITIES_HTML: + return htmlentities($string, ENT_COMPAT, $encoding); + break; + } + return $string; + } + + /** + * reverse XML entities + * + * With the optional second parameter, you may select, which + * entities should be reversed. + * + * + * require_once 'XML/Util.php'; + * + * // reverse XML entites: + * $string = XML_Util::reverseEntities('This string contains < & >.'); + * + * + * With the optional third parameter, you may pass the character encoding + * + * require_once 'XML/Util.php'; + * + * // reverse XML entites in UTF-8: + * $string = XML_Util::reverseEntities( + * 'This string contains < & > as well as' + * . ' ä, ö, ß, à and ê', + * XML_UTIL_ENTITIES_HTML, + * 'UTF-8' + * ); + * + * + * @param string $string string where XML special chars + * should be replaced + * @param int $replaceEntities setting for entities in attribute values + * (one of XML_UTIL_ENTITIES_XML, + * XML_UTIL_ENTITIES_XML_REQUIRED, + * XML_UTIL_ENTITIES_HTML) + * @param string $encoding encoding value (if any)... + * must be a valid encoding as determined + * by the html_entity_decode() function + * + * @return string string with replaced chars + * @access public + * @static + * @see replaceEntities() + */ + function reverseEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML, + $encoding = 'ISO-8859-1') + { + switch ($replaceEntities) { + case XML_UTIL_ENTITIES_XML: + return strtr($string, array( + '&' => '&', + '>' => '>', + '<' => '<', + '"' => '"', + ''' => '\'' )); + break; + case XML_UTIL_ENTITIES_XML_REQUIRED: + return strtr($string, array( + '&' => '&', + '<' => '<', + '"' => '"' )); + break; + case XML_UTIL_ENTITIES_HTML: + return html_entity_decode($string, ENT_COMPAT, $encoding); + break; + } + return $string; + } + + /** + * build an xml declaration + * + * + * require_once 'XML/Util.php'; + * + * // get an XML declaration: + * $xmlDecl = XML_Util::getXMLDeclaration('1.0', 'UTF-8', true); + * + * + * @param string $version xml version + * @param string $encoding character encoding + * @param bool $standalone document is standalone (or not) + * + * @return string xml declaration + * @access public + * @static + * @uses attributesToString() to serialize the attributes of the XML declaration + */ + function getXMLDeclaration($version = '1.0', $encoding = null, + $standalone = null) + { + $attributes = array( + 'version' => $version, + ); + // add encoding + if ($encoding !== null) { + $attributes['encoding'] = $encoding; + } + // add standalone, if specified + if ($standalone !== null) { + $attributes['standalone'] = $standalone ? 'yes' : 'no'; + } + + return sprintf('', + XML_Util::attributesToString($attributes, false)); + } + + /** + * build a document type declaration + * + * + * require_once 'XML/Util.php'; + * + * // get a doctype declaration: + * $xmlDecl = XML_Util::getDocTypeDeclaration('rootTag','myDocType.dtd'); + * + * + * @param string $root name of the root tag + * @param string $uri uri of the doctype definition + * (or array with uri and public id) + * @param string $internalDtd internal dtd entries + * + * @return string doctype declaration + * @access public + * @static + * @since 0.2 + */ + function getDocTypeDeclaration($root, $uri = null, $internalDtd = null) + { + if (is_array($uri)) { + $ref = sprintf(' PUBLIC "%s" "%s"', $uri['id'], $uri['uri']); + } elseif (!empty($uri)) { + $ref = sprintf(' SYSTEM "%s"', $uri); + } else { + $ref = ''; + } + + if (empty($internalDtd)) { + return sprintf('', $root, $ref); + } else { + return sprintf("", $root, $ref, $internalDtd); + } + } + + /** + * create string representation of an attribute list + * + * + * require_once 'XML/Util.php'; + * + * // build an attribute string + * $att = array( + * 'foo' => 'bar', + * 'argh' => 'tomato' + * ); + * + * $attList = XML_Util::attributesToString($att); + * + * + * @param array $attributes attribute array + * @param bool|array $sort sort attribute list alphabetically, + * may also be an assoc array containing + * the keys 'sort', 'multiline', 'indent', + * 'linebreak' and 'entities' + * @param bool $multiline use linebreaks, if more than + * one attribute is given + * @param string $indent string used for indentation of + * multiline attributes + * @param string $linebreak string used for linebreaks of + * multiline attributes + * @param int $entities setting for entities in attribute values + * (one of XML_UTIL_ENTITIES_NONE, + * XML_UTIL_ENTITIES_XML, + * XML_UTIL_ENTITIES_XML_REQUIRED, + * XML_UTIL_ENTITIES_HTML) + * + * @return string string representation of the attributes + * @access public + * @static + * @uses replaceEntities() to replace XML entities in attribute values + * @todo allow sort also to be an options array + */ + function attributesToString($attributes, $sort = true, $multiline = false, + $indent = ' ', $linebreak = "\n", $entities = XML_UTIL_ENTITIES_XML) + { + /* + * second parameter may be an array + */ + if (is_array($sort)) { + if (isset($sort['multiline'])) { + $multiline = $sort['multiline']; + } + if (isset($sort['indent'])) { + $indent = $sort['indent']; + } + if (isset($sort['linebreak'])) { + $multiline = $sort['linebreak']; + } + if (isset($sort['entities'])) { + $entities = $sort['entities']; + } + if (isset($sort['sort'])) { + $sort = $sort['sort']; + } else { + $sort = true; + } + } + $string = ''; + if (is_array($attributes) && !empty($attributes)) { + if ($sort) { + ksort($attributes); + } + if ( !$multiline || count($attributes) == 1) { + foreach ($attributes as $key => $value) { + if ($entities != XML_UTIL_ENTITIES_NONE) { + if ($entities === XML_UTIL_CDATA_SECTION) { + $entities = XML_UTIL_ENTITIES_XML; + } + $value = XML_Util::replaceEntities($value, $entities); + } + $string .= ' ' . $key . '="' . $value . '"'; + } + } else { + $first = true; + foreach ($attributes as $key => $value) { + if ($entities != XML_UTIL_ENTITIES_NONE) { + $value = XML_Util::replaceEntities($value, $entities); + } + if ($first) { + $string .= ' ' . $key . '="' . $value . '"'; + $first = false; + } else { + $string .= $linebreak . $indent . $key . '="' . $value . '"'; + } + } + } + } + return $string; + } + + /** + * Collapses empty tags. + * + * @param string $xml XML + * @param int $mode Whether to collapse all empty tags (XML_UTIL_COLLAPSE_ALL) + * or only XHTML (XML_UTIL_COLLAPSE_XHTML_ONLY) ones. + * + * @return string XML + * @access public + * @static + * @todo PEAR CS - unable to avoid "space after open parens" error + * in the IF branch + */ + function collapseEmptyTags($xml, $mode = XML_UTIL_COLLAPSE_ALL) + { + if ($mode == XML_UTIL_COLLAPSE_XHTML_ONLY) { + return preg_replace( + '/<(area|base(?:font)?|br|col|frame|hr|img|input|isindex|link|meta|' + . 'param)([^>]*)><\/\\1>/s', + '<\\1\\2 />', + $xml); + } else { + return preg_replace('/<(\w+)([^>]*)><\/\\1>/s', '<\\1\\2 />', $xml); + } + } + + /** + * create a tag + * + * This method will call XML_Util::createTagFromArray(), which + * is more flexible. + * + * + * require_once 'XML/Util.php'; + * + * // create an XML tag: + * $tag = XML_Util::createTag('myNs:myTag', + * array('foo' => 'bar'), + * 'This is inside the tag', + * 'http://www.w3c.org/myNs#'); + * + * + * @param string $qname qualified tagname (including namespace) + * @param array $attributes array containg attributes + * @param mixed $content the content + * @param string $namespaceUri URI of the namespace + * @param int $replaceEntities whether to replace XML special chars in + * content, embedd it in a CData section + * or none of both + * @param bool $multiline whether to create a multiline tag where + * each attribute gets written to a single line + * @param string $indent string used to indent attributes + * (_auto indents attributes so they start + * at the same column) + * @param string $linebreak string used for linebreaks + * @param bool $sortAttributes Whether to sort the attributes or not + * + * @return string XML tag + * @access public + * @static + * @see createTagFromArray() + * @uses createTagFromArray() to create the tag + */ + function createTag($qname, $attributes = array(), $content = null, + $namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, + $multiline = false, $indent = '_auto', $linebreak = "\n", + $sortAttributes = true) + { + $tag = array( + 'qname' => $qname, + 'attributes' => $attributes + ); + + // add tag content + if ($content !== null) { + $tag['content'] = $content; + } + + // add namespace Uri + if ($namespaceUri !== null) { + $tag['namespaceUri'] = $namespaceUri; + } + + return XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, + $indent, $linebreak, $sortAttributes); + } + + /** + * create a tag from an array + * this method awaits an array in the following format + *
    +     * array(
    +     *     // qualified name of the tag
    +     *     'qname' => $qname        
    +     *
    +     *     // namespace prefix (optional, if qname is specified or no namespace)
    +     *     'namespace' => $namespace    
    +     *
    +     *     // local part of the tagname (optional, if qname is specified)
    +     *     'localpart' => $localpart,   
    +     *
    +     *     // array containing all attributes (optional)
    +     *     'attributes' => array(),      
    +     *
    +     *     // tag content (optional)
    +     *     'content' => $content,     
    +     *
    +     *     // namespaceUri for the given namespace (optional)
    +     *     'namespaceUri' => $namespaceUri 
    +     * )
    +     * 
    + * + * + * require_once 'XML/Util.php'; + * + * $tag = array( + * 'qname' => 'foo:bar', + * 'namespaceUri' => 'http://foo.com', + * 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), + * 'content' => 'I\'m inside the tag', + * ); + * // creating a tag with qualified name and namespaceUri + * $string = XML_Util::createTagFromArray($tag); + * + * + * @param array $tag tag definition + * @param int $replaceEntities whether to replace XML special chars in + * content, embedd it in a CData section + * or none of both + * @param bool $multiline whether to create a multiline tag where each + * attribute gets written to a single line + * @param string $indent string used to indent attributes + * (_auto indents attributes so they start + * at the same column) + * @param string $linebreak string used for linebreaks + * @param bool $sortAttributes Whether to sort the attributes or not + * + * @return string XML tag + * @access public + * @static + * @see createTag() + * @uses attributesToString() to serialize the attributes of the tag + * @uses splitQualifiedName() to get local part and namespace of a qualified name + * @uses createCDataSection() + * @uses raiseError() + */ + function createTagFromArray($tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, + $multiline = false, $indent = '_auto', $linebreak = "\n", + $sortAttributes = true) + { + if (isset($tag['content']) && !is_scalar($tag['content'])) { + return XML_Util::raiseError('Supplied non-scalar value as tag content', + XML_UTIL_ERROR_NON_SCALAR_CONTENT); + } + + if (!isset($tag['qname']) && !isset($tag['localPart'])) { + return XML_Util::raiseError('You must either supply a qualified name ' + . '(qname) or local tag name (localPart).', + XML_UTIL_ERROR_NO_TAG_NAME); + } + + // if no attributes hav been set, use empty attributes + if (!isset($tag['attributes']) || !is_array($tag['attributes'])) { + $tag['attributes'] = array(); + } + + if (isset($tag['namespaces'])) { + foreach ($tag['namespaces'] as $ns => $uri) { + $tag['attributes']['xmlns:' . $ns] = $uri; + } + } + + if (!isset($tag['qname'])) { + // qualified name is not given + + // check for namespace + if (isset($tag['namespace']) && !empty($tag['namespace'])) { + $tag['qname'] = $tag['namespace'] . ':' . $tag['localPart']; + } else { + $tag['qname'] = $tag['localPart']; + } + } elseif (isset($tag['namespaceUri']) && !isset($tag['namespace'])) { + // namespace URI is set, but no namespace + + $parts = XML_Util::splitQualifiedName($tag['qname']); + + $tag['localPart'] = $parts['localPart']; + if (isset($parts['namespace'])) { + $tag['namespace'] = $parts['namespace']; + } + } + + if (isset($tag['namespaceUri']) && !empty($tag['namespaceUri'])) { + // is a namespace given + if (isset($tag['namespace']) && !empty($tag['namespace'])) { + $tag['attributes']['xmlns:' . $tag['namespace']] = + $tag['namespaceUri']; + } else { + // define this Uri as the default namespace + $tag['attributes']['xmlns'] = $tag['namespaceUri']; + } + } + + // check for multiline attributes + if ($multiline === true) { + if ($indent === '_auto') { + $indent = str_repeat(' ', (strlen($tag['qname'])+2)); + } + } + + // create attribute list + $attList = XML_Util::attributesToString($tag['attributes'], + $sortAttributes, $multiline, $indent, $linebreak, $replaceEntities); + if (!isset($tag['content']) || (string)$tag['content'] == '') { + $tag = sprintf('<%s%s />', $tag['qname'], $attList); + } else { + switch ($replaceEntities) { + case XML_UTIL_ENTITIES_NONE: + break; + case XML_UTIL_CDATA_SECTION: + $tag['content'] = XML_Util::createCDataSection($tag['content']); + break; + default: + $tag['content'] = XML_Util::replaceEntities($tag['content'], + $replaceEntities); + break; + } + $tag = sprintf('<%s%s>%s', $tag['qname'], $attList, $tag['content'], + $tag['qname']); + } + return $tag; + } + + /** + * create a start element + * + * + * require_once 'XML/Util.php'; + * + * // create an XML start element: + * $tag = XML_Util::createStartElement('myNs:myTag', + * array('foo' => 'bar') ,'http://www.w3c.org/myNs#'); + * + * + * @param string $qname qualified tagname (including namespace) + * @param array $attributes array containg attributes + * @param string $namespaceUri URI of the namespace + * @param bool $multiline whether to create a multiline tag where each + * attribute gets written to a single line + * @param string $indent string used to indent attributes (_auto indents + * attributes so they start at the same column) + * @param string $linebreak string used for linebreaks + * @param bool $sortAttributes Whether to sort the attributes or not + * + * @return string XML start element + * @access public + * @static + * @see createEndElement(), createTag() + */ + function createStartElement($qname, $attributes = array(), $namespaceUri = null, + $multiline = false, $indent = '_auto', $linebreak = "\n", + $sortAttributes = true) + { + // if no attributes hav been set, use empty attributes + if (!isset($attributes) || !is_array($attributes)) { + $attributes = array(); + } + + if ($namespaceUri != null) { + $parts = XML_Util::splitQualifiedName($qname); + } + + // check for multiline attributes + if ($multiline === true) { + if ($indent === '_auto') { + $indent = str_repeat(' ', (strlen($qname)+2)); + } + } + + if ($namespaceUri != null) { + // is a namespace given + if (isset($parts['namespace']) && !empty($parts['namespace'])) { + $attributes['xmlns:' . $parts['namespace']] = $namespaceUri; + } else { + // define this Uri as the default namespace + $attributes['xmlns'] = $namespaceUri; + } + } + + // create attribute list + $attList = XML_Util::attributesToString($attributes, $sortAttributes, + $multiline, $indent, $linebreak); + $element = sprintf('<%s%s>', $qname, $attList); + return $element; + } + + /** + * create an end element + * + * + * require_once 'XML/Util.php'; + * + * // create an XML start element: + * $tag = XML_Util::createEndElement('myNs:myTag'); + * + * + * @param string $qname qualified tagname (including namespace) + * + * @return string XML end element + * @access public + * @static + * @see createStartElement(), createTag() + */ + function createEndElement($qname) + { + $element = sprintf('', $qname); + return $element; + } + + /** + * create an XML comment + * + * + * require_once 'XML/Util.php'; + * + * // create an XML start element: + * $tag = XML_Util::createComment('I am a comment'); + * + * + * @param string $content content of the comment + * + * @return string XML comment + * @access public + * @static + */ + function createComment($content) + { + $comment = sprintf('', $content); + return $comment; + } + + /** + * create a CData section + * + * + * require_once 'XML/Util.php'; + * + * // create a CData section + * $tag = XML_Util::createCDataSection('I am content.'); + * + * + * @param string $data data of the CData section + * + * @return string CData section with content + * @access public + * @static + */ + function createCDataSection($data) + { + return sprintf('', + preg_replace('/\]\]>/', ']]]]>', strval($data))); + + } + + /** + * split qualified name and return namespace and local part + * + * + * require_once 'XML/Util.php'; + * + * // split qualified tag + * $parts = XML_Util::splitQualifiedName('xslt:stylesheet'); + * + * the returned array will contain two elements: + *
    +     * array(
    +     *     'namespace' => 'xslt',
    +     *     'localPart' => 'stylesheet'
    +     * );
    +     * 
    + * + * @param string $qname qualified tag name + * @param string $defaultNs default namespace (optional) + * + * @return array array containing namespace and local part + * @access public + * @static + */ + function splitQualifiedName($qname, $defaultNs = null) + { + if (strstr($qname, ':')) { + $tmp = explode(':', $qname); + return array( + 'namespace' => $tmp[0], + 'localPart' => $tmp[1] + ); + } + return array( + 'namespace' => $defaultNs, + 'localPart' => $qname + ); + } + + /** + * check, whether string is valid XML name + * + *

    XML names are used for tagname, attribute names and various + * other, lesser known entities.

    + *

    An XML name may only consist of alphanumeric characters, + * dashes, undescores and periods, and has to start with a letter + * or an underscore.

    + * + * + * require_once 'XML/Util.php'; + * + * // verify tag name + * $result = XML_Util::isValidName('invalidTag?'); + * if (is_a($result, 'PEAR_Error')) { + * print 'Invalid XML name: ' . $result->getMessage(); + * } + * + * + * @param string $string string that should be checked + * + * @return mixed true, if string is a valid XML name, PEAR error otherwise + * @access public + * @static + * @todo support for other charsets + * @todo PEAR CS - unable to avoid 85-char limit on second preg_match + */ + function isValidName($string) + { + // check for invalid chars + if (!preg_match('/^[[:alpha:]_]$/', $string{0})) { + return XML_Util::raiseError('XML names may only start with letter ' + . 'or underscore', XML_UTIL_ERROR_INVALID_START); + } + + // check for invalid chars + if (!preg_match('/^([[:alpha:]_]([[:alnum:]\-\.]*)?:)?[[:alpha:]_]([[:alnum:]\_\-\.]+)?$/', + $string) + ) { + return XML_Util::raiseError('XML names may only contain alphanumeric ' + . 'chars, period, hyphen, colon and underscores', + XML_UTIL_ERROR_INVALID_CHARS); + } + // XML name is valid + return true; + } + + /** + * replacement for XML_Util::raiseError + * + * Avoids the necessity to always require + * PEAR.php + * + * @param string $msg error message + * @param int $code error code + * + * @return PEAR_Error + * @access public + * @static + * @todo PEAR CS - should this use include_once instead? + */ + function raiseError($msg, $code) + { + require_once 'PEAR.php'; + return PEAR::raiseError($msg, $code); + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/data/Base/design/class_diagram.png b/typo3conf/ext/phpunit/PEAR/data/Base/design/class_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..3385fb782ed77a09d99a2e7a1550b7359613451b GIT binary patch literal 233811 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
    |d6p0WI9txtW1u+FNd*jwZm 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 G9D$Td-!k+6sz4 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
    K!$; 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 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/data/Base/design/design.txt b/typo3conf/ext/phpunit/PEAR/data/Base/design/design.txt new file mode 100644 index 0000000..72a080d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/data/Base/design/design.txt @@ -0,0 +1,9 @@ +Base +==== + +Purpose +------- +This is the base package of the eZ publish components, offering the basic +support that all Components need. In the first version this will be the +autoload support. + diff --git a/typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/class_diagram.png b/typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/class_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..ed2f5b021c3de9e1d205c543b139802c2f91c684 GIT binary patch literal 871054 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௰lNQ(MT% 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

    5dN|LrloV%hyuF+bnA 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

    }uq$%YS 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%0DG%52LgopALahR12m*8&7JvQ=z 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 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/console.png b/typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/console.png new file mode 100644 index 0000000000000000000000000000000000000000..4f2f2aa18ffd084014836bdb52d7a823807456d6 GIT binary patch literal 16645 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 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/console.xml b/typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/console.xml new file mode 100644 index 0000000..1ea38f9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/console.xml @@ -0,0 +1,3117 @@ + + + + + Enterprise Architect + 2.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Package + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/console_parameters.png b/typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/console_parameters.png new file mode 100644 index 0000000000000000000000000000000000000000..331e3d6c92b944056b83780bd3609c2b66254541 GIT binary patch literal 8606 zcmd5?cQjn@x*kFhJ<3Sb5Ckz=Bt#3M1VKb+)aasynT#3|ZIGgkWDvc@Ad+B=7Dg{o zCL$OzdI?7F?&O^0ckcP!v+i2=zdQfzwfDPct?zrw^E~hS?N~#7E&6j8&jA1c`a9aU zjQ{{LUI2hRikh7CfLvF;O{Ngp2yvcylB}b>2>EDv&&>*?9Dl z-ev9x38Bb4O%u#=F`afO1Kd7nruo{{)LRvMLz~0J>Ggu<;n&M=Eu&$PYk$1w z_MTzzJDn<+XwK?cODCG>tfMD5GK-RXj~IBU_blMmy2_Pk{=$SbDp6eUw@7$;_Qcvx zMgjSJR`B{ltkpB4zzJ9G!SBy$15!?wG#24~Tl@CgFF!rvGVQ{ZCQshX`zRKHCTx27 z)EXr#qtKfad;{)|`!BLT_mO)h* z^w*ym+8#lvW+OR#Wy0a;v*90j$d{Jr2Vo4S;FnonB_5PqOZ$ghRRYC{@P?Cv z{^zGh%STo@pDXz3PmWPs){G~6{f!KFp3DcTRF3(HHlw^?1F9D*FF9-*)e#V|Z)4G` zM=Ob$->#j`IKW=;#s%%dSP~nL1opf!)mxF24(r`r6t$}#b8sjjUOmQ*7Ww!#6clZ8 z?eKMA$=vr8|JUBQ2Saii;t@u$9=gcRPQi?@#hmm)j}E8QBSaU`4Z2`dw_!z*Z(c0M z(Xe6AL`(_CGD_HZTW5AeUe$pe!-V>94_4081}xu@9|`)BI(zyod)6))N_|AD4v3Nr zBttZPqqL*`?H~IbRJX>1G`ryhN0%SC1Pp<`Xv}HiipD-*bLb>=q?Vw#kKX*L;FiC5 z%zu-W>i&SEGY1lKe99A+`8{&0Ib(qj?q(t(#1dEU?CY$#t6y1FT&N*eFJttiQr z$?JE*P3&szVwak`Bx~WTec)^Pk#=?6{#3bTjM;r~hJxAlJObAFBYJD;GiU6!nX-+k z>_@>WWet;O7a4}qv%@qo!JDf;N4D^#ZwBh8$6B_t8xnW@hR@rMmI8q-P#hAae`O*w z=xAZ{i^|?(?~(aHeD}HJlIn$ooUT-^4bx)^&QmGXTnVbsC@wMIA1uL_o}Jme8So4ad@ElAB_jdOzi^CHt8s0+b)dBm zqKlglw*1bXh8OT^7nAI`=h+~eW8O_vXJ!&a1L)mfqDHTkmHtB)=5}bVu!aWVhdWFy zt?8ys{Lj`w*~+7eGazn2Z{+*zGG?H+I*jz}?DxlM{>1N($$g2}AFu}`eB4CM5@eSS zu9V1USYw(~q0>wXYjGgFF>?*nB{vD4mc*~fWQ_qtty7!}r-=sxqW+-m{|!<81K`9t zd((#0+mxx1^{DsKW>_}BcaNV>a%!I8=o>5SmmN*NKyEJ89W+BWH*;9MHXq#>vTx;P z)Ak$ei)e)iKZjg)Mht8Z1qRO?MvSNBEY1m|`-iyK0?}Jah zoS8j83k>7ZlWFVD?f37jp7Pjh>!vtsL{d6~Mx-d;bXDQ$6)kI%`*P;ePIPhM9(<;$p&P1?2OJ zC0ej``8+9?dr`$=nJrgTDjLiTRtyx4fSjRaprJ!qAQcko*jK{}%$q@b#vtCgmS@&1 z6!8oSCQWJ*wQYEUf%1qk;9WAk$05PNB>I1CHgJ05%W}#jqHoCdTja^a+|QwT@6(gO zP*4bPZF!sEB^}P@IE-zgykU+SBjNl1;5_j)q4HHLGFRGDQTbc1y2v8aFNL%HEvu!v zhmsP@!%%}qgtA+q+o@jTJKf36ph{Mi(Gi2J<0(R$F?Z|hyas&YXu{hKA4V$@?Q5qU zE9{91bzGIw-|6OU%*t+chX=5TO?|o|YvwR_qdBI0yxOxBBhzxk6Sy;N`fLu#d==Kn zBZIpYR(E)`Jv6`Bf4U^Rc}fV6w=Ao;Sa+1Qvk)ZBUih*)Y2U52wuoai!LvCgc@#2@ z&i9L*F5|ox$tRzpWl3LYWai#A{A5g~ML;SSUS<7BOm_GILsbgZT?vP%WpuRUL`jr@ zZF<=?`Ri=+Ea4#h%Sg)uY!!HMlipNJ4MJhTd*sQrqtRoC>-|(#|r9JU-x3g z*pt^dhBphor-Y56<k!x3;*&%mMYE>qR15C*p@lx@cNKzkj3UOf1HttiYhN~E&Ziai|G`BQab{^ zOKy#kj623XOSNO&M7aarG5ltKsfhqH7vP$cP5lC2zU!+Vi7V|?!HZ@eqP7o$Ggk?{ zonnD7?2>QYTdw7L2kBM7^+|rxN_I$)`UqeJWSz{@SLz`|_Comj1Bi3;y;<+(f>_0> zo`2lmIlT*o$XvkC(miBG0&%yxevm7wRT0*q(hv)wPVHFYUi~VrgQ7TN(+o67i-^To_6&W z2?_q7?QzM6h^I66zSuKaT2sU{*7IwT3)2K{wS?!_18B~%Y*+)m1^@AG1rv$HUQH3| z0YHg(hp>QbK@Kctw+>)R^;>L0T}sa;1wLWTS!1PpUV!(_nU=OYPC+?XZ?<;lQrL7N3>Tfcy^i?%A4{zpS;!L_bm; z^jW!iUZP99H|8PG57CY77GRTPO99~v$JfXg`mL87rXn&Bx?q69e_*UX$o)$}4-8@t zqwcXa<>sTIKnYLH+3@BbrvIU_p-417^q^L#J7Hy6+N$M#03zFqpX7s2qr1?<#rfUI zP;M|Bb(KilaJsXM+(sTJc<|3>KjH=-iF*0kPOSNc%H2O85O+m2rLZh-n7ZYaB!)S9SwuZ=CMD^xTLn_-qqcbrf~vJ>naD zxLdus7RCRLq{OdDit-DO{`4QL?>ZE=Y}~35lHW`Z^5+pWb8CX)O;|6f_znzsNwa;( zGyuuVD0Zf;J}jP8P@u3l8a(bN9$gl;WYC%EQCp(~c9w??44_mzMtI|v`Qr(h=5*H0 z)IRdpV$GyO347zg-Y;TvMY6CJI(HeixnBBbzp4_`FsvNYntrhqwjVjim5MM{P1h=> z@vnzN{N9bwVYgGdZ@&BZ%FWoSv?5@Qkm2f#@aMlUmOx0#(l}CoIH#s|-a^}Qn?wPZ ze<*DLlK!qg{|5PgkNXkl6@clr`)NT@vm_Z(=HS(z))?l?DAyD!DMLYOrs$`+Y8sA? zyBFfZ*?KeYMj6?ZkL*8*Y!p;{Lr3Z-F80VnIKZ@$_BjwWrE|{H2H};zS}|E3q3F5@ z^x3I`XEE;Hh9j(!!4GNv0Y3>(om%Qu!S#2_url)FjKeriCyc|DF}h*d^Jhy*hTl4I zM7!q8ch0{weZo`OU;p~cXf8AU|JeA4jD>1AEyf36(*FnnF4G^g5iJo$vDtVw3(Hup zvSFLNa_OGhF zNaMj46#1t)LA|UnuDkJ9Zjg*o|7LWq`F~=BmUi|OSMwy=i_nTwniMbpqvE}d7{j^n z${{@9XXFTyj=rZ5NcL#%kBlDs_S*V0soVYErU9!$r{OZ+KLkMQLk`|iY)vR}Bb{JQ zZ!Z-shwV+E{DE91AjJDJbi}U2Cf_OLdE~EI%0>N;49{-Z8w6l; zUo0y%N2_y#S|2p0%GI4${3y2Y)q%ZQip|i|(K;uT>5GZ_j`7GPrIHs$_ng8usFIL| z1R2&YrZnCeO~OZ>1@pv*xcqowG6E`RIV-2MK#wwRs1I4MAt-H>{=N|13TFv>%KR_+ zr~{T=+?M!WD!eoQG(F|X7)DuHnN*YYg~hhzKoy#;nLk1?^JpJMN`Q$6{~RCv73+VE zNQ&y;#HXC)qx42crI;^!_WhMB|9XYvG*)Rb zJ&V?rVv70so(R3z=X5=KK>;Z{fDs57b<3_9`Z2iR70-Ajipc<&yUF%U${lW#*@>}s~Gg%%r_kh+X$erAJ^ug|{ zp7d76wQnJ3_n zKsrH}R>2`^(J0qjPw1g9;AX}4RB3ngog`Vj+VW&tE?8qixX>MLjyy92oB+IYYo&|} zElg*9NW2Ox&&n^8C?3p)fB5v^sHE+z@y$mszoHcTu*-!QE}xrnk0xgG;lUCNdZdAY zIgK?YvKdR8RFRGTa$fIq9!XMM2mF>49AOiCAlo z3xX<1nJp%HT~r(dm2}6SOHrPB^1Mhj?v6`TZ|%VJX2@1(SJ3fcPyPeNU34R#x0~;m z=)xK(+&N0V)dN8sfA^fR=JC*5wi>9tpbwGZEKox4bJUWWt|X0t1rD&l_}h7vRp{H3 zhN4c<2Z&drMhl&NOE*t2G(m?yua!=DX$n*nb2K^^Sy6>}-Oij@XoV?EqU zfobVVGW2>KtTO5YrzOG--14)J6C^@!a`W zR%T_2&?`dJZoG;&h#dlMTqsB7mcz~BU+~9}ZsWdyN=1@Mwm-v}=YKyxM8bEa9d@=-)8^hl{ z%kf9v|DEA~7rsWB*)+Y@^;;2^0k}FS*@ne`E_mqE-;!?3KxHxp@WlrFCZM%CD>U@< z=Lkv9O}qntdE(TDvI8(T##!|xtTvvE2uNw}$4-VFZjW=)>g_MJ?~1ia?p?8LFcVmK zkFvcU8?5%ra{~3A@~Fa!R&C419#Sx zDOFpk)8LD~M^pYsIOa*J`#G`OH1UmTVEGiVyu%HG9E-n?|IzzLVer)*#hmE^uFZgc z>-#lO$Jqz&B6}q@LCRw_pgP@ z6tZ-2+XzOOmqq~<85`He^Y-8L3b*&ug?KSSZt!z0r7OEIb(G`Oi#$*29hGHRYN5xv zKbp!oUq~;uF@xOX0>SKMSrZcTX7Z8h!L3H7(|n0Ff(W(ceB0|PCM?7pU&ew!Vgbs> zIoEz$RDE#-s`)Gs{`lP-A;S{fezR0_bK$g&*~8{>UGA@}GS>yeAOE`-56DB@cABjH z%E>k09rWG+V?y<@IE?Lq8?x7Q(2B?hEU(Lcq_Cn$8<|3}yuF5-o9kMslg5|+DCa9& z_2YTT$QRImE#^h7BDb7Q zWT{_Nj0@kgKf(-f_@;HOS7T#`vRs7UVoA7@1}NlV&<+zwdnDCqH0aN zzkF(eC%Z$FF)CUn4SplKM?T&G-&y&=xj-VraJB|%nLSc==PtrvDL(5$>Z?gkBX@}< zgSersOq!2xd>5rdo$jv6p5BXx5ZS>-?WiH+K%(??$k6U~8gMTyRq|{*2+B&DxcYEe-OL6Ek&(c( zG8^qx2gN2oA)B?K^r{K4Siu9VF)CADS0)(7+>hy9ex8lrb?;dt(7%TZq94#tpyfQw zsDR~6M}sp@qULR;7dYQbGL9#%i`9W31qIER_SNr|!5RVgp( zL_C|Dd|<7--pPZueet7m0?pyL-|fO+NTb+}&z^0h+8Nttw4kq&CP{DEiop&aH6o&@ z=wrp$gA>459h2-c%eBz^vw>o0JVmg?-ny${7Yu|Cf9&~wm+M1iW2J`d+6dJ}X*^a; zv!hY1yIB3LT3R|uV`bQI5lEF74SKAI|Z8l`0+pqxE9p*2C_EbZqL*$fzyX-50-r`njWAD6qd(va-nD=jQf=j&eTZ!#Vl}0lWB&b&p~2XzZ>C309=y#n^K6$g z59RI11KBt^3!XI_Ow%8Hjex8*2m8s8c)pEw+Y@^=s9$SrXl1QwqmFkPj3HiZs@u}} z-m{F#0mEQUiG_4t#W08c5I)j|(2!5U^kR}2@wy0>5<0AcLY~mJud^#{Pt#r{EgvuG z3_&i@1ZfB$oyC$sTOFJ((Y9dA5~i@c$W)ODAGr{trz`Rq;+cS=)oW$7Nzeh7uZ||D zP>lMo)cW2v%GB(sn{p-P-{`%8Yn>T;)8e5jw72 zx=N7K_F(+#Pki0iARSp9a3GyEo+9ELC8bl&mQ}K3h(f$?U_d}_I12*3nG_p32GrSb zmxrW+FYs=zCS6#2>b^kWcB0N~kHIK;$Y-~eF1w<2uJ1H!<7j{b6+X@dk?&>k+GU_dE)Xu6JGtw6g~$H{P9Yp4OP8>TR#~=R`Sn!((zLXeYZ0^ zLh4!zHcD4EC6}wJ>eN=y(>9U>7!y!*^}IN%Ls6608&RymR9HaNftwvbpD+ zUwHcI`ZzyFaVF^=FSPi)U_K&veMLDg#TwHUtmivvr|m3E`Z&Pi*S7$1j>Gv@X1wD@ zDa}>1%A^1luz!~g%e2K(iDYrQ7E4LP9qx^&Cn3L^YcmI&q|p?-Q=OE(i=b{`Tdv33#8eA~*=@HUe? z>Xv9dTmtW^AChpFr`XS)hi8e@jkK;>?aFFriBhsiay<_q+N5$YUM1okZ}&SZ*D~Gj zp>w=h1Kp-3zP(h?PC<8$F@U(lY;DmzBN>?!DVdrx)xG(?Z70%q7l1n&`nOSPb`k#tUX`P1 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/design-1.3.txt b/typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/design-1.3.txt new file mode 100644 index 0000000..0daea8c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/design-1.3.txt @@ -0,0 +1,578 @@ +eZ component: ConsoleTools, Design, 1.3 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:Author: Tobias Schlitt +:Revision: $Rev$ +:Date: $Date$ +:Status: Draft + +.. contents:: + +===== +Scope +===== + +The scope of this document is to describe the enhancements of the ConsoleTools +component for version 1.3 of the component. The following features are part of +this design document: + +- Basic dialog system to interact with a user through STDIN. +- Enhanced handling of arguments (including help output). + +This document describes a new range of classes, which will be added to +ConsoleTools, to fulfill this needs. + +============= +Dialog system +============= + +Design overview +=============== + +The following section gives a brief introduction of the concept of a simple +dialog system that enables the developer of a console based application to +interact with the user through STDIN. + +Clarification of terms +---------------------- + +User +^^^^ + +The "user" is the person using a program and interacting with it during +runtime. The user has no knowledge about the internals and must be guided +through the dialog system he is interacting with. The term "user" in case of +this document is _not_ the developer using the described component, but the +user who interacts with the final program. + +Developer +^^^^^^^^^ + +In contrast to the "user", the term "developer" in this document refers to the +person who creates a program, using the described component. + +Dialog +^^^^^^ + +The basic idea of a new mechanism to interact with the user through STDIN in +this document is called a "dialog". A dialog is presented to the user by a +certain amount of output it generates and a certain amount of input it +requests afterwards. + +Basic design +------------ + +The core of the new feature described in this document is a dialog. The dialog +is an object, must have the following capabilities: + +- Presents itself to the user on the command line +- Requests data from the user through STDIN. +- Validate the result for its purpose. +- Return the result to the developer. + +A dialog is usually used in a loop, which displays the dialog over and over again +until it received a valid result. + +Class design +============ + +The following classes will realize the idea of dialogs in ConsoleTools. + +ezcConsoleDialog +---------------- + +This interface describes the external API, which is commonly used by developers +and other classes to interact with a dialog object. Each dialog class must +implement this interface. + +__construct( ezcConsoleOutput $output, ezcConsoleDialogOptions $options ) + The constructor of a dialog receives an instance of ezcConsoleOutput, which + it must use for presenting its output, when requested. In addition, it can + receive an option object, which must be an instance or subclass instance of + ezcConsoleDialogOptions. +hasValidResult() + This method must return a boolean value, which indicates, if the dialog + already received a result from the user, which is valid in its context. +getResult() + After the hasValidResult() method returned true, this method will return the + value received from the dialog. +display() + Using this method, the developer can instruct the dialog object to display + itself to the user. The dialog must use the instance of eczConsoleOutput it + received in the constructor for displaying. +reset() + This method resets the dialog internally to the state it had directly after + construction, so that it can be reused by the developer. + +In addition to this interface, an implementation of ezcConsoleDialog can +contain a set of static factory methods, which return a dialog in a +pre-configured state (for example a standard yes/no question, where only the +text needs to be set). + +ezcConsoleDialogOptions +----------------------- + +This is the base option class, which must be accepted by a dialog. It contains +options, which must be valid for each dialog class. A dialog class may request, +that the options it receives are instances of a subclass, if it expects +additional options. Each of the options defined in ezcConsoleDialogOptions must +also be available in this subclass. Every option defined must have a sensible +default value, so that there is no need for the developer to change it. + +The base option class provides the following options: + +format + The name of the format this dialog uses to be displayed. The format + identifier must be defined in the ezcConsoleOutput instance submitted to the + constructor of the dialog. +validator + An instance of ezcConsoleDialogValidator. This validator is responsible for + validation and manipulation of the result a dialog received from the user. An + implementation of ezcConsoleDialog may require a specific sub-class of + ezcConsoleDialogValidator here (e.g. for a menu dialog, which requires a + special validator object to work). + +ezcConsoleDialogViewer +---------------------- + +The ezcConsoleDialogViewer class provides a set of static convenience methods +that can be used by a developer that works with dialogs and by a developer that +creates new dialogs. These methods are: + +displayDialog( ezcConsoleDialog $dialog ) [static] + This method is recommended to be used for displaying dialogs. It performs the + typical loop: Display the dialog over and over again until it received a + valid result. When this state is reached, it returns the dialogs value. +readLine( $trim = true ) [static] + The readLine() method is commonly used in a dialog implementation to read a + line from standard in. It returns the input provided by a user, optionally + trimmed of leading and trailing white spaces. + +ezcConsoleDialogValidator +------------------------- + +The ezcConsoleValidator interface provides signatures for methods that can be used +by a dialog to validate the result it retrieved. The validator is configured by +the user and submitted to the dialog via an option (if a dialog supports this +mechanism). + +__construct( ... ) + The signature of the constructor is left to the validator implementation to + retrieve settings (e.g. the valid results). +validate( mixed $result ) + This method is responsible for validating a given result. The dialog will + submit the result it received to this method which will indicate if the + result was valid by a boolean value. To manipulate / fix a retrieved result, + the dialog implementation can call the fixup() method. +fixup( mixed $result ) + A validator can try to fix a given result to be valid. This manipulation can + be omitted by simply returning the result again. An example for a fixup would + be to convert a date information into a Unix timestamp using strtotime(). The + validate method would then expect an integer value > 0. The dialog + implementation is responsible for calling fixup() as it thinks is appropriate + (e.g. always before calling validate(), only if validate() fails, never). + +Dialog implementations +====================== + +The new feature set comes with a collection of basic dialog implementations, +which will be described in this section. + +ezcConsoleQuestionDialog +------------------------ + +The ezcConsoleQuestionDialog is the most basic imaginable dialog. It asks the +user a simply question and expects a certain answer. A typical output from an +ezcConsoleQuestionDialog object could look like this: :: + + Do you want to continue? (y/n) + +This dialog implementation provides a set of rudimentary options, which can be +used to customize its appearance and enhance its capabilities. For this +purpose, it comes with a custom options class ezcConsoleQuestionDialogOptions, +that accepts the following options in addition to those provided by +ezcConsoleDialogOptions: + +text + This option defines the main "question" text, displayed to the user. +validator + The validator is an instance of ezcConsoleQuestionDialogValidator. For + implementation details, see further below. +showResults + If this boolean option is set to true, the dialog will display the possible + result values behind the question text itself (retrieved from the validator). + If a default value is provided, it will also indicate, which one this is. For + example: :: + + Do you want to continue? (y/n) [y] + + While here "y" and "n" are valid results and "y" is the default result, which + is selected when simply skipping this question by hitting just . + +ezcConsoleQuestionDialogValidator +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The interface if ezcConsoleQuestionValidator inherits from +ezcConsoleDialogValidator and adds the following methods: + +getResultString() + This method returns the result string to be displayed if the option + "showResults" is true in the ezcConsoleQuestionDialogOptions object. + +Concrete implementations of these interface are: + +ezcConsoleQuestionDialogTypeValidator + This validator checks the result to be of a given type (e.g. int, float). It + optionally checks if the result is in a given range (e.g. [0-100]). +ezcConsoleQuestionDialogCollectionValidator + This validator checks the result against a given collection of pre-defined + values (e.g. "y" and "n"). Beside that, it can perform basic operations on + the result before checking it (like strtolower()). +ezcConsoleQuestionDialogRegexValidator + This validator checks the result against a given regex (e.g. + "/([0-2]?[0-9])[:.]([0-6]?[0-9])/" for validation of a time value). In addition + it can perform a manipulation using this regex with a given (e.g. "\1:\2" to + unify the time value given). + +ezcConsoleMenuDialog +-------------------- + +The second dialog implementation shipped with ConsoleTools is the menu dialog, +which is an enhanced version of the question dialog. The menu dialog will +display an ordered set of options and let the user select one of these. A +typical menu can look like this: :: + + You can choose one of the following actions. + + 1) Create something new + 2) Edit something + 3) Delete something + 4) Do something else + + Please choose an action: + +The menu dialog also comes with its own set of options, the +ezcConsoleMenuDialogOptions: + +text + The text displayed before the menu. +selectionText + The text displayed after the menu to indicate to the user that he should make + a selection. +markerChar + The marker character used to divide the marker of a menu entry (e.g. the + number) from the menu value (the text of a menu entry). +validator + The validator must be an instance of ezcConsoleMenuDialogValidator. + +ezcConsoleMenuDialogValidator +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In contrast to ezcConsoleQuestionDialogValidator, this is not an interface, but +a concrete implementation of ezcConsoleDialogValidator. The menu validator +offers 2 properties to determine the menu entries: + +$entries + An array of entries shown as the menu. The keys of this array represent the + markers of the menu entries, the values represent the text shown. + +In addition, the validator can be configured to perform a manipulation on the +result like the ezcConsoleQuestionDialogCollectionValidator (e.g. +strtolower()). + +============================== +Enhanced handling of arguments +============================== + +Design overview +=============== + +The current functionality for handling options and arguments for a console +based application in eZ Components (mainly the class ezcConsoleInput) has only +rudimentary support for dealing with arguments. The current possibility is to +either switch arguments on or off and does not allow to specify the following +things: + +- How many arguments are possible +- Which arguments are mandatory/optional +- Names and types for the arguments. + +The goal of this design section is to provide these 3 features for argument +handling. + +Clarification of terms +---------------------- + +Parameter +^^^^^^^^^ + +The term parameter is a generic term, which covers options and arguments +together. + +Option +^^^^^^ + +An option for a console based application is specified using a short or a long +name and can (optionally) carry a value of a given type. Short names are built +using "-" syntax, long names use "--". Options are already handled +by the ezcConsoleInput class, using objects of ezcConsoleOption. + +Example: :: + + foo.php --save "bar.txt" -a + +"--save" is a long name and the parameter carries a string value "bar.txt". +"-a" is a short name of an option, while this option does not carry any value. + +Argument +^^^^^^^^ + +In contrast to an option, an argument is not specified using a specific name, but +by by the order of submission to the program. Arguments can only be given to a +program, after all options have been specified. + +Example: :: + + foo.php --save "bar.txt" -a -- "baz" 23 + +"baz" is the value of the first argument, 23 the value of the second one. + +Arguments separator +^^^^^^^^^^^^^^^^^^^ + +In some cases the semantic for specifying parameters on the console is not +deterministic. Since the algorithm used to parse parameters cannot handle +nondeterministic semantics, a separator must be used to determine the border +between options and arguments. The separator used is "-- ", which indicates +that anything following it is an argument and does not belong to the option +before it. The seperator is not mandatory and must only be used in cases where +the parsing would not be deterministic. + +Example: :: + + foo.php --save "bar.txt" -a "baz" 23 + foo.php --save "bar.txt" -a -- "baz" 23 + +In the first line, it is not possible to determine if "baz" is the value for +the parameter "-a" or if it is an argument. The second line clarifies this. + +Basic design +------------ + +The core of the new functionality is built upon 2 classes: + +- ezcConsoleArguments +- ezcConsoleArgument + +The first one is a collection class, which takes care of holding all arguments. +The second one is a struct class, which handles 1 specific argument. + +Class design +============ + +ezcConsoleArgument +------------------ + +This struct class represents a single argument and defines the following +properties: + +name + A descriptive name for the argument. This name is used for 2 purposes: + - Displaying it in the help text generated by ezcConsoleInput. + - Identifying and retrieving the object from the argument collection. + This property is mandatory and may not be left out. +type + The data type of the argument. The type is used for validation purposes when + the parameter string of the console application is parsed and is indicated to + the user in the help text generated by ezcConsoleInput. The default for this + property will be ezcConsoleInput::TYPE_STRING. ezcConsoleInput::TYPE_NONE + will not be allowed. +shorthelp + A short help text, which is used by ezcConsoleInput when generating a short + help output. A sensible default will be set for this property. +longhelp + A long help text, which is used by ezcConsoleInput when generating a long + help output. A sensible default will be set for this property. +mandatory + This boolean flag specifies if an argument is mandatory or optional. Since + ezcConsoleArguments is an ordered collection, all arguments following an + optional argument will be handled as optional, too. The default value for + this property is true. +default + This property carries the default value for optional arguments. If these are + not submitted, the default value will be used as the value property. If no + default value was explicitly defined, it is null and therefore the value + property will be null, if the argument was not submitted. +multiple + This booloan property determines, if an argument can carry multiple values. + The default here is false. If this is set to true, no more arguments may + follow the current argument, since multiple defines the number of values to + be undefined. If arguments would follow, the parameter string would be + non-deterministic. Therefore all following arguments are silently ignored. + For arguments with this property true, the returned value is an array. The + default value may be an array, too. +value + This property is not meant to be set by the developer directly, but by + ezcConsoleInput while parsing the parameter string of the application. It + will contain the value submitted for the argument after parsing. If this + argument was not submitted, the value of the default property will be set + here. + +ezcConsoleArguments +------------------- + +This collection class carries the arguments for an application. It keeps track +of the order of the ezcConsoleArgument objects and offers 2 access methods for +them: + +- By their order (using numeric identification) +- By their name + +For these purpose, the ArrayAccess and Iterator interfaces provided by PHP will +be implemented in this class. ArrayAccess will be used for both variants of +access, while Iterator will iterate of the numeric order of the arguments. +Argument names must be unique. The registration of new arguments is only +allowed by number. The retrival is also allowed by name. + +The class does not offer any additional methods to deal with arguments and +purely relies on the given interfaces. + +Integration aspects +=================== + +The current design of ezcConsoleInput is not designed to handle arguments in +the planned way. Therefore its API must be changed slightly. Naturally this +will be done maintaining BC. The following changes are planned: + +Property $argumentDefinition +---------------------------- + +Since ezcConsoleInput already has a property $arguments, which carries the +values of submitted arguments in an array, a new property will be introduced to +carry the instance of ezcConsoleArguments. By default, this property will be +null, which indicates, that the old manor of handling arguments is used. + +If ezcConsoleArguments is used, the preferred way of retrieving argument values +is, to use the ezcConsoleArgument struct of the specific argument. The +$arguments property of ezcConsoleInput will still be set and contain the values +of the provided arguments. + +Switching arguments on/off +-------------------------- + +The ezcConsoleOption class allows to switch arguments on or off for a console +call to the application using its property $arguments. This behaviour will not +be changed. If an option defines that arguments are not allowed, if it is +submitted, all defined arguments will not be allowed. + +It is possible, that this behaviour will be enhanced in the future, so that +options can define a filter rule for arguments instead of a boolean on/off +switch. But this feature is not in scope of the design given here. + +Usage example +============= + +The following example shows the basic of the newly created API. + +Using arguments +--------------- + +:: + + $input = new ezcConsoleInput(); + $input->argumentDefinition = new ezcConsoleArguments(); + + // First argument + $input->argumentDefinition[] = new ezcConsoleArgument( + "infile", + ezcConsoleInput::TYPE_STRING, + "The file to read from.", + "The input file, from which the content to process is read.", + ); + + // Second argument + $input->argumentDefinition[1] = new ezcConsoleArgument( + "outfile" + ); + $input->argumentDefinition[1]->shorthelp = "Output file."; + $input->argumentDefinition[1]->longhelp = "File to output generated + content to. Output will be printed to STDOUT if left out."; + $input->argumentDefinition[1]->mandatory = false; + $input->argumentDefinition[1]->default = "php://output; + + try + { + $input->process(); + } + catch ( ezcConsoleMissingArgumentException $e ) + { + // Only the first argument will possibly trigger this + die( "Argument {$e->argument->name} missing!" ); + } + + // The first argument is always present if no exception occured + $inFile = fopen( $input->argumentDefinition["infile"]->value, "r" ); + // The second one is optional, but has a default + $outFile = fopen( $input->argumentDefinition["infile"]->value, "w" ); + +Generating help +--------------- + +:: + + $input = new ezcConsoleInput(); + $input->argumentDefinition = new ezcConsoleArguments(); + + // First argument + $input->argumentDefinition[] = new ezcConsoleArgument( + "file", + ezcConsoleInput::TYPE_STRING, + "Output file.", + "File to output generated + ); + + // Second argument + $input->argumentDefinition[] = new ezcConsoleArgument( + "bytes", + ezcConsoleInput::TYPE_INT, + "Bytes to write.", + "The number of bytes written to the output file. If left out, + everything will be written.", + false, + -1 + ); + + echo $input->getHelpiText( "Some example program." ); + +Generates: :: + + Usage: test.php [--] [] + Some example program + + Arguments: + Output file. + = -1 Bytes to write. + +Open issues +=========== + +- The access of arguments by number and name is comfortable, but (as described + above) not reliable, if 2 parameters have the same name. It also makes + implementation more complex (if a parameter is removed, namesake has to come + in place. So, do we want this or not? +- The property name $argumentsDefinition is OK for the definition part, but + does actually not make sense, if you access it later to retrieve the value. + Any better naming solution? +- It is sometimes sensible to allow that for 1 argument multiple values are + submitted (e.g. if you expect an undefined number of file names). To resolve + this, we need to invent a property "multiple" for the ezcConsoleArgument + struct. If multiple is defined for 1 argument, no more arguments must follow, + since the algorithm could not determine easily where the multiple values for + the argument end. Do we need this functionality (now)? + + +.. + Local Variables: + mode: rst + fill-column: 79 + End: + vim: et syn=rst tw=79 diff --git a/typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/design.txt b/typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/design.txt new file mode 100644 index 0000000..3a725e0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/data/ConsoleTools/design/design.txt @@ -0,0 +1,114 @@ +eZ publish Enterprise Component: ConsoleTools, Requirements +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Introduction +============ + +Purpose of the ConsoleTools package +----------------------------------- + +The ConsoleTools package will contain several classes to support comfortable +development of console based applications. These classes shall be designed as +independant as possible from each other to let the user flexibly choose, which +ones he likes to use and which not. + +Aimed features are: + +- Comfortable handling of options and parameters (long, short, values,...) +- Formatting assistance for console output (placing, colors,...) +- Convenience functionality to deal with Windoze and Unix based systems + +Current implementation +---------------------- + +Included classes +^^^^^^^^^^^^^^^^ + +2 classes are directly involved in the CLI handling. + +eZScript + General initiallization and shutdown script functionality. Very eZ + publish specific. Handles initialization of database connection for + example, but also some CLI related actions like shutting down every + thing cleanly and returning an exit code. + +eZCLI + Handles general console output, formating and option parsing. + +External classes +^^^^^^^^^^^^^^^^ + +Beside that, there are dependencies to log/debug/whatever and the following +ones. + +eZTextCodec + Base clase for drivers that convert text between different output formats. + Currently has 1 extending class: eZCodePageCodec. Part of the I18N + package. + +General involved classes: +eZPublishSDK, eZDebug, eZINI, eZDebugSetting, eZExecution, +eZExtension, eZDB, eZSession, eZUser, eZModule + +General notes +------------- + +The functionality for console handling seems to be widly spread over the +current eZ publish classes. Beside that, it is not quite feature complete and +mixed around with web handling classes. + +Requirenments +============= + +Design goals +------------ + +The command line handling classes should be redesigned completly, since it's +currently messed up with web related stuff and fully integrated with eZ +publish. + +Following functionality will be included: + +- General in and output handling functionality + +- Output strings + + - Style output (color, underline?, ...) + - Position change + - Error/notice/warning support + +- Handling of options + + - Long / short options + - Dealing with help output + - Optional and required stuff + - Dependencies and exclusion of options + +- Handling of advanced output + + - Progress bars (single, keep multiple in mind) + - Tables + +All parts should be as independant as possible. Some parts depend quite hardly +on the output itself, this is ok. Option parsing and handling should _not_ +depend on the output class. + +Design +====== + +The design for this package has been splitted into 3 categories of classes: + +Output + This type of classes provide low level output functionality for console + based applications (like styling text, line breaking,...). +Generation + This type of classes provide more advanced outputing features (like + generating structures of text automatically, providing advances + tools,...). This type of classes depends on the Output classes described + above, since they output data. +Handling + This type of classes is independant of both above shown categories and + provides features for handling common functions in console based + applications. Since they do not have to output directly, there is no need + to depend on output functionality. + diff --git a/typo3conf/ext/phpunit/PEAR/data/PEAR/package.dtd b/typo3conf/ext/phpunit/PEAR/data/PEAR/package.dtd new file mode 100644 index 0000000..5b471b7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/data/PEAR/package.dtd @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/typo3conf/ext/phpunit/PEAR/data/PEAR/template.spec b/typo3conf/ext/phpunit/PEAR/data/PEAR/template.spec new file mode 100644 index 0000000..37b477f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/data/PEAR/template.spec @@ -0,0 +1,72 @@ +Summary: PEAR: @summary@ +Name: @rpm_package@ +Version: @version@ +Release: 1 +License: @release_license@ +Group: Development/Libraries +Source: http://@master_server@/get/@package@-%{version}.tgz +BuildRoot: %{_tmppath}/%{name}-root +URL: http://@master_server@/package/@package@ +Prefix: %{_prefix} +BuildArchitectures: @arch@ +@extra_headers@ + +%description +@description@ + +%prep +rm -rf %{buildroot}/* +%setup -c -T +# XXX Source files location is missing here in pear cmd +pear -v -c %{buildroot}/pearrc \ + -d php_dir=%{_libdir}/php/pear \ + -d doc_dir=/docs \ + -d bin_dir=%{_bindir} \ + -d data_dir=%{_libdir}/php/pear/data \ + -d test_dir=%{_libdir}/php/pear/tests \ + -d ext_dir=%{_libdir} \@extra_config@ + -s + +%build +echo BuildRoot=%{buildroot} + +%postun +# if refcount = 0 then package has been removed (not upgraded) +if [ "$1" -eq "0" ]; then + pear uninstall --nodeps -r @possible_channel@@package@ + rm @rpm_xml_dir@/@package@.xml +fi + + +%post +# if refcount = 2 then package has been upgraded +if [ "$1" -ge "2" ]; then + pear upgrade --nodeps -r @rpm_xml_dir@/@package@.xml +else + pear install --nodeps -r @rpm_xml_dir@/@package@.xml +fi + +%install +pear -c %{buildroot}/pearrc install --nodeps -R %{buildroot} \ + $RPM_SOURCE_DIR/@package@-%{version}.tgz +rm %{buildroot}/pearrc +rm %{buildroot}/%{_libdir}/php/pear/.filemap +rm %{buildroot}/%{_libdir}/php/pear/.lock +rm -rf %{buildroot}/%{_libdir}/php/pear/.registry +if [ "@doc_files@" != "" ]; then + mv %{buildroot}/docs/@package@/* . + rm -rf %{buildroot}/docs +fi +mkdir -p %{buildroot}@rpm_xml_dir@ +tar -xzf $RPM_SOURCE_DIR/@package@-%{version}.tgz package@package2xml@.xml +cp -p package@package2xml@.xml %{buildroot}@rpm_xml_dir@/@package@.xml + +#rm -rf %{buildroot}/* +#pear -q install -R %{buildroot} -n package@package2xml@.xml +#mkdir -p %{buildroot}@rpm_xml_dir@ +#cp -p package@package2xml@.xml %{buildroot}@rpm_xml_dir@/@package@.xml + +%files + %defattr(-,root,root) + %doc @doc_files@ + / diff --git a/typo3conf/ext/phpunit/PEAR/data/Structures_Graph/LICENSE b/typo3conf/ext/phpunit/PEAR/data/Structures_Graph/LICENSE new file mode 100644 index 0000000..b1e3f5a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/data/Structures_Graph/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/typo3conf/ext/phpunit/PEAR/data/XML_RPC2/Makefile b/typo3conf/ext/phpunit/PEAR/data/XML_RPC2/Makefile new file mode 100644 index 0000000..571d126 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/data/XML_RPC2/Makefile @@ -0,0 +1,15 @@ +run-tests: + make -C tests run-tests + + +phpdoc: + monotone log > CHANGELOG + make -C docs phpdoc + cp CHANGELOG XML + phpdoc --directory XML,docs/tutorials --examplesdir docs/examples --target docs/phpdoc --title "XML_RPC2 Documentation" --parseprivate --defaultpackagename XML_RPC2 --pear -ric --output HTML:Smarty:PHP + rm -f XML/CHANGELOG + +clean: + make -C tests clean + rm -Rf docs/phpdoc + rm -f CHANGELOG diff --git a/typo3conf/ext/phpunit/PEAR/data/vfsStream/LICENSE b/typo3conf/ext/phpunit/PEAR/data/vfsStream/LICENSE new file mode 100644 index 0000000..f20bcda --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/data/vfsStream/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2007-2010, Frank Kleine +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of Stubbles nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/data/vfsStream/VERSION b/typo3conf/ext/phpunit/PEAR/data/vfsStream/VERSION new file mode 100644 index 0000000..6d44daf --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/data/vfsStream/VERSION @@ -0,0 +1 @@ +vfsStream version 0.8.0 \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Archive_Tar/docs/Archive_Tar.txt b/typo3conf/ext/phpunit/PEAR/docs/Archive_Tar/docs/Archive_Tar.txt new file mode 100644 index 0000000..623cafe --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Archive_Tar/docs/Archive_Tar.txt @@ -0,0 +1,461 @@ +Documentation for class Archive_Tar +=================================== +Last update : 2001-08-15 + + + +Overview : +---------- + + The Archive_Tar class helps in creating and managing GNU TAR format + files compressed by GNU ZIP or not. + The class offers basic functions like creating an archive, adding + files in the archive, extracting files from the archive and listing + the archive content. + It also provide advanced functions that allow the adding and + extraction of files with path manipulation. + + +Sample : +-------- + + // ----- Creating the object (uncompressed archive) + $tar_object = new Archive_Tar("tarname.tar"); + $tar_object->setErrorHandling(PEAR_ERROR_PRINT); + + // ----- Creating the archive + $v_list[0]="file.txt"; + $v_list[1]="data/"; + $v_list[2]="file.log"; + $tar_object->create($v_list); + + // ----- Adding files + $v_list[0]="dev/file.txt"; + $v_list[1]="dev/data/"; + $v_list[2]="log/file.log"; + $tar_object->add($v_list); + + // ----- Adding more files + $tar_object->add("release/newfile.log release/readme.txt"); + + // ----- Listing the content + if (($v_list = $tar_object->listContent()) != 0) + for ($i=0; $i"; + echo " .size :'".$v_list[$i][size]."'
    "; + echo " .mtime :'".$v_list[$i][mtime]."' (".date("l dS of F Y h:i:s A", $v_list[$i][mtime]).")
    "; + echo " .mode :'".$v_list[$i][mode]."'
    "; + echo " .uid :'".$v_list[$i][uid]."'
    "; + echo " .gid :'".$v_list[$i][gid]."'
    "; + echo " .typeflag :'".$v_list[$i][typeflag]."'
    "; + } + + // ----- Extracting the archive in directory "install" + $tar_object->extract("install"); + + +Public arguments : +------------------ + +None + + +Public Methods : +---------------- + +Method : Archive_Tar($p_tarname, $compress = null) +Description : + Archive_Tar Class constructor. This flavour of the constructor only + declare a new Archive_Tar object, identifying it by the name of the + tar file. + If the compress argument is set the tar will be read or created as a + gzip or bz2 compressed TAR file. +Arguments : + $p_tarname : A valid filename for the tar archive file. + $p_compress : can be null, 'gz' or 'bz2'. For + compatibility reason it can also be true. This + parameter indicates if gzip or bz2 compression + is required. +Return value : + The Archive_Tar object. +Sample : + $tar_object = new Archive_Tar("tarname.tar"); + $tar_object_compressed = new Archive_Tar("tarname.tgz", true); +How it works : + Initialize the object. + +Method : create($p_filelist) +Description : + This method creates the archive file and add the files / directories + that are listed in $p_filelist. + If the file already exists and is writable, it is replaced by the + new tar. It is a create and not an add. If the file exists and is + read-only or is a directory it is not replaced. The method return + false and a PEAR error text. + The $p_filelist parameter can be an array of string, each string + representing a filename or a directory name with their path if + needed. It can also be a single string with names separated by a + single blank. + See also createModify() method for more details. +Arguments : + $p_filelist : An array of filenames and directory names, or a single + string with names separated by a single blank space. +Return value : + true on success, false on error. +Sample 1 : + $tar_object = new Archive_Tar("tarname.tar"); + $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling + $v_list[0]="file.txt"; + $v_list[1]="data/"; (Optional '/' at the end) + $v_list[2]="file.log"; + $tar_object->create($v_list); +Sample 2 : + $tar_object = new Archive_Tar("tarname.tar"); + $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling + $tar_object->create("file.txt data/ file.log"); +How it works : + Just calling the createModify() method with the right parameters. + +Method : createModify($p_filelist, $p_add_dir, $p_remove_dir = "") +Description : + This method creates the archive file and add the files / directories + that are listed in $p_filelist. + If the file already exists and is writable, it is replaced by the + new tar. It is a create and not an add. If the file exists and is + read-only or is a directory it is not replaced. The method return + false and a PEAR error text. + The $p_filelist parameter can be an array of string, each string + representing a filename or a directory name with their path if + needed. It can also be a single string with names separated by a + single blank. + The path indicated in $p_remove_dir will be removed from the + memorized path of each file / directory listed when this path + exists. By default nothing is removed (empty path "") + The path indicated in $p_add_dir will be added at the beginning of + the memorized path of each file / directory listed. However it can + be set to empty "". The adding of a path is done after the removing + of path. + The path add/remove ability enables the user to prepare an archive + for extraction in a different path than the origin files are. + See also addModify() method for file adding properties. +Arguments : + $p_filelist : An array of filenames and directory names, or a single + string with names separated by a single blank space. + $p_add_dir : A string which contains a path to be added to the + memorized path of each element in the list. + $p_remove_dir : A string which contains a path to be removed from + the memorized path of each element in the list, when + relevant. +Return value : + true on success, false on error. +Sample 1 : + $tar_object = new Archive_Tar("tarname.tar"); + $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling + $v_list[0]="file.txt"; + $v_list[1]="data/"; (Optional '/' at the end) + $v_list[2]="file.log"; + $tar_object->createModify($v_list, "install"); + // files are stored in the archive as : + // install/file.txt + // install/data + // install/data/file1.txt + // install/data/... all the files and sub-dirs of data/ + // install/file.log +Sample 2 : + $tar_object = new Archive_Tar("tarname.tar"); + $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling + $v_list[0]="dev/file.txt"; + $v_list[1]="dev/data/"; (Optional '/' at the end) + $v_list[2]="log/file.log"; + $tar_object->createModify($v_list, "install", "dev"); + // files are stored in the archive as : + // install/file.txt + // install/data + // install/data/file1.txt + // install/data/... all the files and sub-dirs of data/ + // install/log/file.log +How it works : + Open the file in write mode (erasing the existing one if one), + call the _addList() method for adding the files in an empty archive, + add the tar footer (512 bytes block), close the tar file. + + +Method : addModify($p_filelist, $p_add_dir, $p_remove_dir="") +Description : + This method add the files / directories listed in $p_filelist at the + end of the existing archive. If the archive does not yet exists it + is created. + The $p_filelist parameter can be an array of string, each string + representing a filename or a directory name with their path if + needed. It can also be a single string with names separated by a + single blank. + The path indicated in $p_remove_dir will be removed from the + memorized path of each file / directory listed when this path + exists. By default nothing is removed (empty path "") + The path indicated in $p_add_dir will be added at the beginning of + the memorized path of each file / directory listed. However it can + be set to empty "". The adding of a path is done after the removing + of path. + The path add/remove ability enables the user to prepare an archive + for extraction in a different path than the origin files are. + If a file/dir is already in the archive it will only be added at the + end of the archive. There is no update of the existing archived + file/dir. However while extracting the archive, the last file will + replace the first one. This results in a none optimization of the + archive size. + If a file/dir does not exist the file/dir is ignored. However an + error text is send to PEAR error. + If a file/dir is not readable the file/dir is ignored. However an + error text is send to PEAR error. + If the resulting filename/dirname (after the add/remove option or + not) string is greater than 99 char, the file/dir is + ignored. However an error text is send to PEAR error. +Arguments : + $p_filelist : An array of filenames and directory names, or a single + string with names separated by a single blank space. + $p_add_dir : A string which contains a path to be added to the + memorized path of each element in the list. + $p_remove_dir : A string which contains a path to be removed from + the memorized path of each element in the list, when + relevant. +Return value : + true on success, false on error. +Sample 1 : + $tar_object = new Archive_Tar("tarname.tar"); + [...] + $v_list[0]="dev/file.txt"; + $v_list[1]="dev/data/"; (Optional '/' at the end) + $v_list[2]="log/file.log"; + $tar_object->addModify($v_list, "install"); + // files are stored in the archive as : + // install/file.txt + // install/data + // install/data/file1.txt + // install/data/... all the files and sub-dirs of data/ + // install/file.log +Sample 2 : + $tar_object = new Archive_Tar("tarname.tar"); + [...] + $v_list[0]="dev/file.txt"; + $v_list[1]="dev/data/"; (Optional '/' at the end) + $v_list[2]="log/file.log"; + $tar_object->addModify($v_list, "install", "dev"); + // files are stored in the archive as : + // install/file.txt + // install/data + // install/data/file1.txt + // install/data/... all the files and sub-dirs of data/ + // install/log/file.log +How it works : + If the archive does not exists it create it and add the files. + If the archive does exists and is not compressed, it open it, jump + before the last empty 512 bytes block (tar footer) and add the files + at this point. + If the archive does exists and is compressed, a temporary copy file + is created. This temporary file is then 'gzip' read block by block + until the last empty block. The new files are then added in the + compressed file. + The adding of files is done by going through the file/dir list, + adding files per files, in a recursive way through the + directory. Each time a path need to be added/removed it is done + before writing the file header in the archive. + +Method : add($p_filelist) +Description : + This method add the files / directories listed in $p_filelist at the + end of the existing archive. If the archive does not yet exists it + is created. + The $p_filelist parameter can be an array of string, each string + representing a filename or a directory name with their path if + needed. It can also be a single string with names separated by a + single blank. + See addModify() method for details and limitations. +Arguments : + $p_filelist : An array of filenames and directory names, or a single + string with names separated by a single blank space. +Return value : + true on success, false on error. +Sample 1 : + $tar_object = new Archive_Tar("tarname.tar"); + [...] + $v_list[0]="dev/file.txt"; + $v_list[1]="dev/data/"; (Optional '/' at the end) + $v_list[2]="log/file.log"; + $tar_object->add($v_list); +Sample 2 : + $tar_object = new Archive_Tar("tarname.tgz", true); + [...] + $v_list[0]="dev/file.txt"; + $v_list[1]="dev/data/"; (Optional '/' at the end) + $v_list[2]="log/file.log"; + $tar_object->add($v_list); +How it works : + Simply call the addModify() method with the right parameters. + +Method : addString($p_filename, $p_string) +Description : + This method add a single string as a file at the + end of the existing archive. If the archive does not yet exists it + is created. +Arguments : + $p_filename : A string which contains the full filename path + that will be associated with the string. + $p_string : The content of the file added in the archive. +Return value : + true on success, false on error. +Sample 1 : + $v_archive = & new Archive_Tar($p_filename); + $v_archive->setErrorHandling(PEAR_ERROR_PRINT); + $v_result = $v_archive->addString('data/test.txt', 'This is the text of the string'); + + +Method : extract($p_path = "") +Description : + This method extract all the content of the archive in the directory + indicated by $p_path.If $p_path is optional, if not set the archive + is extracted in the current directory. + While extracting a file, if the directory path does not exists it is + created. + See extractModify() for details and limitations. +Arguments : + $p_path : Optional path where the files/dir need to by extracted. +Return value : + true on success, false on error. +Sample : + $tar_object = new Archive_Tar("tarname.tar"); + $tar_object->extract(); +How it works : + Simply call the extractModify() method with appropriate parameters. + +Method : extractModify($p_path, $p_remove_path) +Description : + This method extract all the content of the archive in the directory + indicated by $p_path. When relevant the memorized path of the + files/dir can be modified by removing the $p_remove_path path at the + beginning of the file/dir path. + While extracting a file, if the directory path does not exists it is + created. + While extracting a file, if the file already exists it is replaced + without looking for last modification date. + While extracting a file, if the file already exists and is write + protected, the extraction is aborted. + While extracting a file, if a directory with the same name already + exists, the extraction is aborted. + While extracting a directory, if a file with the same name already + exists, the extraction is aborted. + While extracting a file/directory if the destination directory exist + and is write protected, or does not exist but can not be created, + the extraction is aborted. + If after extraction an extracted file does not show the correct + stored file size, the extraction is aborted. + When the extraction is aborted, a PEAR error text is set and false + is returned. However the result can be a partial extraction that may + need to be manually cleaned. +Arguments : + $p_path : The path of the directory where the files/dir need to by + extracted. + $p_remove_path : Part of the memorized path that can be removed if + present at the beginning of the file/dir path. +Return value : + true on success, false on error. +Sample : + // Imagine tarname.tar with files : + // dev/data/file.txt + // dev/data/log.txt + // readme.txt + $tar_object = new Archive_Tar("tarname.tar"); + $tar_object->extractModify("install", "dev"); + // Files will be extracted there : + // install/data/file.txt + // install/data/log.txt + // install/readme.txt +How it works : + Open the archive and call a more generic function that can extract + only a part of the archive or all the archive. + See extractList() method for more details. + +Method : extractInString($p_filename) +Description : + This method extract from the archive one file identified by $p_filename. + The return value is a string with the file content, or NULL on error. +Arguments : + $p_filename : The path of the file to extract in a string. +Return value : + a string with the file content or NULL. +Sample : + // Imagine tarname.tar with files : + // dev/data/file.txt + // dev/data/log.txt + // dev/readme.txt + $v_archive = & new Archive_Tar('tarname.tar'); + $v_archive->setErrorHandling(PEAR_ERROR_PRINT); + $v_string = $v_archive->extractInString('dev/readme.txt'); + echo $v_string; + +Method : listContent() +Description : + This method returns an array of arrays that describe each + file/directory present in the archive. + The array is not sorted, so it show the position of the file in the + archive. + The file informations are : + $file[filename] : Name and path of the file/dir. + $file[mode] : File permissions (result of fileperms()) + $file[uid] : user id + $file[gid] : group id + $file[size] : filesize + $file[mtime] : Last modification time (result of filemtime()) + $file[typeflag] : "" for file, "5" for directory +Arguments : +Return value : + An array of arrays or 0 on error. +Sample : + $tar_object = new Archive_Tar("tarname.tar"); + if (($v_list = $tar_object->listContent()) != 0) + for ($i=0; $i"; + echo " .size :'".$v_list[$i][size]."'
    "; + echo " .mtime :'".$v_list[$i][mtime]."' (". + date("l dS of F Y h:i:s A", $v_list[$i][mtime]).")
    "; + echo " .mode :'".$v_list[$i][mode]."'
    "; + echo " .uid :'".$v_list[$i][uid]."'
    "; + echo " .gid :'".$v_list[$i][gid]."'
    "; + echo " .typeflag :'".$v_list[$i][typeflag]."'
    "; + } +How it works : + Call the same function as an extract however with a flag to only go + through the archive without extracting the files. + +Method : extractList($p_filelist, $p_path = "", $p_remove_path = "") +Description : + This method extract from the archive only the files indicated in the + $p_filelist. These files are extracted in the current directory or + in the directory indicated by the optional $p_path parameter. + If indicated the $p_remove_path can be used in the same way as it is + used in extractModify() method. +Arguments : + $p_filelist : An array of filenames and directory names, or a single + string with names separated by a single blank space. + $p_path : The path of the directory where the files/dir need to by + extracted. + $p_remove_path : Part of the memorized path that can be removed if + present at the beginning of the file/dir path. +Return value : + true on success, false on error. +Sample : + // Imagine tarname.tar with files : + // dev/data/file.txt + // dev/data/log.txt + // readme.txt + $tar_object = new Archive_Tar("tarname.tar"); + $tar_object->extractList("dev/data/file.txt readme.txt", "install", + "dev"); + // Files will be extracted there : + // install/data/file.txt + // install/readme.txt +How it works : + Go through the archive and extract only the files present in the + list. + diff --git a/typo3conf/ext/phpunit/PEAR/docs/Base/docs/CREDITS b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/CREDITS new file mode 100644 index 0000000..2cc9fc2 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/CREDITS @@ -0,0 +1,16 @@ +CREDITS +======= + +eZ Components team +------------------ + +- Sergey Alexeev +- Sebastian Bergmann +- Jan Borsodi +- Raymond Bosman +- Frederik Holljen +- Kore Nordmann +- Derick Rethans +- Vadym Savchuk +- Tobias Schlitt +- Alexandru Stanoi diff --git a/typo3conf/ext/phpunit/PEAR/docs/Base/docs/LICENSE b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/LICENSE new file mode 100644 index 0000000..7c28222 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/LICENSE @@ -0,0 +1,32 @@ +eZ Components Licence +===================== + +New BSD Licence +--------------- + +Copyright (c) 2005-2008, eZ Systems A.S. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. +* Neither the name of eZ Systems A.S. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/Me/myclass1.php b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/Me/myclass1.php new file mode 100644 index 0000000..4389b63 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/Me/myclass1.php @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/Me/myclass2.php b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/Me/myclass2.php new file mode 100644 index 0000000..0e04f38 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/Me/myclass2.php @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/You/yourclass1.php b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/You/yourclass1.php new file mode 100644 index 0000000..3a399a7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/You/yourclass1.php @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/You/yourclass2.php b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/You/yourclass2.php new file mode 100644 index 0000000..66cbf13 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/You/yourclass2.php @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/autoloads/my_autoload.php b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/autoloads/my_autoload.php new file mode 100644 index 0000000..37e19e9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/autoloads/my_autoload.php @@ -0,0 +1,6 @@ + 'Me/myclass1.php', + 'erMyClass2' => 'Me/myclass2.php', + ); +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/autoloads/your_autoload.php b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/autoloads/your_autoload.php new file mode 100644 index 0000000..ceeeb40 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/repos/autoloads/your_autoload.php @@ -0,0 +1,6 @@ + 'You/yourclass1.php', + 'erYourClass2' => 'You/yourclass2.php', + ); +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial.txt b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial.txt new file mode 100644 index 0000000..188f7ca --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial.txt @@ -0,0 +1,240 @@ +eZ Components - Base +~~~~~~~~~~~~~~~~~~~~ + +.. contents:: Table of Contents + +Introduction +============ + +The Base component provides the basic functionality, such as autoloading, that +all eZ Components need to function properly. The Base component needs to be +loaded specifically. Base can also autoload external class repositories from +outside the eZ Components. + +Aside from the autoload functionality, the Base component also contains a number of +generic Exception classes that all inherit from the ezcBaseException class. + + +Installation +============ + +The installation and configuration of the eZ Components environment is +described in a separate article. Please refer to the `Components Introduction`_ +for instructions on installation and configuration of the eZ Components library +and the Base component. + +.. _Components Introduction: /docs/install + + +Usage +===== + +Debugging +--------- + +By default the ezcBase component's autoload mechanism will not throw an +exception when an autoload class can not be found. In some cases (during +development) it is useful to have an exception with detailed information +about which autoload files were searched for, and in which directories. +ezcBase supports an option that enables this behavior:: + + debug = true; + ezcBase::setOptions( $options ); + ?> + +**Warning**: Exceptions are ignored when they are thrown from an autoload() +handler in PHP. In order to see the exception message that is thrown when a +class can not be found, you need to catch the exception *in* the autoload() +handler. Your autoload() function could then look like:: + + function __autoload( $className ) + { + try + { + ezcBase::autoload( $className ); + } + catch ( Exception $e ) + { + echo $e->getMessage(); + } + } + +Preloading +---------- + +The default autoload policy of the eZ Components is to load every class +file on demand only. It is also possible to load all classes of one +component at the same time, when one of the component's classes is +requested for the first time. You can change this behavior with the +"preload" option that is available through the ezcBaseAutoloadOptions option +class. You can turn preloading on with:: + + preload = true; + ezcBase::setOptions( $options ); + ?> + +Please note that preloading will *not* be done for Exception classes. + +Adding class repositories located outside eZ Components to autoload system +-------------------------------------------------------------------------- + +It can be useful to add repositories of user-defined classes to the eZ +Components autoload system. The ezcBase::addClassRepository() method can be +used to perform this task. You need to arrange the desired external classes +in a class repository. That is, make sure that classes and corresponding +\*_autoload.php files are named and placed according to the explanations below. +After they are in the proper structure, you can call addClassRepository() with +the proper parameters before you use the external classes. +External classes will then be loaded by autoload system. + +ezcBase::addClassRepository() takes two arguments: + +- $basePath is the base path for the whole class repository. +- $autoloadDirPath is the path where autoload files for this repository are found. + +The paths in the autoload files are *not* relative to the package directory +as specified by the $basePath argument. In other words, class definition files will +only be searched for in the location $autoloadDirPath. + +Consider the following example: + +- There is a class repository stored in the directory "./repos". +- Autoload files for this repository are stored in "./repos/autoloads". +- There are two components in this repository: "Me" and "You". +- The "Me" component has the classes "erMyClass1" and "erMyClass2". +- The "You" component has the classes "erYourClass1" and "erYourClass2". + +In this case, you need to create the following files in "./repos/autoloads". +Note that the prefix to _autoload.php ("my" and "your") in the filename is the +first part of the classname (excluding the lowercase classname prefix - "er"). + +Content of my_autoload.php: + +.. include:: repos/autoloads/my_autoload.php + :literal: + +Content of your_autoload.php: + +.. include:: repos/autoloads/your_autoload.php + :literal: + +The directory structure for the external repository is then: :: + + ./repos/autoloads/my_autoload.php + ./repos/autoloads/your_autoload.php + ./repos/Me/myclass1.php + ./repos/Me/myclass2.php + ./repos/You/yourclass1.php + ./repos/You/yourclass2.php + +To use this repository with the autoload mechanism, use the +following code: + +.. include:: tutorial_example_01.php + :literal: + +The above code will output: :: + + Class 'erMyClass2' + Class 'erYourClass1' + +Lazy initialization +------------------- + +Lazy initialization is a mechanism to load and configure a component, only +when it is really used in your application. This mechanism saves time for +parsing the classes and configuration, when the component is not used at all +during one request. The implementation in ezcBaseInit may be reused by other +applications and components, like the following example will show. + +.. include:: tutorial_lazy_initialization.php + :literal: + +The example shows a random class implementing the singleton pattern, which may +be some database connection handler, or anything similar in your case. The +getInstance() method shows a typical PHP 5 implementation except the +additional line 14, which checks, if a configuration callback was provided +earlier and configures the newly created instance. If no configuration +callback was provided, nothing will happen. The customKey is used to receive +the right callback from ezcBaseInit and needs to be known by the user, who +wants to define a configuration callback for your class. + +In line 32 the class used to configure your instance on creation is defined. +The first parameter is the key used earlier in the getInstance method, to +reference the right class, and the second parameter is the name of your +configuration class. + +The configuration class beginning in line 22 just needs to implement the +ezcBaseConfigurationInitializer interface, which defines one +method: configureObject(). This method will be called with the object to +configure as a single parameter. In the example, a new public property on the +customSingleton instance is created, which will be echo'd later to show the +success of the configuration. + +The configuration itself will not happen before the actual instance is created +in line 35 performing the static call on customSingleton::getInstance(). The +var_dump() in the following line shows, that the property value is set and +contains the earlier set value (int) 42. + +File Operations +--------------- + +Finding files recursively +````````````````````````` + +This example shows how to use the ezcBaseFile::findRecursive() method: + +.. include:: tutorial_example_02.php + :literal: + +The code in this example searches for files in the ``/dat/dev/ezcomponents`` +directory. It will only include files that match *all* patterns in the +$includeFilters array (the second parameter). Files that match *any* of the +patterns in the $excludeFilters array (the third parameter) will not be returned. + +In other words, the code above searches for files in the ``dat/dev/ezcomponents`` +directory, which are in the ``src/`` directory and end with ``_autoload.php``, +except for files that are in the ``/autoload/`` directory. + +Removing directories recursively +```````````````````````````````` + +This example shows how to use the ezcBaseFile::removeRecursive() method: + +.. include:: tutorial_example_03.php + :literal: + +This code simply removes the directory ``/dat/dev/ezcomponents/trash`` and all +of its files and sub-directories. + +**Warning: Use this function with care, as it has the potential to erase +everything that the current user has access to.** + +Overloading the callback +```````````````````````` + +The ezcBaseFile::findRecursive() method internally uses the +ezcBaseFile::walkRecursive() method to do the actual recursing. The callback +method ezcBaseFile::findRecursiveCallback() is then responsible for collecting +the data. In case you want to do additional things, such as printing progress, +you can either call walkRecursive() yourself with a callback function of your +choice, or overload the ezcBaseFile class and provide a new +findRecursiveCallback() method. The code below uses +ezcBaseFile::walkRecursive() directly in order to display dots for when ever it +finds a new directory: + +.. include:: tutorial_example_04.php + :literal: + + + +.. + Local Variables: + mode: rst + fill-column: 79 + End: + vim: et syn=rst tw=79 diff --git a/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_autoload.php b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_autoload.php new file mode 100644 index 0000000..c9387c1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_autoload.php @@ -0,0 +1,20 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_01.php b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_01.php new file mode 100644 index 0000000..316780d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_01.php @@ -0,0 +1,9 @@ +toString(); +$yourVar1 = new erYourClass1(); +$yourVar1->toString(); +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_02.php b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_02.php new file mode 100644 index 0000000..3748b60 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_02.php @@ -0,0 +1,11 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_03.php b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_03.php new file mode 100644 index 0000000..3e989b2 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_03.php @@ -0,0 +1,6 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_04.php b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_04.php new file mode 100644 index 0000000..70cb4a9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_example_04.php @@ -0,0 +1,42 @@ +elements[] = $sourceDir . DIRECTORY_SEPARATOR . $fileName; + $context->count++; + $context->size += $fileInfo['size']; + } + + static public function findRecursive( $sourceDir, array $includeFilters = array(), array $excludeFilters = array() ) + { + // create the context, and then start walking over the array + $context = new ezcBaseFileFindContext; + ezcBaseFile::walkRecursive( $sourceDir, $includeFilters, $excludeFilters, + array( 'myProgressFinder', 'findRecursiveCallback' ), $context ); + + // collect the statistics (which we don't do anything with in this example) + $statistics['size'] = $context->size; + $statistics['count'] = $context->count; + + // return the found and pattern-matched files + sort( $context->elements ); + return $context->elements; + } +} + +$files = myProgressFinder::findRecursive( dirname( __FILE__ ) ); +var_dump( $files ); +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_lazy_initialization.php b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_lazy_initialization.php new file mode 100644 index 0000000..7f6f80d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Base/docs/tutorial_lazy_initialization.php @@ -0,0 +1,38 @@ +value = 42; + } +} + +// Register for lazy initilization +ezcBaseInit::setCallback( 'customKey', 'customSingletonConfiguration' ); + +// Configure on first initilization +$object = customSingleton::getInstance(); +var_dump( $object->value ); + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/LICENSE b/typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/LICENSE new file mode 100644 index 0000000..8c177f8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/LICENSE @@ -0,0 +1,458 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/TODO b/typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/TODO new file mode 100644 index 0000000..e51a048 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/TODO @@ -0,0 +1,46 @@ + +Patrick O'Lone suggests the following idea which sounds interesting to +add as an optional mode of Cache_Lite class. +(still not tested in the Cache_Lite context) + +------------------------------------------------------------------------- +If you use the flags: + +ignore_user_abort(true); + +$fd = dio_open($szFilename, O_CREATE | O_EXCL | O_TRUNC | O_WRONLY, +0644); +if (is_resource($fd)) { + + dio_fcntl($fd, F_SETLKW, array('type' => F_WRLCK)); + dio_write($fd, $szBuffer); + dio_fcntl($fd, F_SETLK, array('type' => F_UNLCK)); + dio_close($fd); + +} + +ignore_user_abort(false); + +Only the first process will attempt to create a file. Additional +processes will see that a file already exists (at the system level), and +will fail. Another thing to note is that the file descriptor must be +opened using dio_open(), and certain features, like fgets() won't work +with it. If your just doing a raw write, dio_write() should be just +fine. The dio_read() function should be used like: + +$fd = dio_open($szFilename, O_RDONLY|O_NONBLOCK, 0644); +if (is_resource($fd)) { + + dio_fcntl($fd, F_SETLKW, array('type' => F_RDLCK)); + $szBuffer = dio_read($fd, filesize($szFilename)); + dio_fcntl($fd, F_SETLK, array('type' => F_UNLCK)); + dio_close($fd); + +} + +You still use locking to ensure that a write process can finish before +another attempts to read the file. We also set non-blocking mode in read +mode so that multiple readers can access the same resource at the same +time. NOTE: Direct I/O support must be compiled into PHP for these +features to work (--enable-dio). +------------------------------------------------------------------------- diff --git a/typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/docs/examples b/typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/docs/examples new file mode 100644 index 0000000..ab0a2d1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/docs/examples @@ -0,0 +1,254 @@ +A few examples of Cache_Lite using : +------------------------------------ + +>>> Basic one : + + '/tmp/', + 'lifeTime' => 3600 +); + +// Create a Cache_Lite object +$Cache_Lite = new Cache_Lite($options); + +// Test if thereis a valide cache for this id +if ($data = $Cache_Lite->get($id)) { + + // Cache hit ! + // Content is in $data + // (...) + +} else { // No valid cache found (you have to make the page) + + // Cache miss ! + // Put in $data datas to put in cache + // (...) + $Cache_Lite->save($data); + +} + +?> + + +>>> Usage with blocks +(You can use Cache_Lite for caching blocks and not the whole page) + + '/tmp/', + 'lifeTime' => 3600 +); + +// Create a Cache_Lite object +$Cache_Lite = new Cache_Lite($options); + +if ($data = $Cache_Lite->get('block1')) { + echo($data); +} else { + $data = 'Data of the block 1'; + $Cache_Lite->save($data); +} + +echo('

    Non cached line !

    '); + +if ($data = $Cache_Lite->get('block2')) { + echo($data); +} else { + $data = 'Data of the block 2'; + $Cache_Lite->save($data); +} + +?> + + +A few examples of Cache_Lite_Output using : +------------------------------------------- + +>>> Basic one : + + '/tmp/', + 'lifeTime' => 10 +); + +$cache = new Cache_Lite_Output($options); + +if (!($cache->start('123'))) { + // Cache missed... + for($i=0;$i<1000;$i++) { // Making of the page... + echo('0123456789'); + } + $cache->end(); +} + +?> + +>>> Usage with blocks : +(You can use Cache_Lite_Output for caching blocks and not the whole page) + + '/tmp/', + 'lifeTime' => 10 +); + +$cache = new Cache_Lite_Output($options); + +if (!($cache->start('block1'))) { + // Cache missed... + echo('Data of the block 1 !
    '); + $cache->end(); +} + +echo('

    Non cached line !

    '); + +if (!($cache->start('block2'))) { + // Cache missed... + echo('Data of the block 2 !
    '); + $cache->end(); +} + + +A few examples of Cache_Lite_Function using : +--------------------------------------------- + +>>> With function : + + '/tmp/', + 'lifeTime' => 10 +); + +$cache = new Cache_Lite_Function($options); + +$cache->call('function_to_bench', 12, 45); + +function function_to_bench($arg1, $arg2) +{ + echo "This is the output of the function function_to_bench($arg1, $arg2) !
    "; + return "This is the result of the function function_to_bench($arg1, $arg2) !
    "; +} + +?> + +>>> With method : + + '/tmp/', + 'lifeTime' => 10 +); + +$cache = new Cache_Lite_Function($options); + +$obj = new bench(); +$obj->test = 666; + +$cache->call('obj->method_to_bench', 12, 45); + +class bench +{ + var $test; + + function method_to_bench($arg1, $arg2) + { + echo "\$obj->test = $this->test and this is the output of the method \$obj->method_to_bench($arg1, $arg2) !
    "; + return "\$obj->test = $this->test and this is the result of the method \$obj->method_to_bench($arg1, $arg2) !
    "; + } + +} + +?> + +>>> With static method : + + '/tmp/', + 'lifeTime' => 10 +); + +$cache = new Cache_Lite_Function($options); + +$cache->call('bench::static_method_to_bench', 12, 45); + +class bench +{ + var $test; + + function static_method_to_bench($arg1, $arg2) { + echo "This is the output of the function static_method_to_bench($arg1, $arg2) !
    "; + return "This is the result of the function static_method_to_bench($arg1, $arg2) !
    "; + } +} + +?> + +>>> IMPORTANT : + +If you try to use Cache_Lite_Function with $this object ($cache->call('this->method',...) +for example), have a look first at : + +http://pear.php.net/bugs/bug.php?id=660 + + +A few examples of Cache_Lite_File using : +----------------------------------------- + + '/tmp/', + 'masterFile' => '/home/web/config.xml' +); +$cache = new Cache_Lite_File($options); + +// Set a id for this cache +$id = '123'; + +if ($data = $cache->get($id)) { + + // Cache hit ! + // Content is in $data + // (...) + +} else { // No valid cache found (you have to make the page) + + // Cache miss ! + // Put in $data datas to put in cache + // (...) + $cache->save($data); + +} + + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/docs/technical b/typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/docs/technical new file mode 100644 index 0000000..790696c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/docs/technical @@ -0,0 +1,28 @@ +Technical choices for Cache_Lite... +----------------------------------- + +To begin, the main goals of Cache_Lite : +- performances +- safe use (even on very high traffic or with NFS (file locking doesn't work + with NFS)) +- flexibility (can be used by the end user or as a part of a larger script) + + +For speed reasons, it has been decided to focus on the file container (the +faster one). So, cache is only stored in files. The class is optimized for that. +If you want to use a different cache container, have a look to PEAR/Cache. + +For speed reasons too, the class 'Cache_Lite' has do be independant (so no +'require_once' at all in 'Cache_Lite.php'). But, a conditional include_once +is allowed. For example, when an error is detected, the class include dynamicaly +the PEAR base class 'PEAR.php' to be able to use PEAR::raiseError(). But, in +most cases, PEAR.php isn't included. + +For the second goal (safe use), there is three (optional) mecanisms : +- File Locking : seems to work fine (but not with distributed file system + like NFS...) +- WriteControl : the cache is read and compared just after being stored + (efficient but not perfect) +- ReadControl : a control key (crc32(), md5() ou strlen()) is embeded is the + cache file and compared just after reading (the most efficient + but the slowest) diff --git a/typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/tests/readme b/typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/tests/readme new file mode 100644 index 0000000..6160fe2 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Cache_Lite/tests/readme @@ -0,0 +1,17 @@ +Cache_Lite is perfs oriented. So before commiting, please bench your patch ! + +To bench Cache_Lite, I use the tool 'ab' (distributed with apache). + +(for example) +/usr/sbin/ab -c 10 -n 1000 http://127.0.0.1/ [...] /Cache_Lite/tests/bench.php + +In the output of 'ab', most important things are : +- Failed requests: (must be 0 ! If not, don't commit !) +- Requests per second: XXX [#/sec] (mean) + + +For testing if the cache is ok or not, you can use the script 'test.php', it +will write if the cache has been hit or missed... + + +Fabien (fab@php.net) \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/CREDITS b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/CREDITS new file mode 100644 index 0000000..2cc9fc2 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/CREDITS @@ -0,0 +1,16 @@ +CREDITS +======= + +eZ Components team +------------------ + +- Sergey Alexeev +- Sebastian Bergmann +- Jan Borsodi +- Raymond Bosman +- Frederik Holljen +- Kore Nordmann +- Derick Rethans +- Vadym Savchuk +- Tobias Schlitt +- Alexandru Stanoi diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/LICENSE b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/LICENSE new file mode 100644 index 0000000..7c28222 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/LICENSE @@ -0,0 +1,32 @@ +eZ Components Licence +===================== + +New BSD Licence +--------------- + +Copyright (c) 2005-2008, eZ Systems A.S. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. +* Neither the name of eZ Systems A.S. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_input.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_input.php new file mode 100644 index 0000000..21915de --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_input.php @@ -0,0 +1,104 @@ +registerOption( new ezcConsoleOption( 'h', 'help' ) ); + +// Register complex parameter -f/--file +$file = new ezcConsoleOption( + 'f', + 'file', + ezcConsoleInput::TYPE_STRING, + null, + false, + 'Process a file.', + 'Processes a single file.' +); +$optionHandler->registerOption( $file ); + +// Manipulate parameter -f/--file after registration +$file->multiple = true; + +// Register another complex parameter that depends on -f and excludes -h +$dir = new ezcConsoleOption( + 'd', + 'dir', + ezcConsoleInput::TYPE_STRING, + null, + true, + 'Process a directory.', + 'Processes a complete directory.', + array( new ezcConsoleOptionRule( $optionHandler->getOption( 'f' ) ) ), + array( new ezcConsoleOptionRule( $optionHandler->getOption( 'h' ) ) ) +); +$optionHandler->registerOption( $dir ); + +// Register an alias for this parameter +$optionHandler->registerAlias( 'e', 'extended-dir', $dir ); + +// Process registered parameters and handle errors +try +{ + $optionHandler->process( array( 'example_input.php', '-h' ) ); +} +catch ( ezcConsoleOptionException $e ) +{ + echo $e->getMessage(); + exit( 1 ); +} + +// Process a single parameter +$file = $optionHandler->getOption( 'f' ); +if ( $file->value === false ) +{ + echo "Parameter -{$file->short}/--{$file->long} was not submitted.\n"; +} +elseif ( $file->value === true ) +{ + echo "Parameter -{$file->short}/--{$file->long} was submitted without value.\n"; +} +else +{ + echo "Parameter -{$file->short}/--{$file->long} was submitted with value <".var_export($file->value, true).">.\n"; +} + +// Process all parameters at once: +foreach ( $optionHandler->getOptionValues() as $paramShort => $val ) +{ + switch ( true ) + { + case $val === false: + echo "Parameter $paramShort was not submitted.\n"; + break; + case $val === true: + echo "Parameter $paramShort was submitted without a value.\n"; + break; + case is_array( $val ): + echo "Parameter $paramShort was submitted multiple times with value: <".implode(', ', $val).">.\n"; + break; + default: + echo "Parameter $paramShort was submitted with value: <$val>.\n"; + break; + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_menu_dialog_full.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_menu_dialog_full.php new file mode 100644 index 0000000..b22e490 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_menu_dialog_full.php @@ -0,0 +1,30 @@ +text = "Please choose a possibility:\n"; +$opts->validator = new ezcConsoleMenuDialogDefaultValidator( + array( + "A" => "Selection A", + "B" => "Selection B", + "C" => "Selection C", + "D" => "Selection D", + "Z" => "Selection Z", + ), + "Z" +); + +$dialog = new ezcConsoleMenuDialog( $out, $opts ); + +$res = ezcConsoleDialogViewer::displayDialog( $dialog ); +echo "User seletced $res\n"; + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_output.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_output.php new file mode 100644 index 0000000..ceb8297 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_output.php @@ -0,0 +1,64 @@ +options->verbosityLevel = 10; +// Enable auto wrapping of lines after 40 characters +$out->options->autobreak = 40; + +// Set the color of the default output format to green +$out->formats->default->color = 'green'; + +// Set the color of the output format named 'success' to white +$out->formats->success->color = 'white'; +// Set the style of the output format named 'success' to bold +$out->formats->success->style = array( 'bold' ); + +// Set the color of the output format named 'failure' to red +$out->formats->failure->color = 'red'; +// Set the style of the output format named 'failure' to bold +$out->formats->failure->style = array( 'bold' ); +// Set the background color of the output format named 'failure' to blue +$out->formats->failure->bgcolor = 'blue'; + +// Output text with default format +$out->outputText( 'This is default text ' ); +// Output text with format 'success' +$out->outputText( 'including success message', 'success' ); +// Some more output with default output. +$out->outputText( "and a manual linebreak.\n" ); + +// Manipulate the later output +$out->formats->success->color = 'green'; +$out->formats->default->color = 'blue'; + +// This is visible, since we set verboseLevel to 10, and printed in default format (now blue) +$out->outputText( "Some verbose output.\n", null, 10 ); +// This is not visible, since we set verboseLevel to 10 +$out->outputText( "Some more verbose output.\n", null, 20 ); +// This is visible, since we set verboseLevel to 10, and printed in format 'failure' +$out->outputText( "And some not so verbose, failure output.\n", 'failure', 5 ); + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_progressbar.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_progressbar.php new file mode 100644 index 0000000..9442779 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_progressbar.php @@ -0,0 +1,75 @@ +formats->red->color = "red"; + +// Create progress bar itself +$progress = new ezcConsoleProgressbar( $out, 100, array( 'step' => 5 ) ); + +$progress->options->emptyChar = '-'; +$progress->options->progressChar = $out->formatText('>', "red"); +$progress->options->formatString = "Uploading file : %act%/%max% kb [%bar%]"; + +// Perform actions +$i = 0; +while( $i++ < 20 ) +{ + // Do whatever you want to indicate progress for + usleep( mt_rand( 20000, 2000000 ) ); + // Advance the progressbar by one step ( uploading 5k per run ) + $progress->advance(); +} + +// Finish progress bar and jump to next line. +$progress->finish(); + +$out->outputText( "Successfully uploaded .\n", 'success' ); + +/* +OUTPUT: (sequential, will be printed into 1 line and updated in reallife) + +Uploading file : 5/100 kb [++#----------------------------------------------] +Uploading file : 10/100 kb [+++++#-------------------------------------------] +Uploading file : 15/100 kb [++++++++#----------------------------------------] +Uploading file : 20/100 kb [+++++++++++#-------------------------------------] +Uploading file : 25/100 kb [++++++++++++++#----------------------------------] +Uploading file : 30/100 kb [+++++++++++++++++#-------------------------------] +Uploading file : 35/100 kb [++++++++++++++++++++#----------------------------] +Uploading file : 40/100 kb [+++++++++++++++++++++++#-------------------------] +Uploading file : 45/100 kb [++++++++++++++++++++++++++#----------------------] +Uploading file : 50/100 kb [+++++++++++++++++++++++++++++#-------------------] +Uploading file : 55/100 kb [++++++++++++++++++++++++++++++++#----------------] +Uploading file : 60/100 kb [+++++++++++++++++++++++++++++++++++#-------------] +Uploading file : 65/100 kb [++++++++++++++++++++++++++++++++++++++#----------] +Uploading file : 70/100 kb [+++++++++++++++++++++++++++++++++++++++++#-------] +Uploading file : 75/100 kb [++++++++++++++++++++++++++++++++++++++++++++#----] +Uploading file : 80/100 kb [+++++++++++++++++++++++++++++++++++++++++++++++#-] +Uploading file : 85/100 kb [++++++++++++++++++++++++++++++++++++++++++++++++#] +Uploading file : 90/100 kb [++++++++++++++++++++++++++++++++++++++++++++++++#] +Uploading file : 95/100 kb [++++++++++++++++++++++++++++++++++++++++++++++++#] +Uploading file : 100/100 kb [++++++++++++++++++++++++++++++++++++++++++++++++#] +Uploading file : 100/100 kb [++++++++++++++++++++++++++++++++++++++++++++++++#]Successfully uploaded . + +*/ +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_progressmonitor.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_progressmonitor.php new file mode 100644 index 0000000..a6e571c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_progressmonitor.php @@ -0,0 +1,52 @@ +addEntry( 'ACTION', "Performed action #{$i}." ); +} + +$out->outputLine(); + +/* +OUTPUT: + + 14.3% ACTION Performed action #1. + 28.6% ACTION Performed action #2. + 42.9% ACTION Performed action #3. + 57.1% ACTION Performed action #4. + 71.4% ACTION Performed action #5. + 85.7% ACTION Performed action #6. + 100.0% ACTION Performed action #7. + +*/ +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_question_dialog_collection_full.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_question_dialog_collection_full.php new file mode 100644 index 0000000..a6ff696 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_question_dialog_collection_full.php @@ -0,0 +1,25 @@ +text = "Do you want to proceed?"; +$opts->showResults = true; +$opts->validator = new ezcConsoleQuestionDialogCollectionValidator( + array( "y", "n" ), + "n", + ezcConsoleQuestionDialogCollectionValidator::CONVERT_LOWER +); + +$dialog = new ezcConsoleQuestionDialog( $out, $opts ); + +echo "The user decided to " . ( ezcConsoleDialogViewer::displayDialog( $dialog ) === "n" ? "not " : "" ) . "proceed.\n"; + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_question_dialog_factory_yesno.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_question_dialog_factory_yesno.php new file mode 100644 index 0000000..6318928 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_question_dialog_factory_yesno.php @@ -0,0 +1,25 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_question_dialog_type_full.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_question_dialog_type_full.php new file mode 100644 index 0000000..53be7e6 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_question_dialog_type_full.php @@ -0,0 +1,30 @@ +text = "How old are you?"; +$opts->showResults = true; +$opts->validator = new ezcConsoleQuestionDialogTypeValidator( + ezcConsoleQuestionDialogTypeValidator::TYPE_INT +); + +$dialog = new ezcConsoleQuestionDialog( $out, $opts ); + +if ( ( $res = ezcConsoleDialogViewer::displayDialog( $dialog ) ) < 8 ) +{ + echo "Sorry, I can not believe that you are $res years old!\n"; +} +else +{ + echo "Hey, you're still young! :)\n"; +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_statusbar.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_statusbar.php new file mode 100644 index 0000000..d4feeb7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_statusbar.php @@ -0,0 +1,49 @@ +add( (bool)mt_rand( 0, 1 ) ); +} + +$out->outputLine(); +// Print statistics +$out->outputLine( $status->getSuccessCount() . ' operations succeeded, ' . $status->getFailureCount() . ' failed.' ); + +/* +OUTPUT: + ++-++++-++++-++-+--+- +13 operations succeeded, 7 failed. + +*/ +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_table.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_table.php new file mode 100644 index 0000000..df217b1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_table.php @@ -0,0 +1,77 @@ +formats->headline->color = 'red'; +$out->formats->headline->style = array( 'bold' ); +// Define a new format "sum" +$out->formats->sum->color = 'blue'; +$out->formats->sum->style = array( 'negative' ); + +// Create a new table +$table = new ezcConsoleTable( $out, 60 ); + +// Create first row and in it the first cell +$table[0][0]->content = 'Headline 1'; + +// Create 3 more cells in row 0 +for ( $i = 2; $i < 5; $i++ ) +{ + $table[0][]->content = "Headline $i"; +} + +$data = array( 1, 2, 3, 4 ); + +// Create some more data in the table... +foreach ( $data as $value ) +{ + // Create a new row each time and set it's contents to the actual value + $table[][0]->content = "$value"; +} + +// Set another border format for our headline row +$table[0]->borderFormat = 'headline'; + +// Set the content format for all cells of the 3rd row to "sum" +$table[2]->format = 'sum'; + +$table->outputTable(); +echo "\n"; +/* + +RESULT (without color): + ++------------+------------+------------+------------+ // +| Headline 1 | Headline 2 | Headline 3 | Headline 4 | // Red bordered line ++------------+------------+------------+------------+ // +| 1 | | | | ++------------+------------+------------+------------+ +| 2 | | | | // Content printed in white on blue ++------------+------------+------------+------------+ +| 3 | | | | ++------------+------------+------------+------------+ +| 4 | | | | ++------------+------------+------------+------------+ + +*/ +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_table_2.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_table_2.php new file mode 100644 index 0000000..e83bf11 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/example_table_2.php @@ -0,0 +1,65 @@ +formats->evenRow->color = 'red'; +$out->formats->evenRow->style = array( 'bold' ); + +$out->formats->oddRow->color = 'blue'; +$out->formats->oddRow->style = array( 'bold' ); + +// Define format schemes for even and odd cells +$out->formats->evenCell->color = 'red'; +$out->formats->evenCell->style = array( 'negative' ); + +$out->formats->oddCell->color = 'blue'; +$out->formats->oddCell->style = array( 'negative' ); + +// Create a new table with a width of 60 chars +$table = new ezcConsoleTable( $out, 60 ); + +// Set global cell content align +$table->options->defaultAlign = ezcConsoleTable::ALIGN_CENTER; + +for ( $i = 0; $i < 5; $i ++ ) +{ + for ( $j = 0; $j < 5; $j++ ) + { + // Fill each table cell with ## + $table[$i][$j]->content = '##'; + if ( $i === $j ) + { + // On diagonal line set explicit cell format for even/odd + $table[$i][$j]->format = $j % 2 == 0 ? 'evenCell' : 'oddCell'; + } + } + // Set global format for even/odd rows + $table[$i]->format = $i % 2 == 0 ? 'evenRow' : 'oddRow'; + // Set border format for even/odd rows + $table[$i]->borderFormat = $i % 2 == 0 ? 'evenRow' : 'oddRow'; +} + +$table->outputTable(); +echo "\n"; +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_06.png b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_06.png new file mode 100644 index 0000000000000000000000000000000000000000..2d667ea516f57a5fc887c5d72a255738a404d07a GIT binary patch literal 489 zcmV{k+u;*I2MM^$z}WdtNT?L2oEB07}`?k>w*ud;Tfo9Le$FDzCUC+yJ0%zv2XW f@UCe90Q&IS&gaMXLwo_&Mr)3-`grB|Sn_sn?(P*_Nk_Cg<)+e| zBWPg&@P?)4 zAi@A^6W-SRktT1Ao%o!%z2>;p&XRfC)2czKeQQOY#zKmJv*?bPO{AThqjHtnQN8J^ zT!a@8-ag??6R{@YOSv^C47o%v*(nJ_>x5!X;ax)1NBGFuu#CG&bT!UK-jpp>ajre$ zp(jjGh#9OAFV&p4O{1-%;#qK8e2(tt&hyQv_1`;FMQ{;ZKyW?v!&=OMer$6au9no7 zZBK_avoEQ=^do$_Oro95u_*$<1$c(w#(zy2Wp9adTI^{yPmNy9)aHF@!&llq-jQux zQ5}K!M5>&F_=2P*2+Q$W`R`#V0Ko-7aHTv}veTL;)5=QPtfk#ZHDZ%kEpJ=n+VU9P zQl+n1DbQYnMxT0OJp3_`h#mkS-T--q|4)}25C8xm&p$U{C>6P+xSjw2002ovPDHLk FV1n;;IdlL3 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_08.png b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_08.png new file mode 100644 index 0000000000000000000000000000000000000000..e1c80e3b472c2fbeb3a25fd3f2a8cfdfb74e91bd GIT binary patch literal 844 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 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_10.png b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_10.png new file mode 100644 index 0000000000000000000000000000000000000000..966b1d5aa3ec7027370887b8eed5aa47cec8b1c8 GIT binary patch literal 2964 zcmbtWYgAKL7QVFB0uE!l5GdfQV=L4bqX=1oNmL@rAPAxmP>4(9ArOMdGZ4}`Dgzp6 zYe%NMB2W<_Bn2cqL##^BL5LAZgb>o2YJ>zLh6D)Y-Z>FahUL^Bv$F2Z%HAjE-u<0# zf8WmX@!n@EKub14 z#{ST*pFjBe_(#w$riLG%Frc+~BM@4g|JrG(0`>`*b_-4q$(K|!liHgmV`jt^^2(Ab zD-FMnus5GoH;VZ6OqE9GvjQ%<_Mr2Q(08_4P4+qSxWAF%aL4RhAw5!^BpxlVP|FF~ zLF9U&&t{GzOzcs!@*h1`?A2E$poII?bwWKg+l9M=5qjf_lN8_Xz4=G)Ndb?}DPm=_ zLwc~H3=3kbun9TnDkPP+vvPQ~S4HRP;V~-dp;*JjY+NQPj>xaX^i4Yk>1#!f9g|Xy z1H~O~c-*|Hcx-emr%+oX!8`I*1Nr2k;HzHSk5b($sakTlHL_y*Q2Fsyu3w&P5*$Fo z)!iXw<}uo-!u}^C_T4n6w1w;L+eS}B>Xvt;gce54AVu0(QJVCcHHi@@PiES7*AjJR zXc^5Zdf{IhqfitT(Lc9sn=T@(fq`(b*W{ElLdnZdZ5%)T`9-@Y; z>Xiy~$3$ydaAtEgOi%XoiXW2rx2r{7%<(Or*%&1hYX%R- zowJSpVQfabRDjOQ_&Y$5_L%NVTIs7>xcMl`AG-fgN_2TN;dyaVpmU}eHkM9f?xE}UYv0aKHr`@z<_oCd~vx&-EBRrk@tB42Y zr?gYs;A6a42hYLC5}I8<{4J;GJNdH!lyFoqZhOvFK|Q#G&mOW{e~0FzNVleT*(yfJ zD%1b~%U+hn#-3zF{GOUR1>pGA3*6o+3h1c+sVH*@EzUC>@cdlA#MXjrzF;1XD)E}( zC~Emd{!tbeCZN>$(b%kG^*KypYY4HmSga|E8cTP0QcG0YOD*sEOhon&5YmQYounfD z7f})n@;Kpoa$p{F+`Al}iLKO#5V7eIwQZVV4+9M2SBG$@B-7I;kg4rcUFP9hodQX8 z8l6K1(%xQUqj);Mn^g7!+vDI-9B1Nd4Yc#e!0m2pOC_nkufio}3! z=f^UjIc-@iCvV#4J^AL)U{Ls2YAlcz7lL=2{7w1KHzp%T9U5CjDX*CAhVskce;GQa zHRS?0e4O5r=_a|GUUd_x$~`8H-nm00lNYSJDGTIvk!Wxss6)&iL@xjiz%iG%DZgYI&u;cngNr zIf@SekO13Js%?oJ9MD1C3wl^PHiCj_Vo&8Y;elLG#@et3$8lh*cI#q9dQP7l)lbgy zN0b@?w&OCDsY~w){ONJ?bxX>SB*?99JhrMhkC;(fl^dzyhpf@pDktR({!hQSB-!9! zEpbXBhp1_Z%A}^}w$a)t8at$<7n?>I=hw*SwV2ugJV}&>7=0SckdzKt%~-yM>BB@| zLX5?4xE`TdKgKRDaR%5<8ulbz+NhH|#`}7zYPO#rbFi(rp6p310j;v< z_|RB{3aIn9lnl9&?gLOE-%t396C6g9c;~iMUzWIUllc7CBhSss=dYJg7#Ts!>qqBd zeAd0jiTh1>OSQW-RSVR1d7nJF3pSYmWI6d<<-EX(=g)rue?aK16~D=Y(425MuV&0Q zNL`keGuJgcTx25Td9=$sL<;?16Db!AL?PET7>LqqmlG+Sri7-jy(-8yTo^^@zR(Ud zWBl$V&6I|wL0XO~%4)_ZE*G+EC6kv3NIoldPw9AUrD3CtRdYj0DMj_7krp6=ipQTqx}o2PtCHiQS}6tV!uS7Sbt7K-B*n;CXw9XW z;Lk}0J+Ycu@!Dgpw#aCq6*|T<16wlg<~`+AP~#=Il82%mePbQj9cIRHt3TKk4#$4D jco;P>;17q@O|a1o8`wS)rTzlU&ydGnZya;a@w5K{bFG>o literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial.txt b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial.txt new file mode 100644 index 0000000..2ff40e7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial.txt @@ -0,0 +1,564 @@ +eZ Components - ConsoleTools +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. contents:: Table of Contents + +Introduction +============ + +The ConsoleTools component provides several useful tools to build +applications that run on a computer console (sometimes also called shell or +command line). For example, eZ Publish includes several shell +scripts that perform tasks like clearing caches. + +.. note:: + From version 1.5.2 on, all necessary string operations in ConsoleTools are + performed using `ext/iconv`__. This makes the component binary safe and + allows you to use arbitrary unicode characters in your texts. Please make + sure to convert your text to UTF-8 before submitting it to a method in + ConsoleTools, if you use a different, non ASCII-compatible encoding. + +.. __: http://php.net/iconv + +Class overview +============== + +The ConsoleTools component offers several (mostly independent) classes to +perform different tasks. The main classes are: + +ezcConsoleOutput + ezcConsoleOutput is responsible for printing text to the console. It allows + you to print text in different colors with different background colors. + It can also apply other styling information to the text, making + it bold or underlined for example. It can automatically wrap text + after a certain number of characters are printed (keeping words + intact) and handle output of different verbosity levels. ATTENTION: Windows + does not support the styling of text. + +ezcConsoleInput + Using this little tool, you can handle the options and arguments provided to + your shell application. It is capable of handling and validating three types of + option datatypes (string, int and none) and can handle optional and mandatory + options as well as rules to define relations between them. Rules can include + dependencies and exclusions between options. + +ezcConsoleProgressbar + Most often you will use a console application in favor of a web application + when it comes to processing time-consuming tasks. To indicate the + current progress of a task, a kind of "status + indicator" will be used, which is most commonly a progress bar. + ezcConsoleProgressbar gives you an easy-to-use interface to display this. + It will keep track of re-drawing the bar as needed, showing current + and maximum values, as well as percentage completion. It is + fully configurable regarding its visual appearance. + +ezcConsoleStatusbar + ezcConsoleStatusbar is the "little brother" of ezcConsoleProgressbar. It + also allows you to display the progress of a time-consuming action, but does + not use a fixed bar-like appearance. Instead, it indicates successful + and failed operations by displaying specific characters and keeps a + count of successes and failures. This allows you to indicate + the progress of a process where you don't initially know the number of + actions to be performed. + +ezcConsoleProgressMonitor + Sometimes you need to display the progress of several actions and don't want + to use a progress bar to do so. In this case you need the status indicator. + It allows you to display a status entry for each action and generates the + percentage completion of the current step. + +ezcConsoleTable + This class lets you easily create tables to be displayed on the + console. It has a very convenient interface to create a table and manage the + data it contains. It is highly configurable regarding the table's appearance + (for example, different color and style information for content + and borders on a per-cell basis, character selection for borders, variable + width of the table and so on). ezcConsoleTable will also take care of measuring the + best width for table columns (to make your content fit best), automatically + wrapping content and aligning the content in the cells as indicated. + +ezcConsoleDialog + This interface provides a common API for user interaction elements. A console + dialog can request information from a user and react on this information + interactively. For you as a user of ezcConsoleDialog, a dialog is displayed + to the user and returns a result value to you, which was provided by the user + of your application in some way. Currently 2 implementations of + ezcConsoleDialog exist: ezcConsoleQuestionDialog is a dialog for asking a + simply question and retrieving the answer from the user of an application. + Instances of the ezcConsoleMenuDialog class display a menu to the user and + retrieves his choice of a menu item. + +Usage +===== + +Printing text to the console +---------------------------- + +As mentioned, the class ezcConsoleOutput is used to print text to the console. +Let's look at a basic example: + +.. include:: tutorial_example_01_output_basic.php + :literal: + +The ezcConsoleOutput object is simply instantiated. You can optionally submit +options and predefined formatting options to its constructor, but this can also +be done later. + +In line 7, you can see how format is defined. Formats are created on the fly, +as soon as you access them (for reading or writing) through the $output->formats +attribute. There, we create a format called "info" and assign the color value +"blue" to it. This will make all text printed with this format blue. In line 9, +you can see how the format is applied to some text at printing time. + +The second example shows some more advanced code: + +.. include:: tutorial_example_02_output_advanced.php + :literal: + +In this example, two more formats are defined: "error" and "fatal". These formats +have an additional style attribute set, which makes them both appear bold. The +"fatal" format will also underline the text and give it a black background +color. + +The difference between ezcConsoleOutput->outputText() and +ezcConsoleOutput->outputLine() is that the latter automatically adds a +newline value to your text. The newline sequence used here is adjusted based on +the operating system. The use of ezcConsoleOutput->outputLine() is recommended +over the direct output of, for example, "\n". + +If you leave the second parameter of ezcConsoleOutput::outputText() and +ezcConsoleOutput::outputLine() out, the "default" format is used. The default +is set to your console's default setting, but you can also change this as +for any other format you define. A third variant to format text is +ezcConsoleOutput->formatText(), which returns the formatted string instead of +printing it. + +This example shows some of the options ezcConsoleOutput supports: + +.. include:: tutorial_example_03_output_options.php + :literal: + +autobreak + Will wrap lines automatically after the set amount of characters, keeping + word boundaries intact. + +verbosityLevel + Allows you to specify a third parameter to ezcConsoleOutput->outputLine() and + ezcConsoleOutput->outputText() to indicate a verbosity level for when the text + should be printed. By setting the "verbosityLevel" option for + ezcConsoleOutput, you define which texts will and will not be printed. + +In our example, the call on line 23 would not print out text with the +"verbosityLevel" option set to 3, but the call on line 25 would. + +The last example shows how to change the target of a format, which allows you +to print text e.g. to STDERR. + +.. include:: tutorial_example_output_targets.php + :literal: + +The error message 'Unable to connect to database' will be printed in bold, with +a red foreground color to STDOUT. The default target is +ezcConsoleOutput::TARGET_OUTPUT, which prints to STDOUT and has standar output +buffering in place. If you want to switch out the standard output bufferung, +use ezcConsoleOutput::TARGET_STDOUT. + +Although this feature was originally not designed for that purpose, you can +also use any other arbitrary PHP stream definition as a target. For example +'file:///var/log/my.log' to get the messages redirected to a log file instead +of displaying them. + +Mastering options and arguments +------------------------------- + +Below is a simple example for ezcConsoleInput: + +.. include:: tutorial_example_04_input_basic.php + :literal: + +After instantiating a new ezcConsoleInput object to handle the options, an +option is registered on lines 7-12. This option will be available as "-h" and +"--help". The ezcConsoleInput->process() call makes ezcConsoleInput respond to the +options submitted by the user. If any error occurs with the submitted user +data, the method will throw an exception of type ezcConsoleOptionException. By +default, all options are registered with the value type +ezcConsoleInput::TYPE_NONE, which indicates that they don't expect a value +from the user. If a value is submitted anyway, ezcConsoleInput->process() will +throw a ezcConsoleOptionTypeViolationException. + +On line 23, a check is performed to see whether an option was submitted. If an option was not +submitted, its $value property will contain bool *false*. Depending on the $type +set, it can contain different value types if it was submitted. If you use the +(not shown here) ezcConsoleOption->$multiple property, the value will be an array +containing the specified value types. + +The next example is more advanced: + +.. include:: tutorial_example_05_input_advanced.php + :literal: + +Two options are registered here: "-i" / "--input" and "-o" / "--output". For the +first one, additional properties for the ezcConsoleOption object are submitted +through the constructor. For the second ezcConsoleOption object, you see how to +provide additional properties after construction. We change the type of both +options to expect a string value from the user (lines 13 and 20). + +In lines 25 and 28 we make both parameters depend on each other. If one of them +is submitted without the other, ezcConsoleInput->process() will throw an +ezcConsoleOptionDependencyViolationException. Aside from dependency rules, you can +also define exclusion rules using ezcConsoleOption->addExclusion(). + +On line 43, the method ezcConsoleInput->getSynopsis() is used to retrieve a +synopsis string for the program. The synopsis for our example would look like +this: :: + + $ ./tutorial_example_05_input_advanced.php [-h] [-i [-o ] ] [[--] ] + +The synopsis will indicate the option value types, whether they are optional, the +inter-option dependencies and default values (if set). On line 46, the property +ezcConsoleOption->$shorthelp is accessed, where you can store some short help +information. It has a reasonable default value set. + +On line 49, the submission of the "-o" option is checked. Because this has a +dependency on the "-i" option, a check for that is not necessary. Line 52 +shows how you can access the arguments submitted to the program. +ezcConsoleInput->getArguments() always returns an array (which is empty if no +arguments are submitted). A more advanced way of handling arguments is +explained further below. + +Here is an example of how the defined program would be called: :: + + $ ./tutorial_example_05_input_advanced.php -i /var/www -o /tmp foo bar + +The program would respond by printing the following: :: + + Input: /var/www, Output: /tmp + Arguments: foo, bar + +As you can see, this example does not define, which arguments are expected and +therefore, the program simply accepts any number of arguments and provides them +through the ezcConsoleInput->getArguments() method. The following example +shows, how specific arguments can be defined: + +.. include:: tutorial_example_12_input_arguments.php + :literal: + +As seen before, a help option is registered. In addition, 3 arguments are +registered: The first one with the name "source" is a standard argument. It is +mandatory for the user to submit a value here. The second argument, +"destination" is optional and a default value is assigned, which will be used, +if the user does not provide a value for it. + +The third one ("iterations") is not of type string, but an integer. Because the +second argument is optional, this third one is automatically optional, too. +Since no default value is assigned, it will be null, if the user does not +submit it. If a value is provided, it must be an integer. + +Argument definitions are processed as usual inside the +ezcConsoleInput->process() method, but will throw an +ezcConsoleArgumentException if something goes wrong. If desired, exceptions +about options and arguments can be caught together using ezcConsoleException or +be handled on their own. + +The value of an argument can be fetched from its definition, using its value +property. As can be seen at the very end of the example, for reading purpose, +arguments can be accessed by their name. This does not work for writing +purpose, since a specific order must be given there. + +If the --help option is set, mandatory arguments don't need to be submitted and +are silently ignored. The help text generated by ezcConsoleInput for this +example looks like this: :: + + Usage: $ tutorial_example_12_input_arguments.php [-h] [--] [] [] + A simple text program + + -h / --help No help available. + Arguments: + The source directory. + No help available. + Number of iterations. + + +For further information, please refer to the API documentation of +ezcConsoleInput. + +Progress indication +------------------- + +This example defines a simple progress bar: + +.. include:: tutorial_example_06_progressbar_basic.php + :literal: + +The created progressbar will count to a maximum value of 15, submitted to +ezcConsoleProgressbar->__construct() in line 7. ezcConsoleProgressbar utilizes +ezcConsoleOutput to print the generated progress bar. The call to +ezcConsoleProgressbar->advance() pushes the progress bar one step further on each +call and redraws it (line 11). Calling ezcConsoleProgressbar->finish() will set +the progress bar to 100% immediately. + +The progress bar generated by the example will look like this: + +.. image:: img/consoletools_tutorial_example_06.png + +The next example performs more customization on the progress bar appearance: + +.. include:: tutorial_example_07_progressbar_advanced.php + :literal: + +The defined options array demonstrates only a small subset of options. For +detailed information, see the API documentation on +ezcConsoleProgressbarOptions. The "emptyChar" value defines the character to +prefill the bar, the "barChar" option defines the character to fill the bar +with when calling ezcConsoleProgressbar->advance(). +Using the "formatString" option, you define the appearance of the whole bar. +Here the substitution of several placeholders (like "%fraction%" and "%bar%") +is permitted. "formatString" must contain the "%bar%" placeholder, while all +other values are optional. Any other printable character is permitted. +Formatting options are allowed in the "formatString" option, but +not in any other option. "redrawFrequency" defines how often the +progressbar will be redrawn. In the example this will be every 50th call to +ezcConsoleProgressbar->advance(). + +The resulting progress bar looks like this: + +.. image:: img/consoletools_tutorial_example_07.png + +With ezcConsoleStatusbar, you can indicate the progress of a time-consuming +action in a simpler way. Here is an example: + +.. include:: tutorial_example_08_statusbar.php + :literal: + +This variant of indicating progress only displays success or failure indicators +for an action and allows you to run any number of actions, without specifying +in advance how many you will perform. The "successChar" and "failureChar" options +indicate which string to print on a successful or failed action. Lines 11 and +12 format these strings. + +Indicating a status is done using ezcConsoleStatusbar->add(), which expects +*true* for a succeeded action and *false* for a failed one (line 20). You can +access the number of successes and failures through +ezcConsoleStatusbar->getSuccessCount() and +ezcConsoleStatusbar->getFailureCount(). To make ezcConsoleStatusbar +wrap a line after a certain amount of statuses, you can use +ezcConsoleOutput->$autobreak. + +Here the result of the example: + +.. image:: img/consoletools_tutorial_example_08.png + +Finally, ezcConsoleProgressMonitor can indicate progress, but does not use a +bar-like interface. It simply prints status information about each action you +perform and shows the current progress as a percentage value in relation to the +number of actions you plan to perform overall. + +.. include:: tutorial_example_11_progressmonitor.php + :literal: + +Line 7 creates a new status indicator, which will iterate over 7 actions. +Inside the while loop, we simulate some actions. The +call to $status->addEntry() adds a status entry and causes the indicator to +print the entry. Every entry consists of a tag (first parameter) and a message. + +The result of the example is as follows: + +:: + + 14.3% ACTION Performed action #1. + 28.6% ACTION Performed action #2. + 42.9% ACTION Performed action #3. + 57.1% ACTION Performed action #4. + 71.4% ACTION Performed action #5. + 85.7% ACTION Performed action #6. + 100.0% ACTION Performed action #7. + +More information on these classes can be found in the API documentation of +ezcConsoleProgressbar, ezcConsoleStatusbar and ezcConsoleProgressMonitor. + +Large data served in a table +---------------------------- + +This is the result of a table generated by ezcConsoleTable: + +.. image:: img/consoletools_tutorial_example_09.png + +Here is its corresponding source code: + +.. include:: tutorial_example_09_table_basic.php + :literal: + +ezcConsoleTable (like ezcConsoleStatusbar and ezcConsoleProgressbar) uses the +ezcConsoleOutput class to print to the console. To create a table, you just +need to submit the maximum width of the table to its constructor: +ezcConsoleTable->__construct(). Options for table formatting are inherited +from the table itself to the table rows and from there to the table cells. +On each inheritance level, options can be overridden individually. The +"defaultBorderFormat" option sets the global format value for all borders (line +24). This is overridden in line 26 for the first row of the table. + +Table rows are accessed like an array in PHP (this is achieved by +implementing the ArrayAccess_ interface from SPL_). +ezcConsoleTable implements the Iterator interface (SPL_, too) to allow +iteration over table rows using foreach. Each table row is represented by an +object of type ezcConsoleTableRow, which also implements the ArrayAccess_ and +Iterator interfaces to access cells contained in the rows in the same way. Each +of the named classes allows the access of its properties as usual, in addition +to access to its contained objects through the array interface. + +ezcConsoleTableRow and ezcConsoleTableCell have a $format setting to define the +format of the contained text. All cells (as described above) will inherit the +setting of their parent ezcConsoleTableRow, as long as this has not been +explicitly overridden. The same applies to ezcConsoleTableRow->$align and +ezcConsoleTableCell->$align. Possible align values are: + +- ezcConsoleTable::ALIGN_DEFAULT (inherit from parent) +- ezcConsoleTable::ALIGN_LEFT +- ezcConsoleTable::ALIGN_RIGHT +- ezcConsoleTable::ALIGN_CENTER + +The content of a cell is stored in the ezcConsoleTableCell->$content property +(line 34). The usage of formatted text in a cell is possible, but not recommended. +If you want to define the format of cell content, use the +ezcConsoleTableCell->$format property. + +.. _SPL: http://php.net/spl +.. _ArrayAccess: http://www.php.net/~helly/php/ext/spl/interfaceArrayAccess.html + +Below is a more advanced (but in a way useless) example to show the handling of +tables: + +.. include:: tutorial_example_10_table_advanced.php + :literal: + +The "corner", "lineHorizontal" and "lineVertical" options define which +characters to use for the borders of the table. These options must be +exactly one character long and cannot contain formatting information. To style the +borders, use the ezcConsoleTable->$defaultBorderFormat and +ezcConsoleTableRow->$borderFormat properties. + +The random format and alignment options selected above create the following +table: + +.. image:: img/consoletools_tutorial_example_10.png + +More information on the handling of tables on the shell can be found in the API +documentation of ezcConsoleTable, ezcConsoleTableRow and ezcConsoleTableCell. + +Interacting with the user +------------------------- + +Implementations of the interface ezcConsoleDialog are generic building blocks, +which allow to interact with the user of a shell application using STDIN. A +dialog is initialized, displayed and will return a value provided by the user. +What exactly happens inside a specific dialog may vary. Commonly, the dialog +validates and possibly manipulates the provided value before returning it. + +The most basic dialog is the ezcConsoleQuestionDialog, which prints out some +text and retrieves a single value back. + +.. include:: tutorial_example_13_dialog_question.php + :literal: + +Every dialog expects an instance of ezcConsoleOutput which is used to display +it. The question dialog here will display the text "Do you want to proceed?" +and expects an answer from the user. The $showResults option indicates, that +the possible values the user may provide will be indicated, as well as the +default value, if one is set. + +The mechanism for validating the answer is defined by an instance of +ezcConsoleQuestionDialogValidator. In the example, a collection validator is +used, which defines a collection of valid values. Beside that, it performs a +case conversion on the user provided result before validating it, if desired. + +Displaying a dialog can either be done directly, by calling +ezcConsoleDialog->display(), or the more convenient way, shown in the example. +The ezcConsoleDialogViewer::displayDialog() method displays the dialog in a +loop, until the user provided a valid value, so that the program can rely on +this. In the example, the user is asked after every performed action, if he +still wants to proceed. If the answer is "n" or "N", the program stops. + +An example run of this application could look like this: :: + + Some action performed... + + Do you want to proceed? (y/n) [y] y + + Some action performed... + + Do you want to proceed? (y/n) [y] + + Some action performed... + + Do you want to proceed? (y/n) [y] n + Goodbye! + + +A very similar yes/no question can be created through convenience method very +easily: + +.. include:: tutorial_example_14_dialog_yesnoquestion.php + :literal: + +The created yes/no question dialog contains a custom question and defaults to +"y", if nothing is selected. In contrast to the last example, the dialog +created here also accepts "yes" and "no" as answers. Both phrases can be used +in any typing, e.g. like "yEs" or "NO". This is made possibly by the +ezcConsoleQuestionDialogMappingValidator, which extends +ezcConsoleQuestionDialogCollectionValidator. The mapping validator allows to +define an arbitrary mapping between the user typed answers and expected ones. +Therefore the dialog still only returns either "y" or "n". + +The second dialog type, provided with ConsoleTools, is the +ezcConsoleMenuDialog. Similar to the ezcConsoleQuestionDialog, it displays a +list of menu items to the user and requires him to choose one of these. An +example for this class looks like this: + +.. include:: tutorial_example_15_dialog_menu.php + :literal: + +Again the dialog is instantiated and some options are tweaked to get the +desired behaviour. The validator in this case receives an array of possible +menu items, while the key represents the identifier and the value contains the +text to be displayed for the item. The second argument is the default value, +chosen if the user simply presses . + +An example run of this program could look like this: :: + + Please choose a possibility: + + 1) Perform some more actions + 2) Perform another action + 0) Quit + + Select: [0] 1 + Performing some more actions... + Please choose a possibility: + + 1) Perform some more actions + 2) Perform another action + 0) Quit + + Select: [0] 2 + Performing some other actions! + Please choose a possibility: + + 1) Perform some more actions + 2) Perform another action + 0) Quit + + Select: [0] + +The character used to divide the identifier and text, as well as the text +indicating that a selection must be done, can be tweaked, too. + +Further information about dialogs can be found in the API documentation of +ezcConsoleDialog, ezcConsoleQuestionDialog and ezcConsoleMenuDialog. + + +.. + Local Variables: + mode: rst + fill-column: 79 + End: + vim: et syn=rst tw=79 diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_autoload.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_autoload.php new file mode 100644 index 0000000..c9387c1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_autoload.php @@ -0,0 +1,20 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_01_output_basic.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_01_output_basic.php new file mode 100644 index 0000000..38c444f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_01_output_basic.php @@ -0,0 +1,11 @@ +formats->info->color = 'blue'; + +$output->outputText( 'Test text in color blue', 'info' ); + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_02_output_advanced.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_02_output_advanced.php new file mode 100644 index 0000000..d9f082c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_02_output_advanced.php @@ -0,0 +1,25 @@ +formats->info->color = 'blue'; + +$output->formats->error->color = 'red'; +$output->formats->error->style = array( 'bold' ); + +$output->formats->fatal->color = 'red'; +$output->formats->fatal->style = array( 'bold', 'underlined' ); +$output->formats->fatal->bgcolor = 'black'; + +$output->outputText( 'This is some standard text ' ); +$output->outputText( 'including some error', 'error' ); +$output->outputText( ' wrapped in standard text.' ); +$output->outputText( "\n" ); + +$output->outputLine( 'This is a fatal error message.', 'fatal' ); + +$output->outputText( 'Test' ); + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_03_output_options.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_03_output_options.php new file mode 100644 index 0000000..2946d4e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_03_output_options.php @@ -0,0 +1,27 @@ +formats->info->color = 'blue'; +$output->formats->info->style = array( 'bold' ); + +$output->setOptions( + array( + 'autobreak' => 78, + 'verbosityLevel' => 3 + ) +); + +$output->outputLine( 'This is a very very long info text. It has so much information in '. + 'it, that it will definitly not fit into 1 line. Therefore, '. + 'ezcConsoleOutput will automatically wrap the line for us.', 'info' ); + +$output->outputLine(); + +$output->outputLine( 'This verbose information will currently not be displayed.', 'info', 10 ); + +$output->outputLine( 'But this verbose information will be displayed.', 'info', 2 ); + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_04_input_basic.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_04_input_basic.php new file mode 100644 index 0000000..04b3e8b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_04_input_basic.php @@ -0,0 +1,32 @@ +registerOption( + new ezcConsoleOption( + 'h', + 'help' + ) +); + +try +{ + $input->process(); +} +catch ( ezcConsoleOptionException $e ) +{ + die( $e->getMessage() ); +} + +if ( $helpOption->value !== false ) +{ + echo "Help requested."; +} +else +{ + echo "No help requested."; +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_05_input_advanced.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_05_input_advanced.php new file mode 100644 index 0000000..fad7a5d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_05_input_advanced.php @@ -0,0 +1,55 @@ +registerOption( new ezcConsoleOption( 'h', 'help' ) ); + +$inputOption = $input->registerOption( + new ezcConsoleOption( + 'i', + 'input', + ezcConsoleInput::TYPE_STRING + ) +); + +$outputOption = $input->registerOption( + new ezcConsoleOption( + 'o', + 'output' + ) +); +$outputOption->type = ezcConsoleInput::TYPE_STRING; + +$inputOption->addDependency( + new ezcConsoleOptionRule( $outputOption ) +); +$outputOption->addDependency( + new ezcConsoleOptionRule( $inputOption ) +); + +try +{ + $input->process(); +} +catch ( ezcConsoleOptionException $e ) +{ + die( $e->getMessage() ); +} + +if ( $helpOption->value === true ) +{ + echo $input->getSynopsis() . "\n"; + foreach ( $input->getOptions() as $option ) + { + echo "-{$option->short}/{$option->long}: {$option->shorthelp}\n"; + } +} +elseif ( $outputOption->value !== false ) +{ + echo "Input: {$inputOption->value}, Output: {$outputOption->value}\n"; + echo "Arguments: " . implode( ", ", $input->getArguments() ) . "\n"; +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_06_progressbar_basic.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_06_progressbar_basic.php new file mode 100644 index 0000000..a1b8baa --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_06_progressbar_basic.php @@ -0,0 +1,19 @@ +advance(); + usleep( mt_rand( 2000, 200000 ) ); +} + +$bar->finish(); + +$output->outputLine(); + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_07_progressbar_advanced.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_07_progressbar_advanced.php new file mode 100644 index 0000000..cba694b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_07_progressbar_advanced.php @@ -0,0 +1,29 @@ +formats->bar->color = 'blue'; +$output->formats->bar->style = array( 'bold' ); + +$options = array( + 'emptyChar' => ' ', + 'barChar' => '-', + 'formatString' => '%fraction%% <' . $output->formatText( '%bar%', 'bar' ) . '> Uploaded %act% / %max% kb', + 'redrawFrequency' => 50, +); + +$bar = new ezcConsoleProgressbar( $output, 1024, $options ); + +for ( $i = 0; $i < 1024; $i++ ) +{ + $bar->advance(); + usleep( mt_rand( 200, 2000 ) ); +} + +$bar->finish(); + +$output->outputLine(); + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_08_statusbar.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_08_statusbar.php new file mode 100644 index 0000000..36f8bd6 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_08_statusbar.php @@ -0,0 +1,27 @@ +formats->success->color = 'green'; +$output->formats->failure->color = 'red'; + +$options = array( + 'successChar' => $output->formatText( '+', 'success' ), + 'failureChar' => $output->formatText( '-', 'failure' ), +); + +$status = new ezcConsoleStatusbar( $output, $options ); + +for ( $i = 0; $i < 120; $i++ ) +{ + $nextStatus = ( bool )mt_rand( 0,1 ); + $status->add( $nextStatus ); + usleep( mt_rand( 200, 2000 ) ); +} + +$output->outputLine(); +$output->outputLine( 'Successes: ' . $status->getSuccessCount() . ', Failures: ' . $status->getFailureCount() ); + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_09_table_basic.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_09_table_basic.php new file mode 100644 index 0000000..098f35d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_09_table_basic.php @@ -0,0 +1,43 @@ +formats->headBorder->color = 'blue'; +$output->formats->normalBorder->color = 'gray'; + +$output->formats->headContent->color = 'blue'; +$output->formats->headContent->style = array( 'bold' ); + +$table = new ezcConsoleTable( $output, 78 ); + +$table->options->defaultBorderFormat = 'normalBorder'; + +$table[0]->borderFormat = 'headBorder'; +$table[0]->format = 'headContent'; +$table[0]->align = ezcConsoleTable::ALIGN_CENTER; + +foreach ( $data as $row => $cells ) +{ + foreach ( $cells as $cell ) + { + $table[$row][]->content = $cell; + } +} + +$output->outputLine( 'eZ components team:' ); +$table->outputTable(); +$output->outputLine(); + + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_10_table_advanced.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_10_table_advanced.php new file mode 100644 index 0000000..d4ae285 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_10_table_advanced.php @@ -0,0 +1,38 @@ +formats->blue->color = 'blue'; +$output->formats->blue->style = array( 'bold' ); +$output->formats->red->color = 'red'; +$output->formats->red->style = array( 'bold' ); +$output->formats->green->color = 'green'; +$output->formats->green->style = array( 'bold' ); + +$colors = array( 'red', 'blue', 'green' ); +$aligns = array( ezcConsoleTable::ALIGN_LEFT, ezcConsoleTable::ALIGN_CENTER, ezcConsoleTable::ALIGN_RIGHT ); + +$table = new ezcConsoleTable( $output, 78 ); + +$table->options->corner = ' '; +$table->options->lineHorizontal = ' '; +$table->options->lineVertical = ' '; +$table->options->widthType = ezcConsoleTable::WIDTH_FIXED; + +for ( $i = 0; $i < 10; $i++ ) +{ + for ( $j = 0; $j < 10; $j++ ) + { + $table[$i][$j]->content = '*'; + $table[$i][$j]->format = $colors[array_rand( $colors )]; + $table[$i][$j]->align = $aligns[array_rand( $aligns )]; + } +} + +$table->outputTable(); +$output->outputLine(); + + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_11_progressmonitor.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_11_progressmonitor.php new file mode 100644 index 0000000..7e5746e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_11_progressmonitor.php @@ -0,0 +1,18 @@ +addEntry( 'ACTION', "Performed action #{$i}." ); +} + +$output->outputLine(); + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_12_input_arguments.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_12_input_arguments.php new file mode 100644 index 0000000..90f577f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_12_input_arguments.php @@ -0,0 +1,48 @@ +registerOption( new ezcConsoleOption( 'h', 'help' ) ); +$helpOption->isHelpOption = true; + +$input->argumentDefinition = new ezcConsoleArguments(); + +$input->argumentDefinition[0] = new ezcConsoleArgument( "source" ); +$input->argumentDefinition[0]->shorthelp = "The source directory."; + +$input->argumentDefinition[1] = new ezcConsoleArgument( "destination" ); +$input->argumentDefinition[1]->mandatory = false; +$input->argumentDefinition[1]->default = './'; + +$input->argumentDefinition[2] = new ezcConsoleArgument( "iterations" ); +$input->argumentDefinition[2]->type = ezcConsoleInput::TYPE_INT; +$input->argumentDefinition[2]->shorthelp = "Number of iterations."; +$input->argumentDefinition[2]->longhelp = "The number of iterations to perform."; + + +try +{ + $input->process(); +} +catch ( ezcConsoleException $e ) +{ + die( $e->getMessage() ); +} + +if ( $helpOption->value === true ) +{ + echo $input->getHelpText( "A simple text program" ); +} +else +{ + echo "Source: {$input->argumentDefinition["source"]->value}\n"; + echo "Destination: {$input->argumentDefinition["destination"]->value}\n"; + echo "Iterations: " . ( $input->argumentDefinition["iterations"]->value === null + ? "not set" + : $input->argumentDefinition["iterations"]->value + ); +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_13_dialog_question.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_13_dialog_question.php new file mode 100644 index 0000000..4ad8c34 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_13_dialog_question.php @@ -0,0 +1,24 @@ +options->text = "Do you want to proceed?"; +$question->options->showResults = true; +$question->options->validator = new ezcConsoleQuestionDialogCollectionValidator( + array( "y", "n" ), + "y", + ezcConsoleQuestionDialogCollectionValidator::CONVERT_LOWER +); + +do +{ + echo "\nSome action performed...\n\n"; +} +while ( ezcConsoleDialogViewer::displayDialog( $question ) !== "n" ); + +echo "Goodbye!\n"; + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_14_dialog_yesnoquestion.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_14_dialog_yesnoquestion.php new file mode 100644 index 0000000..6c8202d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_14_dialog_yesnoquestion.php @@ -0,0 +1,21 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_15_dialog_menu.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_15_dialog_menu.php new file mode 100644 index 0000000..4e01081 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_15_dialog_menu.php @@ -0,0 +1,32 @@ +options = new ezcConsoleMenuDialogOptions(); +$menu->options->text = "Please choose a possibility:\n"; +$menu->options->validator = new ezcConsoleMenuDialogDefaultValidator( + array( + "1" => "Perform some more actions", + "2" => "Perform another action", + "0" => "Quit", + ), + "0" +); + +while ( ( $choice = ezcConsoleDialogViewer::displayDialog( $menu ) ) != 0 ) +{ + switch ( $choice ) + { + case 1: + echo "Performing some more actions...\n"; + break; + case 2: + echo "Performing some other actions!\n"; + break; + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_output_targets.php b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_output_targets.php new file mode 100644 index 0000000..173b2cc --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/ConsoleTools/docs/tutorial_example_output_targets.php @@ -0,0 +1,13 @@ +formats->error->color = 'red'; +$output->formats->error->style = array( 'bold' ); +$output->formats->error->target = ezcConsoleOutput::TARGET_STDERR; + +$output->outputLine( 'Unable to connect to database', 'error' ); + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/DbUnit/ChangeLog.markdown b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/ChangeLog.markdown new file mode 100644 index 0000000..7c07afe --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/ChangeLog.markdown @@ -0,0 +1,22 @@ +DbUnit 1.0 +========== + +This is the list of changes for the DbUnit 1.0 release series. + +DbUnit 1.0.2 +------------ + +* Implemented proper error handling for XML dataset processing. + +DbUnit 1.0.1 +------------ + +* Fixed GH-24: YAML dataset does not respect empty tables. +* Fixed GH-25: YAML dataset only looks at columns in first row instead of entire data set. +* Fixed MySQL dataset to respect empty tables. +* Updated list of dependencies in `package.xml`. + +DbUnit 1.0.0 +------------ + +* Initial release as separate component. diff --git a/typo3conf/ext/phpunit/PEAR/docs/DbUnit/LICENSE b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/LICENSE new file mode 100644 index 0000000..cada96c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/LICENSE @@ -0,0 +1,33 @@ +DbUnit + +Copyright (c) 2002-2011, Sebastian Bergmann . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Sebastian Bergmann nor the names of his + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/BankAccount.php b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/BankAccount.php new file mode 100644 index 0000000..dfb436b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/BankAccount.php @@ -0,0 +1,206 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +class BankAccountException extends RuntimeException {} + +/** + * A bank account. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class BankAccount +{ + /** + * The bank account's balance. + * + * @var float + */ + protected $balance = 0; + + /** + * The bank account's number. + * + * @var float + */ + protected $accountNumber = 0; + + /** + * The PDO connection used to store and retrieve bank account information. + * + * @var PDO + */ + protected $pdo; + + public function __construct($accountNumber, PDO $pdo) + { + $this->accountNumber = $accountNumber; + $this->pdo = $pdo; + + $this->loadAccount(); + } + + /** + * Returns the bank account's balance. + * + * @return float + */ + public function getBalance() + { + return $this->balance; + } + + /** + * Sets the bank account's balance. + * + * @param float $balance + * @throws BankAccountException + */ + protected function setBalance($balance) + { + if ($balance >= 0) { + $this->balance = $balance; + $this->updateAccount(); + } else { + throw new BankAccountException; + } + } + + /** + * Returns the bank account's number. + * + * @return float + */ + public function getAccountNumber() + { + return $this->accountNumber; + } + + /** + * Deposits an amount of money to the bank account. + * + * @param float $balance + * @throws BankAccountException + */ + public function depositMoney($balance) + { + $this->setBalance($this->getBalance() + $balance); + + return $this->getBalance(); + } + + /** + * Withdraws an amount of money from the bank account. + * + * @param float $balance + * @throws BankAccountException + */ + public function withdrawMoney($balance) + { + $this->setBalance($this->getBalance() - $balance); + + return $this->getBalance(); + } + + /** + * Loads account information from the database. + */ + protected function loadAccount() + { + $query = "SELECT * FROM bank_account WHERE account_number = ?"; + + $statement = $this->pdo->prepare($query); + + $statement->execute(array($this->accountNumber)); + + if ($bankAccountInfo = $statement->fetch(PDO::FETCH_ASSOC)) + { + $this->balance = $bankAccountInfo['balance']; + } + else + { + $this->balance = 0; + $this->addAccount(); + } + } + + /** + * Saves account information to the database. + */ + protected function updateAccount() + { + $query = "UPDATE bank_account SET balance = ? WHERE account_number = ?"; + + $statement = $this->pdo->prepare($query); + $statement->execute(array($this->balance, $this->accountNumber)); + } + + /** + * Adds account information to the database. + */ + protected function addAccount() + { + $query = "INSERT INTO bank_account (balance, account_number) VALUES(?, ?)"; + + $statement = $this->pdo->prepare($query); + $statement->execute(array($this->balance, $this->accountNumber)); + } + + static public function createTable(PDO $pdo) + { + $query = " + CREATE TABLE bank_account ( + account_number VARCHAR(17) PRIMARY KEY, + balance DECIMAL(9,2) NOT NULL DEFAULT 0 + ); + "; + + $pdo->query($query); + } +} diff --git a/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/BankAccountDBTest.php b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/BankAccountDBTest.php new file mode 100644 index 0000000..a4f5383 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/BankAccountDBTest.php @@ -0,0 +1,146 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +require_once 'PHPUnit/Extensions/Database/TestCase.php'; +require_once 'PHPUnit/Extensions/Database/DataSet/FlatXmlDataSet.php'; + +require_once 'BankAccount.php'; + +/** + * Tests for the BankAccount class. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class BankAccountDBTest extends PHPUnit_Extensions_Database_TestCase +{ + protected $pdo; + + public function __construct() + { + $this->pdo = new PDO('sqlite::memory:'); + BankAccount::createTable($this->pdo); + } + + /** + * Returns the test database connection. + * + * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection + */ + protected function getConnection() + { + return $this->createDefaultDBConnection($this->pdo, 'sqlite'); + } + + protected function getDataSet() + { + return $this->createFlatXMLDataSet(dirname(__FILE__).'/_files/bank-account-seed.xml'); + } + + public function testNewAccountBalanceIsInitiallyZero() + { + $bank_account = new BankAccount('12345678912345678', $this->pdo); + $this->assertEquals(0, $bank_account->getBalance()); + } + + public function testOldAccountInfoInitiallySet() + { + $bank_account = new BankAccount('15934903649620486', $this->pdo); + $this->assertEquals(100, $bank_account->getBalance()); + $this->assertEquals('15934903649620486', $bank_account->getAccountNumber()); + + $bank_account = new BankAccount('15936487230215067', $this->pdo); + $this->assertEquals(1216, $bank_account->getBalance()); + $this->assertEquals('15936487230215067', $bank_account->getAccountNumber()); + + $bank_account = new BankAccount('12348612357236185', $this->pdo); + $this->assertEquals(89, $bank_account->getBalance()); + $this->assertEquals('12348612357236185', $bank_account->getAccountNumber()); + } + + public function testAccountBalanceDeposits() + { + $bank_account = new BankAccount('15934903649620486', $this->pdo); + $bank_account->depositMoney(100); + + $bank_account = new BankAccount('15936487230215067', $this->pdo); + $bank_account->depositMoney(230); + + $bank_account = new BankAccount('12348612357236185', $this->pdo); + $bank_account->depositMoney(24); + + $xml_dataset = $this->createFlatXMLDataSet(dirname(__FILE__).'/_files/bank-account-after-deposits.xml'); + $this->assertDataSetsEqual($xml_dataset, $this->getConnection()->createDataSet()); + } + + public function testAccountBalanceWithdrawals() + { + $bank_account = new BankAccount('15934903649620486', $this->pdo); + $bank_account->withdrawMoney(100); + + $bank_account = new BankAccount('15936487230215067', $this->pdo); + $bank_account->withdrawMoney(230); + + $bank_account = new BankAccount('12348612357236185', $this->pdo); + $bank_account->withdrawMoney(24); + + $xml_dataset = $this->createFlatXMLDataSet(dirname(__FILE__).'/_files/bank-account-after-withdrawals.xml'); + $this->assertDataSetsEqual($xml_dataset, $this->getConnection()->createDataSet()); + } + + public function testNewAccountCreation() + { + $bank_account = new BankAccount('12345678912345678', $this->pdo); + + $xml_dataset = $this->createFlatXMLDataSet(dirname(__FILE__).'/_files/bank-account-after-new-account.xml'); + $this->assertDataSetsEqual($xml_dataset, $this->getConnection()->createDataSet()); + } + /* + */ +} diff --git a/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/BankAccountDBTestMySQL.php b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/BankAccountDBTestMySQL.php new file mode 100644 index 0000000..9a9aef0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/BankAccountDBTestMySQL.php @@ -0,0 +1,146 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://www.phpunit.de/ + * @since File available since Release 1.0.0 + */ + +require_once 'PHPUnit/Extensions/Database/TestCase.php'; +require_once 'PHPUnit/Extensions/Database/DataSet/FlatXmlDataSet.php'; + +require_once 'BankAccount.php'; + +/** + * Tests for the BankAccount class. + * + * @package DbUnit + * @author Mike Lively + * @copyright 2002-2011 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: 1.0.2 + * @link http://www.phpunit.de/ + * @since Class available since Release 1.0.0 + */ +class BankAccountDBTestMySQL extends PHPUnit_Extensions_Database_TestCase +{ + protected $pdo; + + public function __construct() + { + $this->pdo = new PDO('mysql:host=localhost;dbname=test', 'root', 'selkirk'); + BankAccount::createTable($this->pdo); + } + + /** + * Returns the test database connection. + * + * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection + */ + protected function getConnection() + { + return $this->createDefaultDBConnection($this->pdo, 'test'); + } + + protected function getDataSet() + { + return $this->createFlatXMLDataSet(dirname(__FILE__).'/_files/bank-account-seed.xml'); + } + + public function testNewAccountBalanceIsInitiallyZero() + { + $bank_account = new BankAccount('12345678912345678', $this->pdo); + $this->assertEquals(0, $bank_account->getBalance()); + } + + public function testOldAccountInfoInitiallySet() + { + $bank_account = new BankAccount('15934903649620486', $this->pdo); + $this->assertEquals(100, $bank_account->getBalance()); + $this->assertEquals('15934903649620486', $bank_account->getAccountNumber()); + + $bank_account = new BankAccount('15936487230215067', $this->pdo); + $this->assertEquals(1216, $bank_account->getBalance()); + $this->assertEquals('15936487230215067', $bank_account->getAccountNumber()); + + $bank_account = new BankAccount('12348612357236185', $this->pdo); + $this->assertEquals(89, $bank_account->getBalance()); + $this->assertEquals('12348612357236185', $bank_account->getAccountNumber()); + } + + public function testAccountBalanceDeposits() + { + $bank_account = new BankAccount('15934903649620486', $this->pdo); + $bank_account->depositMoney(100); + + $bank_account = new BankAccount('15936487230215067', $this->pdo); + $bank_account->depositMoney(230); + + $bank_account = new BankAccount('12348612357236185', $this->pdo); + $bank_account->depositMoney(24); + + $xml_dataset = $this->createFlatXMLDataSet(dirname(__FILE__).'/_files/bank-account-after-deposits.xml'); + $this->assertDataSetsEqual($xml_dataset, $this->getConnection()->createDataSet()); + } + + public function testAccountBalanceWithdrawals() + { + $bank_account = new BankAccount('15934903649620486', $this->pdo); + $bank_account->withdrawMoney(100); + + $bank_account = new BankAccount('15936487230215067', $this->pdo); + $bank_account->withdrawMoney(230); + + $bank_account = new BankAccount('12348612357236185', $this->pdo); + $bank_account->withdrawMoney(24); + + $xml_dataset = $this->createFlatXMLDataSet(dirname(__FILE__).'/_files/bank-account-after-withdrawals.xml'); + $this->assertDataSetsEqual($xml_dataset, $this->getConnection()->createDataSet()); + } + + public function testNewAccountCreation() + { + $bank_account = new BankAccount('12345678912345678', $this->pdo); + + $xml_dataset = $this->createFlatXMLDataSet(dirname(__FILE__).'/_files/bank-account-after-new-account.xml'); + $this->assertDataSetsEqual($xml_dataset, $this->getConnection()->createDataSet()); + } + /* + */ +} diff --git a/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-after-deposits.xml b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-after-deposits.xml new file mode 100644 index 0000000..ab4f178 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-after-deposits.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-after-new-account.xml b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-after-new-account.xml new file mode 100644 index 0000000..67517ab --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-after-new-account.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-after-withdrawals.xml b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-after-withdrawals.xml new file mode 100644 index 0000000..bc1c0b6 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-after-withdrawals.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-seed.xml b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-seed.xml new file mode 100644 index 0000000..deb2eb9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-seed.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/PEAR/INSTALL b/typo3conf/ext/phpunit/PEAR/docs/PEAR/INSTALL new file mode 100644 index 0000000..965e945 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/PEAR/INSTALL @@ -0,0 +1,54 @@ +PEAR - The PEAR Installer +========================= +Installing the PEAR Installer. + +You should install PEAR on a local development machine first. Installing +PEAR on a remote production machine should only be done after you are +familiar with PEAR and have tested code using PEAR on your development +machine. + +There are two methods of installing PEAR + - PEAR bundled in PHP + - go-pear + +We will first examine how to install PEAR that is bundled with PHP. + +Microsoft Windows +================= +If you are running PHP 5.2.0 or newer, simply download and +run the windows installer (.msi) and PEAR can be automatically +installed. + +Otherwise, for older PHP versions, download the .zip of windows, +there is a script included with your PHP distribution that is called +"go-pear". You must open a command box in order to run it. Click +"start" then click "Run..." and type "cmd.exe" to open a command box. +Use "cd" to change directory to the location of PHP where you unzipped it, +and run the go-pear command. + +Unix +==== +When compiling PHP from source, you simply need to include the +--with-pear directive on the "./configure" command. This is "on" +by default in most PHP versions, but it doesn't hurt to list it +explicitly. You should also consider enabling the zlib extension via +--enable-zlib, so that the PEAR installer will be able to handle gzipped +files (i.e. smaller package files for faster downloads). Later, when you +run "make install" to install PHP itself, part of the process will be +prompts that ask you where you want PEAR to be installed. + +go-pear +======= +For users who cannot perform the above steps, or who wish to obtain the +latest PEAR with a slightly higher risk of failure, use go-pear. go-pear +is obtained by downloading http://pear.php.net/go-pear and saving it as go-pear.php. +After downloading, simply run "php go-pear.php" or open it in a web browser +(windows only) to download and install PEAR. + +You can always ask general installation questions on pear-general@lists.php.net, +a public mailing list devoted to support for PEAR packages and installation- +related issues. + +Happy PHPing, we hope PEAR will be a great tool for your development work! + +$Id: INSTALL 299813 2010-05-26 19:50:00Z dufuz $ \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/PEAR/LICENSE b/typo3conf/ext/phpunit/PEAR/docs/PEAR/LICENSE new file mode 100644 index 0000000..a00a242 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/PEAR/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 1997-2009, + Stig Bakken , + Gregory Beaver , + Helgi Þormar Þorbjörnsson , + Tomas V.V.Cox , + Martin Jansen . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/typo3conf/ext/phpunit/PEAR/docs/PEAR/README b/typo3conf/ext/phpunit/PEAR/docs/PEAR/README new file mode 100644 index 0000000..446b93a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/PEAR/README @@ -0,0 +1,32 @@ +PEAR - The PEAR Installer +========================= + +What is the PEAR Installer? What is PEAR? + +PEAR is the PHP Extension and Application Repository, found at +http://pear.php.net. The PEAR Installer is this software, which +contains executable files and PHP code that is used to download +and install PEAR code from pear.php.net. + +PEAR contains useful software libraries and applications such as +MDB2 (database abstraction), HTML_QuickForm (HTML forms management), +PhpDocumentor (auto-documentation generator), DB_DataObject +(Data Access Abstraction), and many hundreds more. Browse all +available packages at http://pear.php.net, the list is constantly +growing and updating to reflect improvements in the PHP language. + +DOCUMENTATION +============= + +Documentation for PEAR can be found at http://pear.php.net/manual/. +Installation documentation can be found in the INSTALL file included +in this tarball. + +WARNING: DO NOT RUN PEAR WITHOUT INSTALLING IT - if you downloaded this +tarball manually, you MUST install it. Read the instructions in INSTALL +prior to use. + + +Happy PHPing, we hope PEAR will be a great tool for your development work! + +$Id: README 299813 2010-05-26 19:50:00Z dufuz $ \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/PHPUnit/ChangeLog.markdown b/typo3conf/ext/phpunit/PEAR/docs/PHPUnit/ChangeLog.markdown new file mode 100644 index 0000000..85298d7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/PHPUnit/ChangeLog.markdown @@ -0,0 +1,150 @@ +PHPUnit 3.5 +=========== + +This is the list of changes for the PHPUnit 3.5 release series. + +PHPUnit 3.5.14 +-------------- + +* Fixed GH-222: `assertAttribute*()` is too strict. +* Fixed grouping of TestDox messages. Test method names should only be grouped if they are part of a sequence, starting with the initial test method not ending in a number. +* `stream_resolve_include_path()` is now used when available. + +PHPUnit 3.5.13 +-------------- + +* The `--debug` switch is now "public" (listed in `--help`). + +PHPUnit 3.5.12 +-------------- + +* Fixed GH-14: Weird `RuntimeException` when running test suite with process isolation. +* Fixed GH-27: Process isolation does not work on Windows 7 x64. +* Fixed GH-41: Process isolation on Windows does not work. +* Fixed GH-147: Parse error when using process isolation on Windows. + +PHPUnit 3.5.11 +-------------- + +* Fixed GH-127: PHPUnit does not report errors in XML configuration files. +* Fixed an issue with ticket listeners related to tests that use data providers. +* Updated list of dependencies in `package.xml` and added missing runtime checks for optional dependencies. + +PHPUnit 3.5.10 +-------------- + +* Fixed GH-71: `PHPUnit_Framework_TestSuite::addTestFile()` has problems identifying the correct test suite. +* Fixed GH-120: Printer class does not handle "file does not exist" problems correctly. +* Fixed GH-125: Work around [PHP bug #47987](http://bugs.php.net/bug.php?id=47987). + +PHPUnit 3.5.9 +------------- + +* Fixed GH-17: Process Isolation breaks for global objects that implement the `Serializable` interface. +* Fixed GH-64: `./` added to path to test when using PHPUnit on Windows terminal. +* Fixed GH-104: Bootstrap must be relative to the current directory. + +PHPUnit 3.5.8 +------------- + +* Fixed GH-84: If no assertions are made the code should not be marked as covered. +* Fixed GH-115: Make most of the attributes in `PHPUnit_Framework_TestCase` private. + +PHPUnit 3.5.7 +------------- + +* Implemented GH-103: Improved handling of deprecated PHPUnit features. +* Fixed GH-100: `assertSame()` does not give useful output on misordered arrays. +* Fixed GH-105: Backup of static attributes causes memory exhaustion. +* The TextUI test runner now prints the normal progress output in verbose mode. + +PHPUnit 3.5.6 +------------- + +* Fixed GH-87: Fatal error when calling `isPublic()` on dynamically created variable. +* Properly marked `assertType()` and `assertNotType()` as well as `assertAttributeType()` and `assertAttributeNotType()` as deprecated. These assertions will removed in PHPUnit 3.6 and should no longer be used. `assertInternalType()` should be used for asserting internal types such as `integer` or `string` whereas `assertInstanceOf()` should be used for asserting that an object is an instance of a specified class or interface. + +PHPUnit 3.5.5 +------------- + +* Added support for `getMockForAbstractClass()` to the mock builder API. + +PHPUnit 3.5.4 +------------- + +* Added a ticket listener that interacts with the Trac issue API. +* Added support for `E_USER_NOTICE` and `E_USER_WARNING` to `PHPUnit_Framework_Error_Notice` and `PHPUnit_Framework_Error_Warning`, respectively. +* Refactored test dependency handling (required for a bugfix in `PHPUnit_Selenium`). +* Fixed `--stop-on-failure`. + +PHPUnit 3.5.3 +------------- + +* Fixed GH-13: Result XML inconsistent when data provider returns empty array or does not exist. +* Fixed the skeleton generator for tested classes. +* Strict mode is now compatible with process isolation. +* Worked around http://bugs.php.net/bug.php?id=52911 to make process isolation work on Windows. + +PHPUnit 3.5.2 +------------- + +* Tests that are incomplete or skipped no longer yield code coverage in strict mode. +* Fixed GH-34: Bogus bootstrap file raises cryptic error. + +PHPUnit 3.5.1 +------------- + +* Fixed GH-30: `--repeat` option does not work. +* Fixed GH-47: Failure message ignored in `assertSelectCount()`. +* Fixed GH-48: Remove strict incomplete duplication. + +PHPUnit 3.5.0 +------------- + +* Implemented TRAC-834: Refactor collection, processing, and rendering of code coverage information using the [PHP_CodeCoverage](http://github.com/sebastianbergmann/php-code-coverage) component. +* Implemented TRAC-948: Add D-BUS test listener. +* Implemented TRAC-967: Only populate whitelist when code coverage is used. +* Implemented TRAC-985: Sort arrays before diff. +* Implemented TRAC-1033: Supplement commandline option `--stop-on-error` and friends. +* Implemented TRAC-1038: Add `assertInstanceOf()`, `assertAttributeInstanceOf()`, `assertNotInstanceOf()`, and `assertAttributeNotInstanceOf()` as well as `assertInternalType()`, `assertAttributeInternalType()`, `assertNotInternalType()`, and `assertAttributeNotInternalType()`. +* Implemented TRAC-1039: Added support for `regexpi:` matcher to Selenium RC driver. +* Implemented TRAC-1078: Added support for setting superglobals via the XML configuration file. +* Added support for mocking/stubbing of static methods. This requires PHP 5.3 and late static binding. +* Added `assertStringMatchesFormat()` and `assertStringNotMatchesFormat()` as well as `assertStringMatchesFormatFile()` and `assertStringNotMatchesFormatFile()` for `EXPECTF`-like (`run-tests.php`) format string matching. +* Added `assertEmpty()` and `assertNotEmpty()` as well as `assertAttributeEmpty()` and `assertAttributeNotEmpty()`. +* Added the `@expectedExceptionCode` and `@expectedExceptionMessage` annotations. +* Added support for the [XML format of mysqldump](http://dev.mysql.com/doc/refman/5.1/en/mysqldump.html#option_mysqldump_xml) to the database extension. +* Added the `` element to the `` section of the XML configuration file. +* Added the `verbose` attribute to the `` element of the XML configuration file. +* Added a ticket listener that interacts with the GitHub issue API. +* Added a ticket listener that interacts with the GoogleCode issue API. +* Added a test listener that uses [XHProf](http://mirror.facebook.net/facebook/xhprof/doc.html) to profile the tested code. +* Added the `--strict` switch to mark tests that perform no assertions as incomplete. +* The paths in the XML configuration file can now be relative to the directory that contains the XML configuration file. +* The `@author` annotation is now an alias for `@group` allowing to filter tests based on their authors. +* The `PHPUnit_Extensions_SeleniumTestCase::$autoStop` flag has been removed, please start Selenium RC with `-browserSessionReuse` instead. +* The `--log-metrics` and `--log-pmd` switches have been removed. Their functionality has been or will be merged into [PHP_Depend](http://pdepend.org/) and [PHPMD](http://phpmd.org/). Details can be found [here](http://sebastian-bergmann.de/archives/744-On-PHPUnit-and-Software-Metrics.html). +* The `--ansi` switch has been removed, please use `--colors` instead. +* The `--coverage-source` switch has been removed. +* The `--coverage-xml` switch has been removed, please use `--coverage-clover` instead. +* The `--log-graphviz` switch has been removed. +* The `--log-xml` switch has been removed, please use `--log-junit` instead. +* The `--report` switch has been removed, please use `--coverage-html` instead. +* The `--skeleton` switch has been removed, please use `--skeleton-test` instead. +* The `TestListener` implementation that logs to [PEAR::Log](http://pear.php.net/package/Log) sinks has been removed. +* The test database functionality has been removed. +* The shared fixture functionality has been removed. +* `PHPUnit_Extensions_PerformanceTestCase` has been removed. +* `PHPUnit_Extensions_TicketListener_Trac` has been removed. +* The `PHPUnit_Extensions_Story_TestCase` functionality has been deprecated. +* Replaced `PHPUnit_Framework_MockObject` with the [PHPUnit_MockObject](http://github.com/sebastianbergmann/phpunit-mock-objects) component. +* Replaced `PHPUnit_Extensions_Database_TestCase` with the [DbUnit](http://github.com/sebastianbergmann/dbunit) component. +* Replaced `PHPUnit_Extensions_SeleniumTestCase` with the [PHPUnit_Selenium](http://github.com/sebastianbergmann/phpunit-selenium) component. +* Replaced `PHPUnit_Util_FilterIterator` with the [PHP_FileIterator](http://github.com/sebastianbergmann/php-file-iterator) component. +* Replaced `PHPUnit_Util_Template` with the [Text_Template](http://github.com/sebastianbergmann/php-text-template) component. +* Replaced `PHPUnit_Util_Timer` with the [PHP_Timer](http://github.com/sebastianbergmann/php-timer) component. +* Fixed TRAC-1068: `assertSame()` on two floats does not print the error message. +* Fixed GH-7: Code paths that create a `PHPUnit_Framework_Warning` end up serializing/unserializing globals unconditionally. +* PHPUnit now requires PHP 5.2.7 (or later) but PHP 5.3.3 (or later) is highly recommended. +* PHPUnit now uses an autoloader to load its classes. If the tested code requires an autoloader, use `spl_autoload_register()` to register it. +* `PHPUnit/Framework.php` should no longer be included by test code. If needed, include `PHPUnit/Autoload.php` to make PHPUnit's autoloader available. diff --git a/typo3conf/ext/phpunit/PEAR/docs/PHPUnit/LICENSE b/typo3conf/ext/phpunit/PEAR/docs/PHPUnit/LICENSE new file mode 100644 index 0000000..0bd351b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/PHPUnit/LICENSE @@ -0,0 +1,33 @@ +PHPUnit + +Copyright (c) 2002-2011, Sebastian Bergmann . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Sebastian Bergmann nor the names of his + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/typo3conf/ext/phpunit/PEAR/docs/PHPUnit/README.markdown b/typo3conf/ext/phpunit/PEAR/docs/PHPUnit/README.markdown new file mode 100644 index 0000000..56097df --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/PHPUnit/README.markdown @@ -0,0 +1,86 @@ +PHPUnit +======= + +PHPUnit is the de-facto standard for unit testing in PHP projects. It provides both a framework that makes the writing of tests easy as well as the functionality to easily run the tests and analyse their results. + +Installation +------------ + +PHPUnit should be installed using the [PEAR Installer](http://pear.php.net/). This installer is the backbone of PEAR, which provides a distribution system for PHP packages, and is shipped with every release of PHP since version 4.3.0. + +The PEAR channel (`pear.phpunit.de`) that is used to distribute PHPUnit needs to be registered with the local PEAR environment. Furthermore, components that PHPUnit depends upon are hosted on additional PEAR channels. + + pear channel-discover pear.phpunit.de + pear channel-discover components.ez.no + pear channel-discover pear.symfony-project.com + +This has to be done only once. Now the PEAR Installer can be used to install packages from the PHPUnit channel: + + pear install phpunit/PHPUnit + +After the installation you can find the PHPUnit source files inside your local PEAR directory; the path is usually `/usr/lib/php/PHPUnit`. + +Documentation +------------- + +The documentation for PHPUnit is available in different formats: + +* [English, multiple HTML files](http://www.phpunit.de/manual/3.5/en/index.html) +* [English, single HTML file](http://www.phpunit.de/manual/3.5/en/phpunit-book.html) +* [English, PDF](http://www.phpunit.de/manual/3.5/en/phpunit-book.pdf) +* [English, ePub](http://www.phpunit.de/manual/3.5/en/phpunit-book.epub) +* [Japanese, multiple HTML files](http://www.phpunit.de/manual/3.5/ja/index.html) +* [Japanese, single HTML file](http://www.phpunit.de/manual/3.5/ja/phpunit-book.html) +* [Japanese, PDF](http://www.phpunit.de/manual/3.5/ja/phpunit-book.pdf) +* [Japanese, ePub](http://www.phpunit.de/manual/3.5/ja/phpunit-book.epub) + +Mailing Lists +------------- + +* Send an email to `user-subscribe@phpunit.de` to subscribe to the `phpunit-user` mailing list. This is a medium volume list for general PHPUnit support; ask PHPUnit questions here. +* Send an email to `dev-subscribe@phpunit.de` to subscribe to the `phpunit-dev` mailing list. This is a low volume list for those who want to help out with the development of PHPUnit. + +IRC +--- + +The [#phpunit channel on the Freenode IRC network](irc://freenode.net/phpunit) is a place to chat about PHPUnit. + +Using PHPUnit From a Git Checkout +--------------------------------- + +The following commands can be used to perform the initial checkout of PHPUnit and its dependencies from Git: + + mkdir phpunit && cd phpunit + git clone git://github.com/sebastianbergmann/phpunit.git + git clone git://github.com/sebastianbergmann/dbunit.git + git clone git://github.com/sebastianbergmann/php-file-iterator.git + git clone git://github.com/sebastianbergmann/php-text-template.git + git clone git://github.com/sebastianbergmann/php-code-coverage.git + git clone git://github.com/sebastianbergmann/php-token-stream.git + git clone git://github.com/sebastianbergmann/php-timer.git + git clone git://github.com/sebastianbergmann/phpunit-mock-objects.git + git clone git://github.com/sebastianbergmann/phpunit-selenium.git + +The `dbunit`, `php-code-coverage`, `php-file-iterator`, `php-text-template`, `php-timer`, `php-token-stream`, `phpunit`, `phpunit-mock-objects`, and `phpunit-selenium` directories need to be added to the `include_path`. + +The `phpunit/phpunit.php` script can be used to invoke the PHPUnit test runner. + +The following commands can be used to check out the appropriate branches for PHPUnit 3.5: + + cd phpunit && git checkout 3.5 && cd .. + cd dbunit && git checkout 1.0 && cd .. + cd php-file-iterator && git checkout 1.2 && cd .. + cd php-code-coverage && git checkout 1.0 && cd .. + cd php-token-stream && git checkout 1.0 && cd .. + cd phpunit-mock-objects && git checkout 1.0 && cd .. + cd phpunit-selenium && git checkout 1.0 && cd .. + +The following commands can be used to check out the appropriate branches for PHPUnit 3.6: + + cd phpunit && git checkout master && cd .. + cd dbunit && git checkout master && cd .. + cd php-file-iterator && git checkout master && cd .. + cd php-code-coverage && git checkout master && cd .. + cd php-token-stream && git checkout master && cd .. + cd phpunit-mock-objects && git checkout master && cd .. + cd phpunit-selenium && git checkout master && cd .. diff --git a/typo3conf/ext/phpunit/PEAR/docs/PHPUnit_MockObject/ChangeLog.markdown b/typo3conf/ext/phpunit/PEAR/docs/PHPUnit_MockObject/ChangeLog.markdown new file mode 100644 index 0000000..1de4e04 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/PHPUnit_MockObject/ChangeLog.markdown @@ -0,0 +1,57 @@ +PHPUnit_MockObject 1.0 +====================== + +This is the list of changes for the PHPUnit_MockObject 1.0 release series. + +PHPUnit_MockObject 1.0.9 +------------------------ + +* Fixed GH-50: Error when trying to mock `isset()` or `echo()` methods. +* Mocking nonexistent classes in a namespace is now possible. + +PHPUnit_MockObject 1.0.8 +------------------------ + +* The blacklist of uncloneable classes did not work for classes that extend an uncloneable class. +* Updated list of dependencies in `package.xml`. + +PHPUnit_MockObject 1.0.7 +------------------------ + +* Fixed GH-38: Cannot mock methods that return a reference. + +PHPUnit_MockObject 1.0.6 +------------------------ + +* Fixed GH-35: Mocking undeclared methods impossible since 1.0.4. + +PHPUnit_MockObject 1.0.5 +------------------------ + +* Fixed GH-34: Mocking methods with variable parameter count impossible since 1.0.4. + +PHPUnit_MockObject 1.0.4 +------------------------ + +* Fixed GH-3: `returnCallback()` does not work for parameters that are passed by reference. + +PHPUnit_MockObject 1.0.3 +------------------------ + +* Added support for `getMockForAbstractClass()` to the Mock Builder API. + +PHPUnit_MockObject 1.0.2 +------------------------ + +* Fixed GH-27: Inconsistencies in template for mock classes. +* Improved fix for type hinting bug in `PHPUnit_Framework_MockObject_Generator::generateMock()`. + +PHPUnit_MockObject 1.0.1 +------------------------ + +* Fixed type hinting bug in `PHPUnit_Framework_MockObject_Generator::generateMock()`. + +PHPUnit_MockObject 1.0.0 +------------------------ + +* Initial release as separate component. diff --git a/typo3conf/ext/phpunit/PEAR/docs/PHPUnit_MockObject/LICENSE b/typo3conf/ext/phpunit/PEAR/docs/PHPUnit_MockObject/LICENSE new file mode 100644 index 0000000..5be611b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/PHPUnit_MockObject/LICENSE @@ -0,0 +1,33 @@ +PHPUnit_MockObject + +Copyright (c) 2002-2011, Sebastian Bergmann . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Sebastian Bergmann nor the names of his + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/typo3conf/ext/phpunit/PEAR/docs/PHPUnit_Selenium/ChangeLog.markdown b/typo3conf/ext/phpunit/PEAR/docs/PHPUnit_Selenium/ChangeLog.markdown new file mode 100644 index 0000000..d754822 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/PHPUnit_Selenium/ChangeLog.markdown @@ -0,0 +1,25 @@ +PHPUnit_Selenium 1.0 +==================== + +This is the list of changes for the PHPUnit_Selenium 1.0 release series. + +PHPUnit_Selenium 1.0.3 +---------------------- + +* Added support for a `$message` parameter on `assertTrue()` and `assertFalse()` on `SeleniumTestCase`. +* Moved `@method` declaration from method comment into class comment to enable code completion in IDE. + +PHPUnit_Selenium 1.0.2 +---------------------- + +* Updated for PHPUnit 3.5.8. + +PHPUnit_Selenium 1.0.1 +---------------------- + +* Handle test dependencies correctly. + +PHPUnit_Selenium 1.0.0 +---------------------- + +* Initial release as separate component. diff --git a/typo3conf/ext/phpunit/PEAR/docs/PHPUnit_Selenium/LICENSE b/typo3conf/ext/phpunit/PEAR/docs/PHPUnit_Selenium/LICENSE new file mode 100644 index 0000000..cf7774f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/PHPUnit_Selenium/LICENSE @@ -0,0 +1,33 @@ +PHPUnit_Selenium + +Copyright (c) 2002-2011, Sebastian Bergmann . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Sebastian Bergmann nor the names of his + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/typo3conf/ext/phpunit/PEAR/docs/PHP_CodeCoverage/ChangeLog.markdown b/typo3conf/ext/phpunit/PEAR/docs/PHP_CodeCoverage/ChangeLog.markdown new file mode 100644 index 0000000..c412ecc --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/PHP_CodeCoverage/ChangeLog.markdown @@ -0,0 +1,38 @@ +PHP_CodeCoverage 1.0 +==================== + +This is the list of changes for the PHP_CodeCoverage 1.0 release series. + +PHP_CodeCoverage 1.0.4 +---------------------- + +* Fixed an issue where `mkdir()` was called with a wrong argument. +* Updated list of dependencies in `package.xml`. + +PHP_CodeCoverage 1.0.3 +---------------------- + +* Fixed GH-32: `//@codeCoverageIgnore*` (no leading space) no longer works. +* Fixed a bug in `PHP_CodeCoverage_Report_HTML_Node_File::getNumClasses()`. +* Abstract methods are now excluded from code coverage statistics. +* When the directory to which the Clover XML logfile is to be written does not exist it is created. +* Updated bundled RGraph library to version 2010-12-24. +* Updated bundled YUI library to version 2.8.2r1. + +PHP_CodeCoverage 1.0.2 +---------------------- + +* Fixed the `version_compare()` check for Xdebug 2.2. + +PHP_CodeCoverage 1.0.1 +---------------------- + +* Covered lines of uncovered files are now correctly marked as uncovered. +* Fixed the detection of uncovered files. +* A warning is now printed when Xdebug 2.2 (or later) is used and `xdebug.coverage_enable=0` is set. +* Various minor performance optimizations. + +PHP_CodeCoverage 1.0.0 +---------------------- + +* Initial release. diff --git a/typo3conf/ext/phpunit/PEAR/docs/PHP_CodeCoverage/LICENSE b/typo3conf/ext/phpunit/PEAR/docs/PHP_CodeCoverage/LICENSE new file mode 100644 index 0000000..ecf094f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/PHP_CodeCoverage/LICENSE @@ -0,0 +1,33 @@ +PHP_CodeCoverage + +Copyright (c) 2009-2011, Sebastian Bergmann . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Sebastian Bergmann nor the names of his + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/generate.sh b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/generate.sh new file mode 100644 index 0000000..173d87c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/generate.sh @@ -0,0 +1,8 @@ +#!/bin/sh +(cd ..; tar czf docs/arch.tgz "{arch}") +rm -Rf "../{arch}" +rm -Rf ./html +mkdir -p ./html +phpdoc --directory ../Structures,./tutorials --target ./html --title "Structures_Graph Documentation" --output "HTML:frames" --defaultpackagename structures_graph --defaultcategoryname structures --pear +(cd ..; tar --absolute-names -xzf docs/arch.tgz) +#rm arch.tgz diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph.html new file mode 100644 index 0000000..00ec0bc --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph.html @@ -0,0 +1,243 @@ + + + + + + Docs For Class Structures_Graph + + + + +

    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html new file mode 100644 index 0000000..0197946 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html @@ -0,0 +1,105 @@ + + + + + + Docs For Class Structures_Graph_Manipulator_AcyclicTest + + + + +
    +

    Class Structures_Graph_Manipulator_AcyclicTest

    + + +
    +
    Description
    + +
    + +

    The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator which tests whether a graph contains a cycle.

    +

    The definition of an acyclic graph used in this manipulator is that of a DAG. The graph must be directed, or else it is considered cyclic, even when there are no arcs.

    + +

    + Located in /Structures/Graph/Manipulator/AcyclicTest.php (line 55) +

    + + +
    
    +	
    +			
    +
    + + + + +
    +
    Method Summary
    + +
    +
    + +
    + boolean + isAcyclic + (mixed &$graph) +
    +
    +
    +
    + + + +
    +
    Methods
    + +
    + + +
    + +
    + isAcyclic (line 126) +
    + + +

    isAcyclic returns true if a graph contains no cycles, false otherwise.

    +
      +
    • return: true iff graph is acyclic
    • +
    • access: public
    • +
    + +
    + boolean + + isAcyclic + + (mixed &$graph) +
    + + + +
    + +
    +
    + +

    + Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by phpDocumentor 1.2.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.html new file mode 100644 index 0000000..6db747b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.html @@ -0,0 +1,107 @@ + + + + + + Docs For Class Structures_Graph_Manipulator_TopologicalSorter + + + + +
    +

    Class Structures_Graph_Manipulator_TopologicalSorter

    + + +
    +
    Description
    + +
    + +

    The Structures_Graph_Manipulator_TopologicalSorter is a manipulator which is able to return the set of nodes in a graph, sorted by topological order.

    +

    A graph may only be sorted topologically iff it's a DAG. You can test it with the Structures_Graph_Manipulator_AcyclicTest.

    + +

    + Located in /Structures/Graph/Manipulator/TopologicalSorter.php (line 58) +

    + + +
    
    +	
    +			
    +
    + + + + +
    +
    Method Summary
    + +
    +
    + +
    + array + sort + (mixed &$graph) +
    +
    +
    +
    + + + +
    +
    Methods
    + +
    + + +
    + +
    + sort (line 133) +
    + + +

    sort returns the graph's nodes, sorted by topological order.

    +

    The result is an array with as many entries as topological levels. Each entry in this array is an array of nodes within the given topological level.

    +
      +
    • return: The graph's nodes, sorted by topological order.
    • +
    • access: public
    • +
    + +
    + array + + sort + + (mixed &$graph) +
    + + + +
    + +
    +
    + +

    + Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by phpDocumentor 1.2.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Node.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Node.html new file mode 100644 index 0000000..43922b3 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Node.html @@ -0,0 +1,549 @@ + + + + + + Docs For Class Structures_Graph_Node + + + + +
    +

    Class Structures_Graph_Node

    + + +
    +
    Description
    + +
    + +

    The Structures_Graph_Node class represents a Node that can be member of a graph node set.

    +

    A graph node can contain data. Under this API, the node contains default data, and key index data. It behaves, thus, both as a regular data node, and as a dictionary (or associative array) node.

    Regular data is accessed via getData and setData. Key indexed data is accessed via getMetadata and setMetadata.

    + +

    + Located in /Structures/Graph/Node.php (line 57) +

    + + +
    
    +	
    +			
    +
    + + + + +
    +
    Method Summary
    + +
    +
    + +
    + Structures_Graph_Node + Structures_Graph_Node + () +
    + +
    + boolean + connectsTo + (mixed &$target) +
    + +
    + void + connectTo + (Structures_Graph &$destinationNode) +
    + +
    + mixed + &getData + () +
    + + + +
    + mixed + &getMetadata + (string $key, [boolean $nullIfNonexistent = false]) +
    + +
    + array + getNeighbours + () +
    + +
    + integer + inDegree + () +
    + +
    + boolean + metadataKeyExists + (string $key) +
    + +
    + integer + outDegree + () +
    + +
    + mixed + setData + (mixed $data) +
    + +
    + void + setGraph + (Structures_Graph &$graph) +
    + +
    + void + setMetadata + (string $key, mixed $data) +
    + +
    + void + unsetMetadata + (string $key) +
    +
    +
    +
    + + + +
    +
    Methods
    + +
    + + +
    + +
    + Constructor Structures_Graph_Node (line 78) +
    + + +

    Constructor

    +
      +
    • access: public
    • +
    + +
    + Structures_Graph_Node + + Structures_Graph_Node + + () +
    + + + +
    + +
    + +
    + connectsTo (line 275) +
    + + +

    Test wether this node has an arc to the target node

    +
      +
    • return: True if the two nodes are connected
    • +
    • access: public
    • +
    + +
    + boolean + + connectsTo + + (mixed &$target) +
    + + + +
    + +
    + +
    + connectTo (line 236) +
    + + +

    Connect this node to another one.

    +

    If the graph is not directed, the reverse arc, connecting $destinationNode to $this is also created.

    +
      +
    • access: public
    • +
    + +
    + void + + connectTo + + (Structures_Graph &$destinationNode) +
    + + + + +
    + +
    + +
    + getData (line 119) +
    + + +

    Node data getter.

    +

    Each graph node can contain a reference to one variable. This is the getter for that reference.

    +
      +
    • return: Data stored in node
    • +
    • access: public
    • +
    + +
    + mixed + + &getData + + () +
    + + + +
    + +
    + +
    + getGraph (line 90) +
    + + +

    Node graph getter

    +
      +
    • return: Graph where node is stored
    • +
    • access: public
    • +
    + +
    + Structures_Graph + + &getGraph + + () +
    + + + +
    + +
    + +
    + getMetadata (line 171) +
    + + +

    Node metadata getter

    +

    Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an associative array or in a dictionary. This method gets the data under the given key. If the key does not exist, an error will be thrown, so testing using metadataKeyExists might be needed.

    + + +
    + mixed + + &getMetadata + + (string $key, [boolean $nullIfNonexistent = false]) +
    + +
      +
    • + string + $key: Key
    • +
    • + boolean + $nullIfNonexistent: nullIfNonexistent (defaults to false).
    • +
    + + +
    + +
    + +
    + getNeighbours (line 262) +
    + + +

    Return nodes connected to this one.

    +
      +
    • return: Array of nodes
    • +
    • access: public
    • +
    + +
    + array + + getNeighbours + + () +
    + + + +
    + +
    + +
    + inDegree (line 309) +
    + + +

    Calculate the in degree of the node.

    +

    The indegree for a node is the number of arcs entering the node. For non directed graphs, the indegree is equal to the outdegree.

    +
      +
    • return: In degree of the node
    • +
    • access: public
    • +
    + +
    + integer + + inDegree + + () +
    + + + +
    + +
    + +
    + metadataKeyExists (line 151) +
    + + +

    Test for existence of metadata under a given key.

    +

    Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an associative array or in a dictionary. This method tests whether a given metadata key exists for this node.

    +
      +
    • access: public
    • +
    + +
    + boolean + + metadataKeyExists + + (string $key) +
    + +
      +
    • + string + $key: Key to test
    • +
    + + +
    + +
    + +
    + outDegree (line 333) +
    + + +

    Calculate the out degree of the node.

    +

    The outdegree for a node is the number of arcs exiting the node. For non directed graphs, the outdegree is always equal to the indegree.

    +
      +
    • return: Out degree of the node
    • +
    • access: public
    • +
    + +
    + integer + + outDegree + + () +
    + + + +
    + +
    + +
    + setData (line 134) +
    + + +

    Node data setter

    +

    Each graph node can contain a reference to one variable. This is the setter for that reference.

    +
      +
    • return: Data to store in node
    • +
    • access: public
    • +
    + +
    + mixed + + setData + + (mixed $data) +
    + + + +
    + +
    + +
    + setGraph (line 104) +
    + + +

    Node graph setter. This method should not be called directly. Use Graph::addNode instead.

    + + +
    + void + + setGraph + + (Structures_Graph &$graph) +
    + + + + +
    + +
    + +
    + setMetadata (line 214) +
    + + +

    Node metadata setter

    +

    Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an associative array or in a dictionary. This method stores data under the given key. If the key already exists, previously stored data is discarded.

    +
      +
    • access: public
    • +
    + +
    + void + + setMetadata + + (string $key, mixed $data) +
    + +
      +
    • + string + $key: Key
    • +
    • + mixed + $data: Data
    • +
    + + +
    + +
    + +
    + unsetMetadata (line 196) +
    + + +

    Delete metadata by key

    +

    Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an associative array or in a dictionary. This method removes any data that might be stored under the provided key. If the key does not exist, no error is thrown, so it is safe using this method without testing for key existence.

    +
      +
    • access: public
    • +
    + +
    + void + + unsetMetadata + + (string $key) +
    + +
      +
    • + string + $key: Key
    • +
    + + +
    + +
    +
    + +

    + Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by phpDocumentor 1.2.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Manipulator_AcyclicTest_php.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Manipulator_AcyclicTest_php.html new file mode 100644 index 0000000..6834ae0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Manipulator_AcyclicTest_php.html @@ -0,0 +1,119 @@ + + + + + + Docs for page AcyclicTest.php + + + + +
    +

    /Structures/Graph/Manipulator/AcyclicTest.php

    + + +
    +
    Description
    + +
    + +

    This file contains the definition of the Structures_Graph_Manipulator_AcyclicTest graph manipulator.

    + + +
    +
    + + +
    +
    Classes
    + +
    + + + + + + + + + +
    ClassDescription
    + Structures_Graph_Manipulator_AcyclicTest + + The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator which tests whether a graph contains a cycle. +
    +
    +
    + + +
    +
    Includes
    + +
    + +
    + +
    + + require_once + ('PEAR.php') + (line 35) + +
    + + + +
    + +
    + +
    + + require_once + ('Structures/Graph.php') + (line 37) + +
    + + + +
    + +
    + +
    + + require_once + ('Structures/Graph/Node.php') + (line 39) + +
    + + + +
    +
    +
    + + + + +

    + Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by phpDocumentor 1.2.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Manipulator_TopologicalSorter_php.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Manipulator_TopologicalSorter_php.html new file mode 100644 index 0000000..d8cde62 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Manipulator_TopologicalSorter_php.html @@ -0,0 +1,133 @@ + + + + + + Docs for page TopologicalSorter.php + + + + +
    +

    /Structures/Graph/Manipulator/TopologicalSorter.php

    + + +
    +
    Description
    + +
    + +

    This file contains the definition of the Structures_Graph_Manipulator_TopologicalSorter class.

    + + +
    +
    + + +
    +
    Classes
    + +
    + + + + + + + + + +
    ClassDescription
    + Structures_Graph_Manipulator_TopologicalSorter + + The Structures_Graph_Manipulator_TopologicalSorter is a manipulator which is able to return the set of nodes in a graph, sorted by topological order. +
    +
    +
    + + +
    +
    Includes
    + +
    + +
    + +
    + + require_once + ('PEAR.php') + (line 35) + +
    + + + +
    + +
    + +
    + + require_once + ('Structures/Graph.php') + (line 37) + +
    + + + +
    + +
    + +
    + + require_once + ('Structures/Graph/Node.php') + (line 39) + +
    + + + +
    + +
    + +
    + + require_once + ('Structures/Graph/Manipulator/AcyclicTest.php') + (line 41) + +
    + + + +
    +
    +
    + + + + +

    + Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by phpDocumentor 1.2.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Node_php.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Node_php.html new file mode 100644 index 0000000..528a021 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Node_php.html @@ -0,0 +1,105 @@ + + + + + + Docs for page Node.php + + + + +
    +

    /Structures/Graph/Node.php

    + + +
    +
    Description
    + +
    + +

    This file contains the definition of the Structures_Graph_Node class

    + + +
    +
    + + +
    +
    Classes
    + +
    + + + + + + + + + +
    ClassDescription
    + Structures_Graph_Node + + The Structures_Graph_Node class represents a Node that can be member of a graph node set. +
    +
    +
    + + +
    +
    Includes
    + +
    + +
    + +
    + + require_once + ('PEAR.php') + (line 35) + +
    + + + +
    + +
    + +
    + + require_once + ('Structures/Graph.php') + (line 37) + +
    + + + +
    +
    +
    + + + + +

    + Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by phpDocumentor 1.2.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_php.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_php.html new file mode 100644 index 0000000..b00220b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_php.html @@ -0,0 +1,136 @@ + + + + + + Docs for page Graph.php + + + + +
    +

    /Structures/Graph.php

    + + +
    +
    Description
    + +
    + +

    The Graph.php file contains the definition of the Structures_Graph class

    + + +
    +
    + + +
    +
    Classes
    + +
    + + + + + + + + + +
    ClassDescription
    + Structures_Graph + + The Structures_Graph class represents a graph data structure. +
    +
    +
    + + +
    +
    Includes
    + +
    + +
    + +
    + + require_once + ('Structures/Graph/Node.php') + (line 37) + +
    + + +

    Graph Node

    + +
    + +
    + +
    + + require_once + ('PEAR.php') + (line 35) + +
    + + +

    PEAR base classes

    + +
    +
    +
    + + +
    +
    Constants
    + +
    + +
    + +
    + + STRUCTURES_GRAPH_ERROR_GENERIC = 100 + (line 40) + +
    + + + + +
    +
    +
    + + + +

    + Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by phpDocumentor 1.2.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/tutorial_Structures_Graph.pkg.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/tutorial_Structures_Graph.pkg.html new file mode 100644 index 0000000..fd9f790 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/Structures_Graph/tutorial_Structures_Graph.pkg.html @@ -0,0 +1,75 @@ + + + + + + Structures_Graph Tutorial + + + + +
    + +

    Structures_Graph Tutorial

    +

    A first tour of graph datastructure manipulation

    +

    Introduction

    Structures_Graph is a package for creating and manipulating graph datastructures. A graph is a set of objects, called nodes, connected by arcs. When used as a datastructure, usually nodes contain data, and arcs represent relationships between nodes. When arcs have a direction, and can be travelled only one way, graphs are said to be directed. When arcs have no direction, and can always be travelled both ways, graphs are said to be non directed.

    +

    Structures_Graph provides an object oriented API to create and directly query a graph, as well as a set of Manipulator classes to extract information from the graph.

    +

    Creating a Graph

    Creating a graph is done using the simple constructor: +

    +require_once 'Structures/Graph.php';
    +
    +$directedGraph =& new Structures_Graph(true);
    +$nonDirectedGraph =& new Structures_Graph(false);
    +    
    + and passing the constructor a flag telling it whether the graph should be directed. A directed graph will always be directed during its lifetime. It's a permanent characteristic.

    +

    To fill out the graph, we'll need to create some nodes, and then call Graph::addNode. +

    +require_once 'Structures/Graph/Node.php';
    +
    +$nodeOne =& new Structures_Graph_Node();
    +$nodeTwo =& new Structures_Graph_Node();
    +$nodeThree =& new Structures_Graph_Node();
    +
    +$directedGraph->addNode(&$nodeOne);
    +$directedGraph->addNode(&$nodeTwo);
    +$directedGraph->addNode(&$nodeThree);
    +    
    + and then setup the arcs: +
    +$nodeOne->connectTo($nodeTwo);
    +$nodeOne->connectTo($nodeThree);
    +    
    + Note that arcs can only be created after the nodes have been inserted into the graph.

    +

    Associating Data

    Graphs are only useful as datastructures if they can hold data. Structure_Graph stores data in nodes. Each node contains a setter and a getter for its data. +

    +$nodeOne->setData("Node One's Data is a String");
    +$nodeTwo->setData(1976);
    +$nodeThree->setData('Some other string');
    +
    +print("NodeTwo's Data is an integer: " . $nodeTwo->getData());
    +    

    +

    Structure_Graph nodes can also store metadata, alongside with the main data. Metadata differs from regular data just because it is stored under a key, making it possible to store more than one data reference per node. The metadata getter and setter need the key to perform the operation: +

    +$nodeOne->setMetadata('example key', "Node One's Sample Metadata");
    +print("Metadata stored under key 'example key' in node one: " . $nodeOne->getMetadata('example key'));
    +$nodeOne->unsetMetadata('example key');
    +    

    +

    Querying a Graph

    Structures_Graph provides for basic querying of the graph: +

    +// Nodes are able to calculate their indegree and outdegree
    +print("NodeOne's inDegree: " . $nodeOne->inDegree());
    +print("NodeOne's outDegree: " . $nodeOne->outDegree());
    +
    +// and naturally, nodes can report on their arcs
    +$arcs = $nodeOne->getNeighbours();
    +for ($i=0;$i<sizeof($arcs);$i++) {
    +    print("NodeOne has an arc to " . $arcs[$i]->getData());
    +}
    +    

    + + +

    + Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by phpDocumentor 1.2.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/classtrees_Structures_Graph.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/classtrees_Structures_Graph.html new file mode 100644 index 0000000..d3b0c91 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/classtrees_Structures_Graph.html @@ -0,0 +1,36 @@ + + + + + + + + + + + + +

    + +

    +

    Root class Structures_Graph

    + + +

    Root class Structures_Graph_Manipulator_AcyclicTest

    + + +

    Root class Structures_Graph_Manipulator_TopologicalSorter

    + + +

    Root class Structures_Graph_Node

    + + +

    + Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by phpDocumentor 1.2.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/elementindex.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/elementindex.html new file mode 100644 index 0000000..882faeb --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/elementindex.html @@ -0,0 +1,339 @@ + + + + + + + + + + + +

    Full index

    +

    Package indexes

    + +
    +
    + a + c + g + i + m + n + o + r + s + t + u +
    + + +
    +
    a
    + +
    +
    +
    +
    + addNode +
    +
    + +
    Add a Node to the Graph
    +
    +
    + AcyclicTest.php +
    +
    +
    AcyclicTest.php in AcyclicTest.php
    +
    +
    + +
    +
    c
    + +
    +
    +
    +
    + connectsTo +
    +
    + +
    Test wether this node has an arc to the target node
    +
    +
    + connectTo +
    +
    + +
    Connect this node to another one.
    +
    +
    + +
    +
    g
    + +
    +
    +
    +
    + getData +
    +
    + +
    Node data getter.
    +
    +
    + getGraph +
    +
    + +
    Node graph getter
    +
    +
    + getMetadata +
    +
    + +
    Node metadata getter
    +
    +
    + getNeighbours +
    +
    + +
    Return nodes connected to this one.
    +
    +
    + getNodes +
    +
    + +
    Return the node set, in no particular order. For ordered node sets, use a Graph Manipulator insted.
    +
    +
    + Graph.php +
    +
    +
    Graph.php in Graph.php
    +
    +
    + +
    +
    i
    + +
    +
    +
    +
    + inDegree +
    +
    + +
    Calculate the in degree of the node.
    +
    +
    + isAcyclic +
    +
    + +
    isAcyclic returns true if a graph contains no cycles, false otherwise.
    +
    +
    + isDirected +
    +
    + +
    Return true if a graph is directed
    +
    +
    + +
    +
    m
    + +
    +
    +
    +
    + metadataKeyExists +
    +
    + +
    Test for existence of metadata under a given key.
    +
    +
    + +
    +
    n
    + +
    +
    +
    +
    + Node.php +
    +
    +
    Node.php in Node.php
    +
    +
    + +
    +
    o
    + +
    +
    +
    +
    + outDegree +
    +
    + +
    Calculate the out degree of the node.
    +
    +
    + +
    +
    r
    + +
    +
    +
    +
    + removeNode +
    +
    + +
    Remove a Node from the Graph
    +
    +
    + +
    +
    s
    + +
    +
    +
    +
    + setData +
    +
    + +
    Node data setter
    +
    +
    + setGraph +
    +
    + +
    Node graph setter. This method should not be called directly. Use Graph::addNode instead.
    +
    +
    + setMetadata +
    +
    + +
    Node metadata setter
    +
    +
    + sort +
    +
    + +
    sort returns the graph's nodes, sorted by topological order.
    +
    +
    + Structures_Graph +
    +
    +
    Structures_Graph in Graph.php
    +
    The Structures_Graph class represents a graph data structure.
    +
    +
    + Structures_Graph +
    +
    + +
    Constructor
    +
    +
    + STRUCTURES_GRAPH_ERROR_GENERIC +
    +
    + +
    +
    + Structures_Graph_Manipulator_AcyclicTest +
    +
    + +
    The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator which tests whether a graph contains a cycle.
    +
    +
    + Structures_Graph_Manipulator_TopologicalSorter +
    +
    + +
    The Structures_Graph_Manipulator_TopologicalSorter is a manipulator which is able to return the set of nodes in a graph, sorted by topological order.
    +
    +
    + Structures_Graph_Node +
    +
    + +
    Constructor
    +
    +
    + Structures_Graph_Node +
    +
    + +
    The Structures_Graph_Node class represents a Node that can be member of a graph node set.
    +
    +
    + +
    +
    t
    + +
    +
    +
    +
    + TopologicalSorter.php +
    +
    +
    TopologicalSorter.php in TopologicalSorter.php
    +
    +
    + +
    +
    u
    + +
    +
    +
    +
    + unsetMetadata +
    +
    + +
    Delete metadata by key
    +
    +
    + +
    + a + c + g + i + m + n + o + r + s + t + u +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/elementindex_Structures_Graph.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/elementindex_Structures_Graph.html new file mode 100644 index 0000000..373d3a5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/elementindex_Structures_Graph.html @@ -0,0 +1,336 @@ + + + + + + + + + + + +

    [Structures_Graph] element index

    +All elements +
    +
    + a + c + g + i + m + n + o + r + s + t + u +
    + + +
    +
    a
    + +
    +
    +
    +
    + addNode +
    +
    + +
    Add a Node to the Graph
    +
    +
    + AcyclicTest.php +
    +
    +
    AcyclicTest.php in AcyclicTest.php
    +
    +
    + +
    +
    c
    + +
    +
    +
    +
    + connectsTo +
    +
    + +
    Test wether this node has an arc to the target node
    +
    +
    + connectTo +
    +
    + +
    Connect this node to another one.
    +
    +
    + +
    +
    g
    + +
    +
    +
    +
    + getData +
    +
    + +
    Node data getter.
    +
    +
    + getGraph +
    +
    + +
    Node graph getter
    +
    +
    + getMetadata +
    +
    + +
    Node metadata getter
    +
    +
    + getNeighbours +
    +
    + +
    Return nodes connected to this one.
    +
    +
    + getNodes +
    +
    + +
    Return the node set, in no particular order. For ordered node sets, use a Graph Manipulator insted.
    +
    +
    + Graph.php +
    +
    +
    Graph.php in Graph.php
    +
    +
    + +
    +
    i
    + +
    +
    +
    +
    + inDegree +
    +
    + +
    Calculate the in degree of the node.
    +
    +
    + isAcyclic +
    +
    + +
    isAcyclic returns true if a graph contains no cycles, false otherwise.
    +
    +
    + isDirected +
    +
    + +
    Return true if a graph is directed
    +
    +
    + +
    +
    m
    + +
    +
    +
    +
    + metadataKeyExists +
    +
    + +
    Test for existence of metadata under a given key.
    +
    +
    + +
    +
    n
    + +
    +
    +
    +
    + Node.php +
    +
    +
    Node.php in Node.php
    +
    +
    + +
    +
    o
    + +
    +
    +
    +
    + outDegree +
    +
    + +
    Calculate the out degree of the node.
    +
    +
    + +
    +
    r
    + +
    +
    +
    +
    + removeNode +
    +
    + +
    Remove a Node from the Graph
    +
    +
    + +
    +
    s
    + +
    +
    +
    +
    + setData +
    +
    + +
    Node data setter
    +
    +
    + setGraph +
    +
    + +
    Node graph setter. This method should not be called directly. Use Graph::addNode instead.
    +
    +
    + setMetadata +
    +
    + +
    Node metadata setter
    +
    +
    + sort +
    +
    + +
    sort returns the graph's nodes, sorted by topological order.
    +
    +
    + Structures_Graph +
    +
    +
    Structures_Graph in Graph.php
    +
    The Structures_Graph class represents a graph data structure.
    +
    +
    + Structures_Graph +
    +
    + +
    Constructor
    +
    +
    + STRUCTURES_GRAPH_ERROR_GENERIC +
    +
    + +
    +
    + Structures_Graph_Manipulator_AcyclicTest +
    +
    + +
    The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator which tests whether a graph contains a cycle.
    +
    +
    + Structures_Graph_Manipulator_TopologicalSorter +
    +
    + +
    The Structures_Graph_Manipulator_TopologicalSorter is a manipulator which is able to return the set of nodes in a graph, sorted by topological order.
    +
    +
    + Structures_Graph_Node +
    +
    + +
    Constructor
    +
    +
    + Structures_Graph_Node +
    +
    + +
    The Structures_Graph_Node class represents a Node that can be member of a graph node set.
    +
    +
    + +
    +
    t
    + +
    +
    +
    +
    + TopologicalSorter.php +
    +
    +
    TopologicalSorter.php in TopologicalSorter.php
    +
    +
    + +
    +
    u
    + +
    +
    +
    +
    + unsetMetadata +
    +
    + +
    Delete metadata by key
    +
    +
    + +
    + a + c + g + i + m + n + o + r + s + t + u +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/errors.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/errors.html new file mode 100644 index 0000000..c9b3c93 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/errors.html @@ -0,0 +1,16 @@ + + + + + + phpDocumentor Parser Errors and Warnings + + + + + Post-parsing
    +

    + Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by phpDocumentor 1.2.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/index.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/index.html new file mode 100644 index 0000000..f4d550e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/index.html @@ -0,0 +1,24 @@ + + + + + + Structures_Graph Documentation + + + + + + + + + + + <H2>Frame Alert</H2> + <P>This document is designed to be viewed using the frames feature. + If you see this message, you are using a non-frame-capable web client.</P> + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/li_Structures_Graph.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/li_Structures_Graph.html new file mode 100644 index 0000000..f1f8296 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/li_Structures_Graph.html @@ -0,0 +1,53 @@ + + + + + + + + + + +
    Structures_Graph
    + +

    phpDocumentor v 1.2.3

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/media/banner.css b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/media/banner.css new file mode 100644 index 0000000..f2149eb --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/media/banner.css @@ -0,0 +1,32 @@ +body +{ + background-color: #CCCCFF; + margin: 0px; + padding: 0px; +} + +/* Banner (top bar) classes */ + +.banner { } + +.banner-menu +{ + clear: both; + padding: .5em; + border-top: 2px solid #6666AA; +} + +.banner-title +{ + text-align: right; + font-size: 20pt; + font-weight: bold; + margin: .2em; +} + +.package-selector +{ + background-color: #AAAADD; + border: 1px solid black; + color: yellow; +} diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/media/stylesheet.css b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/media/stylesheet.css new file mode 100644 index 0000000..380dcee --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/media/stylesheet.css @@ -0,0 +1,134 @@ +a { color: #336699; text-decoration: none; } +a:hover { color: #6699CC; text-decoration: underline; } +a:active { color: #6699CC; text-decoration: underline; } + +body { background : #FFFFFF; } +body, table { font-family: Georgia, Times New Roman, Times, serif; font-size: 10pt } +p, li { line-height: 140% } +a img { border: 0px; } +dd { margin-left: 0px; padding-left: 1em; } + +/* Page layout/boxes */ + +.info-box {} +.info-box-title { margin: 1em 0em 0em 0em; padding: .25em; font-weight: normal; font-size: 14pt; border: 2px solid #999999; background-color: #CCCCFF } +.info-box-body { border: 1px solid #999999; padding: .5em; } +.nav-bar { font-size: 8pt; white-space: nowrap; text-align: right; padding: .2em; margin: 0em 0em 1em 0em; } + +.oddrow { background-color: #F8F8F8; border: 1px solid #AAAAAA; padding: .5em; margin-bottom: 1em} +.evenrow { border: 1px solid #AAAAAA; padding: .5em; margin-bottom: 1em} + +.page-body { max-width: 800px; margin: auto; } +.tree dl { margin: 0px } + +/* Index formatting classes */ + +.index-item-body { margin-top: .5em; margin-bottom: .5em} +.index-item-description { margin-top: .25em } +.index-item-details { font-weight: normal; font-style: italic; font-size: 8pt } +.index-letter-section { background-color: #EEEEEE; border: 1px dotted #999999; padding: .5em; margin-bottom: 1em} +.index-letter-title { font-size: 12pt; font-weight: bold } +.index-letter-menu { text-align: center; margin: 1em } +.index-letter { font-size: 12pt } + +/* Docbook classes */ + +.description {} +.short-description { font-weight: bold; color: #666666; } +.tags { padding-left: 0em; margin-left: 3em; color: #666666; list-style-type: square; } +.parameters { padding-left: 0em; margin-left: 3em; font-style: italic; list-style-type: square; } +.redefinitions { font-size: 8pt; padding-left: 0em; margin-left: 2em; } +.package { } +.package-title { font-weight: bold; font-size: 14pt; border-bottom: 1px solid black } +.package-details { font-size: 85%; } +.sub-package { font-weight: bold; font-size: 120% } +.tutorial { border-width: thin; border-color: #0066ff } +.tutorial-nav-box { width: 100%; border: 1px solid #999999; background-color: #F8F8F8; } +.nav-button-disabled { color: #999999; } +.nav-button:active, +.nav-button:focus, +.nav-button:hover { background-color: #DDDDDD; outline: 1px solid #999999; text-decoration: none } +.folder-title { font-style: italic } + +/* Generic formatting */ + +.field { font-weight: bold; } +.detail { font-size: 8pt; } +.notes { font-style: italic; font-size: 8pt; } +.separator { background-color: #999999; height: 2px; } +.warning { color: #FF6600; } +.disabled { font-style: italic; color: #999999; } + +/* Code elements */ + +.line-number { } + +.class-table { width: 100%; } +.class-table-header { border-bottom: 1px dotted #666666; text-align: left} +.class-name { color: #000000; font-weight: bold; } + +.method-summary { padding-left: 1em; font-size: 8pt } +.method-header { } +.method-definition { margin-bottom: .3em } +.method-title { font-weight: bold; } +.method-name { font-weight: bold; } +.method-signature { font-size: 85%; color: #666666; margin: .5em 0em } +.method-result { font-style: italic; } + +.var-summary { padding-left: 1em; font-size: 8pt; } +.var-header { } +.var-title { margin-bottom: .3em } +.var-type { font-style: italic; } +.var-name { font-weight: bold; } +.var-default {} +.var-description { font-weight: normal; color: #000000; } + +.include-title { } +.include-type { font-style: italic; } +.include-name { font-weight: bold; } + +.const-title { } +.const-name { font-weight: bold; } + +/* Syntax highlighting */ + +.src-code { border: 1px solid #336699; padding: 1em; background-color: #EEEEEE; } + +.src-comm { color: green; } +.src-id { } +.src-inc { color: #0000FF; } +.src-key { color: #0000FF; } +.src-num { color: #CC0000; } +.src-str { color: #66cccc; } +.src-sym { font-weight: bold; } +.src-var { } + +.src-php { font-weight: bold; } + +.src-doc { color: #009999 } +.src-doc-close-template { color: #0000FF } +.src-doc-coretag { color: #0099FF; font-weight: bold } +.src-doc-inlinetag { color: #0099FF } +.src-doc-internal { color: #6699cc } +.src-doc-tag { color: #0080CC } +.src-doc-template { color: #0000FF } +.src-doc-type { font-style: italic } +.src-doc-var { font-style: italic } + +/* tutorial */ + +.authors { } +.author { font-style: italic; font-weight: bold } +.author-blurb { margin: .5em 0em .5em 2em; font-size: 85%; font-weight: normal; font-style: normal } +.example { border: 1px dashed #999999; background-color: #EEEEEE; padding: .5em } +.listing { border: 1px dashed #999999; background-color: #EEEEEE; padding: .5em; white-space: nowrap } +.release-info { font-size: 85%; font-style: italic; margin: 1em 0em } +.ref-title-box { } +.ref-title { } +.ref-purpose { font-style: italic; color: #666666 } +.ref-synopsis { } +.title { font-weight: bold; margin: 1em 0em 0em 0em; padding: .25em; border: 2px solid #999999; background-color: #CCCCFF } +.cmd-synopsis { margin: 1em 0em } +.cmd-title { font-weight: bold } +.toc { margin-left: 2em; padding-left: 0em } + diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/packages.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/packages.html new file mode 100644 index 0000000..01d657f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/packages.html @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/todolist.html b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/todolist.html new file mode 100644 index 0000000..5a55ee8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/html/todolist.html @@ -0,0 +1,21 @@ + + + + + + Todo List + + + + +

    Todo List

    +

    Structures_Graph

    +

    Structures_Graph::removeNode()

    +
      +
    • This is unimplemented
    • +
    +

    + Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by phpDocumentor 1.2.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/tutorials/Structures_Graph/Structures_Graph.pkg b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/tutorials/Structures_Graph/Structures_Graph.pkg new file mode 100644 index 0000000..23def41 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/Structures_Graph/docs/tutorials/Structures_Graph/Structures_Graph.pkg @@ -0,0 +1,98 @@ + + + Structures_Graph Tutorial + A first tour of graph datastructure manipulation + + + Introduction + + Structures_Graph is a package for creating and manipulating graph datastructures. A graph is a set of objects, called nodes, connected by arcs. When used as a datastructure, usually nodes contain data, and arcs represent relationships between nodes. When arcs have a direction, and can be travelled only one way, graphs are said to be directed. When arcs have no direction, and can always be travelled both ways, graphs are said to be non directed. + + + Structures_Graph provides an object oriented API to create and directly query a graph, as well as a set of Manipulator classes to extract information from the graph. + + + + Creating a Graph + + Creating a graph is done using the simple constructor: + + + + and passing the constructor a flag telling it whether the graph should be directed. A directed graph will always be directed during its lifetime. It's a permanent characteristic. + + + To fill out the graph, we'll need to create some nodes, and then call Graph::addNode. + + addNode(&$nodeOne); +$directedGraph->addNode(&$nodeTwo); +$directedGraph->addNode(&$nodeThree); + ]]> + + and then setup the arcs: + + connectTo($nodeTwo); +$nodeOne->connectTo($nodeThree); + ]]> + + Note that arcs can only be created after the nodes have been inserted into the graph. + + + + Associating Data + + Graphs are only useful as datastructures if they can hold data. Structure_Graph stores data in nodes. Each node contains a setter and a getter for its data. + + setData("Node One's Data is a String"); +$nodeTwo->setData(1976); +$nodeThree->setData('Some other string'); + +print("NodeTwo's Data is an integer: " . $nodeTwo->getData()); + ]]> + + + + Structure_Graph nodes can also store metadata, alongside with the main data. Metadata differs from regular data just because it is stored under a key, making it possible to store more than one data reference per node. The metadata getter and setter need the key to perform the operation: + + setMetadata('example key', "Node One's Sample Metadata"); +print("Metadata stored under key 'example key' in node one: " . $nodeOne->getMetadata('example key')); +$nodeOne->unsetMetadata('example key'); + ]]> + + + + + Querying a Graph + + Structures_Graph provides for basic querying of the graph: + + inDegree()); +print("NodeOne's outDegree: " . $nodeOne->outDegree()); + +// and naturally, nodes can report on their arcs +$arcs = $nodeOne->getNeighbours(); +for ($i=0;$igetData()); +} + ]]> + + + + diff --git a/typo3conf/ext/phpunit/PEAR/docs/XML_RPC2/docs/tutorials/XML_RPC2.lyx b/typo3conf/ext/phpunit/PEAR/docs/XML_RPC2/docs/tutorials/XML_RPC2.lyx new file mode 100644 index 0000000..bc2d0ee --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/XML_RPC2/docs/tutorials/XML_RPC2.lyx @@ -0,0 +1,320 @@ +#LyX 1.3 created this file. For more info see http://www.lyx.org/ +\lyxformat 221 +\textclass docbook-section +\language english +\inputencoding auto +\fontscheme default +\graphics default +\paperfontsize default +\spacing single +\papersize Default +\paperpackage a4 +\use_geometry 0 +\use_amsmath 0 +\use_natbib 0 +\use_numerical_citations 0 +\paperorientation portrait +\secnumdepth 3 +\tocdepth 3 +\paragraph_separation indent +\defskip medskip +\quotes_language english +\quotes_times 2 +\papercolumns 1 +\papersides 1 +\paperpagestyle default + +\layout Title +\added_space_top vfill \added_space_bottom vfill +XML_RPC2 Tutorial +\layout Abstract + +This tutorial introduces basic usage of XML_RPC2 as a client/server library + in XML_RPC operations. + XML_RPC2 is a pear package providing XML_RPC client and server services. + XML-RPC is a simple remote procedure call protocol built using HTTP as + transport and XML as encoding. +\layout Abstract + +As a client library, XML_RPC2 is capable of creating a proxy class which + exposes the methods exported by the server. + As a server library, XML_RPC2 is capable of exposing methods from a class + or object instance, seamlessly exporting local methods as remotely callable + procedures. + +\layout Subsection + +Client usage +\layout Subsubsection + +Basic Usage +\layout Standard + +The most simple way to use the XML_RPC client is by letting XML_RPC2 select + the backend for you, and just give the client factory method the data referring + to the server: +\layout Itemize + +The server URI. +\layout Itemize + +The HTTP proxy URI (null if no proxy). +\layout Itemize + +The method prefix +\layout Code + +require_once('XML/RPC2/Client.php'); +\layout Code + +$client = XML_RPC2_Client::create('http://rpc.example.com:80/', null, ''); +\layout Standard + +The factory will produce a client proxy. + This class exports whichever methods the server exports. + These methods are called just like regular local methods: +\layout Code + +print($client->hello('World')); +\layout Standard + +for a server that exports the method hello. + If the server has methods prefixed by a classname (example.hello), there + are two solutions. + Either call the method using brackets enclosing the otherwise php-invalid + method name: +\layout Code + +print($client->{example.hello}('World')); +\layout Standard + +Or specify a method prefix when creating the client instance: +\layout Code + +$client = XML_RPC2_Client::create('http://rpc.example.com:80/', null, 'example.'); +\layout Code + +print($client->hello('World')); +\layout Subsubsection + +Error handling +\layout Standard + +XML_RPC2 uses exceptions to signal errors. + The phpdoc reference contains a class hierarchy useful to get a grasp of + possible errors. + The most important characteristics of the XML_RPC2 exception tree are: +\layout Itemize + +All XML_RPC2 exceptions are children of XML_RPC2_Exception. + If you want to filter out exceptions from this package, catch XML_RPC2_Exceptio +n +\layout Itemize + +Network failure is signaled by an XML_RPC2_TransportException +\layout Itemize + +Regular XML-RPC fault responses are signaled by an XML_RPC2_FaultException +\layout Itemize + +All other types of XML_RPC2_Exception signal package misuse or bug-induced + misbehaviour +\layout Standard + +Standard usage: +\layout Code + +require_once('XMLrequire_once('XML/RPC2/Client.php'); +\layout Code + +try { +\layout Code + + $client = XML_RPC2_Client::create('http://rpc.example.com:80/', null, + ''); +\layout Code + + print($client->hello('World')); +\layout Code + +} catch (XML_RPC2_TransportException transportException) { +\layout Code + + // Handle network-induced exception +\layout Code + +} catch (XML_RPC2_FaultException fault) { +\layout Code + + // Handle fault returned by remote server +\layout Code + +} catch (XML_RPC2_Exception xmlRpcException) { +\layout Code + + // Handle abnormal XML_RPC2 package exception +\layout Code + +} catch (Exception e) { +\layout Code + + // Handle someone else's fault exception +\layout Code + +} +\layout Standard + +It is good practice to at least expect XML_RPC2_TransportException as network + failure can't ever be ruled out. + +\layout Subsection + +Server usage +\layout Subsubsection + +Basic Usage +\layout Standard + +To export an XML-RPC server using XML_RPC2, the first step is writing the + methods to export. + XML_RPC2 can export class methods (static methods) for a class, or all + methods for an object instance. + For this example, we'll export a class' static methods: +\layout Code + +class EchoServer { +\layout Code + + /** +\layout Code + + * echoecho echoes the message received +\layout Code + + * +\layout Code + + * @param string Message +\layout Code + + * @return string The echo +\layout Code + + */ +\layout Code + +\layout Code + + public static function echoecho($string) +\layout Code + + { +\layout Code + + return $string; +\layout Code + + } +\layout Code + + +\layout Code + + /** +\layout Code + + * Dummy method which won't be exported +\layout Code + + * +\layout Code + + * @xmlrpc.hidden +\layout Code + + */ +\layout Code + + public static function dummy() +\layout Code + + { +\layout Code + + return false; +\layout Code + + } +\layout Code + +\layout Code + + /** +\layout Code + + * hello says hello +\layout Code + + * +\layout Code + + * @param string Name +\layout Code + + * @return string Hello 'name' +\layout Code + + */ +\layout Code + + public function hello($name) +\layout Code + + { +\layout Code + + return "Hello $name"; +\layout Code + + } +\layout Code + +\layout Code + +} +\layout Standard + +Note that the method is documented using phpDoc docblocks. + The docblock is used to deduce the signature and method documentation, + required by the XML-RPC spec. + Non-documented methods are not exported. + Methods tagged with the tag @xmlrpc.hidden are not exported either (the + dummy method above won't be exported). +\layout Standard + +After creating the class, we need to get an XML_RPC2 server to export its + methods remotely: +\layout Code + +require_once 'XML/RPC2/Server.php'; +\layout Code + +$server = XML_RPC2_Server::create('EchoServer'); +\layout Code + +$server->handleCall(); +\layout Standard + +The XML_RPC2_Server automatically exports all of the EchoServer class public + static methods (echoecho in this case). + You may also export all of an instance's public methods (static or otherwise): +\layout Code + +require_once 'XML/RPC2/Server.php'; +\layout Code + +$server = XML_RPC2_Server::create(new EchoServer()); +\layout Code + +$server->handleCall(); +\the_end diff --git a/typo3conf/ext/phpunit/PEAR/docs/XML_Util/examples/example.php b/typo3conf/ext/phpunit/PEAR/docs/XML_Util/examples/example.php new file mode 100644 index 0000000..db00d2b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/XML_Util/examples/example.php @@ -0,0 +1,299 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category XML + * @package XML_Util + * @subpackage Examples + * @author Stephan Schmidt + * @copyright 2003-2008 Stephan Schmidt + * @license http://opensource.org/licenses/bsd-license New BSD License + * @version CVS: $Id: example.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/XML_Util + */ + + /** + * set error level + */ + error_reporting(E_ALL); + + require_once 'XML/Util.php'; + + /** + * replacing XML entities + */ + print 'replace XML entities:
    '; + print XML_Util::replaceEntities('This string contains < & >.'); + print "\n

    \n"; + + /** + * reversing XML entities + */ + print 'replace XML entities:
    '; + print XML_Util::reverseEntities('This string contains < & >.'); + print "\n

    \n"; + + /** + * building XML declaration + */ + print 'building XML declaration:
    '; + print htmlspecialchars(XML_Util::getXMLDeclaration()); + print "\n

    \n"; + + print 'building XML declaration with additional attributes:
    '; + print htmlspecialchars(XML_Util::getXMLDeclaration('1.0', 'UTF-8', true)); + print "\n

    \n"; + + /** + * building document type declaration + */ + print 'building DocType declaration:
    '; + print htmlspecialchars(XML_Util::getDocTypeDeclaration('package', + 'http://pear.php.net/dtd/package-1.0')); + print "\n

    \n"; + + print 'building DocType declaration with public ID (does not exist):
    '; + print htmlspecialchars(XML_Util::getDocTypeDeclaration('package', + array('uri' => 'http://pear.php.net/dtd/package-1.0', + 'id' => '-//PHP//PEAR/DTD PACKAGE 0.1'))); + print "\n

    \n"; + + print 'building DocType declaration with internal DTD:
    '; + print '
    ';
    +    print htmlspecialchars(XML_Util::getDocTypeDeclaration('package', 
    +        'http://pear.php.net/dtd/package-1.0', 
    +        ''));
    +    print '
    '; + print "\n

    \n"; + + /** + * creating an attribute string + */ + $att = array( + 'foo' => 'bar', + 'argh' => 'tomato' + ); + + print 'converting array to string:
    '; + print XML_Util::attributesToString($att); + print "\n

    \n"; + + + /** + * creating an attribute string with linebreaks + */ + $att = array( + 'foo' => 'bar', + 'argh' => 'tomato' + ); + + print 'converting array to string (including line breaks):
    '; + print '
    ';
    +    print XML_Util::attributesToString($att, true, true);
    +    print '
    '; + print "\n

    \n"; + + + /** + * splitting a qualified tag name + */ + print 'splitting qualified tag name:
    '; + print '
    ';
    +    print_r(XML_Util::splitQualifiedName('xslt:stylesheet'));
    +    print '
    '; + print "\n
    \n"; + + + /** + * splitting a qualified tag name (no namespace) + */ + print 'splitting qualified tag name (no namespace):
    '; + print '
    ';
    +    print_r(XML_Util::splitQualifiedName('foo'));
    +    print '
    '; + print "\n
    \n"; + + /** + * splitting a qualified tag name (no namespace, but default namespace specified) + */ + print 'splitting qualified tag name ' + . '(no namespace, but default namespace specified):
    '; + print '
    ';
    +    print_r(XML_Util::splitQualifiedName('foo', 'bar'));
    +    print '
    '; + print "\n
    \n"; + + /** + * verifying XML names + */ + print 'verifying \'My private tag\':
    '; + print '
    ';
    +    print_r(XML_Util::isValidname('My Private Tag'));
    +    print '
    '; + print "\n

    \n"; + + print 'verifying \'-MyTag\':
    '; + print '
    ';
    +    print_r(XML_Util::isValidname('-MyTag'));
    +    print '
    '; + print "\n

    \n"; + + /** + * creating an XML tag + */ + $tag = array( + 'namespace' => 'foo', + 'localPart' => 'bar', + 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), + 'content' => 'I\'m inside the tag' + ); + + print 'creating a tag with namespace and local part:
    '; + print htmlentities(XML_Util::createTagFromArray($tag)); + print "\n

    \n"; + + /** + * creating an XML tag + */ + $tag = array( + 'qname' => 'foo:bar', + 'namespaceUri' => 'http://foo.com', + 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), + 'content' => 'I\'m inside the tag' + ); + + print 'creating a tag with qualified name and namespaceUri:
    '; + print htmlentities(XML_Util::createTagFromArray($tag)); + print "\n

    \n"; + + /** + * creating an XML tag + */ + $tag = array( + 'qname' => 'bar', + 'namespaceUri' => 'http://foo.com', + 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable') + ); + + print 'creating an empty tag without namespace but namespace Uri:
    '; + print htmlentities(XML_Util::createTagFromArray($tag)); + print "\n

    \n"; + + /** + * creating an XML tag with more namespaces + */ + $tag = array( + 'namespace' => 'foo', + 'localPart' => 'bar', + 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), + 'content' => 'I\'m inside the tag', + 'namespaces' => array( + 'bar' => 'http://bar.com', + 'pear' => 'http://pear.php.net', + ) + ); + + print 'creating an XML tag with more namespaces:
    '; + print htmlentities(XML_Util::createTagFromArray($tag)); + print "\n

    \n"; + + /** + * creating an XML tag with a CData Section + */ + $tag = array( + 'qname' => 'foo', + 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), + 'content' => 'I\'m inside the tag' + ); + + print 'creating a tag with CData section:
    '; + print htmlentities(XML_Util::createTagFromArray($tag, XML_UTIL_CDATA_SECTION)); + print "\n

    \n"; + + /** + * creating an XML tag with a CData Section + */ + $tag = array( + 'qname' => 'foo', + 'attributes' => array('key' => 'value', 'argh' => 'tütü'), + 'content' => + 'Also XHTML-tags can be created ' + . 'and HTML entities can be replaced Ä ä Ü ö <>.' + ); + + print 'creating a tag with HTML entities:
    '; + print htmlentities(XML_Util::createTagFromArray($tag, XML_UTIL_ENTITIES_HTML)); + print "\n

    \n"; + + /** + * creating an XML tag with createTag + */ + print 'creating a tag with createTag:
    '; + print htmlentities(XML_Util::createTag('myNs:myTag', + array('foo' => 'bar'), + 'This is inside the tag', + 'http://www.w3c.org/myNs#')); + print "\n

    \n"; + + + /** + * trying to create an XML tag with an array as content + */ + $tag = array( + 'qname' => 'bar', + 'content' => array('foo' => 'bar') + ); + print 'trying to create an XML tag with an array as content:
    '; + print '
    ';
    +    print_r(XML_Util::createTagFromArray($tag));
    +    print '
    '; + print "\n

    \n"; + + /** + * trying to create an XML tag without a name + */ + $tag = array( + 'attributes' => array('foo' => 'bar'), + ); + print 'trying to create an XML tag without a name:
    '; + print '
    ';
    +    print_r(XML_Util::createTagFromArray($tag));
    +    print '
    '; + print "\n

    \n"; +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/XML_Util/examples/example2.php b/typo3conf/ext/phpunit/PEAR/docs/XML_Util/examples/example2.php new file mode 100644 index 0000000..16068e8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/XML_Util/examples/example2.php @@ -0,0 +1,145 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category XML + * @package XML_Util + * @subpackage Examples + * @author Stephan Schmidt + * @copyright 2003-2008 Stephan Schmidt + * @license http://opensource.org/licenses/bsd-license New BSD License + * @version CVS: $Id: example2.php 79708 2011-06-28 07:50:21Z dkd-webler $ + * @link http://pear.php.net/package/XML_Util + */ + + /** + * set error level + */ + error_reporting(E_ALL); + + require_once 'XML/Util.php'; + + /** + * creating a start element + */ + print 'creating a start element:
    '; + print htmlentities(XML_Util::createStartElement('myNs:myTag', + array('foo' => 'bar'), 'http://www.w3c.org/myNs#')); + print "\n

    \n"; + + + /** + * creating a start element + */ + print 'creating a start element:
    '; + print htmlentities(XML_Util::createStartElement('myTag', + array(), 'http://www.w3c.org/myNs#')); + print "\n

    \n"; + + /** + * creating a start element + */ + print 'creating a start element:
    '; + print '
    ';
    +    print htmlentities(XML_Util::createStartElement('myTag', 
    +        array('foo' => 'bar', 'argh' => 'tomato'), 
    +        'http://www.w3c.org/myNs#', true));
    +    print '
    '; + print "\n

    \n"; + + + /** + * creating an end element + */ + print 'creating an end element:
    '; + print htmlentities(XML_Util::createEndElement('myNs:myTag')); + print "\n

    \n"; + + /** + * creating a CData section + */ + print 'creating a CData section:
    '; + print htmlentities(XML_Util::createCDataSection('I am content.')); + print "\n

    \n"; + + /** + * creating a comment + */ + print 'creating a comment:
    '; + print htmlentities(XML_Util::createComment('I am a comment.')); + print "\n

    \n"; + + /** + * creating an XML tag with multiline mode + */ + $tag = array( + 'qname' => 'foo:bar', + 'namespaceUri' => 'http://foo.com', + 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), + 'content' => 'I\'m inside the tag & contain dangerous chars' + ); + + print 'creating a tag with qualified name and namespaceUri:
    '; + print '
    ';
    +    print htmlentities(XML_Util::createTagFromArray($tag, 
    +        XML_UTIL_REPLACE_ENTITIES, true));
    +    print '
    '; + print "\n

    \n"; + + /** + * create an attribute string without replacing the entities + */ + $atts = array('series' => 'Starsky & Hutch', 'channel' => 'ABC'); + print 'creating a attribute string, ' + . 'entities in values already had been replaced:
    '; + print htmlentities(XML_Util::attributesToString($atts, + true, false, false, false, XML_UTIL_ENTITIES_NONE)); + print "\n

    \n"; + + /** + * using the array-syntax for attributesToString() + */ + $atts = array('series' => 'Starsky & Hutch', 'channel' => 'ABC'); + print 'using the array-syntax for attributesToString()
    '; + print htmlentities(XML_Util::attributesToString($atts, + array('entities' => XML_UTIL_ENTITIES_NONE))); + print "\n

    \n"; + + +?> diff --git a/typo3conf/ext/phpunit/PEAR/docs/YAML/LICENSE b/typo3conf/ext/phpunit/PEAR/docs/YAML/LICENSE new file mode 100644 index 0000000..3cef853 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/YAML/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2008-2009 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/typo3conf/ext/phpunit/PEAR/docs/YAML/README.markdown b/typo3conf/ext/phpunit/PEAR/docs/YAML/README.markdown new file mode 100644 index 0000000..e4f80cf --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/YAML/README.markdown @@ -0,0 +1,15 @@ +Symfony YAML: A PHP library that speaks YAML +============================================ + +Symfony YAML is a PHP library that parses YAML strings and converts them to +PHP arrays. It can also converts PHP arrays to YAML strings. Its official +website is at http://components.symfony-project.org/yaml/. + +The documentation is to be found in the `doc/` directory. + +Symfony YAML is licensed under the MIT license (see LICENSE file). + +The Symfony YAML library is developed and maintained by the +[symfony](http://www.symfony-project.org/) project team. It has been extracted +from symfony to be used as a standalone library. Symfony YAML is part of the +[symfony components project](http://components.symfony-project.org/). diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStream.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStream.php.html new file mode 100644 index 0000000..8d1bd97 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStream.php.html @@ -0,0 +1,210 @@ + + + + + + File Source for vfsStream.php + + + +

    Source for file vfsStream.php

    +

    Documentation is available at vfsStream.php

    +
    +
    1. <?php
    2. +
    3. /**
    4. +
    5.  * Some utility methods for vfsStream.
    6. +
    7.  *
    8. +
    9.  * @package  bovigo_vfs
    10. +
    11.  * @version  $Id: vfsStream.php 211 2010-10-06 16:33:05Z google@frankkleine.de $
    12. +
    13.  */
    14. +
    15. /**
    16. +
    17.  * @ignore
    18. +
    19.  */
    20. +
    21. require_once dirname(__FILE__'/vfsStreamWrapper.php';
    22. +
    23. /**
    24. +
    25.  * Some utility methods for vfsStream.
    26. +
    27.  *
    28. +
    29.  * @package  bovigo_vfs
    30. +
    31.  */
    32. +
    33. class vfsStream
    34. +
    35. {
    36. +
    37.     /**
    38. +
    39.      * url scheme
    40. +
    41.      */
    42. +
    43.     const SCHEME       'vfs';
    44. +
    45.     /**
    46. +
    47.      * owner: root
    48. +
    49.      */
    50. +
    51.     const OWNER_ROOT   0;
    52. +
    53.     /**
    54. +
    55.      * owner: user 1
    56. +
    57.      */
    58. +
    59.     const OWNER_USER_1 1;
    60. +
    61.     /**
    62. +
    63.      * owner: user 2
    64. +
    65.      */
    66. +
    67.     const OWNER_USER_2 2;
    68. +
    69.     /**
    70. +
    71.      * group: root
    72. +
    73.      */
    74. +
    75.     const GROUP_ROOT   0;
    76. +
    77.     /**
    78. +
    79.      * group: user 1
    80. +
    81.      */
    82. +
    83.     const GROUP_USER_1 1;
    84. +
    85.     /**
    86. +
    87.      * group: user 2
    88. +
    89.      */
    90. +
    91.     const GROUP_USER_2 2;
    92. +
    93.     /**
    94. +
    95.      * initial umask setting
    96. +
    97.      *
    98. +
    99.      * @var  int 
    100. +
    101.      */
    102. +
    103.     protected static $umask 0000;
    104. +
    105.  
    106. +
    107.     /**
    108. +
    109.      * prepends the scheme to the given URL
    110. +
    111.      *
    112. +
    113.      * @param   string  $path 
    114. +
    115.      * @return  string 
    116. +
    117.      */
    118. +
    119.     public static function url($path)
    120. +
    121.     {
    122. +
    123.         return self::SCHEME '://' str_replace('\\''/'$path);
    124. +
    125.     }
    126. +
    127.  
    128. +
    129.     /**
    130. +
    131.      * restores the path from the url
    132. +
    133.      *
    134. +
    135.      * @param   string  $url 
    136. +
    137.      * @return  string 
    138. +
    139.      */
    140. +
    141.     public static function path($url)
    142. +
    143.     {
    144. +
    145.         // remove line feeds and trailing whitespaces
    146. +
    147.         $path trim($url" \t\r\n\0\x0B/");
    148. +
    149.         $path substr($pathstrlen(self::SCHEME '://'));
    150. +
    151.         $path str_replace('\\''/'$path);
    152. +
    153.         // replace double slashes with single slashes
    154. +
    155.         $path str_replace('//''/'$path);
    156. +
    157.         return $path;
    158. +
    159.     }
    160. +
    161.  
    162. +
    163.     /**
    164. +
    165.      * sets new umask setting and returns previous umask setting
    166. +
    167.      *
    168. +
    169.      * If no value is given only the current umask setting is returned.
    170. +
    171.      *
    172. +
    173.      * @param   int  $umask  optional
    174. +
    175.      * @return  int 
    176. +
    177.      * @since   0.8.0
    178. +
    179.      */
    180. +
    181.     public static function umask($umask null)
    182. +
    183.     {
    184. +
    185.         $oldUmask self::$umask;
    186. +
    187.         if (null !== $umask{
    188. +
    189.             self::$umask $umask;
    190. +
    191.         }
    192. +
    193.  
    194. +
    195.         return $oldUmask;
    196. +
    197.     }
    198. +
    199.  
    200. +
    201.     /**
    202. +
    203.      * helper method for setting up vfsStream in unit tests
    204. +
    205.      *
    206. +
    207.      * Instead of
    208. +
    209.      * vfsStreamWrapper::register();
    210. +
    211.      * vfsStreamWrapper::setRoot(vfsStream::newDirectory('root'));
    212. +
    213.      * you can simply do
    214. +
    215.      * vfsStream::setup()
    216. +
    217.      * which yields the same result. Additionally, the method returns the
    218. +
    219.      * freshly created root directory which you can use to make further
    220. +
    221.      * adjustments to it.
    222. +
    223.      *
    224. +
    225.      * @param   string              $rootDirName  optional  name of root directory
    226. +
    227.      * @param   int                 $permissions  optional  file permissions of root directory
    228. +
    229.      * @return  vfsStreamDirectory 
    230. +
    231.      * @since   0.7.0
    232. +
    233.      */
    234. +
    235.     public static function setup($rootDirName 'root'$permissions null)
    236. +
    237.     {
    238. +
    239.         vfsStreamWrapper::register();
    240. +
    241.         $root self::newDirectory($rootDirName$permissions);
    242. +
    243.         vfsStreamWrapper::setRoot($root);
    244. +
    245.         return $root;
    246. +
    247.     }
    248. +
    249.  
    250. +
    251.     /**
    252. +
    253.      * returns a new file with given name
    254. +
    255.      *
    256. +
    257.      * @param   string         $name 
    258. +
    259.      * @param   int            $permissions  optional
    260. +
    261.      * @return  vfsStreamFile 
    262. +
    263.      */
    264. +
    265.     public static function newFile($name$permissions null)
    266. +
    267.     {
    268. +
    269.         return new vfsStreamFile($name$permissions);
    270. +
    271.     }
    272. +
    273.  
    274. +
    275.     /**
    276. +
    277.      * returns a new directory with given name
    278. +
    279.      *
    280. +
    281.      * If the name contains slashes, a new directory structure will be created.
    282. +
    283.      * The returned directory will always be the parent directory of this
    284. +
    285.      * directory structure.
    286. +
    287.      *
    288. +
    289.      * @param   string              $name 
    290. +
    291.      * @param   int                 $permissions  optional
    292. +
    293.      * @return  vfsStreamDirectory 
    294. +
    295.      */
    296. +
    297.     public static function newDirectory($name$permissions null)
    298. +
    299.     {
    300. +
    301.         if ('/' === $name{0}{
    302. +
    303.             $name substr($name1);
    304. +
    305.         }
    306. +
    307.         
    308. +
    309.         $firstSlash strpos($name'/');
    310. +
    311.         if (false === $firstSlash{
    312. +
    313.             return new vfsStreamDirectory($name$permissions);
    314. +
    315.         }
    316. +
    317.         
    318. +
    319.         $ownName   substr($name0$firstSlash);
    320. +
    321.         $subDirs   substr($name$firstSlash 1);
    322. +
    323.         $directory new vfsStreamDirectory($ownName$permissions);
    324. +
    325.         self::newDirectory($subDirs$permissions)->at($directory);
    326. +
    327.         return $directory;
    328. +
    329.     }
    330. +
    331.  
    332. +
    333.     /**
    334. +
    335.      * returns current user
    336. +
    337.      *
    338. +
    339.      * If the system does not support posix_getuid() the current user will be root (0).
    340. +
    341.      *
    342. +
    343.      * @return  int 
    344. +
    345.      */
    346. +
    347.     public static function getCurrentUser()
    348. +
    349.     {
    350. +
    351.         return function_exists('posix_getuid'posix_getuid(self::OWNER_ROOT;
    352. +
    353.     }
    354. +
    355.  
    356. +
    357.     /**
    358. +
    359.      * returns current group
    360. +
    361.      *
    362. +
    363.      * If the system does not support posix_getgid() the current group will be root (0).
    364. +
    365.      *
    366. +
    367.      * @return  int 
    368. +
    369.      */
    370. +
    371.     public static function getCurrentGroup()
    372. +
    373.     {
    374. +
    375.         return function_exists('posix_getgid'posix_getgid(self::GROUP_ROOT;
    376. +
    377.     }
    378. +
    379. }
    380. +
    381. ?>
    382. +
    +
    +

    + Documentation generated on Fri, 08 Oct 2010 12:16:36 +0200 by phpDocumentor 1.4.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamAbstractContent.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamAbstractContent.php.html new file mode 100644 index 0000000..6f1d977 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamAbstractContent.php.html @@ -0,0 +1,342 @@ + + + + + + File Source for vfsStreamAbstractContent.php + + + +

    Source for file vfsStreamAbstractContent.php

    +

    Documentation is available at vfsStreamAbstractContent.php

    +
    +
    1. <?php
    2. +
    3. /**
    4. +
    5.  * Base stream contents container.
    6. +
    7.  *
    8. +
    9.  * @package  bovigo_vfs
    10. +
    11.  * @version  $Id: vfsStreamAbstractContent.php 214 2010-10-07 20:57:57Z google@frankkleine.de $
    12. +
    13.  */
    14. +
    15. /**
    16. +
    17.  * @ignore
    18. +
    19.  */
    20. +
    21. require_once dirname(__FILE__'/vfsStreamContent.php';
    22. +
    23. /**
    24. +
    25.  * Base stream contents container.
    26. +
    27.  *
    28. +
    29.  * @package  bovigo_vfs
    30. +
    31.  */
    32. +
    33. abstract class vfsStreamAbstractContent implements vfsStreamContent
    34. +
    35. {
    36. +
    37.     /**
    38. +
    39.      * name of the container
    40. +
    41.      *
    42. +
    43.      * @var  string 
    44. +
    45.      */
    46. +
    47.     protected $name;
    48. +
    49.     /**
    50. +
    51.      * type of the container
    52. +
    53.      *
    54. +
    55.      * @var  string 
    56. +
    57.      */
    58. +
    59.     protected $type;
    60. +
    61.     /**
    62. +
    63.      * timestamp of last modification
    64. +
    65.      *
    66. +
    67.      * @var  int 
    68. +
    69.      */
    70. +
    71.     protected $lastModified;
    72. +
    73.     /**
    74. +
    75.      * permissions for content
    76. +
    77.      *
    78. +
    79.      * @var  int 
    80. +
    81.      */
    82. +
    83.     protected $permissions;
    84. +
    85.     /**
    86. +
    87.      * owner of the file
    88. +
    89.      *
    90. +
    91.      * @var  int 
    92. +
    93.      */
    94. +
    95.     protected $user;
    96. +
    97.     /**
    98. +
    99.      * owner group of the file
    100. +
    101.      *
    102. +
    103.      * @var  int 
    104. +
    105.      */
    106. +
    107.     protected $group;
    108. +
    109.  
    110. +
    111.     /**
    112. +
    113.      * constructor
    114. +
    115.      *
    116. +
    117.      * @param  string  $name 
    118. +
    119.      * @param  int     $permissions  optional
    120. +
    121.      */
    122. +
    123.     public function __construct($name$permissions null)
    124. +
    125.     {
    126. +
    127.         $this->name         = $name;
    128. +
    129.         $this->lastModified = time();
    130. +
    131.         if (null === $permissions{
    132. +
    133.             $permissions $this->getDefaultPermissions(~vfsStream::umask();
    134. +
    135.         }
    136. +
    137.  
    138. +
    139.         $this->permissions  = $permissions;
    140. +
    141.         $this->user         = vfsStream::getCurrentUser();
    142. +
    143.         $this->group        = vfsStream::getCurrentGroup();
    144. +
    145.     }
    146. +
    147.  
    148. +
    149.     /**
    150. +
    151.      * returns default permissions for concrete implementation
    152. +
    153.      *
    154. +
    155.      * @return  int 
    156. +
    157.      * @since   0.8.0
    158. +
    159.      */
    160. +
    161.     protected abstract function getDefaultPermissions();
    162. +
    163.  
    164. +
    165.     /**
    166. +
    167.      * returns the file name of the content
    168. +
    169.      *
    170. +
    171.      * @return  string 
    172. +
    173.      */
    174. +
    175.     public function getName()
    176. +
    177.     {
    178. +
    179.         return $this->name;
    180. +
    181.     }
    182. +
    183.  
    184. +
    185.     /**
    186. +
    187.      * renames the content
    188. +
    189.      *
    190. +
    191.      * @param  string  $newName 
    192. +
    193.      */
    194. +
    195.     public function rename($newName)
    196. +
    197.     {
    198. +
    199.         $this->name = $newName;
    200. +
    201.     }
    202. +
    203.  
    204. +
    205.     /**
    206. +
    207.      * checks whether the container can be applied to given name
    208. +
    209.      *
    210. +
    211.      * @param   string  $name 
    212. +
    213.      * @return  bool 
    214. +
    215.      */
    216. +
    217.     public function appliesTo($name)
    218. +
    219.     {
    220. +
    221.         if ($name === $this->name{
    222. +
    223.             return true;
    224. +
    225.         }
    226. +
    227.  
    228. +
    229.         return (substr($name0strlen($this->name)) === $this->name && strpos($name'/'!== false);
    230. +
    231.     }
    232. +
    233.  
    234. +
    235.     /**
    236. +
    237.      * returns the type of the container
    238. +
    239.      *
    240. +
    241.      * @return  int 
    242. +
    243.      */
    244. +
    245.     public function getType()
    246. +
    247.     {
    248. +
    249.         return $this->type;
    250. +
    251.     }
    252. +
    253.  
    254. +
    255.     /**
    256. +
    257.      * alias for lastModified()
    258. +
    259.      *
    260. +
    261.      * @param   int               $filemtime 
    262. +
    263.      * @return  vfsStreamContent 
    264. +
    265.      * @see     lastModified()
    266. +
    267.      */
    268. +
    269.     public function setFilemtime($filemtime)
    270. +
    271.     {
    272. +
    273.         return $this->lastModified($filemtime);
    274. +
    275.     }
    276. +
    277.  
    278. +
    279.     /**
    280. +
    281.      * sets the last modification time of the stream content
    282. +
    283.      *
    284. +
    285.      * @param   int               $filemtime 
    286. +
    287.      * @return  vfsStreamContent 
    288. +
    289.      */
    290. +
    291.     public function lastModified($filemtime)
    292. +
    293.     {
    294. +
    295.         $this->lastModified = $filemtime;
    296. +
    297.         return $this;
    298. +
    299.     }
    300. +
    301.  
    302. +
    303.     /**
    304. +
    305.      * returns the last modification time of the stream content
    306. +
    307.      *
    308. +
    309.      * @return  int 
    310. +
    311.      */
    312. +
    313.     public function filemtime()
    314. +
    315.     {
    316. +
    317.         return $this->lastModified;
    318. +
    319.     }
    320. +
    321.  
    322. +
    323.     /**
    324. +
    325.      * adds content to given container
    326. +
    327.      *
    328. +
    329.      * @param   vfsStreamContainer  $container 
    330. +
    331.      * @return  vfsStreamContent 
    332. +
    333.      */
    334. +
    335.     public function at(vfsStreamContainer $container)
    336. +
    337.     {
    338. +
    339.         $container->addChild($this);
    340. +
    341.         return $this;
    342. +
    343.     }
    344. +
    345.  
    346. +
    347.     /**
    348. +
    349.      * change file mode to given permissions
    350. +
    351.      *
    352. +
    353.      * @param   int               $permissions 
    354. +
    355.      * @return  vfsStreamContent 
    356. +
    357.      */
    358. +
    359.     public function chmod($permissions)
    360. +
    361.     {
    362. +
    363.         $this->permissions = $permissions;
    364. +
    365.         clearstatcache();
    366. +
    367.         return $this;
    368. +
    369.     }
    370. +
    371.  
    372. +
    373.     /**
    374. +
    375.      * returns permissions
    376. +
    377.      *
    378. +
    379.      * @return  int 
    380. +
    381.      */
    382. +
    383.     public function getPermissions()
    384. +
    385.     {
    386. +
    387.         return $this->permissions;
    388. +
    389.     }
    390. +
    391.  
    392. +
    393.     /**
    394. +
    395.      * checks whether content is readable
    396. +
    397.      *
    398. +
    399.      * @param   int   $user   id of user to check for
    400. +
    401.      * @param   int   $group  id of group to check for
    402. +
    403.      * @return  bool 
    404. +
    405.      */
    406. +
    407.     public function isReadable($user$group)
    408. +
    409.     {
    410. +
    411.         if ($this->user === $user{
    412. +
    413.             $check 0400;
    414. +
    415.         elseif ($this->group === $group{
    416. +
    417.             $check 0040;
    418. +
    419.         else {
    420. +
    421.             $check 0004;
    422. +
    423.         }
    424. +
    425.  
    426. +
    427.         return (bool) ($this->permissions $check);
    428. +
    429.     }
    430. +
    431.  
    432. +
    433.     /**
    434. +
    435.      * checks whether content is writable
    436. +
    437.      *
    438. +
    439.      * @param   int   $user   id of user to check for
    440. +
    441.      * @param   int   $group  id of group to check for
    442. +
    443.      * @return  bool 
    444. +
    445.      */
    446. +
    447.     public function isWritable($user$group)
    448. +
    449.     {
    450. +
    451.         if ($this->user === $user{
    452. +
    453.             $check 0200;
    454. +
    455.         elseif ($this->group === $group{
    456. +
    457.             $check 0020;
    458. +
    459.         else {
    460. +
    461.             $check 0002;
    462. +
    463.         }
    464. +
    465.  
    466. +
    467.         return (bool) ($this->permissions $check);
    468. +
    469.     }
    470. +
    471.  
    472. +
    473.     /**
    474. +
    475.      * checks whether content is executable
    476. +
    477.      *
    478. +
    479.      * @param   int   $user   id of user to check for
    480. +
    481.      * @param   int   $group  id of group to check for
    482. +
    483.      * @return  bool 
    484. +
    485.      */
    486. +
    487.     public function isExecutable($user$group)
    488. +
    489.     {
    490. +
    491.         if ($this->user === $user{
    492. +
    493.             $check 0100;
    494. +
    495.         elseif ($this->group === $group{
    496. +
    497.             $check 0010;
    498. +
    499.         else {
    500. +
    501.             $check 0001;
    502. +
    503.         }
    504. +
    505.  
    506. +
    507.         return (bool) ($this->permissions $check);
    508. +
    509.     }
    510. +
    511.  
    512. +
    513.     /**
    514. +
    515.      * change owner of file to given user
    516. +
    517.      *
    518. +
    519.      * @param   int               $user 
    520. +
    521.      * @return  vfsStreamContent 
    522. +
    523.      */
    524. +
    525.     public function chown($user)
    526. +
    527.     {
    528. +
    529.         $this->user = $user;
    530. +
    531.         return $this;
    532. +
    533.     }
    534. +
    535.  
    536. +
    537.     /**
    538. +
    539.      * checks whether file is owned by given user
    540. +
    541.      *
    542. +
    543.      * @param   int  $user 
    544. +
    545.      * @return  bool 
    546. +
    547.      */
    548. +
    549.     public function isOwnedByUser($user)
    550. +
    551.     {
    552. +
    553.         return $this->user === $user;
    554. +
    555.     }
    556. +
    557.  
    558. +
    559.     /**
    560. +
    561.      * returns owner of file
    562. +
    563.      *
    564. +
    565.      * @return  int 
    566. +
    567.      */
    568. +
    569.     public function getUser()
    570. +
    571.     {
    572. +
    573.         return $this->user;
    574. +
    575.     }
    576. +
    577.  
    578. +
    579.     /**
    580. +
    581.      * change owner group of file to given group
    582. +
    583.      *
    584. +
    585.      * @param   int               $group 
    586. +
    587.      * @return  vfsStreamContent 
    588. +
    589.      */
    590. +
    591.     public function chgrp($group)
    592. +
    593.     {
    594. +
    595.         $this->group = $group;
    596. +
    597.         return $this;
    598. +
    599.     }
    600. +
    601.  
    602. +
    603.     /**
    604. +
    605.      * checks whether file is owned by group
    606. +
    607.      *
    608. +
    609.      * @param   int   $group 
    610. +
    611.      * @return  bool 
    612. +
    613.      */
    614. +
    615.     public function isOwnedByGroup($group)
    616. +
    617.     {
    618. +
    619.         return $this->group === $group;
    620. +
    621.     }
    622. +
    623.  
    624. +
    625.     /**
    626. +
    627.      * returns owner group of file
    628. +
    629.      *
    630. +
    631.      * @return  int 
    632. +
    633.      */
    634. +
    635.     public function getGroup()
    636. +
    637.     {
    638. +
    639.         return $this->group;
    640. +
    641.     }
    642. +
    643. }
    644. +
    645. ?>
    646. +
    +
    +

    + Documentation generated on Fri, 08 Oct 2010 12:16:38 +0200 by phpDocumentor 1.4.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamContainer.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamContainer.php.html new file mode 100644 index 0000000..5881bbf --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamContainer.php.html @@ -0,0 +1,72 @@ + + + + + + File Source for vfsStreamContainer.php + + + +

    Source for file vfsStreamContainer.php

    +

    Documentation is available at vfsStreamContainer.php

    +
    +
    1. <?php
    2. +
    3. /**
    4. +
    5.  * Interface for stream contents that are able to store other stream contents.
    6. +
    7.  *
    8. +
    9.  * @package  bovigo_vfs
    10. +
    11.  * @version  $Id: vfsStreamContainer.php 132 2009-07-13 19:13:25Z google@frankkleine.de $
    12. +
    13.  */
    14. +
    15. /**
    16. +
    17.  * Interface for stream contents that are able to store other stream contents.
    18. +
    19.  *
    20. +
    21.  * @package  bovigo_vfs
    22. +
    23.  */
    24. +
    25. interface vfsStreamContainer extends IteratorAggregate
    26. +
    27. {
    28. +
    29.     /**
    30. +
    31.      * adds child to the directory
    32. +
    33.      *
    34. +
    35.      * @param  vfsStreamContent  $child 
    36. +
    37.      */
    38. +
    39.     public function addChild(vfsStreamContent $child);
    40. +
    41.  
    42. +
    43.     /**
    44. +
    45.      * removes child from the directory
    46. +
    47.      *
    48. +
    49.      * @param   string  $name 
    50. +
    51.      * @return  bool 
    52. +
    53.      */
    54. +
    55.     public function removeChild($name);
    56. +
    57.  
    58. +
    59.     /**
    60. +
    61.      * checks whether the container contains a child with the given name
    62. +
    63.      *
    64. +
    65.      * @param   string  $name 
    66. +
    67.      * @return  bool 
    68. +
    69.      */
    70. +
    71.     public function hasChild($name);
    72. +
    73.  
    74. +
    75.     /**
    76. +
    77.      * returns the child with the given name
    78. +
    79.      *
    80. +
    81.      * @param   string  $name 
    82. +
    83.      * @return  vfsStreamContent 
    84. +
    85.      */
    86. +
    87.     public function getChild($name);
    88. +
    89.  
    90. +
    91.     /**
    92. +
    93.      * returns a list of children for this directory
    94. +
    95.      *
    96. +
    97.      * @return  array<vfsStreamContent> 
    98. +
    99.      */
    100. +
    101.     public function getChildren();
    102. +
    103. }
    104. +
    105. ?>
    106. +
    +
    +

    + Documentation generated on Fri, 08 Oct 2010 12:16:38 +0200 by phpDocumentor 1.4.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamContainerIterator.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamContainerIterator.php.html new file mode 100644 index 0000000..067c02d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamContainerIterator.php.html @@ -0,0 +1,108 @@ + + + + + + File Source for vfsStreamContainerIterator.php + + + +

    Source for file vfsStreamContainerIterator.php

    +

    Documentation is available at vfsStreamContainerIterator.php

    +
    +
    1. <?php
    2. +
    3. /**
    4. +
    5.  * Iterator for children of a directory container.
    6. +
    7.  *
    8. +
    9.  * @package  bovigo_vfs
    10. +
    11.  * @version  $Id: vfsStreamContainerIterator.php 132 2009-07-13 19:13:25Z google@frankkleine.de $
    12. +
    13.  */
    14. +
    15. /**
    16. +
    17.  * Iterator for children of a directory container.
    18. +
    19.  *
    20. +
    21.  * @package  bovigo_vfs
    22. +
    23.  */
    24. +
    25. class vfsStreamContainerIterator implements Iterator
    26. +
    27. {
    28. +
    29.     /**
    30. +
    31.      * list of children from container to iterate over
    32. +
    33.      *
    34. +
    35.      * @var  array<vfsStreamContent> 
    36. +
    37.      */
    38. +
    39.     protected $children = array();
    40. +
    41.  
    42. +
    43.     /**
    44. +
    45.      * constructor
    46. +
    47.      *
    48. +
    49.      * @param  array<vfsStreamContent>  $children 
    50. +
    51.      */
    52. +
    53.     public function __construct(array $children)
    54. +
    55.     {
    56. +
    57.         $this->children $children;
    58. +
    59.         reset($this->children);
    60. +
    61.     }
    62. +
    63.  
    64. +
    65.     /**
    66. +
    67.      * resets children pointer
    68. +
    69.      */
    70. +
    71.     public function rewind()
    72. +
    73.     {
    74. +
    75.         reset($this->children);
    76. +
    77.     }
    78. +
    79.  
    80. +
    81.     /**
    82. +
    83.      * returns the current child
    84. +
    85.      *
    86. +
    87.      * @return  vfsStreamContent 
    88. +
    89.      */
    90. +
    91.     public function current()
    92. +
    93.     {
    94. +
    95.         $child current($this->children);
    96. +
    97.         if (false === $child{
    98. +
    99.             return null;
    100. +
    101.         }
    102. +
    103.         
    104. +
    105.         return $child;
    106. +
    107.     }
    108. +
    109.  
    110. +
    111.     /**
    112. +
    113.      * returns the name of the current child
    114. +
    115.      *
    116. +
    117.      * @return  string 
    118. +
    119.      */
    120. +
    121.     public function key()
    122. +
    123.     {
    124. +
    125.         $child current($this->children);
    126. +
    127.         if (false === $child{
    128. +
    129.             return null;
    130. +
    131.         }
    132. +
    133.         
    134. +
    135.         return $child->getName();
    136. +
    137.     }
    138. +
    139.  
    140. +
    141.     /**
    142. +
    143.      * iterates to next child
    144. +
    145.      */
    146. +
    147.     public function next()
    148. +
    149.     {
    150. +
    151.         next($this->children);
    152. +
    153.     }
    154. +
    155.  
    156. +
    157.     /**
    158. +
    159.      * checks if the current value is valid
    160. +
    161.      *
    162. +
    163.      * @return  bool 
    164. +
    165.      */
    166. +
    167.     public function valid()
    168. +
    169.     {
    170. +
    171.         return (false !== current($this->children));
    172. +
    173.     }
    174. +
    175. }
    176. +
    177. ?>
    178. +
    +
    +

    + Documentation generated on Fri, 08 Oct 2010 12:16:38 +0200 by phpDocumentor 1.4.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamContent.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamContent.php.html new file mode 100644 index 0000000..f2e3324 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamContent.php.html @@ -0,0 +1,213 @@ + + + + + + File Source for vfsStreamContent.php + + + +

    Source for file vfsStreamContent.php

    +

    Documentation is available at vfsStreamContent.php

    +
    +
    1. <?php
    2. +
    3. /**
    4. +
    5.  * Interface for stream contents.
    6. +
    7.  *
    8. +
    9.  * @package  bovigo_vfs
    10. +
    11.  * @version  $Id: vfsStreamContent.php 201 2010-06-08 20:15:45Z google@frankkleine.de $
    12. +
    13.  */
    14. +
    15. /**
    16. +
    17.  * @ignore
    18. +
    19.  */
    20. +
    21. require_once dirname(__FILE__'/vfsStreamContainer.php';
    22. +
    23. /**
    24. +
    25.  * Interface for stream contents.
    26. +
    27.  *
    28. +
    29.  * @package  bovigo_vfs
    30. +
    31.  */
    32. +
    33. interface vfsStreamContent
    34. +
    35. {
    36. +
    37.     /**
    38. +
    39.      * stream content type: file
    40. +
    41.      *
    42. +
    43.      * @see  getType()
    44. +
    45.      */
    46. +
    47.     const TYPE_FILE 0100000;
    48. +
    49.     /**
    50. +
    51.      * stream content type: directory
    52. +
    53.      *
    54. +
    55.      * @see  getType()
    56. +
    57.      */
    58. +
    59.     const TYPE_DIR  0040000;
    60. +
    61.     /**
    62. +
    63.      * stream content type: symbolic link
    64. +
    65.      *
    66. +
    67.      * @see  getType();
    68. +
    69.      */
    70. +
    71.     #const TYPE_LINK = 0120000;
    72. +
    73.  
    74. +
    75.     /**
    76. +
    77.      * returns the file name of the content
    78. +
    79.      *
    80. +
    81.      * @return  string 
    82. +
    83.      */
    84. +
    85.     public function getName();
    86. +
    87.  
    88. +
    89.     /**
    90. +
    91.      * renames the content
    92. +
    93.      *
    94. +
    95.      * @param  string  $newName 
    96. +
    97.      */
    98. +
    99.     public function rename($newName);
    100. +
    101.  
    102. +
    103.     /**
    104. +
    105.      * checks whether the container can be applied to given name
    106. +
    107.      *
    108. +
    109.      * @param   string  $name 
    110. +
    111.      * @return  bool 
    112. +
    113.      */
    114. +
    115.     public function appliesTo($name);
    116. +
    117.  
    118. +
    119.     /**
    120. +
    121.      * returns the type of the container
    122. +
    123.      *
    124. +
    125.      * @return  int 
    126. +
    127.      */
    128. +
    129.     public function getType();
    130. +
    131.  
    132. +
    133.     /**
    134. +
    135.      * returns size of content
    136. +
    137.      *
    138. +
    139.      * @return  int 
    140. +
    141.      */
    142. +
    143.     public function size();
    144. +
    145.  
    146. +
    147.     /**
    148. +
    149.      * alias for lastModified()
    150. +
    151.      *
    152. +
    153.      * @param   int               $filemtime 
    154. +
    155.      * @return  vfsStreamContent 
    156. +
    157.      * @see     lastModified()
    158. +
    159.      */
    160. +
    161.     public function setFilemtime($filemtime);
    162. +
    163.  
    164. +
    165.     /**
    166. +
    167.      * sets the last modification time of the stream content
    168. +
    169.      *
    170. +
    171.      * @param   int               $filemtime 
    172. +
    173.      * @return  vfsStreamContent 
    174. +
    175.      */
    176. +
    177.     public function lastModified($filemtime);
    178. +
    179.  
    180. +
    181.     /**
    182. +
    183.      * returns the last modification time of the stream content
    184. +
    185.      *
    186. +
    187.      * @return  int 
    188. +
    189.      */
    190. +
    191.     public function filemtime();
    192. +
    193.  
    194. +
    195.     /**
    196. +
    197.      * adds content to given container
    198. +
    199.      *
    200. +
    201.      * @param   vfsStreamContainer  $container 
    202. +
    203.      * @return  vfsStreamContent 
    204. +
    205.      */
    206. +
    207.     public function at(vfsStreamContainer $container);
    208. +
    209.  
    210. +
    211.     /**
    212. +
    213.      * change file mode to given permissions
    214. +
    215.      *
    216. +
    217.      * @param   int               $permissions 
    218. +
    219.      * @return  vfsStreamContent 
    220. +
    221.      */
    222. +
    223.     public function chmod($permissions);
    224. +
    225.  
    226. +
    227.     /**
    228. +
    229.      * returns permissions
    230. +
    231.      *
    232. +
    233.      * @return  int 
    234. +
    235.      */
    236. +
    237.     public function getPermissions();
    238. +
    239.  
    240. +
    241.     /**
    242. +
    243.      * checks whether content is readable
    244. +
    245.      *
    246. +
    247.      * @param   int   $user   id of user to check for
    248. +
    249.      * @param   int   $group  id of group to check for
    250. +
    251.      * @return  bool 
    252. +
    253.      */
    254. +
    255.     public function isReadable($user$group);
    256. +
    257.  
    258. +
    259.     /**
    260. +
    261.      * checks whether content is writable
    262. +
    263.      *
    264. +
    265.      * @param   int   $user   id of user to check for
    266. +
    267.      * @param   int   $group  id of group to check for
    268. +
    269.      * @return  bool 
    270. +
    271.      */
    272. +
    273.     public function isWritable($user$group);
    274. +
    275.  
    276. +
    277.     /**
    278. +
    279.      * checks whether content is executable
    280. +
    281.      *
    282. +
    283.      * @param   int   $user   id of user to check for
    284. +
    285.      * @param   int   $group  id of group to check for
    286. +
    287.      * @return  bool 
    288. +
    289.      */
    290. +
    291.     public function isExecutable($user$group);
    292. +
    293.  
    294. +
    295.     /**
    296. +
    297.      * change owner of file to given user
    298. +
    299.      *
    300. +
    301.      * @param   int               $user 
    302. +
    303.      * @return  vfsStreamContent 
    304. +
    305.      */
    306. +
    307.     public function chown($user);
    308. +
    309.  
    310. +
    311.     /**
    312. +
    313.      * checks whether file is owned by given user
    314. +
    315.      *
    316. +
    317.      * @param   int  $user 
    318. +
    319.      * @return  bool 
    320. +
    321.      */
    322. +
    323.     public function isOwnedByUser($user);
    324. +
    325.  
    326. +
    327.     /**
    328. +
    329.      * returns owner of file
    330. +
    331.      *
    332. +
    333.      * @return  int 
    334. +
    335.      */
    336. +
    337.     public function getUser();
    338. +
    339.  
    340. +
    341.     /**
    342. +
    343.      * change owner group of file to given group
    344. +
    345.      *
    346. +
    347.      * @param   int               $group 
    348. +
    349.      * @return  vfsStreamContent 
    350. +
    351.      */
    352. +
    353.     public function chgrp($group);
    354. +
    355.  
    356. +
    357.     /**
    358. +
    359.      * checks whether file is owned by group
    360. +
    361.      *
    362. +
    363.      * @param   int   $group 
    364. +
    365.      * @return  bool 
    366. +
    367.      */
    368. +
    369.     public function isOwnedByGroup($group);
    370. +
    371.  
    372. +
    373.     /**
    374. +
    375.      * returns owner group of file
    376. +
    377.      *
    378. +
    379.      * @return  int 
    380. +
    381.      */
    382. +
    383.     public function getGroup();
    384. +
    385. }
    386. +
    387. ?>
    388. +
    +
    +

    + Documentation generated on Fri, 08 Oct 2010 12:16:39 +0200 by phpDocumentor 1.4.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamDirectory.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamDirectory.php.html new file mode 100644 index 0000000..5acabc5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamDirectory.php.html @@ -0,0 +1,231 @@ + + + + + + File Source for vfsStreamDirectory.php + + + +

    Source for file vfsStreamDirectory.php

    +

    Documentation is available at vfsStreamDirectory.php

    +
    +
    1. <?php
    2. +
    3. /**
    4. +
    5.  * Directory container.
    6. +
    7.  *
    8. +
    9.  * @package  bovigo_vfs
    10. +
    11.  * @version  $Id: vfsStreamDirectory.php 211 2010-10-06 16:33:05Z google@frankkleine.de $
    12. +
    13.  */
    14. +
    15. /**
    16. +
    17.  * @ignore
    18. +
    19.  */
    20. +
    21. require_once dirname(__FILE__'/vfsStreamAbstractContent.php';
    22. +
    23. require_once dirname(__FILE__'/vfsStreamContainer.php';
    24. +
    25. require_once dirname(__FILE__'/vfsStreamContainerIterator.php';
    26. +
    27. require_once dirname(__FILE__'/vfsStreamException.php';
    28. +
    29. /**
    30. +
    31.  * Directory container.
    32. +
    33.  *
    34. +
    35.  * @package  bovigo_vfs
    36. +
    37.  */
    38. +
    39. +
    40. {
    41. +
    42.     /**
    43. +
    44.      * list of directory children
    45. +
    46.      *
    47. +
    48.      * @var  array<string,vfsStreamContent> 
    49. +
    50.      */
    51. +
    52.     protected $children = array();
    53. +
    54.  
    55. +
    56.     /**
    57. +
    58.      * constructor
    59. +
    60.      *
    61. +
    62.      * @param   string  $name 
    63. +
    64.      * @param   int     $permissions  optional
    65. +
    66.      * @throws  vfsStreamException
    67. +
    68.      */
    69. +
    70.     public function __construct($name$permissions null)
    71. +
    72.     {
    73. +
    74.         if (strstr($name'/'!== false{
    75. +
    76.             throw new vfsStreamException('Directory name can not contain /.');
    77. +
    78.         }
    79. +
    80.  
    81. +
    82.         $this->type = vfsStreamContent::TYPE_DIR;
    83. +
    84.         parent::__construct($name$permissions);
    85. +
    86.     }
    87. +
    88.  
    89. +
    90.     /**
    91. +
    92.      * returns default permissions for concrete implementation
    93. +
    94.      *
    95. +
    96.      * @return  int 
    97. +
    98.      * @since   0.8.0
    99. +
    100.      */
    101. +
    102.     protected function getDefaultPermissions()
    103. +
    104.     {
    105. +
    106.         return 0777;
    107. +
    108.     }
    109. +
    110.  
    111. +
    112.     /**
    113. +
    114.      * returns size of directory
    115. +
    116.      *
    117. +
    118.      * The size of a directory is always 0 bytes. To calculate the summarized
    119. +
    120.      * size of all children in the directory use sizeSummarized().
    121. +
    122.      *
    123. +
    124.      * @return  int 
    125. +
    126.      */
    127. +
    128.     public function size()
    129. +
    130.     {
    131. +
    132.         return 0;
    133. +
    134.     }
    135. +
    136.  
    137. +
    138.     /**
    139. +
    140.      * returns summarized size of directory and its children
    141. +
    142.      *
    143. +
    144.      * @return  int 
    145. +
    146.      */
    147. +
    148.     public function sizeSummarized()
    149. +
    150.     {
    151. +
    152.         $size 0;
    153. +
    154.         foreach ($this->children as $child{
    155. +
    156.             if ($child->getType(=== vfsStreamContent::TYPE_DIR{
    157. +
    158.                 $size += $child->sizeSummarized();
    159. +
    160.             else {
    161. +
    162.                 $size += $child->size();
    163. +
    164.             }
    165. +
    166.         }
    167. +
    168.         
    169. +
    170.         return $size;
    171. +
    172.     }
    173. +
    174.  
    175. +
    176.     /**
    177. +
    178.      * renames the content
    179. +
    180.      *
    181. +
    182.      * @param   string  $newName 
    183. +
    184.      * @throws  vfsStreamException
    185. +
    186.      */
    187. +
    188.     public function rename($newName)
    189. +
    190.     {
    191. +
    192.         if (strstr($newName'/'!== false{
    193. +
    194.             throw new vfsStreamException('Directory name can not contain /.');
    195. +
    196.         }
    197. +
    198.         
    199. +
    200.         parent::rename($newName);
    201. +
    202.     }
    203. +
    204.  
    205. +
    206.     /**
    207. +
    208.      * adds child to the directory
    209. +
    210.      *
    211. +
    212.      * @param  vfsStreamContent  $child 
    213. +
    214.      */
    215. +
    216.     public function addChild(vfsStreamContent $child)
    217. +
    218.     {
    219. +
    220.         $this->children[$child->getName()$child;
    221. +
    222.     }
    223. +
    224.  
    225. +
    226.     /**
    227. +
    228.      * removes child from the directory
    229. +
    230.      *
    231. +
    232.      * @param   string  $name 
    233. +
    234.      * @return  bool 
    235. +
    236.      */
    237. +
    238.     public function removeChild($name)
    239. +
    240.     {
    241. +
    242.         foreach ($this->children as $key => $child{
    243. +
    244.             if ($child->appliesTo($name=== true{
    245. +
    246.                 unset($this->children[$key]);
    247. +
    248.                 return true;
    249. +
    250.             }
    251. +
    252.         }
    253. +
    254.         
    255. +
    256.         return false;
    257. +
    258.     }
    259. +
    260.  
    261. +
    262.     /**
    263. +
    264.      * checks whether the container contains a child with the given name
    265. +
    266.      *
    267. +
    268.      * @param   string  $name 
    269. +
    270.      * @return  bool 
    271. +
    272.      */
    273. +
    274.     public function hasChild($name)
    275. +
    276.     {
    277. +
    278.         return ($this->getChild($name!== null);
    279. +
    280.     }
    281. +
    282.  
    283. +
    284.     /**
    285. +
    286.      * returns the child with the given name
    287. +
    288.      *
    289. +
    290.      * @param   string  $name 
    291. +
    292.      * @return  vfsStreamContent 
    293. +
    294.      */
    295. +
    296.     public function getChild($name)
    297. +
    298.     {
    299. +
    300.         $childName $this->getRealChildName($name);
    301. +
    302.         foreach ($this->children as $child{
    303. +
    304.             if ($child->getName(=== $childName{
    305. +
    306.                 return $child;
    307. +
    308.             }
    309. +
    310.             
    311. +
    312.             if ($child->appliesTo($childName=== true && $child->hasChild($childName=== true{
    313. +
    314.                 return $child->getChild($childName);
    315. +
    316.             }
    317. +
    318.         }
    319. +
    320.         
    321. +
    322.         return null;
    323. +
    324.     }
    325. +
    326.  
    327. +
    328.     /**
    329. +
    330.      * helper method to detect the real child name
    331. +
    332.      *
    333. +
    334.      * @param   string  $name 
    335. +
    336.      * @return  string 
    337. +
    338.      */
    339. +
    340.     protected function getRealChildName($name)
    341. +
    342.     {
    343. +
    344.         if ($this->appliesTo($name=== true{
    345. +
    346.             return self::getChildName($name$this->name);
    347. +
    348.         }
    349. +
    350.         
    351. +
    352.         return $name;
    353. +
    354.     }
    355. +
    356.  
    357. +
    358.     /**
    359. +
    360.      * helper method to calculate the child name
    361. +
    362.      *
    363. +
    364.      * @param   string  $name 
    365. +
    366.      * @param   string  $ownName 
    367. +
    368.      * @return  string 
    369. +
    370.      */
    371. +
    372.     protected static function getChildName($name$ownName)
    373. +
    374.     {
    375. +
    376.         return substr($namestrlen($ownName1);
    377. +
    378.     }
    379. +
    380.  
    381. +
    382.     /**
    383. +
    384.      * returns a list of children for this directory
    385. +
    386.      *
    387. +
    388.      * @return  array<vfsStreamContent> 
    389. +
    390.      */
    391. +
    392.     public function getChildren()
    393. +
    394.     {
    395. +
    396.         return array_values($this->children);
    397. +
    398.     }
    399. +
    400.  
    401. +
    402.     /**
    403. +
    404.      * returns iterator for the children
    405. +
    406.      *
    407. +
    408.      * @return  vfsStreamContainerIterator 
    409. +
    410.      */
    411. +
    412.     public function getIterator()
    413. +
    414.     {
    415. +
    416.         return new vfsStreamContainerIterator($this->children);
    417. +
    418.     }
    419. +
    420. }
    421. +
    422. ?>
    423. +
    +
    +

    + Documentation generated on Fri, 08 Oct 2010 12:16:40 +0200 by phpDocumentor 1.4.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamException.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamException.php.html new file mode 100644 index 0000000..d557762 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamException.php.html @@ -0,0 +1,36 @@ + + + + + + File Source for vfsStreamException.php + + + +

    Source for file vfsStreamException.php

    +

    Documentation is available at vfsStreamException.php

    +
    +
    1. <?php
    2. +
    3. /**
    4. +
    5.  * Exception for streamwrapper subpackage.
    6. +
    7.  *
    8. +
    9.  * @package  bovigo_vfs
    10. +
    11.  * @version  $Id$
    12. +
    13.  */
    14. +
    15. /**
    16. +
    17.  * Exception for streamwrapper subpackage.
    18. +
    19.  *
    20. +
    21.  * @package  bovigo_vfs
    22. +
    23.  */
    24. +
    25. class vfsStreamException extends Exception
    26. +
    27. {
    28. +
    29.     // intentionally empty
    30. +
    31. }
    32. +
    33. ?>
    34. +
    +
    +

    + Documentation generated on Fri, 08 Oct 2010 12:16:40 +0200 by phpDocumentor 1.4.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamFile.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamFile.php.html new file mode 100644 index 0000000..8768255 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamFile.php.html @@ -0,0 +1,222 @@ + + + + + + File Source for vfsStreamFile.php + + + +

    Source for file vfsStreamFile.php

    +

    Documentation is available at vfsStreamFile.php

    +
    +
    1. <?php
    2. +
    3. /**
    4. +
    5.  * File container.
    6. +
    7.  *
    8. +
    9.  * @package  bovigo_vfs
    10. +
    11.  * @version  $Id: vfsStreamFile.php 211 2010-10-06 16:33:05Z google@frankkleine.de $
    12. +
    13.  */
    14. +
    15. /**
    16. +
    17.  * @ignore
    18. +
    19.  */
    20. +
    21. require_once dirname(__FILE__'/vfsStreamAbstractContent.php';
    22. +
    23. /**
    24. +
    25.  * File container.
    26. +
    27.  *
    28. +
    29.  * @package  bovigo_vfs
    30. +
    31.  */
    32. +
    33. +
    34. {
    35. +
    36.     /**
    37. +
    38.      * the real content of the file
    39. +
    40.      *
    41. +
    42.      * @var  string 
    43. +
    44.      */
    45. +
    46.     protected $content;
    47. +
    48.     /**
    49. +
    50.      * amount of read bytes
    51. +
    52.      *
    53. +
    54.      * @var  int 
    55. +
    56.      */
    57. +
    58.     protected $bytes_read = 0;
    59. +
    60.  
    61. +
    62.     /**
    63. +
    64.      * constructor
    65. +
    66.      *
    67. +
    68.      * @param  string  $name 
    69. +
    70.      * @param  int     $permissions  optional
    71. +
    72.      */
    73. +
    74.     public function __construct($name$permissions null)
    75. +
    76.     {
    77. +
    78.         $this->type = vfsStreamContent::TYPE_FILE;
    79. +
    80.         parent::__construct($name$permissions);
    81. +
    82.     }
    83. +
    84.  
    85. +
    86.     /**
    87. +
    88.      * returns default permissions for concrete implementation
    89. +
    90.      *
    91. +
    92.      * @return  int 
    93. +
    94.      * @since   0.8.0
    95. +
    96.      */
    97. +
    98.     protected function getDefaultPermissions()
    99. +
    100.     {
    101. +
    102.         return 0666;
    103. +
    104.     }
    105. +
    106.  
    107. +
    108.     /**
    109. +
    110.      * checks whether the container can be applied to given name
    111. +
    112.      *
    113. +
    114.      * @param   string  $name 
    115. +
    116.      * @return  bool 
    117. +
    118.      */
    119. +
    120.     public function appliesTo($name)
    121. +
    122.     {
    123. +
    124.         return ($name === $this->name);
    125. +
    126.     }
    127. +
    128.  
    129. +
    130.     /**
    131. +
    132.      * alias for withContent()
    133. +
    134.      *
    135. +
    136.      * @param   string  $content 
    137. +
    138.      * @return  vfsStreamFile 
    139. +
    140.      * @see     withContent()
    141. +
    142.      */
    143. +
    144.     public function setContent($content)
    145. +
    146.     {
    147. +
    148.         return $this->withContent($content);
    149. +
    150.     }
    151. +
    152.  
    153. +
    154.     /**
    155. +
    156.      * sets the contents of the file
    157. +
    158.      *
    159. +
    160.      * Setting content with this method does not change the time when the file
    161. +
    162.      * was last modified.
    163. +
    164.      *
    165. +
    166.      * @param   string  $content 
    167. +
    168.      * @return  vfsStreamFile 
    169. +
    170.      * @see     setContent()
    171. +
    172.      */
    173. +
    174.     public function withContent($content)
    175. +
    176.     {
    177. +
    178.         $this->content = $content;
    179. +
    180.         return $this;
    181. +
    182.     }
    183. +
    184.  
    185. +
    186.     /**
    187. +
    188.      * returns the contents of the file
    189. +
    190.      *
    191. +
    192.      * @return  string 
    193. +
    194.      */
    195. +
    196.     public function getContent()
    197. +
    198.     {
    199. +
    200.         return $this->content;
    201. +
    202.     }
    203. +
    204.  
    205. +
    206.     /**
    207. +
    208.      * reads the given amount of bytes from content
    209. +
    210.      *
    211. +
    212.      * @param   int     $count 
    213. +
    214.      * @return  string 
    215. +
    216.      */
    217. +
    218.     public function read($count)
    219. +
    220.     {
    221. +
    222.         $data substr($this->content$this->bytes_read$count);
    223. +
    224.         $this->bytes_read += $count;
    225. +
    226.         return $data;
    227. +
    228.     }
    229. +
    230.  
    231. +
    232.     /**
    233. +
    234.      * returns the content until its end from current offset
    235. +
    236.      *
    237. +
    238.      * @return  string 
    239. +
    240.      */
    241. +
    242.     public function readUntilEnd()
    243. +
    244.     {
    245. +
    246.         return substr($this->content$this->bytes_read);
    247. +
    248.     }
    249. +
    250.  
    251. +
    252.     /**
    253. +
    254.      * writes an amount of data
    255. +
    256.      *
    257. +
    258.      * Using this method changes the time when the file was last modified.
    259. +
    260.      *
    261. +
    262.      * @param   string  $data 
    263. +
    264.      * @return  amount of written bytes
    265. +
    266.      */
    267. +
    268.     public function write($data)
    269. +
    270.     {
    271. +
    272.         $dataLen           strlen($data);
    273. +
    274.         $this->content     = substr($this->content0$this->bytes_read$data substr($this->content$this->bytes_read + $dataLen);
    275. +
    276.         $this->bytes_read += $dataLen;
    277. +
    278.         $this->filemtime   time();
    279. +
    280.         return $dataLen;
    281. +
    282.     }
    283. +
    284.  
    285. +
    286.     /**
    287. +
    288.      * checks whether pointer is at end of file
    289. +
    290.      *
    291. +
    292.      * @return  bool 
    293. +
    294.      */
    295. +
    296.     public function eof()
    297. +
    298.     {
    299. +
    300.         return $this->bytes_read >= strlen($this->content);
    301. +
    302.     }
    303. +
    304.  
    305. +
    306.     /**
    307. +
    308.      * returns the current position within the file
    309. +
    310.      *
    311. +
    312.      * @return  int 
    313. +
    314.      */
    315. +
    316.     public function getBytesRead()
    317. +
    318.     {
    319. +
    320.         return $this->bytes_read;
    321. +
    322.     }
    323. +
    324.  
    325. +
    326.     /**
    327. +
    328.      * seeks to the given offset
    329. +
    330.      *
    331. +
    332.      * @param   int   $offset 
    333. +
    334.      * @param   int   $whence 
    335. +
    336.      * @return  bool 
    337. +
    338.      */
    339. +
    340.     public function seek($offset$whence)
    341. +
    342.     {
    343. +
    344.         switch ($whence{
    345. +
    346.             case SEEK_CUR:
    347. +
    348.                 $this->bytes_read += $offset;
    349. +
    350.                 return true;
    351. +
    352.             
    353. +
    354.             case SEEK_END:
    355. +
    356.                 $this->bytes_read = strlen($this->content$offset;
    357. +
    358.                 return true;
    359. +
    360.             
    361. +
    362.             case SEEK_SET:
    363. +
    364.                 $this->bytes_read = $offset;
    365. +
    366.                 return true;
    367. +
    368.             
    369. +
    370.             default:
    371. +
    372.                 return false;
    373. +
    374.         }
    375. +
    376.         
    377. +
    378.         return false;
    379. +
    380.     }
    381. +
    382.  
    383. +
    384.     /**
    385. +
    386.      * returns size of content
    387. +
    388.      *
    389. +
    390.      * @return  int 
    391. +
    392.      */
    393. +
    394.     public function size()
    395. +
    396.     {
    397. +
    398.         return strlen($this->content);
    399. +
    400.     }
    401. +
    402. }
    403. +
    404. ?>
    405. +
    +
    +

    + Documentation generated on Fri, 08 Oct 2010 12:16:41 +0200 by phpDocumentor 1.4.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamWrapper.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamWrapper.php.html new file mode 100644 index 0000000..3b4b065 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamWrapper.php.html @@ -0,0 +1,700 @@ + + + + + + File Source for vfsStreamWrapper.php + + + +

    Source for file vfsStreamWrapper.php

    +

    Documentation is available at vfsStreamWrapper.php

    +
    +
    1. <?php
    2. +
    3. /**
    4. +
    5.  * Stream wrapper to mock file system requests.
    6. +
    7.  *
    8. +
    9.  * @package  bovigo_vfs
    10. +
    11.  * @version  $Id: vfsStreamWrapper.php 214 2010-10-07 20:57:57Z google@frankkleine.de $
    12. +
    13.  */
    14. +
    15. /**
    16. +
    17.  * @ignore
    18. +
    19.  */
    20. +
    21. require_once dirname(__FILE__'/vfsStreamDirectory.php';
    22. +
    23. require_once dirname(__FILE__'/vfsStreamFile.php';
    24. +
    25. require_once dirname(__FILE__'/vfsStreamException.php';
    26. +
    27. /**
    28. +
    29.  * Stream wrapper to mock file system requests.
    30. +
    31.  *
    32. +
    33.  * @package  bovigo_vfs
    34. +
    35.  */
    36. +
    37. +
    38. {
    39. +
    40.     /**
    41. +
    42.      * open file for reading
    43. +
    44.      */
    45. +
    46.     const READ                   'r';
    47. +
    48.     /**
    49. +
    50.      * truncate file
    51. +
    52.      */
    53. +
    54.     const TRUNCATE               'w';
    55. +
    56.     /**
    57. +
    58.      * set file pointer to end, append new data
    59. +
    60.      */
    61. +
    62.     const APPEND                 'a';
    63. +
    64.     /**
    65. +
    66.      * set file pointer to start, overwrite existing data
    67. +
    68.      */
    69. +
    70.     const WRITE                  'x';
    71. +
    72.     /**
    73. +
    74.      * file mode: read only
    75. +
    76.      */
    77. +
    78.     const READONLY               0;
    79. +
    80.     /**
    81. +
    82.      * file mode: write only
    83. +
    84.      */
    85. +
    86.     const WRITEONLY              1;
    87. +
    88.     /**
    89. +
    90.      * file mode: read and write
    91. +
    92.      */
    93. +
    94.     const ALL                    2;
    95. +
    96.     /**
    97. +
    98.      * switch whether class has already been registered as stream wrapper or not
    99. +
    100.      *
    101. +
    102.      * @var  bool 
    103. +
    104.      */
    105. +
    106.     protected static $registered false;
    107. +
    108.     /**
    109. +
    110.      * root content
    111. +
    112.      *
    113. +
    114.      * @var  vfsStreamContent 
    115. +
    116.      */
    117. +
    118.     protected static $root;
    119. +
    120.     /**
    121. +
    122.      * file mode: read only, write only, all
    123. +
    124.      *
    125. +
    126.      * @var  int 
    127. +
    128.      */
    129. +
    130.     protected $mode;
    131. +
    132.     /**
    133. +
    134.      * shortcut to file container
    135. +
    136.      *
    137. +
    138.      * @var  vfsStreamFile 
    139. +
    140.      */
    141. +
    142.     protected $content;
    143. +
    144.     /**
    145. +
    146.      * shortcut to directory container
    147. +
    148.      *
    149. +
    150.      * @var  vfsStreamDirectory 
    151. +
    152.      */
    153. +
    154.     protected $dir;
    155. +
    156.     /**
    157. +
    158.      * shortcut to directory container iterator
    159. +
    160.      *
    161. +
    162.      * @var  vfsStreamDirectory 
    163. +
    164.      */
    165. +
    166.     protected $dirIterator;
    167. +
    168.  
    169. +
    170.     /**
    171. +
    172.      * method to register the stream wrapper
    173. +
    174.      *
    175. +
    176.      * Please be aware that a call to this method will reset the root element
    177. +
    178.      * to null.
    179. +
    180.      * If the stream is already registered the method returns silently. If there
    181. +
    182.      * is already another stream wrapper registered for the scheme used by
    183. +
    184.      * vfsStream a vfsStreamException will be thrown.
    185. +
    186.      *
    187. +
    188.      * @throws  vfsStreamException
    189. +
    190.      */
    191. +
    192.     public static function register()
    193. +
    194.     {
    195. +
    196.         self::$root null;
    197. +
    198.         if (true === self::$registered{
    199. +
    200.             return;
    201. +
    202.         }
    203. +
    204.  
    205. +
    206.         if (@stream_wrapper_register(vfsStream::SCHEME__CLASS__=== false{
    207. +
    208.             throw new vfsStreamException('A handler has already been registered for the ' vfsStream::SCHEME ' protocol.');
    209. +
    210.         }
    211. +
    212.  
    213. +
    214.         self::$registered true;
    215. +
    216.     }
    217. +
    218.  
    219. +
    220.     /**
    221. +
    222.      * sets the root content
    223. +
    224.      *
    225. +
    226.      * @param  vfsStreamContent  $root 
    227. +
    228.      */
    229. +
    230.     public static function setRoot(vfsStreamContent $root)
    231. +
    232.     {
    233. +
    234.         self::$root $root;
    235. +
    236.     }
    237. +
    238.  
    239. +
    240.     /**
    241. +
    242.      * returns the root content
    243. +
    244.      *
    245. +
    246.      * @return  vfsStreamContent 
    247. +
    248.      */
    249. +
    250.     public static function getRoot()
    251. +
    252.     {
    253. +
    254.         return self::$root;
    255. +
    256.     }
    257. +
    258.  
    259. +
    260.     /**
    261. +
    262.      * returns content for given path
    263. +
    264.      *
    265. +
    266.      * @param   string            $path 
    267. +
    268.      * @return  vfsStreamContent 
    269. +
    270.      */
    271. +
    272.     protected function getContent($path)
    273. +
    274.     {
    275. +
    276.         if (null === self::$root{
    277. +
    278.             return null;
    279. +
    280.         }
    281. +
    282.         
    283. +
    284.         if (self::$root->getName(=== $path{
    285. +
    286.             return self::$root;
    287. +
    288.         }
    289. +
    290.         
    291. +
    292.         if (self::$root->hasChild($path=== true{
    293. +
    294.             return self::$root->getChild($path);
    295. +
    296.         }
    297. +
    298.         
    299. +
    300.         return null;
    301. +
    302.     }
    303. +
    304.  
    305. +
    306.     /**
    307. +
    308.      * returns content for given path but only when it is of given type
    309. +
    310.      *
    311. +
    312.      * @param   string            $path 
    313. +
    314.      * @param   int               $type 
    315. +
    316.      * @return  vfsStreamContent 
    317. +
    318.      */
    319. +
    320.     protected function getContentOfType($path$type)
    321. +
    322.     {
    323. +
    324.         $content $this->getContent($path);
    325. +
    326.         if (null !== $content && $content->getType(=== $type{
    327. +
    328.             return $content;
    329. +
    330.         }
    331. +
    332.         
    333. +
    334.         return null;
    335. +
    336.     }
    337. +
    338.  
    339. +
    340.     /**
    341. +
    342.      * splits path into its dirname and the basename
    343. +
    344.      *
    345. +
    346.      * @param   string  $path 
    347. +
    348.      * @return  array 
    349. +
    350.      */
    351. +
    352.     protected function splitPath($path)
    353. +
    354.     {
    355. +
    356.         $lastSlashPos strrpos($path'/');
    357. +
    358.         if (false === $lastSlashPos{
    359. +
    360.             return array('dirname' => '''basename' => $path);
    361. +
    362.         }
    363. +
    364.         
    365. +
    366.         return array('dirname'  => substr($path0$lastSlashPos),
    367. +
    368.                      'basename' => substr($path$lastSlashPos 1)
    369. +
    370.                );
    371. +
    372.     }
    373. +
    374.  
    375. +
    376.     /**
    377. +
    378.      * helper method to resolve a path from /foo/bar/. to /foo/bar
    379. +
    380.      *
    381. +
    382.      * @param   string  $path 
    383. +
    384.      * @return  string 
    385. +
    386.      */
    387. +
    388.     protected function resolvePath($path)
    389. +
    390.     {
    391. +
    392.         $newPath  array();
    393. +
    394.         foreach (explode('/'$pathas $pathPart{
    395. +
    396.             if ('.' !== $pathPart{
    397. +
    398.                 if ('..' !== $pathPart{
    399. +
    400.                     $newPath[$pathPart;
    401. +
    402.                 else {
    403. +
    404.                     array_pop($newPath);
    405. +
    406.                 }
    407. +
    408.             }
    409. +
    410.         }
    411. +
    412.  
    413. +
    414.         return implode('/'$newPath);
    415. +
    416.     }
    417. +
    418.  
    419. +
    420.     /**
    421. +
    422.      * open the stream
    423. +
    424.      *
    425. +
    426.      * @param   string  $path         the path to open
    427. +
    428.      * @param   string  $mode         mode for opening
    429. +
    430.      * @param   string  $options      options for opening
    431. +
    432.      * @param   string  $opened_path  full path that was actually opened
    433. +
    434.      * @return  bool 
    435. +
    436.      */
    437. +
    438.     public function stream_open($path$mode$options$opened_path)
    439. +
    440.     {
    441. +
    442.         $extended ((strstr($mode'+'!== false(true(false));
    443. +
    444.         $mode     str_replace(array('b''+')''$mode);
    445. +
    446.         if (in_array($modearray('r''w''a''x')) === false{
    447. +
    448.             if (!($options STREAM_REPORT_ERRORS)) {
    449. +
    450.                 trigger_error('Illegal mode ' $mode ', use r, w, a  or x, flavoured with b and/or +'E_USER_WARNING);
    451. +
    452.             }
    453. +
    454.  
    455. +
    456.             return false;
    457. +
    458.         }
    459. +
    460.  
    461. +
    462.         $this->mode    = $this->calculateMode($mode$extended);
    463. +
    464.         $path          $this->resolvePath(vfsStream::path($path));
    465. +
    466.         $this->content = $this->getContentOfType($pathvfsStreamContent::TYPE_FILE);
    467. +
    468.         if (null !== $this->content{
    469. +
    470.             if (self::WRITE === $mode{
    471. +
    472.                 if (!($options STREAM_REPORT_ERRORS)) {
    473. +
    474.                     trigger_error('File ' $path ' already exists, can not open with mode x'E_USER_WARNING);
    475. +
    476.                 }
    477. +
    478.  
    479. +
    480.                 return false;
    481. +
    482.             }
    483. +
    484.  
    485. +
    486.             $this->content->seek(0SEEK_SET);
    487. +
    488.             if (self::TRUNCATE === $mode && $this->content->isWritable(vfsStream::getCurrentUser()vfsStream::getCurrentGroup()) === true{
    489. +
    490.                 $this->content->setContent('')// truncate
    491. +
    492.             elseif (self::APPEND === $mode{
    493. +
    494.                 $this->content->seek(0SEEK_END);
    495. +
    496.             }
    497. +
    498.  
    499. +
    500.             return true;
    501. +
    502.         }
    503. +
    504.         
    505. +
    506.         $names $this->splitPath($path);
    507. +
    508.         if (empty($names['dirname']=== true{
    509. +
    510.             if (!($options STREAM_REPORT_ERRORS)) {
    511. +
    512.                 trigger_error('File ' $names['basename'' does not exist'E_USER_WARNING);
    513. +
    514.             }
    515. +
    516.             
    517. +
    518.             return false;
    519. +
    520.         }
    521. +
    522.  
    523. +
    524.         $dir $this->getContentOfType($names['dirname']vfsStreamContent::TYPE_DIR);
    525. +
    526.         if (null === $dir{
    527. +
    528.             if (!($options STREAM_REPORT_ERRORS)) {
    529. +
    530.                 trigger_error('Directory ' $names['dirname'' does not exist'E_USER_WARNING);
    531. +
    532.             }
    533. +
    534.  
    535. +
    536.             return false;
    537. +
    538.         elseif ($dir->hasChild($names['basename']=== true{
    539. +
    540.             if (!($options STREAM_REPORT_ERRORS)) {
    541. +
    542.                 trigger_error('Directory ' $names['dirname'' already contains a director named ' $names['basename']E_USER_WARNING);
    543. +
    544.             }
    545. +
    546.  
    547. +
    548.             return false;
    549. +
    550.         }
    551. +
    552.  
    553. +
    554.         if (self::READ === $mode{
    555. +
    556.             if (!($options STREAM_REPORT_ERRORS)) {
    557. +
    558.                 trigger_error('Can not open non-existing file ' $path ' for reading'E_USER_WARNING);
    559. +
    560.             }
    561. +
    562.  
    563. +
    564.             return false;
    565. +
    566.         }
    567. +
    568.  
    569. +
    570.         if ($dir->isWritable(vfsStream::getCurrentUser()vfsStream::getCurrentGroup()) === false{
    571. +
    572.             if (!($options STREAM_REPORT_ERRORS)) {
    573. +
    574.                 trigger_error('Can not create new file in non-writable path ' $names['dirname']E_USER_WARNING);
    575. +
    576.             }
    577. +
    578.  
    579. +
    580.             return false;
    581. +
    582.         }
    583. +
    584.  
    585. +
    586.         $this->content = vfsStream::newFile($names['basename'])->at($dir);
    587. +
    588.         return true;
    589. +
    590.     }
    591. +
    592.  
    593. +
    594.     /**
    595. +
    596.      * calculates the file mode
    597. +
    598.      *
    599. +
    600.      * @param   string  $mode      opening mode: r, w, a or x
    601. +
    602.      * @param   bool    $extended  true if + was set with opening mode
    603. +
    604.      * @return  int 
    605. +
    606.      */
    607. +
    608.     protected function calculateMode($mode$extended)
    609. +
    610.     {
    611. +
    612.         if (true === $extended{
    613. +
    614.             return self::ALL;
    615. +
    616.         }
    617. +
    618.  
    619. +
    620.         if (self::READ === $mode{
    621. +
    622.             return self::READONLY;
    623. +
    624.         }
    625. +
    626.  
    627. +
    628.         return self::WRITEONLY;
    629. +
    630.     }
    631. +
    632.  
    633. +
    634.     /**
    635. +
    636.      * closes the stream
    637. +
    638.      */
    639. +
    640.     public function stream_close()
    641. +
    642.     {
    643. +
    644.         // nothing to do
    645. +
    646.     }
    647. +
    648.  
    649. +
    650.     /**
    651. +
    652.      * read the stream up to $count bytes
    653. +
    654.      *
    655. +
    656.      * @param   int     $count  amount of bytes to read
    657. +
    658.      * @return  string 
    659. +
    660.      */
    661. +
    662.     public function stream_read($count)
    663. +
    664.     {
    665. +
    666.         if (self::WRITEONLY === $this->mode{
    667. +
    668.             return '';
    669. +
    670.         }
    671. +
    672.  
    673. +
    674.         if ($this->content->isReadable(vfsStream::getCurrentUser()vfsStream::getCurrentGroup()) === false{
    675. +
    676.             return '';
    677. +
    678.         }
    679. +
    680.         
    681. +
    682.         return $this->content->read($count);
    683. +
    684.     }
    685. +
    686.  
    687. +
    688.     /**
    689. +
    690.      * writes data into the stream
    691. +
    692.      *
    693. +
    694.      * @param   string  $data 
    695. +
    696.      * @return  int     amount of bytes written
    697. +
    698.      */
    699. +
    700.     public function stream_write($data)
    701. +
    702.     {
    703. +
    704.         if (self::READONLY === $this->mode{
    705. +
    706.             return 0;
    707. +
    708.         }
    709. +
    710.  
    711. +
    712.         if ($this->content->isWritable(vfsStream::getCurrentUser()vfsStream::getCurrentGroup()) === false{
    713. +
    714.             return 0;
    715. +
    716.         }
    717. +
    718.         
    719. +
    720.         return $this->content->write($data);
    721. +
    722.     }
    723. +
    724.  
    725. +
    726.     /**
    727. +
    728.      * checks whether stream is at end of file
    729. +
    730.      *
    731. +
    732.      * @return  bool 
    733. +
    734.      */
    735. +
    736.     public function stream_eof()
    737. +
    738.     {
    739. +
    740.         return $this->content->eof();
    741. +
    742.     }
    743. +
    744.  
    745. +
    746.     /**
    747. +
    748.      * returns the current position of the stream
    749. +
    750.      *
    751. +
    752.      * @return  int 
    753. +
    754.      */
    755. +
    756.     public function stream_tell()
    757. +
    758.     {
    759. +
    760.         return $this->content->getBytesRead();
    761. +
    762.     }
    763. +
    764.  
    765. +
    766.     /**
    767. +
    768.      * seeks to the given offset
    769. +
    770.      *
    771. +
    772.      * @param   int   $offset 
    773. +
    774.      * @param   int   $whence 
    775. +
    776.      * @return  bool 
    777. +
    778.      */
    779. +
    780.     public function stream_seek($offset$whence)
    781. +
    782.     {
    783. +
    784.         return $this->content->seek($offset$whence);
    785. +
    786.     }
    787. +
    788.  
    789. +
    790.     /**
    791. +
    792.      * flushes unstored data into storage
    793. +
    794.      *
    795. +
    796.      * @return  bool 
    797. +
    798.      */
    799. +
    800.     public function stream_flush()
    801. +
    802.     {
    803. +
    804.         return true;
    805. +
    806.     }
    807. +
    808.  
    809. +
    810.     /**
    811. +
    812.      * returns status of stream
    813. +
    814.      *
    815. +
    816.      * @return  array 
    817. +
    818.      */
    819. +
    820.     public function stream_stat()
    821. +
    822.     {
    823. +
    824.         $fileStat array('dev'     => 0,
    825. +
    826.                           'ino'     => 0,
    827. +
    828.                           'mode'    => $this->content->getType($this->content->getPermissions(),
    829. +
    830.                           'nlink'   => 0,
    831. +
    832.                           'uid'     => $this->content->getUser(),
    833. +
    834.                           'gid'     => $this->content->getGroup(),
    835. +
    836.                           'rdev'    => 0,
    837. +
    838.                           'size'    => $this->content->size(),
    839. +
    840.                           'atime'   => $this->content->filemtime(),
    841. +
    842.                           'mtime'   => $this->content->filemtime(),
    843. +
    844.                           'ctime'   => $this->content->filemtime(),
    845. +
    846.                           'blksize' => -1,
    847. +
    848.                           'blocks'  => -1
    849. +
    850.                     );
    851. +
    852.         return array_merge(array_values($fileStat)$fileStat);
    853. +
    854.     }
    855. +
    856.  
    857. +
    858.     /**
    859. +
    860.      * remove the data under the given path
    861. +
    862.      *
    863. +
    864.      * @param   string  $path 
    865. +
    866.      * @return  bool 
    867. +
    868.      */
    869. +
    870.     public function unlink($path)
    871. +
    872.     {
    873. +
    874.         $realPath $this->resolvePath(vfsStream::path($path));
    875. +
    876.         $content  $this->getContent($realPath);
    877. +
    878.         if (null === $content || $content->isWritable(vfsStream::getCurrentUser()vfsStream::getCurrentGroup()) === false{
    879. +
    880.             return false;
    881. +
    882.         }
    883. +
    884.         
    885. +
    886.         if (self::$root->getName(=== $realPath{
    887. +
    888.             // delete root? very brave. :)
    889. +
    890.             self::$root null;
    891. +
    892.             clearstatcache();
    893. +
    894.             return true;
    895. +
    896.         }
    897. +
    898.         
    899. +
    900.         $names   $this->splitPath($realPath);
    901. +
    902.         $content $this->getContent($names['dirname']);
    903. +
    904.         if ($content->isWritable(vfsStream::getCurrentUser()vfsStream::getCurrentGroup()) === false{
    905. +
    906.             return false;
    907. +
    908.         }
    909. +
    910.         
    911. +
    912.         clearstatcache();
    913. +
    914.         return $content->removeChild($names['basename']);
    915. +
    916.     }
    917. +
    918.  
    919. +
    920.     /**
    921. +
    922.      * rename from one path to another
    923. +
    924.      *
    925. +
    926.      * @param   string  $path_from 
    927. +
    928.      * @param   string  $path_to 
    929. +
    930.      * @return  bool 
    931. +
    932.      * @author  Benoit Aubuchon
    933. +
    934.      */
    935. +
    936.     public function rename($path_from$path_to)
    937. +
    938.     {
    939. +
    940.         $srcRealPath $this->resolvePath(vfsStream::path($path_from));
    941. +
    942.         $dstRealPath vfsStream::path($path_to);
    943. +
    944.         $srcContent  $this->getContent($srcRealPath);
    945. +
    946.         if (null == $srcContent{
    947. +
    948.             trigger_error(' No such file or directory'E_USER_WARNING);
    949. +
    950.             return false;
    951. +
    952.         }
    953. +
    954.  
    955. +
    956.         $dstContent clone $srcContent;
    957. +
    958.         $dstNames   $this->splitPath($dstRealPath);
    959. +
    960.         // Renaming the filename
    961. +
    962.         $dstContent->rename($dstNames['basename']);
    963. +
    964.         // Copying to the destination
    965. +
    966.         $dstParentContent $this->getContent($dstNames['dirname']);
    967. +
    968.         if (null == $dstParentContent{
    969. +
    970.             trigger_error('No such file or directory'E_USER_WARNING);
    971. +
    972.             return false;
    973. +
    974.         }
    975. +
    976.  
    977. +
    978.         if ($dstParentContent->getType(!== vfsStreamContent::TYPE_DIR{
    979. +
    980.             trigger_error('Target is not a directory'E_USER_WARNING);
    981. +
    982.             return false;
    983. +
    984.         }
    985. +
    986.  
    987. +
    988.         $dstParentContent->addChild($dstContent);
    989. +
    990.         // Removing the source
    991. +
    992.         return $this->unlink($path_from);
    993. +
    994.     }
    995. +
    996.  
    997. +
    998.     /**
    999. +
    1000.      * creates a new directory
    1001. +
    1002.      *
    1003. +
    1004.      * @param   string  $path 
    1005. +
    1006.      * @param   int     $mode 
    1007. +
    1008.      * @param   int     $options 
    1009. +
    1010.      * @return  bool 
    1011. +
    1012.      */
    1013. +
    1014.     public function mkdir($path$mode$options)
    1015. +
    1016.     {
    1017. +
    1018.         $umask vfsStream::umask();
    1019. +
    1020.         if ($umask{
    1021. +
    1022.             $permissions $mode ~$umask;
    1023. +
    1024.         else {
    1025. +
    1026.             $permissions $mode;
    1027. +
    1028.         }
    1029. +
    1030.         
    1031. +
    1032.         $path vfsStream::path($path);
    1033. +
    1034.         if (null === self::$root{
    1035. +
    1036.             self::$root vfsStream::newDirectory($path$permissions);
    1037. +
    1038.             return true;
    1039. +
    1040.         }
    1041. +
    1042.         
    1043. +
    1044.         $maxDepth count(explode('/'$path));
    1045. +
    1046.         $names    $this->splitPath($path);
    1047. +
    1048.         $newDirs  $names['basename'];
    1049. +
    1050.         $dir      null;
    1051. +
    1052.         $i        0;
    1053. +
    1054.         while ($dir === null && $i $maxDepth{
    1055. +
    1056.             $dir     $this->getContent($names['dirname']);
    1057. +
    1058.             $names   $this->splitPath($names['dirname']);
    1059. +
    1060.             $newDirs $names['basename''/' $newDirs;
    1061. +
    1062.             $i++;
    1063. +
    1064.         }
    1065. +
    1066.         
    1067. +
    1068.         if (null === $dir
    1069. +
    1070.           || $dir->getType(!== vfsStreamContent::TYPE_DIR
    1071. +
    1072.           || $dir->isWritable(vfsStream::getCurrentUser()vfsStream::getCurrentGroup()) === false{
    1073. +
    1074.             return false;
    1075. +
    1076.         }
    1077. +
    1078.         
    1079. +
    1080.         $newDirs str_replace($dir->getName('/'''$newDirs);
    1081. +
    1082.         $recursive ((STREAM_MKDIR_RECURSIVE $options!== 0(true(false);
    1083. +
    1084.         if (strpos($newDirs'/'!== false && false === $recursive{
    1085. +
    1086.             return false;
    1087. +
    1088.         }
    1089. +
    1090.  
    1091. +
    1092.         vfsStream::newDirectory($newDirs$permissions)->at($dir);
    1093. +
    1094.         return true;
    1095. +
    1096.     }
    1097. +
    1098.  
    1099. +
    1100.     /**
    1101. +
    1102.      * removes a directory
    1103. +
    1104.      *
    1105. +
    1106.      * @param   string  $path 
    1107. +
    1108.      * @param   int     $options 
    1109. +
    1110.      * @return  bool 
    1111. +
    1112.      * @todo    consider $options with STREAM_MKDIR_RECURSIVE
    1113. +
    1114.      */
    1115. +
    1116.     public function rmdir($path$options)
    1117. +
    1118.     {
    1119. +
    1120.         $path  $this->resolvePath(vfsStream::path($path));
    1121. +
    1122.         $child $this->getContentOfType($pathvfsStreamContent::TYPE_DIR);
    1123. +
    1124.         if (null === $child{
    1125. +
    1126.             return false;
    1127. +
    1128.         }
    1129. +
    1130.         
    1131. +
    1132.         // can only remove empty directories
    1133. +
    1134.         if (count($child->getChildren()) 0{
    1135. +
    1136.             return false;
    1137. +
    1138.         }
    1139. +
    1140.         
    1141. +
    1142.         if (self::$root->getName(=== $path{
    1143. +
    1144.             // delete root? very brave. :)
    1145. +
    1146.             self::$root null;
    1147. +
    1148.             clearstatcache();
    1149. +
    1150.             return true;
    1151. +
    1152.         }
    1153. +
    1154.         
    1155. +
    1156.         $names $this->splitPath($path);
    1157. +
    1158.         $dir   $this->getContentOfType($names['dirname']vfsStreamContent::TYPE_DIR);
    1159. +
    1160.         if ($dir->isWritable(vfsStream::getCurrentUser()vfsStream::getCurrentGroup()) === false{
    1161. +
    1162.             return false;
    1163. +
    1164.         }
    1165. +
    1166.         
    1167. +
    1168.         clearstatcache();
    1169. +
    1170.         return $dir->removeChild($child->getName());
    1171. +
    1172.     }
    1173. +
    1174.  
    1175. +
    1176.     /**
    1177. +
    1178.      * opens a directory
    1179. +
    1180.      *
    1181. +
    1182.      * @param   string  $path 
    1183. +
    1184.      * @param   int     $options 
    1185. +
    1186.      * @return  bool 
    1187. +
    1188.      */
    1189. +
    1190.     public function dir_opendir($path$options)
    1191. +
    1192.     {
    1193. +
    1194.         $path      $this->resolvePath(vfsStream::path($path));
    1195. +
    1196.         $this->dir = $this->getContentOfType($pathvfsStreamContent::TYPE_DIR);
    1197. +
    1198.         if (null === $this->dir || $this->dir->isReadable(vfsStream::getCurrentUser()vfsStream::getCurrentGroup()) === false{
    1199. +
    1200.             return false;
    1201. +
    1202.         }
    1203. +
    1204.         
    1205. +
    1206.         $this->dirIterator = $this->dir->getIterator();
    1207. +
    1208.         return true;
    1209. +
    1210.     }
    1211. +
    1212.  
    1213. +
    1214.     /**
    1215. +
    1216.      * reads directory contents
    1217. +
    1218.      *
    1219. +
    1220.      * @return  string 
    1221. +
    1222.      */
    1223. +
    1224.     public function dir_readdir()
    1225. +
    1226.     {
    1227. +
    1228.         $dir $this->dirIterator->current();
    1229. +
    1230.         if (null === $dir{
    1231. +
    1232.             return false;
    1233. +
    1234.         }
    1235. +
    1236.         
    1237. +
    1238.         $this->dirIterator->next();
    1239. +
    1240.         return $dir->getName();
    1241. +
    1242.     }
    1243. +
    1244.  
    1245. +
    1246.     /**
    1247. +
    1248.      * reset directory iteration
    1249. +
    1250.      *
    1251. +
    1252.      * @return  bool 
    1253. +
    1254.      */
    1255. +
    1256.     public function dir_rewinddir()
    1257. +
    1258.     {
    1259. +
    1260.         return $this->dirIterator->rewind();
    1261. +
    1262.     }
    1263. +
    1264.  
    1265. +
    1266.     /**
    1267. +
    1268.      * closes directory
    1269. +
    1270.      *
    1271. +
    1272.      * @return  bool 
    1273. +
    1274.      */
    1275. +
    1276.     public function dir_closedir()
    1277. +
    1278.     {
    1279. +
    1280.         $this->dirIterator = null;
    1281. +
    1282.         return true;
    1283. +
    1284.     }
    1285. +
    1286.  
    1287. +
    1288.     /**
    1289. +
    1290.      * returns status of url
    1291. +
    1292.      *
    1293. +
    1294.      * @param   string  $path   path of url to return status for
    1295. +
    1296.      * @param         $flags  flags set by the stream API
    1297. +
    1298.      * @return  array 
    1299. +
    1300.      */
    1301. +
    1302.     public function url_stat($path$flags)
    1303. +
    1304.     {
    1305. +
    1306.         $path    $this->resolvePath(vfsStream::path($path));
    1307. +
    1308.         $content $this->getContent($path);
    1309. +
    1310.         if (null === $content{
    1311. +
    1312.             if (!($flags STREAM_URL_STAT_QUIET)) {
    1313. +
    1314.                 trigger_error(' No such file or directory'E_USER_WARNING);
    1315. +
    1316.             }
    1317. +
    1318.             return false;
    1319. +
    1320.  
    1321. +
    1322.         }
    1323. +
    1324.  
    1325. +
    1326.         $fileStat array('dev'     => 0,
    1327. +
    1328.                           'ino'     => 0,
    1329. +
    1330.                           'mode'    => $content->getType($content->getPermissions(),
    1331. +
    1332.                           'nlink'   => 0,
    1333. +
    1334.                           'uid'     => $content->getUser(),
    1335. +
    1336.                           'gid'     => $content->getGroup(),
    1337. +
    1338.                           'rdev'    => 0,
    1339. +
    1340.                           'size'    => $content->size(),
    1341. +
    1342.                           'atime'   => $content->filemtime(),
    1343. +
    1344.                           'mtime'   => $content->filemtime(),
    1345. +
    1346.                           'ctime'   => $content->filemtime(),
    1347. +
    1348.                           'blksize' => -1,
    1349. +
    1350.                           'blocks'  => -1
    1351. +
    1352.                     );
    1353. +
    1354.         return array_merge(array_values($fileStat)$fileStat);
    1355. +
    1356.     }
    1357. +
    1358. }
    1359. +
    1360. ?>
    1361. +
    +
    +

    + Documentation generated on Fri, 08 Oct 2010 12:16:44 +0200 by phpDocumentor 1.4.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/blank.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/blank.html new file mode 100644 index 0000000..df001af --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/blank.html @@ -0,0 +1,13 @@ + + + vfsStream + + + + +

    vfsStream

    +Welcome to bovigo_vfs!
    +
    +This documentation was generated by phpDocumentor v1.4.3
    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStream.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStream.php.html new file mode 100644 index 0000000..23255de --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStream.php.html @@ -0,0 +1,144 @@ + + + + + + Docs for page vfsStream.php + + + + + +
    +

    File/vfsStream.php

    + + +
    +
    Description
    + +
    + +

    Some utility methods for vfsStream.

    + + +
    +
    + + +
    +
    Classes
    + +
    + + + + + + + + + +
    ClassDescription
    +  class + vfsStream + + Some utility methods for vfsStream. +
    +
    +
    + + + + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:36 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamAbstractContent.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamAbstractContent.php.html new file mode 100644 index 0000000..38469ee --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamAbstractContent.php.html @@ -0,0 +1,144 @@ + + + + + + Docs for page vfsStreamAbstractContent.php + + + + + +
    +

    File/vfsStreamAbstractContent.php

    + + +
    +
    Description
    + +
    + +

    Base stream contents container.

    +
      +
    • version: $Id: vfsStreamAbstractContent.php 214 2010-10-07 20:57:57Z google@frankkleine.de $
    • +
    • filesource: Source Code for this file
    • +
    + +
    +
    + + +
    +
    Classes
    + +
    + + + + + + + + + +
    ClassDescription
    + Abstract class + vfsStreamAbstractContent + + Base stream contents container. +
    +
    +
    + + + + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:37 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamContainer.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamContainer.php.html new file mode 100644 index 0000000..2dfe76b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamContainer.php.html @@ -0,0 +1,144 @@ + + + + + + Docs for page vfsStreamContainer.php + + + + + +
    +

    File/vfsStreamContainer.php

    + + +
    +
    Description
    + +
    + +

    Interface for stream contents that are able to store other stream contents.

    +
      +
    • version: $Id: vfsStreamContainer.php 132 2009-07-13 19:13:25Z google@frankkleine.de $
    • +
    • filesource: Source Code for this file
    • +
    + +
    +
    + + +
    +
    Classes
    + +
    + + + + + + + + + +
    ClassDescription
    +  class + vfsStreamContainer + + Interface for stream contents that are able to store other stream contents. +
    +
    +
    + + + + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:38 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamContainerIterator.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamContainerIterator.php.html new file mode 100644 index 0000000..b2847d7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamContainerIterator.php.html @@ -0,0 +1,144 @@ + + + + + + Docs for page vfsStreamContainerIterator.php + + + + + +
    +

    File/vfsStreamContainerIterator.php

    + + +
    +
    Description
    + +
    + +

    Iterator for children of a directory container.

    +
      +
    • version: $Id: vfsStreamContainerIterator.php 132 2009-07-13 19:13:25Z google@frankkleine.de $
    • +
    • filesource: Source Code for this file
    • +
    + +
    +
    + + +
    +
    Classes
    + +
    + + + + + + + + + +
    ClassDescription
    +  class + vfsStreamContainerIterator + + Iterator for children of a directory container. +
    +
    +
    + + + + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:38 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamContent.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamContent.php.html new file mode 100644 index 0000000..542e3bb --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamContent.php.html @@ -0,0 +1,144 @@ + + + + + + Docs for page vfsStreamContent.php + + + + + +
    +

    File/vfsStreamContent.php

    + + +
    +
    Description
    + +
    + +

    Interface for stream contents.

    +
      +
    • version: $Id: vfsStreamContent.php 201 2010-06-08 20:15:45Z google@frankkleine.de $
    • +
    • filesource: Source Code for this file
    • +
    + +
    +
    + + +
    +
    Classes
    + +
    + + + + + + + + + +
    ClassDescription
    +  class + vfsStreamContent + + Interface for stream contents. +
    +
    +
    + + + + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:39 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamDirectory.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamDirectory.php.html new file mode 100644 index 0000000..1b90c1b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamDirectory.php.html @@ -0,0 +1,202 @@ + + + + + + Docs for page vfsStreamDirectory.php + + + + + +
    +

    File/vfsStreamDirectory.php

    + + +
    +
    Description
    + +
    + +

    Directory container.

    +
      +
    • version: $Id: vfsStreamDirectory.php 211 2010-10-06 16:33:05Z google@frankkleine.de $
    • +
    • filesource: Source Code for this file
    • +
    + +
    +
    + + +
    +
    Classes
    + +
    + + + + + + + + + +
    ClassDescription
    +  class + vfsStreamDirectory + + Directory container. +
    +
    +
    + + +
    +
    Includes
    + +
    + +
    + +
    +  + + require_once + (dirname(__FILE__).'/vfsStreamContainer.php') + (line 12) + +
    + + + +
    + +
    + +
    +  + + require_once + (dirname(__FILE__).'/vfsStreamContainerIterator.php') + (line 13) + +
    + + + +
    + +
    + +
    +  + + require_once + (dirname(__FILE__).'/vfsStreamException.php') + (line 14) + +
    + + + +
    +
    +
    + + + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:39 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamException.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamException.php.html new file mode 100644 index 0000000..a32f388 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamException.php.html @@ -0,0 +1,144 @@ + + + + + + Docs for page vfsStreamException.php + + + + + +
    +

    File/vfsStreamException.php

    + + +
    +
    Description
    + +
    + +

    Exception for streamwrapper subpackage.

    + + +
    +
    + + +
    +
    Classes
    + +
    + + + + + + + + + +
    ClassDescription
    +  class + vfsStreamException + + Exception for streamwrapper subpackage. +
    +
    +
    + + + + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:40 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamFile.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamFile.php.html new file mode 100644 index 0000000..de120e5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamFile.php.html @@ -0,0 +1,144 @@ + + + + + + Docs for page vfsStreamFile.php + + + + + +
    +

    File/vfsStreamFile.php

    + + +
    +
    Description
    + +
    + +

    File container.

    +
      +
    • version: $Id: vfsStreamFile.php 211 2010-10-06 16:33:05Z google@frankkleine.de $
    • +
    • filesource: Source Code for this file
    • +
    + +
    +
    + + +
    +
    Classes
    + +
    + + + + + + + + + +
    ClassDescription
    +  class + vfsStreamFile + + File container. +
    +
    +
    + + + + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:40 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamWrapper.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamWrapper.php.html new file mode 100644 index 0000000..201be38 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamWrapper.php.html @@ -0,0 +1,187 @@ + + + + + + Docs for page vfsStreamWrapper.php + + + + + +
    +

    File/vfsStreamWrapper.php

    + + +
    +
    Description
    + +
    + +

    Stream wrapper to mock file system requests.

    +
      +
    • version: $Id: vfsStreamWrapper.php 214 2010-10-07 20:57:57Z google@frankkleine.de $
    • +
    • filesource: Source Code for this file
    • +
    + +
    +
    + + +
    +
    Classes
    + +
    + + + + + + + + + +
    ClassDescription
    +  class + vfsStreamWrapper + + Stream wrapper to mock file system requests. +
    +
    +
    + + +
    +
    Includes
    + +
    + +
    + +
    +  + + require_once + (dirname(__FILE__).'/vfsStreamFile.php') + (line 12) + +
    + + + +
    + +
    + +
    +  + + require_once + (dirname(__FILE__).'/vfsStreamException.php') + (line 13) + +
    + + + +
    +
    +
    + + + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:41 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStream.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStream.html new file mode 100644 index 0000000..5827679 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStream.html @@ -0,0 +1,716 @@ + + + + + + Docs For Class vfsStream + + + + + +
    +

     Class vfsStream

    + + +
    +
    Description
    + +
    + +

    Some utility methods for vfsStream.

    +

    + Located in /vfsStream.php (line 17) +

    + + +
    
    +	
    +			
    +
    + + + +
    +
    Class Constant Summary
    + +
    +
    +
    +  + GROUP_ROOT = 0 + +
    +
    +  + GROUP_USER_1 = 1 + +
    +
    +  + GROUP_USER_2 = 2 + +
    +
    +  + OWNER_ROOT = 0 + +
    +
    +  + OWNER_USER_1 = 1 + +
    +
    +  + OWNER_USER_2 = 2 + +
    +
    +  + SCHEME = 'vfs' + +
    +
    +
    +
    + + +
    +
    Variable Summary
    + +
    +
    +
    +  + static int + $umask +
    +
    +
    +
    + + +
    +
    Method Summary
    + +
    +
    + +
    +  + static int + getCurrentGroup + () +
    + +
    +  + static int + getCurrentUser + () +
    + +
    +  + static vfsStreamDirectory + newDirectory + (string $name, [int $permissions = null]) +
    + +
    +  + static vfsStreamFile + newFile + (string $name, [int $permissions = null]) +
    + +
    +  + static string + path + (string $url) +
    + +
    +  + static vfsStreamDirectory + setup + ([string $rootDirName = 'root'], [int $permissions = null]) +
    + +
    +  + static int + umask + ([int $umask = null]) +
    + +
    +  + static string + url + (string $path) +
    +
    +
    +
    + + +
    +
    Variables
    + +
    + +
    + +
    + + + static int + $umask + = 0000 (line 52) + +
    + + +

    initial umask setting

    +
      +
    • access: protected
    • +
    + + + + + +
    + + +
    +
    + + +
    +
    Methods
    + +
    + + +
    + +
    + + static getCurrentGroup (line 186) +
    + + +

    returns current group

    +

    If the system does not support posix_getgid() the current group will be root (0).

    +
      +
    • access: public
    • +
    + +
    + static int + + getCurrentGroup + + () +
    + + + +
    + +
    + +
    + + static getCurrentUser (line 174) +
    + + +

    returns current user

    +

    If the system does not support posix_getuid() the current user will be root (0).

    +
      +
    • access: public
    • +
    + +
    + static int + + getCurrentUser + + () +
    + + + +
    + +
    + +
    + + static newDirectory (line 149) +
    + + +

    returns a new directory with given name

    +

    If the name contains slashes, a new directory structure will be created. The returned directory will always be the parent directory of this directory structure.

    +
      +
    • access: public
    • +
    + +
    + static vfsStreamDirectory + + newDirectory + + (string $name, [int $permissions = null]) +
    + +
      +
    • + string + $name
    • +
    • + int + $permissions: optional
    • +
    + + +
    + +
    + +
    + + static newFile (line 133) +
    + + +

    returns a new file with given name

    +
      +
    • access: public
    • +
    + +
    + static vfsStreamFile + + newFile + + (string $name, [int $permissions = null]) +
    + +
      +
    • + string + $name
    • +
    • + int + $permissions: optional
    • +
    + + +
    + +
    + +
    + + static path (line 71) +
    + + +

    restores the path from the url

    +
      +
    • access: public
    • +
    + +
    + static string + + path + + (string $url) +
    + +
      +
    • + string + $url
    • +
    + + +
    + +
    + +
    + + static setup (line 118) +
    + + +

    helper method for setting up vfsStream in unit tests

    +

    Instead of vfsStreamWrapper::register(); vfsStreamWrapper::setRoot(vfsStream::newDirectory('root')); you can simply do vfsStream::setup() which yields the same result. Additionally, the method returns the freshly created root directory which you can use to make further adjustments to it.

    +
      +
    • since: 0.7.0
    • +
    • access: public
    • +
    + +
    + static vfsStreamDirectory + + setup + + ([string $rootDirName = 'root'], [int $permissions = null]) +
    + +
      +
    • + string + $rootDirName: optional name of root directory
    • +
    • + int + $permissions: optional file permissions of root directory
    • +
    + + +
    + +
    + +
    + + static umask (line 91) +
    + + +

    sets new umask setting and returns previous umask setting

    +

    If no value is given only the current umask setting is returned.

    +
      +
    • since: 0.8.0
    • +
    • access: public
    • +
    + +
    + static int + + umask + + ([int $umask = null]) +
    + +
      +
    • + int + $umask: optional
    • +
    + + +
    + +
    + +
    + + static url (line 60) +
    + + +

    prepends the scheme to the given URL

    +
      +
    • access: public
    • +
    + +
    + static string + + url + + (string $path) +
    + +
      +
    • + string + $path
    • +
    + + +
    + +
    +
    + + +
    +
    Class Constants
    + +
    + +
    + +
    + + + GROUP_ROOT + = 0 + (line 38) + +
    + + +

    group: root

    + + +
    + +
    + +
    + + + GROUP_USER_1 + = 1 + (line 42) + +
    + + +

    group: user 1

    + + +
    + +
    + +
    + + + GROUP_USER_2 + = 2 + (line 46) + +
    + + +

    group: user 2

    + + +
    + +
    + +
    + + + OWNER_ROOT + = 0 + (line 26) + +
    + + +

    owner: root

    + + +
    + +
    + +
    + + + OWNER_USER_1 + = 1 + (line 30) + +
    + + +

    owner: user 1

    + + +
    + +
    + +
    + + + OWNER_USER_2 + = 2 + (line 34) + +
    + + +

    owner: user 2

    + + +
    + +
    + +
    + + + SCHEME + = 'vfs' + (line 22) + +
    + + +

    url scheme

    + + +
    + +
    +
    + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:37 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamAbstractContent.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamAbstractContent.html new file mode 100644 index 0000000..78f38d8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamAbstractContent.html @@ -0,0 +1,1322 @@ + + + + + + Docs For Class vfsStreamAbstractContent + + + + + +
    +

    Abstract Class vfsStreamAbstractContent

    + + +
    +
    Description
    + +
    +

    + Implements interfaces: +

    +

    + +

    Base stream contents container.

    +
      +
    • abstract:
    • +
    +

    + Located in /vfsStreamAbstractContent.php (line 17) +

    + + +
    
    +	
    +			
    +
    + + +
    +
    Direct descendents
    + +
    + + + + + + + + + + + + + +
    ClassDescription
    +  class + vfsStreamDirectory + + Directory container. +
    +  class + vfsStreamFile + + File container. +
    +
    +
    + + + +
    +
    Variable Summary
    + +
    +
    +
    +  + int + $group +
    +
    +  + int + $lastModified +
    +
    +  + string + $name +
    +
    +  + int + $permissions +
    +
    +  + string + $type +
    +
    +  + int + $user +
    +
    +
    +
    + + +
    +
    Method Summary
    + +
    +
    + +
    +  + vfsStreamAbstractContent + __construct + (string $name, [int $permissions = null]) +
    + +
    +  + bool + appliesTo + (string $name) +
    + +
    +  + vfsStreamContent + at + (vfsStreamContainer $container) +
    + +
    +  + vfsStreamContent + chgrp + (int $group) +
    + +
    +  + vfsStreamContent + chmod + (int $permissions) +
    + +
    +  + vfsStreamContent + chown + (int $user) +
    + +
    +  + int + filemtime + () +
    + +
    +  + int + getDefaultPermissions + () +
    + +
    +  + int + getGroup + () +
    + +
    +  + string + getName + () +
    + +
    +  + int + getPermissions + () +
    + +
    +  + int + getType + () +
    + +
    +  + int + getUser + () +
    + +
    +  + bool + isExecutable + (int $user, int $group) +
    + +
    +  + bool + isOwnedByGroup + (int $group) +
    + +
    +  + bool + isOwnedByUser + (int $user) +
    + +
    +  + bool + isReadable + (int $user, int $group) +
    + +
    +  + bool + isWritable + (int $user, int $group) +
    + +
    +  + vfsStreamContent + lastModified + (int $filemtime) +
    + +
    +  + void + rename + (string $newName) +
    + +
    +  + vfsStreamContent + setFilemtime + (int $filemtime) +
    +
    +
    +
    + + +
    +
    Variables
    + +
    + + +
    + +
    + + + int + $group + (line 54) + +
    + + +

    owner group of the file

    +
      +
    • access: protected
    • +
    + + + + + +
    + +
    + +
    + + + int + $lastModified + (line 36) + +
    + + +

    timestamp of last modification

    +
      +
    • access: protected
    • +
    + + + + + +
    + +
    + +
    + + + string + $name + (line 24) + +
    + + +

    name of the container

    +
      +
    • access: protected
    • +
    + + + + + +
    + +
    + +
    + + + int + $permissions + (line 42) + +
    + + +

    permissions for content

    +
      +
    • access: protected
    • +
    + + + + + +
    + +
    + +
    + + + string + $type + (line 30) + +
    + + +

    type of the container

    +
      +
    • access: protected
    • +
    + + + + + +
    + +
    + +
    + + + int + $user + (line 48) + +
    + + +

    owner of the file

    +
      +
    • access: protected
    • +
    + + + + + +
    + +
    +
    + + +
    +
    Methods
    + +
    + + +
    + +
    + + Constructor __construct (line 62) +
    + + +

    constructor

    +
      +
    • access: public
    • +
    + +
    + vfsStreamAbstractContent + + __construct + + (string $name, [int $permissions = null]) +
    + +
      +
    • + string + $name
    • +
    • + int + $permissions: optional
    • +
    + + +
    +
    Redefined in descendants as:
    + +
    + +
    + +
    + + appliesTo (line 109) +
    + + +

    checks whether the container can be applied to given name

    +
      +
    • access: public
    • +
    + +
    + bool + + appliesTo + + (string $name) +
    + +
      +
    • + string + $name
    • +
    + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::appliesTo()
    +
    checks whether the container can be applied to given name
    +
    + +
    +
    Redefined in descendants as:
    + +
    + +
    + +
    + + at (line 168) +
    + + +

    adds content to given container

    +
      +
    • access: public
    • +
    + +
    + vfsStreamContent + + at + + (vfsStreamContainer $container) +
    + + + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::at()
    +
    adds content to given container
    +
    + +
    + +
    + +
    + + chgrp (line 296) +
    + + +

    change owner group of file to given group

    +
      +
    • access: public
    • +
    + +
    + vfsStreamContent + + chgrp + + (int $group) +
    + +
      +
    • + int + $group
    • +
    + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::chgrp()
    +
    change owner group of file to given group
    +
    + +
    + +
    + +
    + + chmod (line 180) +
    + + +

    change file mode to given permissions

    +
      +
    • access: public
    • +
    + +
    + vfsStreamContent + + chmod + + (int $permissions) +
    + +
      +
    • + int + $permissions
    • +
    + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::chmod()
    +
    change file mode to given permissions
    +
    + +
    + +
    + +
    + + chown (line 263) +
    + + +

    change owner of file to given user

    +
      +
    • access: public
    • +
    + +
    + vfsStreamContent + + chown + + (int $user) +
    + +
      +
    • + int + $user
    • +
    + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::chown()
    +
    change owner of file to given user
    +
    + +
    + +
    + +
    + + filemtime (line 157) +
    + + +

    returns the last modification time of the stream content

    +
      +
    • access: public
    • +
    + +
    + int + + filemtime + + () +
    + + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::filemtime()
    +
    returns the last modification time of the stream content
    +
    + +
    + +
    + +
    + + getDefaultPermissions (line 81) +
    + + +

    returns default permissions for concrete implementation

    +
      +
    • abstract:
    • +
    • since: 0.8.0
    • +
    • access: protected
    • +
    + +
    + int + + getDefaultPermissions + + () +
    + + + +
    +
    Redefined in descendants as:
    + +
    + +
    + +
    + + getGroup (line 318) +
    + + +

    returns owner group of file

    +
      +
    • access: public
    • +
    + +
    + int + + getGroup + + () +
    + + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::getGroup()
    +
    returns owner group of file
    +
    + +
    + +
    + +
    + + getName (line 88) +
    + + +

    returns the file name of the content

    +
      +
    • access: public
    • +
    + +
    + string + + getName + + () +
    + + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::getName()
    +
    returns the file name of the content
    +
    + +
    + +
    + +
    + + getPermissions (line 192) +
    + + +

    returns permissions

    +
      +
    • access: public
    • +
    + +
    + int + + getPermissions + + () +
    + + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::getPermissions()
    +
    returns permissions
    +
    + +
    + +
    + +
    + + getType (line 123) +
    + + +

    returns the type of the container

    +
      +
    • access: public
    • +
    + +
    + int + + getType + + () +
    + + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::getType()
    +
    returns the type of the container
    +
    + +
    + +
    + +
    + + getUser (line 285) +
    + + +

    returns owner of file

    +
      +
    • access: public
    • +
    + +
    + int + + getUser + + () +
    + + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::getUser()
    +
    returns owner of file
    +
    + +
    + +
    + +
    + + isExecutable (line 244) +
    + + +

    checks whether content is executable

    +
      +
    • access: public
    • +
    + +
    + bool + + isExecutable + + (int $user, int $group) +
    + +
      +
    • + int + $user: id of user to check for
    • +
    • + int + $group: id of group to check for
    • +
    + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::isExecutable()
    +
    checks whether content is executable
    +
    + +
    + +
    + +
    + + isOwnedByGroup (line 308) +
    + + +

    checks whether file is owned by group

    +
      +
    • access: public
    • +
    + +
    + bool + + isOwnedByGroup + + (int $group) +
    + +
      +
    • + int + $group
    • +
    + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::isOwnedByGroup()
    +
    checks whether file is owned by group
    +
    + +
    + +
    + +
    + + isOwnedByUser (line 275) +
    + + +

    checks whether file is owned by given user

    +
      +
    • access: public
    • +
    + +
    + bool + + isOwnedByUser + + (int $user) +
    + +
      +
    • + int + $user
    • +
    + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::isOwnedByUser()
    +
    checks whether file is owned by given user
    +
    + +
    + +
    + +
    + + isReadable (line 204) +
    + + +

    checks whether content is readable

    +
      +
    • access: public
    • +
    + +
    + bool + + isReadable + + (int $user, int $group) +
    + +
      +
    • + int + $user: id of user to check for
    • +
    • + int + $group: id of group to check for
    • +
    + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::isReadable()
    +
    checks whether content is readable
    +
    + +
    + +
    + +
    + + isWritable (line 224) +
    + + +

    checks whether content is writable

    +
      +
    • access: public
    • +
    + +
    + bool + + isWritable + + (int $user, int $group) +
    + +
      +
    • + int + $user: id of user to check for
    • +
    • + int + $group: id of group to check for
    • +
    + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::isWritable()
    +
    checks whether content is writable
    +
    + +
    + +
    + +
    + + lastModified (line 146) +
    + + +

    sets the last modification time of the stream content

    +
      +
    • access: public
    • +
    + +
    + vfsStreamContent + + lastModified + + (int $filemtime) +
    + +
      +
    • + int + $filemtime
    • +
    + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::lastModified()
    +
    sets the last modification time of the stream content
    +
    + +
    + +
    + +
    + + rename (line 98) +
    + + +

    renames the content

    +
      +
    • access: public
    • +
    + +
    + void + + rename + + (string $newName) +
    + +
      +
    • + string + $newName
    • +
    + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::rename()
    +
    renames the content
    +
    + +
    +
    Redefined in descendants as:
    + +
    + +
    + +
    + + setFilemtime (line 135) +
    + + +

    alias for lastModified()

    + + +
    + vfsStreamContent + + setFilemtime + + (int $filemtime) +
    + +
      +
    • + int + $filemtime
    • +
    + +
    +
    Implementation of:
    +
    +
    vfsStreamContent::setFilemtime()
    +
    alias for lastModified()
    +
    + +
    + +
    +
    + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:38 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamContainer.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamContainer.html new file mode 100644 index 0000000..8c2334b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamContainer.html @@ -0,0 +1,332 @@ + + + + + + Docs For Class vfsStreamContainer + + + + + +
    +

     ClassInterface vfsStreamContainer

    + + +
    +
    Description
    + +
    + +

    Interface for stream contents that are able to store other stream contents.

    +

    + Located in /vfsStreamContainer.php (line 13) +

    + + +
    IteratorAggregate
    +   |
    +   --vfsStreamContainer
    + +
    +
    + + + + + +
    +
    Method Summary
    + +
    +
    + +
    +  + void + addChild + (vfsStreamContent $child) +
    + +
    +  + vfsStreamContent + getChild + (string $name) +
    + +
    +  + array + getChildren + () +
    + +
    +  + bool + hasChild + (string $name) +
    + +
    +  + bool + removeChild + (string $name) +
    +
    +
    +
    + + + +
    +
    Methods
    + +
    + + +
    + +
    + + addChild (line 20) +
    + + +

    adds child to the directory

    +
      +
    • access: public
    • +
    + +
    + void + + addChild + + (vfsStreamContent $child) +
    + + + + +
    + +
    + +
    + + getChild (line 44) +
    + + +

    returns the child with the given name

    +
      +
    • access: public
    • +
    + +
    + vfsStreamContent + + getChild + + (string $name) +
    + +
      +
    • + string + $name
    • +
    + + +
    + +
    + +
    + + getChildren (line 51) +
    + + +

    returns a list of children for this directory

    +
      +
    • access: public
    • +
    + +
    + array + + getChildren + + () +
    + + + +
    + +
    + +
    + + hasChild (line 36) +
    + + +

    checks whether the container contains a child with the given name

    +
      +
    • access: public
    • +
    + +
    + bool + + hasChild + + (string $name) +
    + +
      +
    • + string + $name
    • +
    + + +
    + +
    + +
    + + removeChild (line 28) +
    + + +

    removes child from the directory

    +
      +
    • access: public
    • +
    + +
    + bool + + removeChild + + (string $name) +
    + +
      +
    • + string + $name
    • +
    + + +
    + +
    +
    + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:38 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamContainerIterator.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamContainerIterator.html new file mode 100644 index 0000000..c14185b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamContainerIterator.html @@ -0,0 +1,442 @@ + + + + + + Docs For Class vfsStreamContainerIterator + + + + + +
    +

     Class vfsStreamContainerIterator

    + + +
    +
    Description
    + +
    +

    + Implements interfaces: +

      +
    • Iterator (internal interface)
    +

    + +

    Iterator for children of a directory container.

    +

    + Located in /vfsStreamContainerIterator.php (line 13) +

    + + +
    
    +	
    +			
    +
    + + + + +
    +
    Variable Summary
    + +
    +
    +
    +  + array + $children +
    +
    +
    +
    + + +
    +
    Method Summary
    + +
    +
    + +
    +  + vfsStreamContainerIterator + __construct + ( $children) +
    + +
    +  + vfsStreamContent + current + () +
    + +
    +  + string + key + () +
    + +
    +  + void + next + () +
    + +
    +  + void + rewind + () +
    + +
    +  + bool + valid + () +
    +
    +
    +
    + + +
    +
    Variables
    + +
    + + +
    + +
    + + + array + $children + = array() (line 20) + +
    + + +

    list of children from container to iterate over

    +
      +
    • access: protected
    • +
    + + + + + +
    + +
    +
    + + +
    +
    Methods
    + +
    + + +
    + +
    + + Constructor __construct (line 27) +
    + + +

    constructor

    +
      +
    • access: public
    • +
    + +
    + vfsStreamContainerIterator + + __construct + + ( $children) +
    + +
      +
    • + array + $children
    • +
    + + +
    + +
    + +
    + + current (line 46) +
    + + +

    returns the current child

    +
      +
    • access: public
    • +
    + +
    + vfsStreamContent + + current + + () +
    + + +
    +
    Implementation of:
    +
    +
    Iterator::current
    +
    + +
    + +
    + +
    + + key (line 61) +
    + + +

    returns the name of the current child

    +
      +
    • access: public
    • +
    + +
    + string + + key + + () +
    + + +
    +
    Implementation of:
    +
    +
    Iterator::key
    +
    + +
    + +
    + +
    + + next (line 74) +
    + + +

    iterates to next child

    +
      +
    • access: public
    • +
    + +
    + void + + next + + () +
    + + +
    +
    Implementation of:
    +
    +
    Iterator::next
    +
    + +
    + +
    + +
    + + rewind (line 36) +
    + + +

    resets children pointer

    +
      +
    • access: public
    • +
    + +
    + void + + rewind + + () +
    + + +
    +
    Implementation of:
    +
    +
    Iterator::rewind
    +
    + +
    + +
    + +
    + + valid (line 84) +
    + + +

    checks if the current value is valid

    +
      +
    • access: public
    • +
    + +
    + bool + + valid + + () +
    + + +
    +
    Implementation of:
    +
    +
    Iterator::valid
    +
    + +
    + +
    +
    + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:38 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamContent.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamContent.html new file mode 100644 index 0000000..7d368fb --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamContent.html @@ -0,0 +1,952 @@ + + + + + + Docs For Class vfsStreamContent + + + + + +
    +

     ClassInterface vfsStreamContent

    + + +
    +
    Description
    + +
    + +

    Interface for stream contents.

    +

    + Located in /vfsStreamContent.php (line 17) +

    + + +
    
    +	
    +			
    +
    + + + +
    +
    Class Constant Summary
    + +
    +
    +
    +  + TYPE_DIR = 0040000 + +
    +
    +  + TYPE_FILE = 0100000 + +
    +
    +
    +
    + + + +
    +
    Method Summary
    + +
    +
    + +
    +  + bool + appliesTo + (string $name) +
    + +
    +  + vfsStreamContent + at + (vfsStreamContainer $container) +
    + +
    +  + vfsStreamContent + chgrp + (int $group) +
    + +
    +  + vfsStreamContent + chmod + (int $permissions) +
    + +
    +  + vfsStreamContent + chown + (int $user) +
    + +
    +  + int + filemtime + () +
    + +
    +  + int + getGroup + () +
    + +
    +  + string + getName + () +
    + +
    +  + int + getPermissions + () +
    + +
    +  + int + getType + () +
    + +
    +  + int + getUser + () +
    + +
    +  + bool + isExecutable + (int $user, int $group) +
    + +
    +  + bool + isOwnedByGroup + (int $group) +
    + +
    +  + bool + isOwnedByUser + (int $user) +
    + +
    +  + bool + isReadable + (int $user, int $group) +
    + +
    +  + bool + isWritable + (int $user, int $group) +
    + +
    +  + vfsStreamContent + lastModified + (int $filemtime) +
    + +
    +  + void + rename + (string $newName) +
    + +
    +  + vfsStreamContent + setFilemtime + (int $filemtime) +
    + +
    +  + int + size + () +
    +
    +
    +
    + + + +
    +
    Methods
    + +
    + + +
    + +
    + + appliesTo (line 58) +
    + + +

    checks whether the container can be applied to given name

    +
      +
    • access: public
    • +
    + +
    + bool + + appliesTo + + (string $name) +
    + +
      +
    • + string + $name
    • +
    + + +
    + +
    + +
    + + at (line 104) +
    + + +

    adds content to given container

    +
      +
    • access: public
    • +
    + +
    + vfsStreamContent + + at + + (vfsStreamContainer $container) +
    + + + + +
    + +
    + +
    + + chgrp (line 177) +
    + + +

    change owner group of file to given group

    +
      +
    • access: public
    • +
    + +
    + vfsStreamContent + + chgrp + + (int $group) +
    + +
      +
    • + int + $group
    • +
    + + +
    + +
    + +
    + + chmod (line 112) +
    + + +

    change file mode to given permissions

    +
      +
    • access: public
    • +
    + +
    + vfsStreamContent + + chmod + + (int $permissions) +
    + +
      +
    • + int + $permissions
    • +
    + + +
    + +
    + +
    + + chown (line 154) +
    + + +

    change owner of file to given user

    +
      +
    • access: public
    • +
    + +
    + vfsStreamContent + + chown + + (int $user) +
    + +
      +
    • + int + $user
    • +
    + + +
    + +
    + +
    + + filemtime (line 96) +
    + + +

    returns the last modification time of the stream content

    +
      +
    • access: public
    • +
    + +
    + int + + filemtime + + () +
    + + + +
    + +
    + +
    + + getGroup (line 192) +
    + + +

    returns owner group of file

    +
      +
    • access: public
    • +
    + +
    + int + + getGroup + + () +
    + + + +
    + +
    + +
    + + getName (line 43) +
    + + +

    returns the file name of the content

    +
      +
    • access: public
    • +
    + +
    + string + + getName + + () +
    + + + +
    + +
    + +
    + + getPermissions (line 119) +
    + + +

    returns permissions

    +
      +
    • access: public
    • +
    + +
    + int + + getPermissions + + () +
    + + + +
    + +
    + +
    + + getType (line 65) +
    + + +

    returns the type of the container

    +
      +
    • access: public
    • +
    + +
    + int + + getType + + () +
    + + + +
    + +
    + +
    + + getUser (line 169) +
    + + +

    returns owner of file

    +
      +
    • access: public
    • +
    + +
    + int + + getUser + + () +
    + + + +
    + +
    + +
    + + isExecutable (line 146) +
    + + +

    checks whether content is executable

    +
      +
    • access: public
    • +
    + +
    + bool + + isExecutable + + (int $user, int $group) +
    + +
      +
    • + int + $user: id of user to check for
    • +
    • + int + $group: id of group to check for
    • +
    + + +
    + +
    + +
    + + isOwnedByGroup (line 185) +
    + + +

    checks whether file is owned by group

    +
      +
    • access: public
    • +
    + +
    + bool + + isOwnedByGroup + + (int $group) +
    + +
      +
    • + int + $group
    • +
    + + +
    + +
    + +
    + + isOwnedByUser (line 162) +
    + + +

    checks whether file is owned by given user

    +
      +
    • access: public
    • +
    + +
    + bool + + isOwnedByUser + + (int $user) +
    + +
      +
    • + int + $user
    • +
    + + +
    + +
    + +
    + + isReadable (line 128) +
    + + +

    checks whether content is readable

    +
      +
    • access: public
    • +
    + +
    + bool + + isReadable + + (int $user, int $group) +
    + +
      +
    • + int + $user: id of user to check for
    • +
    • + int + $group: id of group to check for
    • +
    + + +
    + +
    + +
    + + isWritable (line 137) +
    + + +

    checks whether content is writable

    +
      +
    • access: public
    • +
    + +
    + bool + + isWritable + + (int $user, int $group) +
    + +
      +
    • + int + $user: id of user to check for
    • +
    • + int + $group: id of group to check for
    • +
    + + +
    + +
    + +
    + + lastModified (line 89) +
    + + +

    sets the last modification time of the stream content

    +
      +
    • access: public
    • +
    + +
    + vfsStreamContent + + lastModified + + (int $filemtime) +
    + +
      +
    • + int + $filemtime
    • +
    + + +
    + +
    + +
    + + rename (line 50) +
    + + +

    renames the content

    +
      +
    • access: public
    • +
    + +
    + void + + rename + + (string $newName) +
    + +
      +
    • + string + $newName
    • +
    + + +
    + +
    + +
    + + setFilemtime (line 81) +
    + + +

    alias for lastModified()

    + + +
    + vfsStreamContent + + setFilemtime + + (int $filemtime) +
    + +
      +
    • + int + $filemtime
    • +
    + + +
    + +
    + +
    + + size (line 72) +
    + + +

    returns size of content

    +
      +
    • access: public
    • +
    + +
    + int + + size + + () +
    + + + +
    + +
    +
    + + +
    +
    Class Constants
    + +
    + +
    + +
    + + + TYPE_DIR + = 0040000 + (line 30) + +
    + + +

    stream content type: directory

    + + + +
    + +
    + +
    + + + TYPE_FILE + = 0100000 + (line 24) + +
    + + +

    stream content type: file

    + + + +
    + +
    +
    + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:39 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamDirectory.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamDirectory.html new file mode 100644 index 0000000..162ff27 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamDirectory.html @@ -0,0 +1,813 @@ + + + + + + Docs For Class vfsStreamDirectory + + + + + +
    +

     Class vfsStreamDirectory

    + + +
    +
    Description
    + +
    +

    + Implements interfaces: +

    +

    + +

    Directory container.

    +

    + Located in /vfsStreamDirectory.php (line 20) +

    + + +
    vfsStreamAbstractContent
    +   |
    +   --vfsStreamDirectory
    + +
    +
    + + + + +
    +
    Variable Summary
    + +
    +
    +
    +  + array + $children +
    +
    +
    +
    + + +
    +
    Method Summary
    + +
    +
    + +
    +  + static string + getChildName + (string $name, string $ownName) +
    + +
    +  + vfsStreamDirectory + __construct + (string $name, [int $permissions = null]) +
    + +
    +  + void + addChild + (vfsStreamContent $child) +
    + +
    +  + vfsStreamContent + getChild + (string $name) +
    + +
    +  + array + getChildren + () +
    + +
    +  + int + getDefaultPermissions + () +
    + + + +
    +  + string + getRealChildName + (string $name) +
    + +
    +  + bool + hasChild + (string $name) +
    + +
    +  + bool + removeChild + (string $name) +
    + +
    +  + void + rename + (string $newName) +
    + +
    +  + int + size + () +
    + +
    +  + int + sizeSummarized + () +
    +
    +
    +
    + + +
    +
    Variables
    + +
    + + +
    + +
    + + + array + $children + = array() (line 27) + +
    + + +

    list of directory children

    +
      +
    • access: protected
    • +
    + + + + + +
    +

    Inherited Variables

    + +

    Inherited from vfsStreamAbstractContent

    +
    + + + vfsStreamAbstractContent::$group
    +
    + + + vfsStreamAbstractContent::$lastModified
    +
    + + + vfsStreamAbstractContent::$name
    +
    + + + vfsStreamAbstractContent::$permissions
    +
    + + + vfsStreamAbstractContent::$type
    +
    + + + vfsStreamAbstractContent::$user
    +
    +
    + +
    +
    + + +
    +
    Methods
    + +
    + + +
    + +
    + + static getChildName (line 187) +
    + + +

    helper method to calculate the child name

    +
      +
    • access: protected
    • +
    + +
    + static string + + getChildName + + (string $name, string $ownName) +
    + +
      +
    • + string + $name
    • +
    • + string + $ownName
    • +
    + + +
    + +
    + +
    + + Constructor __construct (line 36) +
    + + +

    constructor

    +
      +
    • throws: vfsStreamException
    • +
    • access: public
    • +
    + +
    + vfsStreamDirectory + + __construct + + (string $name, [int $permissions = null]) +
    + +
      +
    • + string + $name
    • +
    • + int + $permissions: optional
    • +
    + +
    +
    Redefinition of:
    +
    +
    vfsStreamAbstractContent::__construct()
    +
    constructor
    +
    + +
    + +
    + +
    + + addChild (line 109) +
    + + +

    adds child to the directory

    +
      +
    • access: public
    • +
    + +
    + void + + addChild + + (vfsStreamContent $child) +
    + + + +
    +
    Implementation of:
    +
    +
    vfsStreamContainer::addChild()
    +
    adds child to the directory
    +
    + +
    + +
    + +
    + + getChild (line 149) +
    + + +

    returns the child with the given name

    +
      +
    • access: public
    • +
    + +
    + vfsStreamContent + + getChild + + (string $name) +
    + +
      +
    • + string + $name
    • +
    + +
    +
    Implementation of:
    +
    +
    vfsStreamContainer::getChild()
    +
    returns the child with the given name
    +
    + +
    + +
    + +
    + + getChildren (line 197) +
    + + +

    returns a list of children for this directory

    +
      +
    • access: public
    • +
    + +
    + array + + getChildren + + () +
    + + +
    +
    Implementation of:
    +
    +
    vfsStreamContainer::getChildren()
    +
    returns a list of children for this directory
    +
    + +
    + +
    + +
    + + getDefaultPermissions (line 52) +
    + + +

    returns default permissions for concrete implementation

    +
      +
    • since: 0.8.0
    • +
    • access: protected
    • +
    + +
    + int + + getDefaultPermissions + + () +
    + + +
    +
    Redefinition of:
    +
    +
    vfsStreamAbstractContent::getDefaultPermissions()
    +
    returns default permissions for concrete implementation
    +
    + +
    + +
    + +
    + + getIterator (line 207) +
    + + +

    returns iterator for the children

    +
      +
    • access: public
    • +
    + +
    + vfsStreamContainerIterator + + getIterator + + () +
    + + + +
    + +
    + +
    + + getRealChildName (line 171) +
    + + +

    helper method to detect the real child name

    +
      +
    • access: protected
    • +
    + +
    + string + + getRealChildName + + (string $name) +
    + +
      +
    • + string + $name
    • +
    + + +
    + +
    + +
    + + hasChild (line 138) +
    + + +

    checks whether the container contains a child with the given name

    +
      +
    • access: public
    • +
    + +
    + bool + + hasChild + + (string $name) +
    + +
      +
    • + string + $name
    • +
    + +
    +
    Implementation of:
    +
    +
    vfsStreamContainer::hasChild()
    +
    checks whether the container contains a child with the given name
    +
    + +
    + +
    + +
    + + removeChild (line 120) +
    + + +

    removes child from the directory

    +
      +
    • access: public
    • +
    + +
    + bool + + removeChild + + (string $name) +
    + +
      +
    • + string + $name
    • +
    + +
    +
    Implementation of:
    +
    +
    vfsStreamContainer::removeChild()
    +
    removes child from the directory
    +
    + +
    + +
    + +
    + + rename (line 95) +
    + + +

    renames the content

    +
      +
    • throws: vfsStreamException
    • +
    • access: public
    • +
    + +
    + void + + rename + + (string $newName) +
    + +
      +
    • + string + $newName
    • +
    + +
    +
    Redefinition of:
    +
    +
    vfsStreamAbstractContent::rename()
    +
    renames the content
    +
    + +
    + +
    + +
    + + size (line 65) +
    + + +

    returns size of directory

    +

    The size of a directory is always 0 bytes. To calculate the summarized size of all children in the directory use sizeSummarized().

    +
      +
    • access: public
    • +
    + +
    + int + + size + + () +
    + + + +
    + +
    + +
    + + sizeSummarized (line 75) +
    + + +

    returns summarized size of directory and its children

    +
      +
    • access: public
    • +
    + +
    + int + + sizeSummarized + + () +
    + + + +
    +

    Inherited Methods

    + + +

    Inherited From vfsStreamAbstractContent

    +
    +  + vfsStreamAbstractContent::__construct()
    +  + vfsStreamAbstractContent::appliesTo()
    +  + vfsStreamAbstractContent::at()
    +  + vfsStreamAbstractContent::chgrp()
    +  + vfsStreamAbstractContent::chmod()
    +  + vfsStreamAbstractContent::chown()
    +  + vfsStreamAbstractContent::filemtime()
    +  + vfsStreamAbstractContent::getDefaultPermissions()
    +  + vfsStreamAbstractContent::getGroup()
    +  + vfsStreamAbstractContent::getName()
    +  + vfsStreamAbstractContent::getPermissions()
    +  + vfsStreamAbstractContent::getType()
    +  + vfsStreamAbstractContent::getUser()
    +  + vfsStreamAbstractContent::isExecutable()
    +  + vfsStreamAbstractContent::isOwnedByGroup()
    +  + vfsStreamAbstractContent::isOwnedByUser()
    +  + vfsStreamAbstractContent::isReadable()
    +  + vfsStreamAbstractContent::isWritable()
    +  + vfsStreamAbstractContent::lastModified()
    +  + vfsStreamAbstractContent::rename()
    +  + vfsStreamAbstractContent::setFilemtime()
    +
    + +
    +
    + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:40 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamException.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamException.html new file mode 100644 index 0000000..db27ae2 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamException.html @@ -0,0 +1,212 @@ + + + + + + Docs For Class vfsStreamException + + + + + +
    +

     Class vfsStreamException

    + + +
    +
    Description
    + +
    + +

    Exception for streamwrapper subpackage.

    +

    + Located in /vfsStreamException.php (line 13) +

    + + +
    Exception
    +   |
    +   --vfsStreamException
    + +
    +
    + + + + + + +
    +
    Variables
    + +
    + +

    Inherited Variables

    + +

    Inherited from Exception (Internal Class)

    +
    + + + $code
    +
    + + + $file
    +
    + + + $line
    +
    + + + $message
    +
    + + + $string
    +
    + + + $trace
    +
    +
    + +
    +
    + + +
    +
    Methods
    + +
    + +

    Inherited Methods

    + + +

    Inherited From Exception (Internal Class)

    +
    +  + constructor __construct ( [$message = ], [$code = ] )
    +  + getCode ( )
    +  + getFile ( )
    +  + getLine ( )
    +  + getMessage ( )
    +  + getTrace ( )
    +  + getTraceAsString ( )
    +  + __clone ( )
    +  + __toString ( )
    +
    + +
    +
    + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:40 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamFile.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamFile.html new file mode 100644 index 0000000..df79d68 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamFile.html @@ -0,0 +1,803 @@ + + + + + + Docs For Class vfsStreamFile + + + + + +
    +

     Class vfsStreamFile

    + + +
    +
    Description
    + +
    + +

    File container.

    +

    + Located in /vfsStreamFile.php (line 17) +

    + + +
    vfsStreamAbstractContent
    +   |
    +   --vfsStreamFile
    + +
    +
    + + + + +
    +
    Variable Summary
    + +
    +
    +
    +  + int + $bytes_read +
    +
    +  + string + $content +
    +
    +
    +
    + + +
    +
    Method Summary
    + +
    +
    + +
    +  + vfsStreamFile + __construct + (string $name, [int $permissions = null]) +
    + +
    +  + bool + appliesTo + (string $name) +
    + +
    +  + bool + eof + () +
    + +
    +  + int + getBytesRead + () +
    + +
    +  + string + getContent + () +
    + +
    +  + int + getDefaultPermissions + () +
    + +
    +  + string + read + (int $count) +
    + +
    +  + string + readUntilEnd + () +
    + +
    +  + bool + seek + (int $offset, int $whence) +
    + +
    +  + vfsStreamFile + setContent + (string $content) +
    + +
    +  + int + size + () +
    + +
    +  + vfsStreamFile + withContent + (string $content) +
    + +
    +  + amount + write + (string $data) +
    +
    +
    +
    + + +
    +
    Variables
    + +
    + + +
    + +
    + + + int + $bytes_read + = 0 (line 30) + +
    + + +

    amount of read bytes

    +
      +
    • access: protected
    • +
    + + + + + +
    + +
    + +
    + + + string + $content + (line 24) + +
    + + +

    the real content of the file

    +
      +
    • access: protected
    • +
    + + + + + +
    +

    Inherited Variables

    + +

    Inherited from vfsStreamAbstractContent

    +
    + + + vfsStreamAbstractContent::$group
    +
    + + + vfsStreamAbstractContent::$lastModified
    +
    + + + vfsStreamAbstractContent::$name
    +
    + + + vfsStreamAbstractContent::$permissions
    +
    + + + vfsStreamAbstractContent::$type
    +
    + + + vfsStreamAbstractContent::$user
    +
    +
    + +
    +
    + + +
    +
    Methods
    + +
    + + +
    + +
    + + Constructor __construct (line 38) +
    + + +

    constructor

    +
      +
    • access: public
    • +
    + +
    + vfsStreamFile + + __construct + + (string $name, [int $permissions = null]) +
    + +
      +
    • + string + $name
    • +
    • + int + $permissions: optional
    • +
    + +
    +
    Redefinition of:
    +
    +
    vfsStreamAbstractContent::__construct()
    +
    constructor
    +
    + +
    + +
    + +
    + + appliesTo (line 61) +
    + + +

    checks whether the container can be applied to given name

    +
      +
    • access: public
    • +
    + +
    + bool + + appliesTo + + (string $name) +
    + +
      +
    • + string + $name
    • +
    + +
    +
    Redefinition of:
    +
    +
    vfsStreamAbstractContent::appliesTo()
    +
    checks whether the container can be applied to given name
    +
    + +
    + +
    + +
    + + eof (line 149) +
    + + +

    checks whether pointer is at end of file

    +
      +
    • access: public
    • +
    + +
    + bool + + eof + + () +
    + + + +
    + +
    + +
    + + getBytesRead (line 159) +
    + + +

    returns the current position within the file

    +
      +
    • access: public
    • +
    + +
    + int + + getBytesRead + + () +
    + + + +
    + +
    + +
    + + getContent (line 99) +
    + + +

    returns the contents of the file

    +
      +
    • access: public
    • +
    + +
    + string + + getContent + + () +
    + + + +
    + +
    + +
    + + getDefaultPermissions (line 50) +
    + + +

    returns default permissions for concrete implementation

    +
      +
    • since: 0.8.0
    • +
    • access: protected
    • +
    + +
    + int + + getDefaultPermissions + + () +
    + + +
    +
    Redefinition of:
    +
    +
    vfsStreamAbstractContent::getDefaultPermissions()
    +
    returns default permissions for concrete implementation
    +
    + +
    + +
    + +
    + + read (line 110) +
    + + +

    reads the given amount of bytes from content

    +
      +
    • access: public
    • +
    + +
    + string + + read + + (int $count) +
    + +
      +
    • + int + $count
    • +
    + + +
    + +
    + +
    + + readUntilEnd (line 122) +
    + + +

    returns the content until its end from current offset

    +
      +
    • access: public
    • +
    + +
    + string + + readUntilEnd + + () +
    + + + +
    + +
    + +
    + + seek (line 171) +
    + + +

    seeks to the given offset

    +
      +
    • access: public
    • +
    + +
    + bool + + seek + + (int $offset, int $whence) +
    + +
      +
    • + int + $offset
    • +
    • + int + $whence
    • +
    + + +
    + +
    + +
    + + setContent (line 73) +
    + + +

    alias for withContent()

    + + +
    + vfsStreamFile + + setContent + + (string $content) +
    + +
      +
    • + string + $content
    • +
    + + +
    + +
    + +
    + + size (line 198) +
    + + +

    returns size of content

    +
      +
    • access: public
    • +
    + +
    + int + + size + + () +
    + + + +
    + +
    + +
    + + withContent (line 88) +
    + + +

    sets the contents of the file

    +

    Setting content with this method does not change the time when the file was last modified.

    + + +
    + vfsStreamFile + + withContent + + (string $content) +
    + +
      +
    • + string + $content
    • +
    + + +
    + +
    + +
    + + write (line 135) +
    + + +

    writes an amount of data

    +

    Using this method changes the time when the file was last modified.

    +
      +
    • return: of written bytes
    • +
    • access: public
    • +
    + +
    + amount + + write + + (string $data) +
    + +
      +
    • + string + $data
    • +
    + + +
    +

    Inherited Methods

    + + +

    Inherited From vfsStreamAbstractContent

    +
    +  + vfsStreamAbstractContent::__construct()
    +  + vfsStreamAbstractContent::appliesTo()
    +  + vfsStreamAbstractContent::at()
    +  + vfsStreamAbstractContent::chgrp()
    +  + vfsStreamAbstractContent::chmod()
    +  + vfsStreamAbstractContent::chown()
    +  + vfsStreamAbstractContent::filemtime()
    +  + vfsStreamAbstractContent::getDefaultPermissions()
    +  + vfsStreamAbstractContent::getGroup()
    +  + vfsStreamAbstractContent::getName()
    +  + vfsStreamAbstractContent::getPermissions()
    +  + vfsStreamAbstractContent::getType()
    +  + vfsStreamAbstractContent::getUser()
    +  + vfsStreamAbstractContent::isExecutable()
    +  + vfsStreamAbstractContent::isOwnedByGroup()
    +  + vfsStreamAbstractContent::isOwnedByUser()
    +  + vfsStreamAbstractContent::isReadable()
    +  + vfsStreamAbstractContent::isWritable()
    +  + vfsStreamAbstractContent::lastModified()
    +  + vfsStreamAbstractContent::rename()
    +  + vfsStreamAbstractContent::setFilemtime()
    +
    + +
    +
    + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:41 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamWrapper.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamWrapper.html new file mode 100644 index 0000000..5694006 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamWrapper.html @@ -0,0 +1,1507 @@ + + + + + + Docs For Class vfsStreamWrapper + + + + + +
    +

     Class vfsStreamWrapper

    + + +
    +
    Description
    + +
    + +

    Stream wrapper to mock file system requests.

    +

    + Located in /vfsStreamWrapper.php (line 19) +

    + + +
    
    +	
    +			
    +
    + + + +
    +
    Class Constant Summary
    + +
    +
    +
    +  + ALL = 2 + +
    +
    +  + APPEND = 'a' + +
    +
    +  + READ = 'r' + +
    +
    +  + READONLY = 0 + +
    +
    +  + TRUNCATE = 'w' + +
    +
    +  + WRITE = 'x' + +
    +
    +  + WRITEONLY = 1 + +
    +
    +
    +
    + + +
    +
    Variable Summary
    + +
    +
    +
    +  + static bool + $registered +
    +
    +  + static vfsStreamContent + $root +
    + + + +
    +  + int + $mode +
    +
    +
    +
    + + +
    +
    Method Summary
    + +
    +
    + +
    +  + static vfsStreamContent + getRoot + () +
    + +
    +  + static void + register + () +
    + +
    +  + static void + setRoot + (vfsStreamContent $root) +
    + +
    +  + int + calculateMode + (string $mode, bool $extended) +
    + +
    +  + bool + dir_closedir + () +
    + +
    +  + bool + dir_opendir + (string $path, int $options) +
    + +
    +  + string + dir_readdir + () +
    + +
    +  + bool + dir_rewinddir + () +
    + +
    +  + vfsStreamContent + getContent + (string $path) +
    + +
    +  + vfsStreamContent + getContentOfType + (string $path, int $type) +
    + +
    +  + bool + mkdir + (string $path, int $mode, int $options) +
    + +
    +  + bool + rename + (string $path_from, string $path_to) +
    + +
    +  + string + resolvePath + (string $path) +
    + +
    +  + bool + rmdir + (string $path, int $options) +
    + +
    +  + array + splitPath + (string $path) +
    + +
    +  + void + stream_close + () +
    + +
    +  + bool + stream_eof + () +
    + +
    +  + bool + stream_flush + () +
    + +
    +  + bool + stream_open + (string $path, string $mode, string $options, string $opened_path) +
    + +
    +  + string + stream_read + (int $count) +
    + +
    +  + bool + stream_seek + (int $offset, int $whence) +
    + +
    +  + array + stream_stat + () +
    + +
    +  + int + stream_tell + () +
    + +
    +  + int + stream_write + (string $data) +
    + +
    +  + bool + unlink + (string $path) +
    + +
    +  + array + url_stat + (string $path, ? $flags) +
    +
    +
    +
    + + +
    +
    Variables
    + +
    + +
    + +
    + + + static bool + $registered + = false (line 54) + +
    + + +

    switch whether class has already been registered as stream wrapper or not

    +
      +
    • access: protected
    • +
    + + + + + +
    + +
    + +
    + + + static vfsStreamContent + $root + (line 60) + +
    + + +

    root content

    +
      +
    • access: protected
    • +
    + + + + + +
    + + +
    + +
    + + + vfsStreamFile + $content + (line 72) + +
    + + +

    shortcut to file container

    +
      +
    • access: protected
    • +
    + + + + + +
    + +
    + +
    + + + vfsStreamDirectory + $dir + (line 78) + +
    + + +

    shortcut to directory container

    +
      +
    • access: protected
    • +
    + + + + + +
    + +
    + +
    + + + vfsStreamDirectory + $dirIterator + (line 84) + +
    + + +

    shortcut to directory container iterator

    +
      +
    • access: protected
    • +
    + + + + + +
    + +
    + +
    + + + int + $mode + (line 66) + +
    + + +

    file mode: read only, write only, all

    +
      +
    • access: protected
    • +
    + + + + + +
    + +
    +
    + + +
    +
    Methods
    + +
    + + +
    + +
    + + static getRoot (line 126) +
    + + +

    returns the root content

    +
      +
    • access: public
    • +
    + +
    + static vfsStreamContent + + getRoot + + () +
    + + + +
    + +
    + +
    + + static register (line 97) +
    + + +

    method to register the stream wrapper

    +

    Please be aware that a call to this method will reset the root element to null. If the stream is already registered the method returns silently. If there is already another stream wrapper registered for the scheme used by vfsStream a vfsStreamException will be thrown.

    +
      +
    • throws: vfsStreamException
    • +
    • access: public
    • +
    + +
    + static void + + register + + () +
    + + + +
    + +
    + +
    + + static setRoot (line 116) +
    + + +

    sets the root content

    +
      +
    • access: public
    • +
    + +
    + static void + + setRoot + + (vfsStreamContent $root) +
    + + + + +
    + +
    + +
    + + calculateMode (line 305) +
    + + +

    calculates the file mode

    +
      +
    • access: protected
    • +
    + +
    + int + + calculateMode + + (string $mode, bool $extended) +
    + +
      +
    • + string + $mode: opening mode: r, w, a or x
    • +
    • + bool + $extended: true if + was set with opening mode
    • +
    + + +
    + +
    + +
    + + dir_closedir (line 639) +
    + + +

    closes directory

    +
      +
    • access: public
    • +
    + +
    + bool + + dir_closedir + + () +
    + + + +
    + +
    + +
    + + dir_opendir (line 596) +
    + + +

    opens a directory

    +
      +
    • access: public
    • +
    + +
    + bool + + dir_opendir + + (string $path, int $options) +
    + +
      +
    • + string + $path
    • +
    • + int + $options
    • +
    + + +
    + +
    + +
    + + dir_readdir (line 613) +
    + + +

    reads directory contents

    +
      +
    • access: public
    • +
    + +
    + string + + dir_readdir + + () +
    + + + +
    + +
    + +
    + + dir_rewinddir (line 629) +
    + + +

    reset directory iteration

    +
      +
    • access: public
    • +
    + +
    + bool + + dir_rewinddir + + () +
    + + + +
    + +
    + +
    + + getContent (line 137) +
    + + +

    returns content for given path

    +
      +
    • access: protected
    • +
    + +
    + vfsStreamContent + + getContent + + (string $path) +
    + +
      +
    • + string + $path
    • +
    + + +
    + +
    + +
    + + getContentOfType (line 161) +
    + + +

    returns content for given path but only when it is of given type

    +
      +
    • access: protected
    • +
    + +
    + vfsStreamContent + + getContentOfType + + (string $path, int $type) +
    + +
      +
    • + string + $path
    • +
    • + int + $type
    • +
    + + +
    + +
    + +
    + + mkdir (line 508) +
    + + +

    creates a new directory

    +
      +
    • access: public
    • +
    + +
    + bool + + mkdir + + (string $path, int $mode, int $options) +
    + +
      +
    • + string + $path
    • +
    • + int + $mode
    • +
    • + int + $options
    • +
    + + +
    + +
    + +
    + + rename (line 469) +
    + + +

    rename from one path to another

    +
      +
    • author: Benoit Aubuchon
    • +
    • access: public
    • +
    + +
    + bool + + rename + + (string $path_from, string $path_to) +
    + +
      +
    • + string + $path_from
    • +
    • + string + $path_to
    • +
    + + +
    + +
    + +
    + + resolvePath (line 195) +
    + + +

    helper method to resolve a path from /foo/bar/. to /foo/bar

    +
      +
    • access: protected
    • +
    + +
    + string + + resolvePath + + (string $path) +
    + +
      +
    • + string + $path
    • +
    + + +
    + +
    + +
    + + rmdir (line 559) +
    + + +

    removes a directory

    +
      +
    • todo: consider $options with STREAM_MKDIR_RECURSIVE
    • +
    • access: public
    • +
    + +
    + bool + + rmdir + + (string $path, int $options) +
    + +
      +
    • + string + $path
    • +
    • + int + $options
    • +
    + + +
    + +
    + +
    + + splitPath (line 177) +
    + + +

    splits path into its dirname and the basename

    +
      +
    • access: protected
    • +
    + +
    + array + + splitPath + + (string $path) +
    + +
      +
    • + string + $path
    • +
    + + +
    + +
    + +
    + + stream_close (line 321) +
    + + +

    closes the stream

    +
      +
    • access: public
    • +
    + +
    + void + + stream_close + + () +
    + + + +
    + +
    + +
    + + stream_eof (line 369) +
    + + +

    checks whether stream is at end of file

    +
      +
    • access: public
    • +
    + +
    + bool + + stream_eof + + () +
    + + + +
    + +
    + +
    + + stream_flush (line 401) +
    + + +

    flushes unstored data into storage

    +
      +
    • access: public
    • +
    + +
    + bool + + stream_flush + + () +
    + + + +
    + +
    + +
    + + stream_open (line 220) +
    + + +

    open the stream

    +
      +
    • access: public
    • +
    + +
    + bool + + stream_open + + (string $path, string $mode, string $options, string $opened_path) +
    + +
      +
    • + string + $path: the path to open
    • +
    • + string + $mode: mode for opening
    • +
    • + string + $options: options for opening
    • +
    • + string + $opened_path: full path that was actually opened
    • +
    + + +
    + +
    + +
    + + stream_read (line 332) +
    + + +

    read the stream up to $count bytes

    +
      +
    • access: public
    • +
    + +
    + string + + stream_read + + (int $count) +
    + +
      +
    • + int + $count: amount of bytes to read
    • +
    + + +
    + +
    + +
    + + stream_seek (line 391) +
    + + +

    seeks to the given offset

    +
      +
    • access: public
    • +
    + +
    + bool + + stream_seek + + (int $offset, int $whence) +
    + +
      +
    • + int + $offset
    • +
    • + int + $whence
    • +
    + + +
    + +
    + +
    + + stream_stat (line 411) +
    + + +

    returns status of stream

    +
      +
    • access: public
    • +
    + +
    + array + + stream_stat + + () +
    + + + +
    + +
    + +
    + + stream_tell (line 379) +
    + + +

    returns the current position of the stream

    +
      +
    • access: public
    • +
    + +
    + int + + stream_tell + + () +
    + + + +
    + +
    + +
    + + stream_write (line 351) +
    + + +

    writes data into the stream

    +
      +
    • return: amount of bytes written
    • +
    • access: public
    • +
    + +
    + int + + stream_write + + (string $data) +
    + +
      +
    • + string + $data
    • +
    + + +
    + +
    + +
    + + unlink (line 436) +
    + + +

    remove the data under the given path

    +
      +
    • access: public
    • +
    + +
    + bool + + unlink + + (string $path) +
    + +
      +
    • + string + $path
    • +
    + + +
    + +
    + +
    + + url_stat (line 652) +
    + + +

    returns status of url

    +
      +
    • access: public
    • +
    + +
    + array + + url_stat + + (string $path, ? $flags) +
    + +
      +
    • + string + $path: path of url to return status for
    • +
    • + ? + $flags: flags set by the stream API
    • +
    + + +
    + +
    +
    + + +
    +
    Class Constants
    + +
    + +
    + +
    + + + ALL + = 2 + (line 48) + +
    + + +

    file mode: read and write

    + + +
    + +
    + +
    + + + APPEND + = 'a' + (line 32) + +
    + + +

    set file pointer to end, append new data

    + + +
    + +
    + +
    + + + READ + = 'r' + (line 24) + +
    + + +

    open file for reading

    + + +
    + +
    + +
    + + + READONLY + = 0 + (line 40) + +
    + + +

    file mode: read only

    + + +
    + +
    + +
    + + + TRUNCATE + = 'w' + (line 28) + +
    + + +

    truncate file

    + + +
    + +
    + +
    + + + WRITE + = 'x' + (line 36) + +
    + + +

    set file pointer to start, overwrite existing data

    + + +
    + +
    + +
    + + + WRITEONLY + = 1 + (line 44) + +
    + + +

    file mode: write only

    + + +
    + +
    +
    + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:44 +0200 by phpDocumentor 1.4.3 +

    +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/classtrees_bovigo_vfs.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/classtrees_bovigo_vfs.html new file mode 100644 index 0000000..edf7cd8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/classtrees_bovigo_vfs.html @@ -0,0 +1,49 @@ + + + + + + + + + + + +

    + +

    +

    Root interface vfsStreamContent

    + + +

    Root interface IteratorAggregate

    + + +

    Root class vfsStream

    + + +

    Root class vfsStreamAbstractContent

    + + +

    Root class vfsStreamContainerIterator

    + + +

    Root class vfsStreamWrapper

    + + +

    Root class Exception

    + + +

    + Documentation generated on Fri, 08 Oct 2010 12:16:36 +0200 by phpDocumentor 1.4.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/elementindex.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/elementindex.html new file mode 100644 index 0000000..6f10982 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/elementindex.html @@ -0,0 +1,1538 @@ + + + + + + + + + + +

    Full index

    +

    Package indexes

    + +
    +
    + a + b + c + d + e + f + g + h + i + k + l + m + n + o + p + r + s + t + u + v + w + _ +
    + + +
    +
    a
    + +
    +
    +
    +
    + Method + addChild +
    +
    +
    vfsStreamDirectory::addChild() in vfsStreamDirectory.php
    +
    adds child to the directory
    +
    +
    + Method + addChild +
    +
    +
    vfsStreamContainer::addChild() in vfsStreamContainer.php
    +
    adds child to the directory
    +
    +
    + Class Constant + ALL +
    +
    +
    vfsStreamWrapper::ALL in vfsStreamWrapper.php
    +
    file mode: read and write
    +
    +
    + Class Constant + APPEND +
    +
    +
    vfsStreamWrapper::APPEND in vfsStreamWrapper.php
    +
    set file pointer to end, append new data
    +
    +
    + Method + appliesTo +
    +
    +
    vfsStreamFile::appliesTo() in vfsStreamFile.php
    +
    checks whether the container can be applied to given name
    +
    +
    + Method + appliesTo +
    +
    +
    vfsStreamContent::appliesTo() in vfsStreamContent.php
    +
    checks whether the container can be applied to given name
    +
    +
    + Method + appliesTo +
    +
    +
    vfsStreamAbstractContent::appliesTo() in vfsStreamAbstractContent.php
    +
    checks whether the container can be applied to given name
    +
    +
    + Method + at +
    +
    +
    vfsStreamContent::at() in vfsStreamContent.php
    +
    adds content to given container
    +
    +
    + Method + at +
    +
    +
    vfsStreamAbstractContent::at() in vfsStreamAbstractContent.php
    +
    adds content to given container
    +
    +
    + +
    +
    b
    + +
    +
    +
    +
    + Variable + $bytes_read +
    +
    +
    vfsStreamFile::$bytes_read in vfsStreamFile.php
    +
    amount of read bytes
    +
    +
    + +
    +
    c
    + +
    +
    +
    +
    + Variable + $children +
    +
    +
    vfsStreamContainerIterator::$children in vfsStreamContainerIterator.php
    +
    list of children from container to iterate over
    +
    +
    + Variable + $children +
    +
    +
    vfsStreamDirectory::$children in vfsStreamDirectory.php
    +
    list of directory children
    +
    +
    + Variable + $content +
    +
    +
    vfsStreamFile::$content in vfsStreamFile.php
    +
    the real content of the file
    +
    +
    + Variable + $content +
    +
    +
    vfsStreamWrapper::$content in vfsStreamWrapper.php
    +
    shortcut to file container
    +
    +
    + Method + calculateMode +
    +
    +
    vfsStreamWrapper::calculateMode() in vfsStreamWrapper.php
    +
    calculates the file mode
    +
    +
    + Method + chgrp +
    +
    +
    vfsStreamContent::chgrp() in vfsStreamContent.php
    +
    change owner group of file to given group
    +
    +
    + Method + chgrp +
    +
    +
    vfsStreamAbstractContent::chgrp() in vfsStreamAbstractContent.php
    +
    change owner group of file to given group
    +
    +
    + Method + chmod +
    +
    +
    vfsStreamAbstractContent::chmod() in vfsStreamAbstractContent.php
    +
    change file mode to given permissions
    +
    +
    + Method + chmod +
    +
    +
    vfsStreamContent::chmod() in vfsStreamContent.php
    +
    change file mode to given permissions
    +
    +
    + Method + chown +
    +
    +
    vfsStreamAbstractContent::chown() in vfsStreamAbstractContent.php
    +
    change owner of file to given user
    +
    +
    + Method + chown +
    +
    +
    vfsStreamContent::chown() in vfsStreamContent.php
    +
    change owner of file to given user
    +
    +
    + Method + current +
    +
    +
    vfsStreamContainerIterator::current() in vfsStreamContainerIterator.php
    +
    returns the current child
    +
    +
    + +
    +
    d
    + +
    +
    +
    +
    + Variable + $dir +
    +
    +
    vfsStreamWrapper::$dir in vfsStreamWrapper.php
    +
    shortcut to directory container
    +
    +
    + Variable + $dirIterator +
    +
    +
    vfsStreamWrapper::$dirIterator in vfsStreamWrapper.php
    +
    shortcut to directory container iterator
    +
    +
    + Method + dir_closedir +
    +
    +
    vfsStreamWrapper::dir_closedir() in vfsStreamWrapper.php
    +
    closes directory
    +
    +
    + Method + dir_opendir +
    +
    +
    vfsStreamWrapper::dir_opendir() in vfsStreamWrapper.php
    +
    opens a directory
    +
    +
    + Method + dir_readdir +
    +
    +
    vfsStreamWrapper::dir_readdir() in vfsStreamWrapper.php
    +
    reads directory contents
    +
    +
    + Method + dir_rewinddir +
    +
    +
    vfsStreamWrapper::dir_rewinddir() in vfsStreamWrapper.php
    +
    reset directory iteration
    +
    +
    + +
    +
    e
    + +
    +
    +
    +
    + Method + eof +
    +
    +
    vfsStreamFile::eof() in vfsStreamFile.php
    +
    checks whether pointer is at end of file
    +
    +
    + +
    +
    f
    + +
    +
    +
    +
    + Method + filemtime +
    +
    +
    vfsStreamContent::filemtime() in vfsStreamContent.php
    +
    returns the last modification time of the stream content
    +
    +
    + Method + filemtime +
    +
    +
    vfsStreamAbstractContent::filemtime() in vfsStreamAbstractContent.php
    +
    returns the last modification time of the stream content
    +
    +
    + +
    +
    g
    + +
    +
    +
    +
    + Variable + $group +
    +
    +
    vfsStreamAbstractContent::$group in vfsStreamAbstractContent.php
    +
    owner group of the file
    +
    +
    + Method + getBytesRead +
    +
    +
    vfsStreamFile::getBytesRead() in vfsStreamFile.php
    +
    returns the current position within the file
    +
    +
    + Method + getChild +
    +
    +
    vfsStreamContainer::getChild() in vfsStreamContainer.php
    +
    returns the child with the given name
    +
    +
    + Method + getChild +
    +
    +
    vfsStreamDirectory::getChild() in vfsStreamDirectory.php
    +
    returns the child with the given name
    +
    +
    + Method + getChildName +
    +
    +
    vfsStreamDirectory::getChildName() in vfsStreamDirectory.php
    +
    helper method to calculate the child name
    +
    +
    + Method + getChildren +
    +
    +
    vfsStreamContainer::getChildren() in vfsStreamContainer.php
    +
    returns a list of children for this directory
    +
    +
    + Method + getChildren +
    +
    +
    vfsStreamDirectory::getChildren() in vfsStreamDirectory.php
    +
    returns a list of children for this directory
    +
    +
    + Method + getContent +
    +
    +
    vfsStreamFile::getContent() in vfsStreamFile.php
    +
    returns the contents of the file
    +
    +
    + Method + getContent +
    +
    +
    vfsStreamWrapper::getContent() in vfsStreamWrapper.php
    +
    returns content for given path
    +
    +
    + Method + getContentOfType +
    +
    +
    vfsStreamWrapper::getContentOfType() in vfsStreamWrapper.php
    +
    returns content for given path but only when it is of given type
    +
    +
    + Method + getCurrentGroup +
    +
    + +
    returns current group
    +
    +
    + Method + getCurrentUser +
    +
    + +
    returns current user
    +
    +
    + Method + getDefaultPermissions +
    +
    + +
    returns default permissions for concrete implementation
    +
    +
    + Method + getDefaultPermissions +
    +
    + +
    returns default permissions for concrete implementation
    +
    +
    + Method + getDefaultPermissions +
    +
    + +
    returns default permissions for concrete implementation
    +
    +
    + Method + getGroup +
    +
    +
    vfsStreamAbstractContent::getGroup() in vfsStreamAbstractContent.php
    +
    returns owner group of file
    +
    +
    + Method + getGroup +
    +
    +
    vfsStreamContent::getGroup() in vfsStreamContent.php
    +
    returns owner group of file
    +
    +
    + Method + getIterator +
    +
    +
    vfsStreamDirectory::getIterator() in vfsStreamDirectory.php
    +
    returns iterator for the children
    +
    +
    + Method + getName +
    +
    +
    vfsStreamContent::getName() in vfsStreamContent.php
    +
    returns the file name of the content
    +
    +
    + Method + getName +
    +
    +
    vfsStreamAbstractContent::getName() in vfsStreamAbstractContent.php
    +
    returns the file name of the content
    +
    +
    + Method + getPermissions +
    +
    +
    vfsStreamContent::getPermissions() in vfsStreamContent.php
    +
    returns permissions
    +
    +
    + Method + getPermissions +
    +
    +
    vfsStreamAbstractContent::getPermissions() in vfsStreamAbstractContent.php
    +
    returns permissions
    +
    +
    + Method + getRealChildName +
    +
    +
    vfsStreamDirectory::getRealChildName() in vfsStreamDirectory.php
    +
    helper method to detect the real child name
    +
    +
    + Method + getRoot +
    +
    +
    vfsStreamWrapper::getRoot() in vfsStreamWrapper.php
    +
    returns the root content
    +
    +
    + Method + getType +
    +
    +
    vfsStreamAbstractContent::getType() in vfsStreamAbstractContent.php
    +
    returns the type of the container
    +
    +
    + Method + getType +
    +
    +
    vfsStreamContent::getType() in vfsStreamContent.php
    +
    returns the type of the container
    +
    +
    + Method + getUser +
    +
    +
    vfsStreamAbstractContent::getUser() in vfsStreamAbstractContent.php
    +
    returns owner of file
    +
    +
    + Method + getUser +
    +
    +
    vfsStreamContent::getUser() in vfsStreamContent.php
    +
    returns owner of file
    +
    +
    + Class Constant + GROUP_ROOT +
    +
    +
    vfsStream::GROUP_ROOT in vfsStream.php
    +
    group: root
    +
    +
    + Class Constant + GROUP_USER_1 +
    +
    +
    vfsStream::GROUP_USER_1 in vfsStream.php
    +
    group: user 1
    +
    +
    + Class Constant + GROUP_USER_2 +
    +
    +
    vfsStream::GROUP_USER_2 in vfsStream.php
    +
    group: user 2
    +
    +
    + +
    +
    h
    + +
    +
    +
    +
    + Method + hasChild +
    +
    +
    vfsStreamDirectory::hasChild() in vfsStreamDirectory.php
    +
    checks whether the container contains a child with the given name
    +
    +
    + Method + hasChild +
    +
    +
    vfsStreamContainer::hasChild() in vfsStreamContainer.php
    +
    checks whether the container contains a child with the given name
    +
    +
    + +
    +
    i
    + +
    +
    +
    +
    + Method + isExecutable +
    +
    +
    vfsStreamContent::isExecutable() in vfsStreamContent.php
    +
    checks whether content is executable
    +
    +
    + Method + isExecutable +
    +
    +
    vfsStreamAbstractContent::isExecutable() in vfsStreamAbstractContent.php
    +
    checks whether content is executable
    +
    +
    + Method + isOwnedByGroup +
    +
    +
    vfsStreamContent::isOwnedByGroup() in vfsStreamContent.php
    +
    checks whether file is owned by group
    +
    +
    + Method + isOwnedByGroup +
    +
    +
    vfsStreamAbstractContent::isOwnedByGroup() in vfsStreamAbstractContent.php
    +
    checks whether file is owned by group
    +
    +
    + Method + isOwnedByUser +
    +
    +
    vfsStreamContent::isOwnedByUser() in vfsStreamContent.php
    +
    checks whether file is owned by given user
    +
    +
    + Method + isOwnedByUser +
    +
    +
    vfsStreamAbstractContent::isOwnedByUser() in vfsStreamAbstractContent.php
    +
    checks whether file is owned by given user
    +
    +
    + Method + isReadable +
    +
    +
    vfsStreamContent::isReadable() in vfsStreamContent.php
    +
    checks whether content is readable
    +
    +
    + Method + isReadable +
    +
    +
    vfsStreamAbstractContent::isReadable() in vfsStreamAbstractContent.php
    +
    checks whether content is readable
    +
    +
    + Method + isWritable +
    +
    +
    vfsStreamContent::isWritable() in vfsStreamContent.php
    +
    checks whether content is writable
    +
    +
    + Method + isWritable +
    +
    +
    vfsStreamAbstractContent::isWritable() in vfsStreamAbstractContent.php
    +
    checks whether content is writable
    +
    +
    + +
    +
    k
    + +
    +
    +
    +
    + Method + key +
    +
    +
    vfsStreamContainerIterator::key() in vfsStreamContainerIterator.php
    +
    returns the name of the current child
    +
    +
    + +
    +
    l
    + +
    +
    +
    +
    + Variable + $lastModified +
    +
    +
    vfsStreamAbstractContent::$lastModified in vfsStreamAbstractContent.php
    +
    timestamp of last modification
    +
    +
    + Method + lastModified +
    +
    +
    vfsStreamContent::lastModified() in vfsStreamContent.php
    +
    sets the last modification time of the stream content
    +
    +
    + Method + lastModified +
    +
    +
    vfsStreamAbstractContent::lastModified() in vfsStreamAbstractContent.php
    +
    sets the last modification time of the stream content
    +
    +
    + +
    +
    m
    + +
    +
    +
    +
    + Variable + $mode +
    +
    +
    vfsStreamWrapper::$mode in vfsStreamWrapper.php
    +
    file mode: read only, write only, all
    +
    +
    + Method + mkdir +
    +
    +
    vfsStreamWrapper::mkdir() in vfsStreamWrapper.php
    +
    creates a new directory
    +
    +
    + +
    +
    n
    + +
    +
    +
    +
    + Variable + $name +
    +
    +
    vfsStreamAbstractContent::$name in vfsStreamAbstractContent.php
    +
    name of the container
    +
    +
    + Method + newDirectory +
    +
    +
    vfsStream::newDirectory() in vfsStream.php
    +
    returns a new directory with given name
    +
    +
    + Method + newFile +
    +
    +
    vfsStream::newFile() in vfsStream.php
    +
    returns a new file with given name
    +
    +
    + Method + next +
    +
    +
    vfsStreamContainerIterator::next() in vfsStreamContainerIterator.php
    +
    iterates to next child
    +
    +
    + +
    +
    o
    + +
    +
    +
    +
    + Class Constant + OWNER_ROOT +
    +
    +
    vfsStream::OWNER_ROOT in vfsStream.php
    +
    owner: root
    +
    +
    + Class Constant + OWNER_USER_1 +
    +
    +
    vfsStream::OWNER_USER_1 in vfsStream.php
    +
    owner: user 1
    +
    +
    + Class Constant + OWNER_USER_2 +
    +
    +
    vfsStream::OWNER_USER_2 in vfsStream.php
    +
    owner: user 2
    +
    +
    + +
    +
    p
    + +
    +
    +
    +
    + Variable + $permissions +
    +
    +
    vfsStreamAbstractContent::$permissions in vfsStreamAbstractContent.php
    +
    permissions for content
    +
    +
    + Method + path +
    +
    +
    vfsStream::path() in vfsStream.php
    +
    restores the path from the url
    +
    +
    + +
    +
    r
    + +
    +
    +
    +
    + Variable + $registered +
    +
    +
    vfsStreamWrapper::$registered in vfsStreamWrapper.php
    +
    switch whether class has already been registered as stream wrapper or not
    +
    +
    + Variable + $root +
    +
    +
    vfsStreamWrapper::$root in vfsStreamWrapper.php
    +
    root content
    +
    +
    + Class Constant + READ +
    +
    +
    vfsStreamWrapper::READ in vfsStreamWrapper.php
    +
    open file for reading
    +
    +
    + Method + read +
    +
    +
    vfsStreamFile::read() in vfsStreamFile.php
    +
    reads the given amount of bytes from content
    +
    +
    + Class Constant + READONLY +
    +
    +
    vfsStreamWrapper::READONLY in vfsStreamWrapper.php
    +
    file mode: read only
    +
    +
    + Method + readUntilEnd +
    +
    +
    vfsStreamFile::readUntilEnd() in vfsStreamFile.php
    +
    returns the content until its end from current offset
    +
    +
    + Method + register +
    +
    +
    vfsStreamWrapper::register() in vfsStreamWrapper.php
    +
    method to register the stream wrapper
    +
    +
    + Method + removeChild +
    +
    +
    vfsStreamContainer::removeChild() in vfsStreamContainer.php
    +
    removes child from the directory
    +
    +
    + Method + removeChild +
    +
    +
    vfsStreamDirectory::removeChild() in vfsStreamDirectory.php
    +
    removes child from the directory
    +
    +
    + Method + rename +
    +
    +
    vfsStreamAbstractContent::rename() in vfsStreamAbstractContent.php
    +
    renames the content
    +
    +
    + Method + rename +
    +
    +
    vfsStreamWrapper::rename() in vfsStreamWrapper.php
    +
    rename from one path to another
    +
    +
    + Method + rename +
    +
    +
    vfsStreamDirectory::rename() in vfsStreamDirectory.php
    +
    renames the content
    +
    +
    + Method + rename +
    +
    +
    vfsStreamContent::rename() in vfsStreamContent.php
    +
    renames the content
    +
    +
    + Method + resolvePath +
    +
    +
    vfsStreamWrapper::resolvePath() in vfsStreamWrapper.php
    +
    helper method to resolve a path from /foo/bar/. to /foo/bar
    +
    +
    + Method + rewind +
    +
    +
    vfsStreamContainerIterator::rewind() in vfsStreamContainerIterator.php
    +
    resets children pointer
    +
    +
    + Method + rmdir +
    +
    +
    vfsStreamWrapper::rmdir() in vfsStreamWrapper.php
    +
    removes a directory
    +
    +
    + +
    +
    s
    + +
    +
    +
    +
    + Class Constant + SCHEME +
    +
    +
    vfsStream::SCHEME in vfsStream.php
    +
    url scheme
    +
    +
    + Method + seek +
    +
    +
    vfsStreamFile::seek() in vfsStreamFile.php
    +
    seeks to the given offset
    +
    +
    + Method + setContent +
    +
    +
    vfsStreamFile::setContent() in vfsStreamFile.php
    +
    alias for withContent()
    +
    +
    + Method + setFilemtime +
    +
    +
    vfsStreamAbstractContent::setFilemtime() in vfsStreamAbstractContent.php
    +
    alias for lastModified()
    +
    +
    + Method + setFilemtime +
    +
    +
    vfsStreamContent::setFilemtime() in vfsStreamContent.php
    +
    alias for lastModified()
    +
    +
    + Method + setRoot +
    +
    +
    vfsStreamWrapper::setRoot() in vfsStreamWrapper.php
    +
    sets the root content
    +
    +
    + Method + setup +
    +
    +
    vfsStream::setup() in vfsStream.php
    +
    helper method for setting up vfsStream in unit tests
    +
    +
    + Method + size +
    +
    +
    vfsStreamContent::size() in vfsStreamContent.php
    +
    returns size of content
    +
    +
    + Method + size +
    +
    +
    vfsStreamFile::size() in vfsStreamFile.php
    +
    returns size of content
    +
    +
    + Method + size +
    +
    +
    vfsStreamDirectory::size() in vfsStreamDirectory.php
    +
    returns size of directory
    +
    +
    + Method + sizeSummarized +
    +
    +
    vfsStreamDirectory::sizeSummarized() in vfsStreamDirectory.php
    +
    returns summarized size of directory and its children
    +
    +
    + Method + splitPath +
    +
    +
    vfsStreamWrapper::splitPath() in vfsStreamWrapper.php
    +
    splits path into its dirname and the basename
    +
    +
    + Method + stream_close +
    +
    +
    vfsStreamWrapper::stream_close() in vfsStreamWrapper.php
    +
    closes the stream
    +
    +
    + Method + stream_eof +
    +
    +
    vfsStreamWrapper::stream_eof() in vfsStreamWrapper.php
    +
    checks whether stream is at end of file
    +
    +
    + Method + stream_flush +
    +
    +
    vfsStreamWrapper::stream_flush() in vfsStreamWrapper.php
    +
    flushes unstored data into storage
    +
    +
    + Method + stream_open +
    +
    +
    vfsStreamWrapper::stream_open() in vfsStreamWrapper.php
    +
    open the stream
    +
    +
    + Method + stream_read +
    +
    +
    vfsStreamWrapper::stream_read() in vfsStreamWrapper.php
    +
    read the stream up to $count bytes
    +
    +
    + Method + stream_seek +
    +
    +
    vfsStreamWrapper::stream_seek() in vfsStreamWrapper.php
    +
    seeks to the given offset
    +
    +
    + Method + stream_stat +
    +
    +
    vfsStreamWrapper::stream_stat() in vfsStreamWrapper.php
    +
    returns status of stream
    +
    +
    + Method + stream_tell +
    +
    +
    vfsStreamWrapper::stream_tell() in vfsStreamWrapper.php
    +
    returns the current position of the stream
    +
    +
    + Method + stream_write +
    +
    +
    vfsStreamWrapper::stream_write() in vfsStreamWrapper.php
    +
    writes data into the stream
    +
    +
    + +
    +
    t
    + +
    +
    +
    +
    + Variable + $type +
    +
    +
    vfsStreamAbstractContent::$type in vfsStreamAbstractContent.php
    +
    type of the container
    +
    +
    + Class Constant + TRUNCATE +
    +
    +
    vfsStreamWrapper::TRUNCATE in vfsStreamWrapper.php
    +
    truncate file
    +
    +
    + Class Constant + TYPE_DIR +
    +
    +
    vfsStreamContent::TYPE_DIR in vfsStreamContent.php
    +
    stream content type: directory
    +
    +
    + Class Constant + TYPE_FILE +
    +
    +
    vfsStreamContent::TYPE_FILE in vfsStreamContent.php
    +
    stream content type: file
    +
    +
    + +
    +
    u
    + +
    +
    +
    +
    + Variable + $umask +
    +
    +
    vfsStream::$umask in vfsStream.php
    +
    initial umask setting
    +
    +
    + Variable + $user +
    +
    +
    vfsStreamAbstractContent::$user in vfsStreamAbstractContent.php
    +
    owner of the file
    +
    +
    + Method + umask +
    +
    +
    vfsStream::umask() in vfsStream.php
    +
    sets new umask setting and returns previous umask setting
    +
    +
    + Method + unlink +
    +
    +
    vfsStreamWrapper::unlink() in vfsStreamWrapper.php
    +
    remove the data under the given path
    +
    +
    + Method + url +
    +
    +
    vfsStream::url() in vfsStream.php
    +
    prepends the scheme to the given URL
    +
    +
    + Method + url_stat +
    +
    +
    vfsStreamWrapper::url_stat() in vfsStreamWrapper.php
    +
    returns status of url
    +
    +
    + +
    +
    v
    + +
    +
    +
    +
    + Method + valid +
    +
    +
    vfsStreamContainerIterator::valid() in vfsStreamContainerIterator.php
    +
    checks if the current value is valid
    +
    +
    + Class + vfsStream +
    +
    +
    vfsStream in vfsStream.php
    +
    Some utility methods for vfsStream.
    +
    +
    + Page + vfsStream.php +
    +
    +
    vfsStream.php in vfsStream.php
    +
    +
    + Class + vfsStreamAbstractContent +
    +
    +
    vfsStreamAbstractContent in vfsStreamAbstractContent.php
    +
    Base stream contents container.
    +
    +
    + Page + vfsStreamAbstractContent.php +
    +
    +
    vfsStreamAbstractContent.php in vfsStreamAbstractContent.php
    +
    +
    + Class + vfsStreamContainer +
    +
    +
    vfsStreamContainer in vfsStreamContainer.php
    +
    Interface for stream contents that are able to store other stream contents.
    +
    +
    + Page + vfsStreamContainer.php +
    +
    +
    vfsStreamContainer.php in vfsStreamContainer.php
    +
    +
    + Class + vfsStreamContainerIterator +
    +
    +
    vfsStreamContainerIterator in vfsStreamContainerIterator.php
    +
    Iterator for children of a directory container.
    +
    +
    + Page + vfsStreamContainerIterator.php +
    +
    +
    vfsStreamContainerIterator.php in vfsStreamContainerIterator.php
    +
    +
    + Class + vfsStreamContent +
    +
    +
    vfsStreamContent in vfsStreamContent.php
    +
    Interface for stream contents.
    +
    +
    + Page + vfsStreamContent.php +
    +
    +
    vfsStreamContent.php in vfsStreamContent.php
    +
    +
    + Class + vfsStreamDirectory +
    +
    +
    vfsStreamDirectory in vfsStreamDirectory.php
    +
    Directory container.
    +
    +
    + Page + vfsStreamDirectory.php +
    +
    +
    vfsStreamDirectory.php in vfsStreamDirectory.php
    +
    +
    + Class + vfsStreamException +
    +
    +
    vfsStreamException in vfsStreamException.php
    +
    Exception for streamwrapper subpackage.
    +
    +
    + Page + vfsStreamException.php +
    +
    +
    vfsStreamException.php in vfsStreamException.php
    +
    +
    + Class + vfsStreamFile +
    +
    +
    vfsStreamFile in vfsStreamFile.php
    +
    File container.
    +
    +
    + Page + vfsStreamFile.php +
    +
    +
    vfsStreamFile.php in vfsStreamFile.php
    +
    +
    + Class + vfsStreamWrapper +
    +
    +
    vfsStreamWrapper in vfsStreamWrapper.php
    +
    Stream wrapper to mock file system requests.
    +
    +
    + Page + vfsStreamWrapper.php +
    +
    +
    vfsStreamWrapper.php in vfsStreamWrapper.php
    +
    +
    + +
    +
    w
    + +
    +
    +
    +
    + Method + withContent +
    +
    +
    vfsStreamFile::withContent() in vfsStreamFile.php
    +
    sets the contents of the file
    +
    +
    + Class Constant + WRITE +
    +
    +
    vfsStreamWrapper::WRITE in vfsStreamWrapper.php
    +
    set file pointer to start, overwrite existing data
    +
    +
    + Method + write +
    +
    +
    vfsStreamFile::write() in vfsStreamFile.php
    +
    writes an amount of data
    +
    +
    + Class Constant + WRITEONLY +
    +
    +
    vfsStreamWrapper::WRITEONLY in vfsStreamWrapper.php
    +
    file mode: write only
    +
    +
    + +
    +
    _
    + +
    +
    +
    +
    + Method + __construct +
    +
    +
    vfsStreamFile::__construct() in vfsStreamFile.php
    +
    constructor
    +
    +
    + Method + __construct +
    +
    +
    vfsStreamDirectory::__construct() in vfsStreamDirectory.php
    +
    constructor
    +
    +
    + Method + __construct +
    +
    +
    vfsStreamContainerIterator::__construct() in vfsStreamContainerIterator.php
    +
    constructor
    +
    +
    + Method + __construct +
    +
    +
    vfsStreamAbstractContent::__construct() in vfsStreamAbstractContent.php
    +
    constructor
    +
    +
    + +
    + a + b + c + d + e + f + g + h + i + k + l + m + n + o + p + r + s + t + u + v + w + _ +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/elementindex_bovigo_vfs.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/elementindex_bovigo_vfs.html new file mode 100644 index 0000000..2e86478 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/elementindex_bovigo_vfs.html @@ -0,0 +1,1535 @@ + + + + + + + + + + +

    [bovigo_vfs] element index

    +All elements +
    +
    + a + b + c + d + e + f + g + h + i + k + l + m + n + o + p + r + s + t + u + v + w + _ +
    + + +
    +
    _
    + +
    +
    +
    +
    + Method + __construct +
    +
    +
    vfsStreamFile::__construct() in vfsStreamFile.php
    +
    constructor
    +
    +
    + Method + __construct +
    +
    +
    vfsStreamDirectory::__construct() in vfsStreamDirectory.php
    +
    constructor
    +
    +
    + Method + __construct +
    +
    +
    vfsStreamContainerIterator::__construct() in vfsStreamContainerIterator.php
    +
    constructor
    +
    +
    + Method + __construct +
    +
    +
    vfsStreamAbstractContent::__construct() in vfsStreamAbstractContent.php
    +
    constructor
    +
    +
    + +
    +
    a
    + +
    +
    +
    +
    + Method + addChild +
    +
    +
    vfsStreamDirectory::addChild() in vfsStreamDirectory.php
    +
    adds child to the directory
    +
    +
    + Method + addChild +
    +
    +
    vfsStreamContainer::addChild() in vfsStreamContainer.php
    +
    adds child to the directory
    +
    +
    + Class Constant + ALL +
    +
    +
    vfsStreamWrapper::ALL in vfsStreamWrapper.php
    +
    file mode: read and write
    +
    +
    + Class Constant + APPEND +
    +
    +
    vfsStreamWrapper::APPEND in vfsStreamWrapper.php
    +
    set file pointer to end, append new data
    +
    +
    + Method + appliesTo +
    +
    +
    vfsStreamFile::appliesTo() in vfsStreamFile.php
    +
    checks whether the container can be applied to given name
    +
    +
    + Method + appliesTo +
    +
    +
    vfsStreamContent::appliesTo() in vfsStreamContent.php
    +
    checks whether the container can be applied to given name
    +
    +
    + Method + appliesTo +
    +
    +
    vfsStreamAbstractContent::appliesTo() in vfsStreamAbstractContent.php
    +
    checks whether the container can be applied to given name
    +
    +
    + Method + at +
    +
    +
    vfsStreamContent::at() in vfsStreamContent.php
    +
    adds content to given container
    +
    +
    + Method + at +
    +
    +
    vfsStreamAbstractContent::at() in vfsStreamAbstractContent.php
    +
    adds content to given container
    +
    +
    + +
    +
    b
    + +
    +
    +
    +
    + Variable + $bytes_read +
    +
    +
    vfsStreamFile::$bytes_read in vfsStreamFile.php
    +
    amount of read bytes
    +
    +
    + +
    +
    c
    + +
    +
    +
    +
    + Variable + $children +
    +
    +
    vfsStreamContainerIterator::$children in vfsStreamContainerIterator.php
    +
    list of children from container to iterate over
    +
    +
    + Variable + $children +
    +
    +
    vfsStreamDirectory::$children in vfsStreamDirectory.php
    +
    list of directory children
    +
    +
    + Variable + $content +
    +
    +
    vfsStreamFile::$content in vfsStreamFile.php
    +
    the real content of the file
    +
    +
    + Variable + $content +
    +
    +
    vfsStreamWrapper::$content in vfsStreamWrapper.php
    +
    shortcut to file container
    +
    +
    + Method + calculateMode +
    +
    +
    vfsStreamWrapper::calculateMode() in vfsStreamWrapper.php
    +
    calculates the file mode
    +
    +
    + Method + chgrp +
    +
    +
    vfsStreamContent::chgrp() in vfsStreamContent.php
    +
    change owner group of file to given group
    +
    +
    + Method + chgrp +
    +
    +
    vfsStreamAbstractContent::chgrp() in vfsStreamAbstractContent.php
    +
    change owner group of file to given group
    +
    +
    + Method + chmod +
    +
    +
    vfsStreamAbstractContent::chmod() in vfsStreamAbstractContent.php
    +
    change file mode to given permissions
    +
    +
    + Method + chmod +
    +
    +
    vfsStreamContent::chmod() in vfsStreamContent.php
    +
    change file mode to given permissions
    +
    +
    + Method + chown +
    +
    +
    vfsStreamAbstractContent::chown() in vfsStreamAbstractContent.php
    +
    change owner of file to given user
    +
    +
    + Method + chown +
    +
    +
    vfsStreamContent::chown() in vfsStreamContent.php
    +
    change owner of file to given user
    +
    +
    + Method + current +
    +
    +
    vfsStreamContainerIterator::current() in vfsStreamContainerIterator.php
    +
    returns the current child
    +
    +
    + +
    +
    d
    + +
    +
    +
    +
    + Variable + $dir +
    +
    +
    vfsStreamWrapper::$dir in vfsStreamWrapper.php
    +
    shortcut to directory container
    +
    +
    + Variable + $dirIterator +
    +
    +
    vfsStreamWrapper::$dirIterator in vfsStreamWrapper.php
    +
    shortcut to directory container iterator
    +
    +
    + Method + dir_closedir +
    +
    +
    vfsStreamWrapper::dir_closedir() in vfsStreamWrapper.php
    +
    closes directory
    +
    +
    + Method + dir_opendir +
    +
    +
    vfsStreamWrapper::dir_opendir() in vfsStreamWrapper.php
    +
    opens a directory
    +
    +
    + Method + dir_readdir +
    +
    +
    vfsStreamWrapper::dir_readdir() in vfsStreamWrapper.php
    +
    reads directory contents
    +
    +
    + Method + dir_rewinddir +
    +
    +
    vfsStreamWrapper::dir_rewinddir() in vfsStreamWrapper.php
    +
    reset directory iteration
    +
    +
    + +
    +
    e
    + +
    +
    +
    +
    + Method + eof +
    +
    +
    vfsStreamFile::eof() in vfsStreamFile.php
    +
    checks whether pointer is at end of file
    +
    +
    + +
    +
    f
    + +
    +
    +
    +
    + Method + filemtime +
    +
    +
    vfsStreamContent::filemtime() in vfsStreamContent.php
    +
    returns the last modification time of the stream content
    +
    +
    + Method + filemtime +
    +
    +
    vfsStreamAbstractContent::filemtime() in vfsStreamAbstractContent.php
    +
    returns the last modification time of the stream content
    +
    +
    + +
    +
    g
    + +
    +
    +
    +
    + Variable + $group +
    +
    +
    vfsStreamAbstractContent::$group in vfsStreamAbstractContent.php
    +
    owner group of the file
    +
    +
    + Method + getBytesRead +
    +
    +
    vfsStreamFile::getBytesRead() in vfsStreamFile.php
    +
    returns the current position within the file
    +
    +
    + Method + getChild +
    +
    +
    vfsStreamContainer::getChild() in vfsStreamContainer.php
    +
    returns the child with the given name
    +
    +
    + Method + getChild +
    +
    +
    vfsStreamDirectory::getChild() in vfsStreamDirectory.php
    +
    returns the child with the given name
    +
    +
    + Method + getChildName +
    +
    +
    vfsStreamDirectory::getChildName() in vfsStreamDirectory.php
    +
    helper method to calculate the child name
    +
    +
    + Method + getChildren +
    +
    +
    vfsStreamContainer::getChildren() in vfsStreamContainer.php
    +
    returns a list of children for this directory
    +
    +
    + Method + getChildren +
    +
    +
    vfsStreamDirectory::getChildren() in vfsStreamDirectory.php
    +
    returns a list of children for this directory
    +
    +
    + Method + getContent +
    +
    +
    vfsStreamFile::getContent() in vfsStreamFile.php
    +
    returns the contents of the file
    +
    +
    + Method + getContent +
    +
    +
    vfsStreamWrapper::getContent() in vfsStreamWrapper.php
    +
    returns content for given path
    +
    +
    + Method + getContentOfType +
    +
    +
    vfsStreamWrapper::getContentOfType() in vfsStreamWrapper.php
    +
    returns content for given path but only when it is of given type
    +
    +
    + Method + getCurrentGroup +
    +
    + +
    returns current group
    +
    +
    + Method + getCurrentUser +
    +
    + +
    returns current user
    +
    +
    + Method + getDefaultPermissions +
    +
    + +
    returns default permissions for concrete implementation
    +
    +
    + Method + getDefaultPermissions +
    +
    + +
    returns default permissions for concrete implementation
    +
    +
    + Method + getDefaultPermissions +
    +
    + +
    returns default permissions for concrete implementation
    +
    +
    + Method + getGroup +
    +
    +
    vfsStreamAbstractContent::getGroup() in vfsStreamAbstractContent.php
    +
    returns owner group of file
    +
    +
    + Method + getGroup +
    +
    +
    vfsStreamContent::getGroup() in vfsStreamContent.php
    +
    returns owner group of file
    +
    +
    + Method + getIterator +
    +
    +
    vfsStreamDirectory::getIterator() in vfsStreamDirectory.php
    +
    returns iterator for the children
    +
    +
    + Method + getName +
    +
    +
    vfsStreamContent::getName() in vfsStreamContent.php
    +
    returns the file name of the content
    +
    +
    + Method + getName +
    +
    +
    vfsStreamAbstractContent::getName() in vfsStreamAbstractContent.php
    +
    returns the file name of the content
    +
    +
    + Method + getPermissions +
    +
    +
    vfsStreamContent::getPermissions() in vfsStreamContent.php
    +
    returns permissions
    +
    +
    + Method + getPermissions +
    +
    +
    vfsStreamAbstractContent::getPermissions() in vfsStreamAbstractContent.php
    +
    returns permissions
    +
    +
    + Method + getRealChildName +
    +
    +
    vfsStreamDirectory::getRealChildName() in vfsStreamDirectory.php
    +
    helper method to detect the real child name
    +
    +
    + Method + getRoot +
    +
    +
    vfsStreamWrapper::getRoot() in vfsStreamWrapper.php
    +
    returns the root content
    +
    +
    + Method + getType +
    +
    +
    vfsStreamAbstractContent::getType() in vfsStreamAbstractContent.php
    +
    returns the type of the container
    +
    +
    + Method + getType +
    +
    +
    vfsStreamContent::getType() in vfsStreamContent.php
    +
    returns the type of the container
    +
    +
    + Method + getUser +
    +
    +
    vfsStreamAbstractContent::getUser() in vfsStreamAbstractContent.php
    +
    returns owner of file
    +
    +
    + Method + getUser +
    +
    +
    vfsStreamContent::getUser() in vfsStreamContent.php
    +
    returns owner of file
    +
    +
    + Class Constant + GROUP_ROOT +
    +
    +
    vfsStream::GROUP_ROOT in vfsStream.php
    +
    group: root
    +
    +
    + Class Constant + GROUP_USER_1 +
    +
    +
    vfsStream::GROUP_USER_1 in vfsStream.php
    +
    group: user 1
    +
    +
    + Class Constant + GROUP_USER_2 +
    +
    +
    vfsStream::GROUP_USER_2 in vfsStream.php
    +
    group: user 2
    +
    +
    + +
    +
    h
    + +
    +
    +
    +
    + Method + hasChild +
    +
    +
    vfsStreamDirectory::hasChild() in vfsStreamDirectory.php
    +
    checks whether the container contains a child with the given name
    +
    +
    + Method + hasChild +
    +
    +
    vfsStreamContainer::hasChild() in vfsStreamContainer.php
    +
    checks whether the container contains a child with the given name
    +
    +
    + +
    +
    i
    + +
    +
    +
    +
    + Method + isExecutable +
    +
    +
    vfsStreamContent::isExecutable() in vfsStreamContent.php
    +
    checks whether content is executable
    +
    +
    + Method + isExecutable +
    +
    +
    vfsStreamAbstractContent::isExecutable() in vfsStreamAbstractContent.php
    +
    checks whether content is executable
    +
    +
    + Method + isOwnedByGroup +
    +
    +
    vfsStreamContent::isOwnedByGroup() in vfsStreamContent.php
    +
    checks whether file is owned by group
    +
    +
    + Method + isOwnedByGroup +
    +
    +
    vfsStreamAbstractContent::isOwnedByGroup() in vfsStreamAbstractContent.php
    +
    checks whether file is owned by group
    +
    +
    + Method + isOwnedByUser +
    +
    +
    vfsStreamContent::isOwnedByUser() in vfsStreamContent.php
    +
    checks whether file is owned by given user
    +
    +
    + Method + isOwnedByUser +
    +
    +
    vfsStreamAbstractContent::isOwnedByUser() in vfsStreamAbstractContent.php
    +
    checks whether file is owned by given user
    +
    +
    + Method + isReadable +
    +
    +
    vfsStreamContent::isReadable() in vfsStreamContent.php
    +
    checks whether content is readable
    +
    +
    + Method + isReadable +
    +
    +
    vfsStreamAbstractContent::isReadable() in vfsStreamAbstractContent.php
    +
    checks whether content is readable
    +
    +
    + Method + isWritable +
    +
    +
    vfsStreamContent::isWritable() in vfsStreamContent.php
    +
    checks whether content is writable
    +
    +
    + Method + isWritable +
    +
    +
    vfsStreamAbstractContent::isWritable() in vfsStreamAbstractContent.php
    +
    checks whether content is writable
    +
    +
    + +
    +
    k
    + +
    +
    +
    +
    + Method + key +
    +
    +
    vfsStreamContainerIterator::key() in vfsStreamContainerIterator.php
    +
    returns the name of the current child
    +
    +
    + +
    +
    l
    + +
    +
    +
    +
    + Variable + $lastModified +
    +
    +
    vfsStreamAbstractContent::$lastModified in vfsStreamAbstractContent.php
    +
    timestamp of last modification
    +
    +
    + Method + lastModified +
    +
    +
    vfsStreamContent::lastModified() in vfsStreamContent.php
    +
    sets the last modification time of the stream content
    +
    +
    + Method + lastModified +
    +
    +
    vfsStreamAbstractContent::lastModified() in vfsStreamAbstractContent.php
    +
    sets the last modification time of the stream content
    +
    +
    + +
    +
    m
    + +
    +
    +
    +
    + Variable + $mode +
    +
    +
    vfsStreamWrapper::$mode in vfsStreamWrapper.php
    +
    file mode: read only, write only, all
    +
    +
    + Method + mkdir +
    +
    +
    vfsStreamWrapper::mkdir() in vfsStreamWrapper.php
    +
    creates a new directory
    +
    +
    + +
    +
    n
    + +
    +
    +
    +
    + Variable + $name +
    +
    +
    vfsStreamAbstractContent::$name in vfsStreamAbstractContent.php
    +
    name of the container
    +
    +
    + Method + newDirectory +
    +
    +
    vfsStream::newDirectory() in vfsStream.php
    +
    returns a new directory with given name
    +
    +
    + Method + newFile +
    +
    +
    vfsStream::newFile() in vfsStream.php
    +
    returns a new file with given name
    +
    +
    + Method + next +
    +
    +
    vfsStreamContainerIterator::next() in vfsStreamContainerIterator.php
    +
    iterates to next child
    +
    +
    + +
    +
    o
    + +
    +
    +
    +
    + Class Constant + OWNER_ROOT +
    +
    +
    vfsStream::OWNER_ROOT in vfsStream.php
    +
    owner: root
    +
    +
    + Class Constant + OWNER_USER_1 +
    +
    +
    vfsStream::OWNER_USER_1 in vfsStream.php
    +
    owner: user 1
    +
    +
    + Class Constant + OWNER_USER_2 +
    +
    +
    vfsStream::OWNER_USER_2 in vfsStream.php
    +
    owner: user 2
    +
    +
    + +
    +
    p
    + +
    +
    +
    +
    + Variable + $permissions +
    +
    +
    vfsStreamAbstractContent::$permissions in vfsStreamAbstractContent.php
    +
    permissions for content
    +
    +
    + Method + path +
    +
    +
    vfsStream::path() in vfsStream.php
    +
    restores the path from the url
    +
    +
    + +
    +
    r
    + +
    +
    +
    +
    + Variable + $registered +
    +
    +
    vfsStreamWrapper::$registered in vfsStreamWrapper.php
    +
    switch whether class has already been registered as stream wrapper or not
    +
    +
    + Variable + $root +
    +
    +
    vfsStreamWrapper::$root in vfsStreamWrapper.php
    +
    root content
    +
    +
    + Class Constant + READ +
    +
    +
    vfsStreamWrapper::READ in vfsStreamWrapper.php
    +
    open file for reading
    +
    +
    + Method + read +
    +
    +
    vfsStreamFile::read() in vfsStreamFile.php
    +
    reads the given amount of bytes from content
    +
    +
    + Class Constant + READONLY +
    +
    +
    vfsStreamWrapper::READONLY in vfsStreamWrapper.php
    +
    file mode: read only
    +
    +
    + Method + readUntilEnd +
    +
    +
    vfsStreamFile::readUntilEnd() in vfsStreamFile.php
    +
    returns the content until its end from current offset
    +
    +
    + Method + register +
    +
    +
    vfsStreamWrapper::register() in vfsStreamWrapper.php
    +
    method to register the stream wrapper
    +
    +
    + Method + removeChild +
    +
    +
    vfsStreamContainer::removeChild() in vfsStreamContainer.php
    +
    removes child from the directory
    +
    +
    + Method + removeChild +
    +
    +
    vfsStreamDirectory::removeChild() in vfsStreamDirectory.php
    +
    removes child from the directory
    +
    +
    + Method + rename +
    +
    +
    vfsStreamAbstractContent::rename() in vfsStreamAbstractContent.php
    +
    renames the content
    +
    +
    + Method + rename +
    +
    +
    vfsStreamWrapper::rename() in vfsStreamWrapper.php
    +
    rename from one path to another
    +
    +
    + Method + rename +
    +
    +
    vfsStreamDirectory::rename() in vfsStreamDirectory.php
    +
    renames the content
    +
    +
    + Method + rename +
    +
    +
    vfsStreamContent::rename() in vfsStreamContent.php
    +
    renames the content
    +
    +
    + Method + resolvePath +
    +
    +
    vfsStreamWrapper::resolvePath() in vfsStreamWrapper.php
    +
    helper method to resolve a path from /foo/bar/. to /foo/bar
    +
    +
    + Method + rewind +
    +
    +
    vfsStreamContainerIterator::rewind() in vfsStreamContainerIterator.php
    +
    resets children pointer
    +
    +
    + Method + rmdir +
    +
    +
    vfsStreamWrapper::rmdir() in vfsStreamWrapper.php
    +
    removes a directory
    +
    +
    + +
    +
    s
    + +
    +
    +
    +
    + Class Constant + SCHEME +
    +
    +
    vfsStream::SCHEME in vfsStream.php
    +
    url scheme
    +
    +
    + Method + seek +
    +
    +
    vfsStreamFile::seek() in vfsStreamFile.php
    +
    seeks to the given offset
    +
    +
    + Method + setContent +
    +
    +
    vfsStreamFile::setContent() in vfsStreamFile.php
    +
    alias for withContent()
    +
    +
    + Method + setFilemtime +
    +
    +
    vfsStreamAbstractContent::setFilemtime() in vfsStreamAbstractContent.php
    +
    alias for lastModified()
    +
    +
    + Method + setFilemtime +
    +
    +
    vfsStreamContent::setFilemtime() in vfsStreamContent.php
    +
    alias for lastModified()
    +
    +
    + Method + setRoot +
    +
    +
    vfsStreamWrapper::setRoot() in vfsStreamWrapper.php
    +
    sets the root content
    +
    +
    + Method + setup +
    +
    +
    vfsStream::setup() in vfsStream.php
    +
    helper method for setting up vfsStream in unit tests
    +
    +
    + Method + size +
    +
    +
    vfsStreamContent::size() in vfsStreamContent.php
    +
    returns size of content
    +
    +
    + Method + size +
    +
    +
    vfsStreamFile::size() in vfsStreamFile.php
    +
    returns size of content
    +
    +
    + Method + size +
    +
    +
    vfsStreamDirectory::size() in vfsStreamDirectory.php
    +
    returns size of directory
    +
    +
    + Method + sizeSummarized +
    +
    +
    vfsStreamDirectory::sizeSummarized() in vfsStreamDirectory.php
    +
    returns summarized size of directory and its children
    +
    +
    + Method + splitPath +
    +
    +
    vfsStreamWrapper::splitPath() in vfsStreamWrapper.php
    +
    splits path into its dirname and the basename
    +
    +
    + Method + stream_close +
    +
    +
    vfsStreamWrapper::stream_close() in vfsStreamWrapper.php
    +
    closes the stream
    +
    +
    + Method + stream_eof +
    +
    +
    vfsStreamWrapper::stream_eof() in vfsStreamWrapper.php
    +
    checks whether stream is at end of file
    +
    +
    + Method + stream_flush +
    +
    +
    vfsStreamWrapper::stream_flush() in vfsStreamWrapper.php
    +
    flushes unstored data into storage
    +
    +
    + Method + stream_open +
    +
    +
    vfsStreamWrapper::stream_open() in vfsStreamWrapper.php
    +
    open the stream
    +
    +
    + Method + stream_read +
    +
    +
    vfsStreamWrapper::stream_read() in vfsStreamWrapper.php
    +
    read the stream up to $count bytes
    +
    +
    + Method + stream_seek +
    +
    +
    vfsStreamWrapper::stream_seek() in vfsStreamWrapper.php
    +
    seeks to the given offset
    +
    +
    + Method + stream_stat +
    +
    +
    vfsStreamWrapper::stream_stat() in vfsStreamWrapper.php
    +
    returns status of stream
    +
    +
    + Method + stream_tell +
    +
    +
    vfsStreamWrapper::stream_tell() in vfsStreamWrapper.php
    +
    returns the current position of the stream
    +
    +
    + Method + stream_write +
    +
    +
    vfsStreamWrapper::stream_write() in vfsStreamWrapper.php
    +
    writes data into the stream
    +
    +
    + +
    +
    t
    + +
    +
    +
    +
    + Variable + $type +
    +
    +
    vfsStreamAbstractContent::$type in vfsStreamAbstractContent.php
    +
    type of the container
    +
    +
    + Class Constant + TRUNCATE +
    +
    +
    vfsStreamWrapper::TRUNCATE in vfsStreamWrapper.php
    +
    truncate file
    +
    +
    + Class Constant + TYPE_DIR +
    +
    +
    vfsStreamContent::TYPE_DIR in vfsStreamContent.php
    +
    stream content type: directory
    +
    +
    + Class Constant + TYPE_FILE +
    +
    +
    vfsStreamContent::TYPE_FILE in vfsStreamContent.php
    +
    stream content type: file
    +
    +
    + +
    +
    u
    + +
    +
    +
    +
    + Variable + $umask +
    +
    +
    vfsStream::$umask in vfsStream.php
    +
    initial umask setting
    +
    +
    + Variable + $user +
    +
    +
    vfsStreamAbstractContent::$user in vfsStreamAbstractContent.php
    +
    owner of the file
    +
    +
    + Method + umask +
    +
    +
    vfsStream::umask() in vfsStream.php
    +
    sets new umask setting and returns previous umask setting
    +
    +
    + Method + unlink +
    +
    +
    vfsStreamWrapper::unlink() in vfsStreamWrapper.php
    +
    remove the data under the given path
    +
    +
    + Method + url +
    +
    +
    vfsStream::url() in vfsStream.php
    +
    prepends the scheme to the given URL
    +
    +
    + Method + url_stat +
    +
    +
    vfsStreamWrapper::url_stat() in vfsStreamWrapper.php
    +
    returns status of url
    +
    +
    + +
    +
    v
    + +
    +
    +
    +
    + Method + valid +
    +
    +
    vfsStreamContainerIterator::valid() in vfsStreamContainerIterator.php
    +
    checks if the current value is valid
    +
    +
    + Class + vfsStream +
    +
    +
    vfsStream in vfsStream.php
    +
    Some utility methods for vfsStream.
    +
    +
    + Page + vfsStream.php +
    +
    +
    vfsStream.php in vfsStream.php
    +
    +
    + Class + vfsStreamAbstractContent +
    +
    +
    vfsStreamAbstractContent in vfsStreamAbstractContent.php
    +
    Base stream contents container.
    +
    +
    + Page + vfsStreamAbstractContent.php +
    +
    +
    vfsStreamAbstractContent.php in vfsStreamAbstractContent.php
    +
    +
    + Class + vfsStreamContainer +
    +
    +
    vfsStreamContainer in vfsStreamContainer.php
    +
    Interface for stream contents that are able to store other stream contents.
    +
    +
    + Page + vfsStreamContainer.php +
    +
    +
    vfsStreamContainer.php in vfsStreamContainer.php
    +
    +
    + Class + vfsStreamContainerIterator +
    +
    +
    vfsStreamContainerIterator in vfsStreamContainerIterator.php
    +
    Iterator for children of a directory container.
    +
    +
    + Page + vfsStreamContainerIterator.php +
    +
    +
    vfsStreamContainerIterator.php in vfsStreamContainerIterator.php
    +
    +
    + Class + vfsStreamContent +
    +
    +
    vfsStreamContent in vfsStreamContent.php
    +
    Interface for stream contents.
    +
    +
    + Page + vfsStreamContent.php +
    +
    +
    vfsStreamContent.php in vfsStreamContent.php
    +
    +
    + Class + vfsStreamDirectory +
    +
    +
    vfsStreamDirectory in vfsStreamDirectory.php
    +
    Directory container.
    +
    +
    + Page + vfsStreamDirectory.php +
    +
    +
    vfsStreamDirectory.php in vfsStreamDirectory.php
    +
    +
    + Class + vfsStreamException +
    +
    +
    vfsStreamException in vfsStreamException.php
    +
    Exception for streamwrapper subpackage.
    +
    +
    + Page + vfsStreamException.php +
    +
    +
    vfsStreamException.php in vfsStreamException.php
    +
    +
    + Class + vfsStreamFile +
    +
    +
    vfsStreamFile in vfsStreamFile.php
    +
    File container.
    +
    +
    + Page + vfsStreamFile.php +
    +
    +
    vfsStreamFile.php in vfsStreamFile.php
    +
    +
    + Class + vfsStreamWrapper +
    +
    +
    vfsStreamWrapper in vfsStreamWrapper.php
    +
    Stream wrapper to mock file system requests.
    +
    +
    + Page + vfsStreamWrapper.php +
    +
    +
    vfsStreamWrapper.php in vfsStreamWrapper.php
    +
    +
    + +
    +
    w
    + +
    +
    +
    +
    + Method + withContent +
    +
    +
    vfsStreamFile::withContent() in vfsStreamFile.php
    +
    sets the contents of the file
    +
    +
    + Class Constant + WRITE +
    +
    +
    vfsStreamWrapper::WRITE in vfsStreamWrapper.php
    +
    set file pointer to start, overwrite existing data
    +
    +
    + Method + write +
    +
    +
    vfsStreamFile::write() in vfsStreamFile.php
    +
    writes an amount of data
    +
    +
    + Class Constant + WRITEONLY +
    +
    +
    vfsStreamWrapper::WRITEONLY in vfsStreamWrapper.php
    +
    file mode: write only
    +
    +
    + +
    + a + b + c + d + e + f + g + h + i + k + l + m + n + o + p + r + s + t + u + v + w + _ +
    + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/errors.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/errors.html new file mode 100644 index 0000000..7a81dce --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/errors.html @@ -0,0 +1,19 @@ + + + + + + phpDocumentor Parser Errors and Warnings + + + + Post-parsing
    + +

    Post-parsing

    +

    Warnings:


    +Warning - Class vfsStreamContainer parent IteratorAggregate not found
    +

    + Documentation generated on Fri, 08 Oct 2010 12:16:44 +0200 by phpDocumentor 1.4.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/index.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/index.html new file mode 100644 index 0000000..08e802e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/index.html @@ -0,0 +1,24 @@ + + + + + + vfsStream + + + + + + + + + + + <H2>Frame Alert</H2> + <P>This document is designed to be viewed using the frames feature. + If you see this message, you are using a non-frame-capable web client.</P> + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/li_bovigo_vfs.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/li_bovigo_vfs.html new file mode 100644 index 0000000..798925f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/li_bovigo_vfs.html @@ -0,0 +1,219 @@ + + + + + + + + + + + + +

    bovigo_vfs

    +
    + +
    +

    + Generated by + phpDocumentor 1.4.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/banner.css b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/banner.css new file mode 100644 index 0000000..19a383c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/banner.css @@ -0,0 +1,32 @@ +body +{ + background-color: #EEEEEE; + margin: 0px; + padding: 0px; +} + +/* Banner (top bar) classes */ + +.banner { } + +.banner-menu +{ + clear: both; + padding: .5em; + border-top: 2px solid #AAAAAA; +} + +.banner-title +{ + text-align: right; + font-size: 20pt; + font-weight: bold; + margin: .2em; +} + +.package-selector +{ + background-color: #DDDDDD; + border: 1px solid #AAAAAA; + color: #000090; +} diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractClass.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractClass.png new file mode 100644 index 0000000000000000000000000000000000000000..afa9d1d9261500c57ec37cff1de8cf43b31dbf25 GIT binary patch literal 620 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vkfZSaHJ|V9E z|NjRvPcK>oB;jC!uy7wgKahK+w)SFm^_jG^eUXv70s?k;dvAAg+Gb<3&cI-?g2GG& zh8_lnGzNx)iHU~;0{$Bt?{jhjD)_IizRSYmznt6_Lqnj-|B{khH8nS=tN#}e_{zt( zR#EXk2ggfJ&eakUK)aWTi~nF?_`tyMoPps!1H*L&hBwx{7GaqsHK2b=zCZk2F6c8jl1JVN5*@+%rr7PI}^11C*oaK4^xC05VCJK_3< zud|-<{@_}WT(>@P3->I)OHK!WY*;^8{ZU{D!{pbT`vks!nK+ee*>;`t+%u+Jea(8o vR5x-}=mldp!DT+b`?hi(nsMPiM;)`hf`a|hX9_^KGcb6%`njxgN@xNA_;dCz literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractClass_logo.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractClass_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8f65c390e37b548578390c0bdbe4a4bc469c4d19 GIT binary patch literal 1232 zcmb`F`%jZ+6vq#W@U{$S1TZXV4viCPx3q`=k`4L zo1#BJx0H}AAicqQU>vV%^^<9m|tWsIx<8LP>5;)!-8{5Ba8xawKa^8)JAwolYrP3xG ze;gi;N)W-psLCUuuq7;v;PILTf-XM)dx3ypvzvl~UU4|4;9xV4hpH34zB3F)V?aO$ zn|+nbCFt}9e}9{g&n%sOWyOknOy(?=N>C`M!zl`-mcbw}tb)O4@%Ek}kw)FzM%>+P z&dw7gQYD>^Hi$-;0kAkbTLCIOJjMZr0D1sUQ>kWvt0dArfEIuTfD>f$DGaLt_zu7T zPzaEN77pxLob%;x2CG}`xIIwL@5%qsVT}twSp0*)++a!sc%Q?K z`N@jCeTp+nwyR|s`Xqf{xt8ToY?#m#I3M+++}?TZyynf|!6(h%ZXB5YwRD&DpE->+ zQa?!d&ipfd^zwzIKtBJ~qLA$Mj4wHSb~mtdtP52mbBN=vTM#>mfmycxM}yu)6Bg^4@lw*?MFu3*Llv~ zTq;{9ldCeY*UL|oCB+&|W}C3XvTUffR~(q#WAaNg-nYFVl1oFwjfcGkWO1Lan7mWj zTHAk$B{{PsrhD+|_&Dv{Dq|lMERc7*{?yjm*&4fucG~As73P}JZF+xm+H<2#y7rxG zW9=q?%ZBwC`JJPAZS{(h+4A?WNris0W9rS3rW|*EzKH2={VP|ERZ$+~<|y91p2^}Q nm5>e}t(H)$%7m@A#{7td(X}C*54y81qwfI{akQvb7@z$w+j=f( literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractMethod.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractMethod.png new file mode 100644 index 0000000000000000000000000000000000000000..605ccbe58e04d8f1462227f08369ef6d8e5d4fe0 GIT binary patch literal 696 zcmV;p0!RIcP){TiMy!!e(Yf-7_V#G2iUr zLy?{{R5VTt!-qRXx-)@b&OX;WKp!2|aT>;Q#=c z001J6D>1||Q0X(T002sRN{?O-R{#J232;bRa{vGf5&!@T5&_cPe*6Fc02XvbSad^j zWnpw_Z*Cw|X>DZyFf=bPGA}SQ*^*j90000WbVXQnQ*UN;cVTj608L?Ia&K*AWNBd_ zMrm?ocW-iQb0AGvyOAm+0002PNklfMHT-Bv8QIEs=+ZPf$A`E>2c0)H#Sj$PWnk1p@>G(zLXgfTkY(YJ2o$Mf2{EX7&_@CL4Lsu zf=WupE-s;IY31eR9Y|p2?lbS+y#t0XRlwut?cae`au#?*7Bet#3xP1>rMq>1fPxAo zt`Q}{`DrEPiAAXlzKO|2`MIennTZN+nMJAP`9;~q3ceA$Cu*qx)rx`CIv1rTmSpDV zDTHL^rZO0q=o=X68yMf56y*d|@zK-8F{EOS?)lqMO%4*R4`(`@EDFELx7ssVZORd| zq%5HzwQYvlS2%cGPXFHD@~{05-~Gi~FPw_9ndsyAvUly>(4LD`8%wTUDBXMa-M%{6 zPZCGZ>%ZQD?T}l&!`s7tUKsOr`-?Wu<;}Q-LQ_10v>q37%ry4uIK**v&qDxa`a*R3vrciLZ8L}yD) oC>0QH(U@~sMxOVvCC6j?c~N@r8XNCh0zJ>*>FVdQ&MBb@0EQ=S+yDRo literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractPrivateClass_logo.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractPrivateClass_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4e68f570dcb38ee67756ce2231bb5c38e77cce71 GIT binary patch literal 1615 zcmd5)X;Twc6n!ia!lFSW4Jkrc1`LPY$1sj(#lRGf?-K4OF)W1MOFm{ z#7YHOM1d45sY*y?RaT*Ff-H@QqJv;$S_hSqKJ6F#4|-7%db^6N%JBAT-(9*4o%q znVVM{8z&gwu}%jHt3R3eeo)zwv3Rdtk> zHkX%IR8+_c3#BLl`T3*C$>o`ujcI8r9xppPdr&AWJ9+Y=SiH#R_r%1&N)#a> zLp)xoP^jW?x*{TSg~HD8@MMu_J|N&;P>>Mv3@w(yNtt`_4MTNcqLq} z%GI^Y$LAr10vpK)47}svp&}CHWHOh_eLy0K*z8s^S%t^Hv9+Bb5@VQ58Hse=#f8OU z!IlG<%q?^C0ynn}bMx!Y&f#=AmrftS zz{0{8=0u^Owi_rERBYA2Al=^ngo6W*NbJU9H<8F%9BxBfdvV7O=!jBFYZ-~mv9x@x zsR@ORv9^X@%xG!71fbr~a2|np3MB<#5&&q>5CDxxWG?{FDLDW|y1G&TngOW$U}y!L z4IC~XfGhw62!t2_EEWrG`q&@}0J;|r4?^#yB9<>37+4Ughj_fi#GHz2*JLti8^rv7 zu=W9PsQxe5o@p5i8$iZ+2Ey)icfJp`vH6pmki>~-0U~xRPm~y%5D9!j!xLhUM@H~N zaUT4H$i&!$Xd%ugKz7d73jRgE|LdL*87kt(3UD0$@kl^$b|5%85QsCyT&R@#EjpFV zNxB$0{_dMGCPphR1jGN@&Te?$F)~u1_bJ2p$i%={-+*sD-;Or!G|aRk{(Pj}Kd}0H zUF|6ogUq)Y;t|lhxz(~t`eQ_RUoq1-eLFT?AP8E>XkA)fHggqi^htaeb*$=!t4&v9 zqXdHJ6|UE%Zb#CMmiE)kj0RV6b=%tA)%tp^#^=wTC2c+JUMy1oOuKh7@94hZJCoCG zXxaS2yJN@J#J33U`c+%lKU?M&7D~KdDwWEKxzE31HT2^+xj+0k>P|X8pxN^#{*0l; zJtxPg-}2sdI`*|*oC&-#etYRjR+M_H)cIG6TS0l{{gE&BmCtq~sCpA%t$SPejT1KZ zhgY7Xi)In=GWoXzL>tiaEgkbHwlbdGz1?uS;}g9r9hTrqerW-%FO1@shEpP|okxi= zPM5cWANffS>kbM9sa+||;ebojEN0yA9yek&f^IImjYjiE#g2W+w}g5r{lcI0tMbXg zn)g@NIfMqbGFiEQJ-TD7%ey9VJ;gYDC9Ao8C1ZwKf{tkXg^MxlZFwOFr^!}`w~YQU zd1uJz%3r<80}oBt)q-)m&*Rf}D)wh9&K|(^9IVw$da;MNxX>Y)R&c|pBRwc!j(BVG z1gV@=8A+_ZCz$E2gI1@w{L*m@r+H)9vC7|V^Qd`Hj&)~W1WkS8@5e~OE~BI%6gwn= zr*W1_Ms>6Hs`1daQJXsTMk+A3=fdt{i_4foPsd6$>Q%`uT3s3z34l|D0EF>7@e!`_b&3NDRW2J ly0$Y=SuS5{3YHYFR9bNnjKnZ6dJUX%K&SaqC6tg;{{UJF@sa=l literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractPrivateMethod.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/AbstractPrivateMethod.png new file mode 100644 index 0000000000000000000000000000000000000000..41cc9f021734b6f99a723a687827190f2ae645e2 GIT binary patch literal 874 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vk7#J8+1AIbU z|Ns9Flwsj#1(FdZp_~dll^g2aJA$}1LE7U51%YJBiZnqBFdculhYlSI zePQDH(Aed!@#@v9{V!U0T+*|>Vq|mPaK+-qHfL>(<z;@U}mwJ#*$v?ZZY|dku|t z>TYOnx7uW^y4kR+tIJ@Wf$1uBpzT)k?NpbUwl>yHs;P72AM0gsJN85x|f1nsNASyQ)C^V z5(o6cX?uI1gPQ_$zUt}*MFj!9qne@NAL##8Sy?4sMa%1B#506*U(#MpQkI2X< zc`N_t;!<)|IwT?j3`C$$JEf(8o_)r^aG!xeU0r=914Ae{#Jqy9S^>kcyd=mkm_blU z$=KK>G&D3VtsLmpnX6WvIdc~R-hlxyN~jN}hd;CiI)SsmBeIx*fm;ZK886+f`vVjd zD{+k|aV|AI6tkVJh3R1!8b9vC_gtf zB{NaMEwd=KJijQrSiv`9_e3ofpxV=(E{-7;bCLzbgr`rKFk#BGq?87R>nEOk>FJpx zR5!!H#V1TpU<$_pmPbOx#d~EhvfQbWT_nhq+3L!8?pK_VPC(<7l;G z*2$BHZrL7j2|sUR5%A_P)N-TQ+}Y|GrRdK zV81Pn)+>0zGnMUCiP|Spqc&^AG^y;y-0mPhgGJ5$HDs$bXTdY0@m-PJEq%`?TdG9A z`7w;w(EZ*psMAWc}ikt!qr000(rMObu0a%Ew3 zX>V>IRB3Hx05CK!FfuPNGue__LI3~&s7XXYRCt_C%4rvYKmdi|(V{3Sky0s2sVw0{ z3ns_0{QqBM)L8Df_c<4+W|ZRbuE?ptT;0z>z23f%IS}<{hVT1%ezB)pU1LBR7z?!4 zdf1$>0)?RM<32r|FI3$jzfkuMegO9fmRSW?+;gd{A6?vpl~i!EaT78927Y{aY)A+t zD;|Uj0{6%|rRRA`LWdbZAQrk%Pf@@U0ViwJZw&^h9P>Z*1$ZnRgm9bKlmGw#07*qo IM6N<$g0d3*MgRZ+ literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Class_logo.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Class_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6f223c479a6c6fefab504deb84ab824d2e744713 GIT binary patch literal 1600 zcmd5*`!|$%9DdQB9VXJcrO7tT6s8%5m)$T$<9->p85y@dE{&RXZA?TG%_2nB{k}w+ z>>y&K8JEf>)@4JEu#A%^x8$DGyKmbsyZ^yH=X@^b^L>8!JkR-jlN{|WrKJu_0RSLv zZDr;RS2P?)5fX5&yJ6f47l|;kH4TA4Ow2fl06^Tq(T-*gK@j``L!Zj}+HeO}zBX0; zizS_}vsy(-{E4`_@#vbdi+5fGm5%u5_tDdPtzuhX8qOmN&M4C`MSV{xS#?0cPBr16I(qS$$iDTJrh_s?O!p#8Hcm?#qi{w{Bl~rNTh%>k zux{n)ub}uDC~68~PeK9XP|o0n-x!qAyY4;;IgdbbU2Fb*kj)U}I`FAP@Yeb{ME(1wR2$S zCnkTzwDp5^%MQJH%Za}Qw(J@Sb}rN|#d2rO_**uOn}$u>PW5Z&eqR6^w@vF-EowJR z?ytf7pRC>Vy0c(Xy#ZElT5*>`i$x}PS71@3%2n|0Ix}zDrR23?#T;0%YIu7FmT6El z2Nu24DVZbXi)=HebP7bUa4>sWJ4d9GHAl=E1#c}<6Gn-tBHfgEozyY>%|Y;&c|yW4 zku#~q8L_(3kLUF3#=OE^@6x?8LyQ_DL=9+0x1A2}#zl7MT$&`ZUJ%&*xUeUhY#|}I zSN$R%Hj~6`#Raq+3+8G3+=%z@#4@=!KOxb#LH%4E&aW2hTXDiu02{99&efzpfNj@w zsn?)ZV`*i_sYO_)-;O(09;Z}d95XSL46I%8F`F_qo10kk0*qOr$PC`va_ndpbYvy|{2GJehB@IiF4o$aZ>K{XIGb8+#H_!n;6$gipr{DZ!g z{{X(k{~?NKvs$nq$xth|FaSV)_a(%J{)*XyhiJArolOn#XGi$37y!k`j};QcILGus zTQFISh!9pl7@9&C{EEZET*WV3Qx?OA%?t@f)0jaFfT*WU)YT?}FEiZ9@ONZdo1LLu zF7opRBrE~}wa)fRZUyglRb^$GxSn2Pg91AFWDunfuj18GhDIRNFt3KCaO!XG6XR&1 z28*aehm}!<>IiA_!AaB^KQ(Cz%0e>k6#30Eu? zFVRRBHaEw|$2T?#1h?9*(e0eWnYQm1Hr1B!cKi1WHPMl!yyD`-M9a|7P&O+nm`UBf zx#`hy(nM;f-efI&Ys=m~Cg$M5y1IM!ni-dtGv`C5w7MQkIj2kLO^;6v4}(M!NmW%J zqg~58a-sbR!Ac6xD=uAAR*p0`XIvs=o+nJC@!AI@u?L*fb6sg?her$|Pd^gJMy6kX zyY5=9aetfR0c3@|$s=BsOcoC~V2u4xFqbA7rlWwKMHLuT_IuR@E0N<;1(y5jqdklr zA18PT(&hJAnw&ypeXE(*jBty~<~W1~;xeKKN4`lJ4URwYtcit4vd9TpEPUi`Ko+~! znxf<=Hu;%f(yED6tR88cY6$)$k_sYx5+paB)@w47v$fpK_KbB9<-0uWWx$V$Y(nJvu4LwpP~GnArV?p7r+FCdX3sF>*+w zM8ps6Vm(S|1s-pS4xBiFG!w(f$;lxV0eSz9%%(EsBY==fcwRHDvGW Fe*-2SG_e2x literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Constant.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Constant.png new file mode 100644 index 0000000000000000000000000000000000000000..a9c6f28b3591824c0732239096324984401092e5 GIT binary patch literal 752 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 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Index.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Index.png new file mode 100644 index 0000000000000000000000000000000000000000..6558ec393a6e0b35fb7776a52b4ca9c10da0d5c3 GIT binary patch literal 584 zcmV-O0=NB%P)sGc1s$KlTB|5tUFl&jIZ$KRg6;GCqm5-wl6(B`4Q;1)J+i=@-=`2U5V zz0~Rd#@X$9lDq;jjf$eZgrL)or^gjMgq*e3yWRhls?|-6=3oE-010qNS#tmY3h)2` z3h)6!tTdPa001C#MObuGZ)S9NVRB^vO<`klZ*65{X<;BnX>w(EZ*psMAWc}ikt!qr z000(rMObu0a%Ew3X>V>IRB3Hx05CK!FfuPNGue__LI3~&s!2paRCt^{$?Fn1@%ouFXELYW(Fj^6Z(U`)_51(-|7XseY25!>(WA}p^8eefzIoSOHBLL@ zu5c=u23 zg#EgG*R(4R8Bcv1+IdSoXt7!L5tEf~j@@~uVBhR|_Md6WYSZ+C#*073PQ0UAdtN0gNKbwkHzugYdUHQk=cz1X!nX~(+V z_vf=O_Fb>Npdzh8PLU=1Pe4dSL)YuZgf>gNH%uxGi_eHC{A4Kd*st(Y%3;N2oyz=} znqKw`%X@Y1uQTv0S!*U^fJH$hN@BTe&;g&?!xjVTG>^jPxS@?+*er933 sa(UjQ<*PC{8=_;sg?l=%aQ~mEp5P)i@yk~|9Z;Bfy85}Sb4q9e05`Dm_y7O^ literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Interface_logo.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Interface_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6f223c479a6c6fefab504deb84ab824d2e744713 GIT binary patch literal 1600 zcmd5*`!|$%9DdQB9VXJcrO7tT6s8%5m)$T$<9->p85y@dE{&RXZA?TG%_2nB{k}w+ z>>y&K8JEf>)@4JEu#A%^x8$DGyKmbsyZ^yH=X@^b^L>8!JkR-jlN{|WrKJu_0RSLv zZDr;RS2P?)5fX5&yJ6f47l|;kH4TA4Ow2fl06^Tq(T-*gK@j``L!Zj}+HeO}zBX0; zizS_}vsy(-{E4`_@#vbdi+5fGm5%u5_tDdPtzuhX8qOmN&M4C`MSV{xS#?0cPBr16I(qS$$iDTJrh_s?O!p#8Hcm?#qi{w{Bl~rNTh%>k zux{n)ub}uDC~68~PeK9XP|o0n-x!qAyY4;;IgdbbU2Fb*kj)U}I`FAP@Yeb{ME(1wR2$S zCnkTzwDp5^%MQJH%Za}Qw(J@Sb}rN|#d2rO_**uOn}$u>PW5Z&eqR6^w@vF-EowJR z?ytf7pRC>Vy0c(Xy#ZElT5*>`i$x}PS71@3%2n|0Ix}zDrR23?#T;0%YIu7FmT6El z2Nu24DVZbXi)=HebP7bUa4>sWJ4d9GHAl=E1#c}<6Gn-tBHfgEozyY>%|Y;&c|yW4 zku#~q8L_(3kLUF3#=OE^@6x?8LyQ_DL=9+0x1A2}#zl7MT$&`ZUJ%&*xUeUhY#|}I zSN$R%Hj~6`#Raq+3+8G3+=%z@#4@=!KOxb#LH%4E&aW2hTXDiu02{99&efzpfNj@w zsn?)ZV`*i_sYO_)-;O(09;Z}d95XSL46I%8F`F_qo10kk0*qOr$PC`va_ndpbYvy|{2GJehB@IiF4o$aZ>K{XIGb8+#H_!n;6$gipr{DZ!g z{{X(k{~?NKvs$nq$xth|FaSV)_a(%J{)*XyhiJArolOn#XGi$37y!k`j};QcILGus zTQFISh!9pl7@9&C{EEZET*WV3Qx?OA%?t@f)0jaFfT*WU)YT?}FEiZ9@ONZdo1LLu zF7opRBrE~}wa)fRZUyglRb^$GxSn2Pg91AFWDunfuj18GhDIRNFt3KCaO!XG6XR&1 z28*aehm}!<>IiA_!AaB^KQ(Cz%0e>k6#30Eu? zFVRRBHaEw|$2T?#1h?9*(e0eWnYQm1Hr1B!cKi1WHPMl!yyD`-M9a|7P&O+nm`UBf zx#`hy(nM;f-efI&Ys=m~Cg$M5y1IM!ni-dtGv`C5w7MQkIj2kLO^;6v4}(M!NmW%J zqg~58a-sbR!Ac6xD=uAAR*p0`XIvs=o+nJC@!AI@u?L*fb6sg?her$|Pd^gJMy6kX zyY5=9aetfR0c3@|$s=BsOcoC~V2u4xFqbA7rlWwKMHLuT_IuR@E0N<;1(y5jqdklr zA18PT(&hJAnw&ypeXE(*jBty~<~W1~;xeKKN4`lJ4URwYtcit4vd9TpEPUi`Ko+~! znxf<=Hu;%f(yED6tR88cY6$)$k_sYx5+paB)@w47v$fpK_KbB9<-0uWWx$V$Y(nJvu4LwpP~GnArV?p7r+FCdX3sF>*+w zM8ps6Vm(S|1s-pS4xBiFG!w(f$;lxV0eSz9%%(EsBY==fcwRHDvGW Fe*-2SG_e2x literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/L.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/L.png new file mode 100644 index 0000000000000000000000000000000000000000..eb334edaeac52e2f473ffd92a49b025fb6148ec3 GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv*$P6UUaa~gcQtTz3zOL*Scz79Am98pQqyvRG z3p^r=85p=efH0%e8j~47LAC&&5ZCE_)&Kwh7Y~}?0Tf{>3Gxg6&+v4+fftY`;pyTS tQgJK!NBsYWhyUvpj=8p5Ib^(%U@*zon(m*SoDEdN;OXk;vd$@?2>{+EE2IDb literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Lminus.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Lminus.png new file mode 100644 index 0000000000000000000000000000000000000000..f7c43c0aa3bebb499e86eb744b1e47b9a9445ba7 GIT binary patch literal 219 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv*!VDzYUPT51DfSXiUsv`EJiLsmQh${X`~(Vd z7I;J!Gca&{0AWU_H6}BFf(8LTA+A9B|NsBf`>KHqVn8Lk#c`lIrjj7P;QtIyw;Ol? zc?O;?jv*Ddk_A|pTm=*lC~zFVdQ&MBb@0OtiQr2qf` literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Lplus.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Lplus.png new file mode 100644 index 0000000000000000000000000000000000000000..848ec2fc3bbaab6345864c303684ff8a86559cfb GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv*!VDzYUPT51DfSXiUsv`EJiLtR`ZJfMMF533 z3p^r=85p=efH0%e8j~47L4yFF5LY1m|NsB#ebqn)F`$y&;y6$pQ%R6t@PCG<+YP*c zJX22>$B>F!$pS1)t^$e&6gZd#)XV}^6#`leL>0XheB5$;*x1}$U0qr4a0#d>%paztiFSddoE z=FO+Zs9v~B@b&OYf=WY?JVJfcJk32QO)AOb$urFVKXE`Ry)jqsH71)XJB8YEt>{GE zGvwvuGqv|cy!A6?%sp|-T8&j?o?bnP-A{*1r^4t+dqpBkBPV|V>IRB3Hx05CK!FfuPNGue__LI3~& zAaq4obW?9;ba!ELWdKcKV{&h8Wn^h#AVz6&Wp{6KYjYq?Si6xbBme*ayGcYrRCt_Y z&;kMn2M1Xdeh6R)4Ab%Sw6|x9hYPq^SqVCeF?quTBwVb*o#mC81mFUy;m%?#?D`xC z0cWuYe|IAv4`YZxESp$_l#sZsh-s)UL?ALUMqSb?I@nP<)JGU7U}h%a#vI_K=%}q7 zq~RmZ$N<)8;N{4}qYx4zCu$87;NdY>VCC|)P=g6*o7-s0FmMCSfC?zsMKS0(@xufx vP5c-vI3ex;lft~dN-&p#Ny9iND4!ny)Wjn48}#yJ00000NkvXXu0mjf>`)kw literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Page.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Page.png new file mode 100644 index 0000000000000000000000000000000000000000..ffe7986ee2e78f7079d6de1a13ef29bff125f7a8 GIT binary patch literal 592 zcmV-W0wTQkb(FJYg{r&I=J@>oPidBsr@_|i|DM0#0xyTVySs>p zi0u&l@7S9O=i(&oFz-*}d|5-wk#ve_0k zZi}ST)an1e-~WcE$O18qgrL(EJcN#?$DzRBm8#XK#^imQz1B}9Gynhq32;bRa{vGe z@Bjb`@Bu=sG?)MY03dWlSaefwW^{L9a%BKbVPkS{ZDnL>VIW3na%FdKa%*!SO<22; zDkJ~^02XvbSad^jWnpw_Z*Cw|X>DZyFf=bPGA}SQ*^*j900025Nkl8X^a6$`;}MU&lC(fZYGN)*U*T&WTYe`t|6?P&^gvL>{}6e8nl zLI{`JKlCFG|LqoMkSE{iD56H;IN0Sraje`6bqbr=>+Ac4L(v&iSUtNMDLgY2KvhT^ eCV+sH1<((?kR=WgbuC-~0000)GO-L0AERF6v)dP%qbhFs5=j^@`6F?l_(@;?;SYFPR0 zI9jbQwZey3=y8ba9+c^JAk$@k`bNJ*XM8mL<6q0r!V+YD551g+rvHRYW=KB^jl71Q zyjUEXf%<=gv{N57&;Ray_CaNWG~<7$j7xBl@^MHtX718|yz^v1Gcq;sXrgWOL-%8| zeAujcX!zyfo16VFq#9G>J(EnWtL=RyR-0NB6V)oy zRmEie9Z=A1gd35_HMMe(FE?E78WVI3@nv91+wgViUAV!rpFqJ)Wl_to!seceCS_?; zZ;4o$E4k0B*A>>Q@@^>L31o}zmDNbO)e5c<%)AP+E5P*1yXjXRr0_e>m1)_fP3L*4 zq>@`n#eK};ri8-Yv`eDs;=aU7t-G*r(;{fc=?O5OKSe$`R3j_d*nP9?x%J(%fQEH%67mU3Hek2mE8BI_V-TD<8{d?o6-ef!PG`p%c&+4{j^aUgcH zPg_HSd3If0jjtfvXN7{Bm9@0` z{!FFF(*y6@p7PEXiOALIn)UNaUZG?FMfe@usLHF4iAJOOeEx9SoR_ols++f6a=J|s z5ggQNwU#-2UgKh&U;x$U?l6kKlg`fF$Kh~T&%}(*P&e;MzM$e1iDYH5)s7SzdNQ)O zW|LFc9?jNAIaVEr_>4^{Y;|6Zw5lrHumeb(iS9?J(ExtAVJMHD8w=kA5FA7#v<61y F{sZ~k(bNC{ literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/PrivateClass.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/PrivateClass.png new file mode 100644 index 0000000000000000000000000000000000000000..470e6d5684f29e52abb36ee6036a4d0b717f92e4 GIT binary patch literal 790 zcmV+x1L^#UP)WmEhNm^6>N2zOCt|Fuvb2MPgIr%?-{0R%gxJKy#3oLoEQio1TB$RW z>}rOS@9*z3X3RRU*Z=?jNYVd(pWkzHbE2lGGqCn7nbbf>Stx6=M8@%WtGpvWd{9$d zW@ctxl-^f`)gwrPNl|4eO^Yjd!Y3yuC{eAu(Bd|2#VxYmFkYoDiPgf`>UMyN)z#HS z%>A{^=P{-CPSgKgi`geqs99WJM7{YbYtFRD+-aQPBu9}dn9Ep?+$&_jF0SJ+!SP*W zX)~JcM@?QQa<)}jTP=IfF8)Ib00009a7bBm000XT000XT0n*)m`~Uy|Aaq4obW?9; zba!ELWdKcKV{&h8Wn^h#AVz6&Wp{6KYjYq?Si6xbBme*a7IZ~ebVG7wVRUJ4ZXi@? zZDjy3G%qkRFEBINl3GFl008buL_t(|oMUj)Q(}VxtyFm#HwHbAypTdL(6@<=mvd%N zQkP73cXv}CPB4cExH8Hr zR9dNMl-WZB*f~Ua3V1C`?H#MY0*R^toKm_>URD+2h7KTs7*P=&Pi7Gj&r(CfOje+P zFt?7JoTp{7PL{MZM8L#S&O(+`PDicC$POfs3ly+qPy-6^M{5QG1%xD+<>aCiZ7tPU z^H~Lf0(?n|mdsYno>sEH;pIUBhYhhT*-1^kj&-m>@4F3035e9 Ui&^Ep{Qv*}07*qoM6N<$f)e~=1ONa4 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/PrivateClass_logo.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/PrivateClass_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..590e00640baeca2f541347cc1c5067c255030bba GIT binary patch literal 1836 zcmdT^`&Sa!7N)T^!|2#(lU~J2d<$xV*reb%if{uGAB2xcCr~6EBoS~N3`R%8oA1Z9 zjI?x2^HGvbVw2{xv>MSY!8DVxe2kTOO|w!{=Jd;~yVm^+?p|x3z1KPWoOQnaedlBa z1?)G}hv`Eg5JNJFKm!r}(V==^BvfbjfuJYElj%?>bo^=HBn0wFeULw$sMG1d%HLKu zxBzkwfr3JzfTUsI<@w&3l8(u&mT`$j!bTAk>Lj{8{G)6;Xhe<^xY#~9JI zx3?b|Ud!owO;hVQDqYy%2IZmdeCu=a(B{wGi%O+3M75INIh1s3f~0znAN+9Y`W*B2 zYFSHH*zMJT-gTef-zyY~$j*1CuC)_;*9A8gz*V^|uYx-Nq_)2&cB}^f_O_;`#Wz=Dmm0WGd_5vmZPn;Z@Y$?s-xl010-LVn-j7_WpUmV?gQ z#@BnsDCw;D-Mk{e0y63*g(>ik5-}JIM`rWR*c|KVbAjP(z>W_i1`*!8_i(%|;{uGC z=1*tRXf#K<;z00WJ9@QwgxE5?z#+KKmR3oohFArc09Du>_{D}=45RaiWSTAcoE0S( z@N0$7w#FA*`D6m3Ej=?Wu_-VQ{;qw(T^K2l4WQn_MPTm22Kq5Uga8S_V6a;oN&P@u zQzBZxL5Q(6h7b}0@Ff42os>5;w6y`Ds8kaR|6@St|4;V1Z*vQP`#GOQZH!5*#rSH(*E!w%R>-W{9c69(j2#gn5S*Pqeeq^v zzkL7CbksY8FY>ZH_y6!U8jYr2bRG(APR1>F*_YGqtw{Yg0`Hk*&pV0b&!3yS)ld!| zn-f5urNP6I+p~<`D6nDn7fewiT>32o*H`kl6t(#{?$F=*N%E5432(0YCHDnRmtM{%F+ZC$WQDv++M6`c7mUI8vfQsyf=ACU$>$DI+n##uKp{O$Xh-}+|U_|mnTX|Q;*F+<{u+T@*V3jZ|K z&~S*U?dR?=dYp2%b8#zklwvgU3(HA5ZJ*GQU#Pd#ydxV9O*j5)xBk^zxanB&!TRJbl+-sIOMSY7+S!-!q6vOvO6U|hJ<$tucw(e2>IopzU zf2Q#2*c**a=_FsApXeEHs+lu9>UQWW!OhK72-@dJnVPY@2A%?hObj3>@XYkT0K34m Aj{pDw literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/PrivateMethod.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/PrivateMethod.png new file mode 100644 index 0000000000000000000000000000000000000000..d01f2b314b973da7318cdb98a71a326f383e5864 GIT binary patch literal 918 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vk7#J8E0(?ST z|NsBrx}lMUpA{(2slZdYq28zK9FXna5yY)2U{iVAD08bu#A0RNsVOVc1TDmPHTipb zdQ55!GnYS0Uh*_%;nVQBj{~OMck8;@+}kAODC6$#?$PP#(BP7mmKGHirRd(Fy|8-qYX6HC z9+&iNuNW;|w!-GTq4$nAHfL?^c7FHT`aNmOeB(356Bn%kIv{R`xBWrwnKNf)W>PYjD}zLwkAT3uZo(G~1G(Z;{#vR6}oNlA%PpSD}U zF^_6j=PGB;3=*#Y$WwN}P*Q6H7Al^Atid zb5j`%O!N(m^bL$}PKt5@s!#x_2+mI{DNig)W$;Z*F3QhMP037DaLX)8Ezd8?E>`f3 z*ga881*rD2r;B4q#hhdTK`}8wQQ_$c$qh{j*4F9e`#W^>b~G%TwQJr~Z#{D#1vl?l z|LazJX0WSGSg|%ebAsU9Bi!N!<-8wzw);;`Y~fl`b(`(zvrGw95l%-IFCTC1&!2ls zzwGV0^wWWiW15+nU*5!-t};9e3k&TQp8P2% zX10&@>Zv(AJSVl5iLPpE{gyxy^(5I^ sFWFixmIS`k36rN!*Izp!t?eTtSH52M{Yh~%f!<^AboFyt=akR{02;ETy8r+H literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/PrivateVariable.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/PrivateVariable.png new file mode 100644 index 0000000000000000000000000000000000000000..d76b21d4e9e8656a68989f007945ab14507ae23c GIT binary patch literal 772 zcmV+f1N;1mP)%f|KD9dx9b1xbjG4eNtEH2jam85a{u&(X=GITZxLbNk_B|L=MK=xa7(sn)kg@8o`zfK1-9S*@a5ux7 zfmfd7&Z|n=(z?t5000SaNLh0L01EH`01EH{Laa2H0000WbVXQnQ*UN;cVTj608L?I za&K*AWNBd_Mrm?ocW-iQb0AGvyOAm+0000MbVXQnLvm$dbZKvHAXI5>WdJZVFEBDM zFf-YbT0#H-0Od(UK~#90W8e{Sh>wpK_v7H<0s#g#e~U6rcWa$YHYh)|I4&;C+*d}O z2f|lomMalTR8dirW#a+!op`m(q>74+J*{+kKztWlvm~$d^mHFbLpC7aKvFO=TL8$- z(9YH4VPIntQ#1*-Nlnd2bB@(uW8hJbF68FUi^)(>aJDaCV_;(~R6mrqkrNJ-9N zW6+HbC{^VT@L*JM&I(uJVNf@UHVOzZ($7!fbQ1-dZx^5&WvUzCEm6)Q&B_DjGcf1| zBm@>j=z`qG8lcY2t!~7v&IWNmtEDgym~unB%LM?}VJts-{;Z7v0000paztiFSddoE z=FO+Zs9v~B@b&OYf=WY?JVJfcJk32QO)AOb$urFVKXE`Ry)jqsH71)XJB8YEt>{GE zGvwvuGqv|cy!A6?%sp|-T8&j?o?bnP-A{*1r^4t+dqpBkBPV|V>IRB3Hx05CK!FfuPNGue__LI3~& zAaq4obW?9;ba!ELWdKcKV{&h8Wn^h#AVz6&Wp{6KYjYq?Si6xbBme*ayGcYrRCt_Y z&;kMn2M1Xdeh6R)4Ab%Sw6|x9hYPq^SqVCeF?quTBwVb*o#mC81mFUy;m%?#?D`xC z0cWuYe|IAv4`YZxESp$_l#sZsh-s)UL?ALUMqSb?I@nP<)JGU7U}h%a#vI_K=%}q7 zq~RmZ$N<)8;N{4}qYx4zCu$87;NdY>VCC|)P=g6*o7-s0FmMCSfC?zsMKS0(@xufx vP5c-vI3ex;lft~dN-&p#Ny9iND4!ny)Wjn48}#yJ00000NkvXXu0mjf>`)kw literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/StaticVariable.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/StaticVariable.png new file mode 100644 index 0000000000000000000000000000000000000000..8e820193cf930c4147eba542a1b50626933d1f42 GIT binary patch literal 688 zcmV;h0#E&kP)ugtEVnh;=iW%reFK|K(=fyleQ_jJUz6HFV9ct*geON>7>N>(GgmfJ|kL+1=gU z^~Y`c%U_K>y!eySuyp^oG^8 zOJ%3#Pt*VAzglvk(fQzS|Kx&gliM$y+%{plJI?=wq~ZVfjLxV|_|0oEwD7g7kJ`IY z``=&x-kSgDYyawSp@vA;vQq!uhw#*m-@tNLp5*`PleCyn|MHYq)&I_`O8L%mFH&Tq z00009a7bBm000W`000W`0Ya=am;e9(Aaq4obW?9;ba!ELWdKcKV{&h8Wn^h#AVz6& zWp{6KYjYq?Si6xbBme*a7IZ~ebVG7wVRUJ4ZXi@?ZDjy3G%qkRFEBINl3GFl007WQ zL_t(|oMT{NQ!(J+;Bd9(Wn%#W1{OIVrx+F&;*6wS&87O>I`iFMG>&~Wn?kpl^s3aTqPC~9aZgzBhqu>l3V zEJEUe@?l}Z!7lo83@mJN_9niTy1Jpl!gdkiKmisO)({&oUzpiX1}q>a${hye3fnpI z39x|#*m&f1fLvyFNkfn=ASHU{Ea4lA_OTmCm4hW!rK?49w W#UB-s5zQI^0000H> zJR*x37`Q%wFr(8NlNmrkwg8_H*Xe!L|Ns9N51QZs6k#d}@(cdY@N~O@7mz3J>Eakt raVz;p{QriB|LYZwxwcz9n9R-~pRXx?mgVYJpb`d8S3j3^P6#nkpi;(?AirP+hi5m^fE-m% z7srr_TgeFwOpI(f46|1#2yiGY`Di?KiU>FVdQ I&MBb@06e2A@c;k- literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Tplus.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Tplus.png new file mode 100644 index 0000000000000000000000000000000000000000..2c8d8f4fd38259b2ef70fc63fad505fb0a0f55a4 GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv*!VDzYUPT51DfSXiUsv`EJiLtRLI=-jc>;wv z3p^r=85p=efH0%e8j~47L4yFF5LY1m|NsB#ebqn)F`$y&;y6$pQ%R6t@PCG<+YP*c zJY!E6$B>F!$pS1)t^$e&6gZd#)XV}^6#`leL>0XheB5$;*x1}$U0qr4a0#d>%86hy4NT6+w`tp00i_>zopr0L}p{>Hq)$ literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Variable.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/Variable.png new file mode 100644 index 0000000000000000000000000000000000000000..8e820193cf930c4147eba542a1b50626933d1f42 GIT binary patch literal 688 zcmV;h0#E&kP)ugtEVnh;=iW%reFK|K(=fyleQ_jJUz6HFV9ct*geON>7>N>(GgmfJ|kL+1=gU z^~Y`c%U_K>y!eySuyp^oG^8 zOJ%3#Pt*VAzglvk(fQzS|Kx&gliM$y+%{plJI?=wq~ZVfjLxV|_|0oEwD7g7kJ`IY z``=&x-kSgDYyawSp@vA;vQq!uhw#*m-@tNLp5*`PleCyn|MHYq)&I_`O8L%mFH&Tq z00009a7bBm000W`000W`0Ya=am;e9(Aaq4obW?9;ba!ELWdKcKV{&h8Wn^h#AVz6& zWp{6KYjYq?Si6xbBme*a7IZ~ebVG7wVRUJ4ZXi@?ZDjy3G%qkRFEBINl3GFl007WQ zL_t(|oMT{NQ!(J+;Bd9(Wn%#W1{OIVrx+F&;*6wS&87O>I`iFMG>&~Wn?kpl^s3aTqPC~9aZgzBhqu>l3V zEJEUe@?l}Z!7lo83@mJN_9niTy1Jpl!gdkiKmisO)({&oUzpiX1}q>a${hye3fnpI z39x|#*m&f1fLvyFNkfn=ASHU{Ea4lA_OTmCm4hW!rK?49w W#UB-s5zQI^0000(x0NIF%{nuT>i_6Z|J+03z&LVrQvdj0nPvbd zPMvIEmeZ?!4s&x# z#i%Uo#W*vP>T-Bh-n}vA&qc6+7`mT2TL1t632;bRa{vGe@Bjb`@Bu=sG?)MY03dWl zSaefwW^{L9a%BKbVPkS{ZDnL>VIW3na%FdKa%*!SO<22;DkJ~^02XvbSad^jWnpw_ zZ*Cw|X>DZyFf=bPGA}SQ*^*j90002ANklU5Ub z)J&2>v72qTTu7E`nx@t2xdQKkZtdZYg4lY+yP)e911YGU#WzGE3Im~vZA6xzk`9>4 zNL8_RMr5ZhnC39*aq{=8RR=h(7tdcVhw%9H0)imQWkC?GbCM*z2n^6y_rKc*n=K%t TSg55|Cs*qzIWRJ6ld^s^>bP0l+XkKHvAUX literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/file.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/file.png new file mode 100644 index 0000000000000000000000000000000000000000..0bb2427f8afe94b50835b0a6fb2f7fc4b6624bb9 GIT binary patch literal 462 zcmeAS@N?(olHy`uVBq!ia0vp^{6H+o!2~3GGZMc6DV-A6h!W?b)Wnj^{5*w_%-mFl zkkV8IBTEIZ#5@Hf0|O%FdgViBVQqh^b}u-UUD* z&H|6fVg?4j!ywFfJby(BP>?0v(btiIVPik{pF~y$21Zp+7srr_TgiX^|F>tp*udH$ zEiL_V#ftUo-3uDh%uP)G{Qt|SZB_7q!9$E~2FI`q8Re^|Ns4w54;**JyG{r3reJX3bz{Zf3vmrZqg`n}6P+S5*tz>i^H* z#2~u%W)Z8#mr%xxhMwd+SvmjaL%%Odb!ew<(5(2Ban^6jjOpAT8-5&KS>(Rw-29d% zNdZfFap?uEMT+k<(v+DOT$Z%I^ZS1lw?N{?lj=*DIus0-A5UO#>EQ|b(2vWFmuh=~9H|IVo^qIey?Dz1hsy_{P4Pvu|$000SaNLh0L01EH`01EH{Laa2H0000W zbVXQnQ*UN;cVTj608L?Ia&K*AWNBd_Mrm?ocW-iQb0AGvyOAm+0000MbVXQnLvm$d zbZKvHAXI5>WdJZVFEBDMFf-YbT0#H-0F6mRK~#90WyotAfiM_=;n!)RO))lyYKg9G zDu)jI|9{59Wq7{b4-9^S|1r5?yt?|k_gEL_vSjsQJ~o|}aLiJr)OMPgdUXK!BBdrI ziX117J(mLBNUinDT$y2+3p0|WwfAs4W|lcJ!*ci>ABPQvf>`e66oz{@WlRWx5Nh&6 i1*3pkRRDgc|J5D1CKP}NM>^*K0000|Jy16 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/function_folder.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/function_folder.png new file mode 100644 index 0000000000000000000000000000000000000000..8b3d6e3b12902fd6de044496082464dbc7639d42 GIT binary patch literal 605 zcmV-j0;2tiP)|{;@VQH zutK?#8|2oVPNX5otuVc-H2>T~`qMo_z!(4RRPW0<*~LTu^jkBj5P!Tt|K&_$wm39v z5ILL=BqI z!r&0NoVJJLDxgp-+TMLq>XzlVuBikpI}FsMP+>!akcx{yaKxWv;lIWQI-(jqRCU$Q00000NkvXXu0mjfHW&%O literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/minus.gif b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/minus.gif new file mode 100644 index 0000000000000000000000000000000000000000..f502662bccc750fa7163df74d83beb34041d8509 GIT binary patch literal 54 zcmZ?wbhEHb>%!0InVFe0X3Tk++2-cv|NsBJy}eg}(|db+t*x!g)adv3 z_j7Y|rn=z0$>ZMM-tX`4KW@&Ajg7^{#b#z^wY9a6sobTdrOeFC+TiVjgM-%A*0aLm zTwGj+qT6qh*h+WM*WK!7W@ee0nXJF&WQx{%o7>so?BwU}l&#?3;^@xa?}MP(t-ap6 zEIdd6000SaNLh0L01m?d01m?e$8V@)0000MbVXQnLvm$dbZKvHAXI5>WdJZVFEKJN zFf-)xbMgQH03dWlSaefwW^{L9a%BKbVPkS{ZDnL>VIW3na%FdKa%*!SO<22;DkJ~^ z0ZK_kK~#90g_GNIgCGzd~1b@PXAis>##hF-Lcwks_T5{Gt1=G+~a%dFwQCnQZU3J+k?=iHfkBIVqw%X0=b%mMM4MWsfC|3Za zJLI<3MRLMm2C;EFN?uzwL|DX3a6V)!kcPBr r4(}qx0<9ZuvwaL3$t_-E{1p8KSMoIIFM}#&00000NkvXXu0mjfmFG8p literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/next_button_disabled.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/next_button_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..4a11780fc0ec50dd27cdb6a52f863c511e32b61a GIT binary patch literal 543 zcmV+)0^t3LP)D z03dWlSaefwW^{L9a%BKbVPkS{ZDnL>VIW3na%FdKa%*!SO<22;DkJ~^02XvbSad^j zWnpw_Z*Cw|X>DZyFf=bQGA}SQTlLsPeLfOt#LNVQ}_yWVA&J!XM&=yzgAag0bSrwNq7QKuW}AeCmE|^Nojv;1W49t( zJ^R_7npd}q|9AEYBEEOSPL(b=(wtUnF~5x!^#c9rjMvp>dVHd>fI6h^x!+-x^4?w{ zA}`WpEJtxdM>gE74H3rQb1zDxCZhMp#IYTl92jdPHrzr4kKJTmn+Eji>=$zWWK{du hHd63A_=WQ``UAH88gT1vi|haZ002ovPDHLkV1oT`@4^58 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/package.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/package.png new file mode 100644 index 0000000000000000000000000000000000000000..b04cf566d4ac41fa95f87664cf65325cc51e8a64 GIT binary patch literal 668 zcmV;N0%QG&P)t@djQ|x-^8(p z?4%BxbRnvSIo8(J;;cKFW&rs3_^P0a=H}+Wz`&@4HsP26zocrIZ4l3l0QR&iRXPBo zdnn+jGIdY@nPvdLr+C=OsEk?wl583Es}SUx0Hl8}w3Siws0*g0p<_e<_q#u(c^k{N zhsBHlt8)OYia^7{zq@__-VIW3na%FdKa%*!SO<22;DkJ~^02XvbSad^jWnpw_ zZ*Cw|X>DZyFf=bPGA}SQ*^*j90002jNklc}6)3g8( z2ru$H580mZyrWAbSccU12f~7K5mUsGBX6FN7o9)y4In#v$>W9q0000@uL8oa~j{sfyu2e|KUjW+DCy{0JN1+^UXT2cmT$oA=$Mq|M6Jhn+c_M3;+0E zbx;8R*gvs`8movsnPvdrmjLt9Kjg6{xsNKVeGbg7FZ<$8{qAY-)kDUkCzNLg*TZiA z)ja?7TfLMa+qE&-lK}C{I^?=9yq74~zG|$36Zh6a^rZm*+(ZBWW~z4x;hqqmcOiRJ z0IiEc|K?4LUIG8;Po#Y-wvr&V>IRB3Hx05CK!FfuPNGue__LI3~&Aaq4obW?9;ba!ELWdKcKV{&h8 zWn^h#AVz6&Wp{6KYjYq?Si6xbBme*aqDe$SRCt_K&07n zYC8yeE(c9}CP^I;-Xj?!ixGY5~lHzpft}vlT9I`brT10000%q?FnVFe0X3Vv2q^)rKP2vv)}0J@jq_P*4*ihjg4kzX1%?=#l^*vtlzDzt>WeD%*@Qz*49dQ&}@*_ zgM)*ny5P~$Sz@EU>hb z00009a7bBm000id000id0mpBsWB>pF7IZ~ebVG7wVRUJ4ZXi@?ZDjy3G%qnSFEBIY z@^kV4001C#MObuGZ)S9NVRB^vO<`klZ*65{X<;BnX>w(EZ*psMAWc}ikt!qr00BTr zL_t(|oOP4!R>L3+K%uvC@aN(<}}S| z_cY8cJz7aQY#zo&M2jq~x36itf~8liMJ`!c@Asvy$I6;i&)Dnru()HiB+edazpMKd zEoJN8-)<(BGm@V>Kss~sJD&cma7A&3Rf z-i?ioW@cust*yny#e;)`TwGjcW@ee0nN!N#@Bjb+32;bRa{vGi!vFvd!vV){sAK>D z03dWlSaefwW^{L9a%BKbVPkS{ZDnL>VIW3na%FdKa%*!SO<22;DkJ~^02XvbSad^j zWnpw_Z*Cw|X>DZyFf=bQGA}SQx z*6k)+-YhrkG_XnH4KgoalbW`Y#C%zLMG(A8#WIe0Sdy)s;aR#>iI`s&ukbi9->Bn; zl^kv0>?j`lHcTk$X~oOxj`mj&)#BNTkGP5zKdfml{jyB_s;gQ~-J%yw(;cg&WqD+e z@4Tv&%scxQ+Swu0bZj8*=8QhlX_YI61C}V0RhrpeSIKn$X;_d%y$~5a%u?9ODEgSKg~J500000NkvXXu0mjffsXN< literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/private_class_logo.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/private_class_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..590e00640baeca2f541347cc1c5067c255030bba GIT binary patch literal 1836 zcmdT^`&Sa!7N)T^!|2#(lU~J2d<$xV*reb%if{uGAB2xcCr~6EBoS~N3`R%8oA1Z9 zjI?x2^HGvbVw2{xv>MSY!8DVxe2kTOO|w!{=Jd;~yVm^+?p|x3z1KPWoOQnaedlBa z1?)G}hv`Eg5JNJFKm!r}(V==^BvfbjfuJYElj%?>bo^=HBn0wFeULw$sMG1d%HLKu zxBzkwfr3JzfTUsI<@w&3l8(u&mT`$j!bTAk>Lj{8{G)6;Xhe<^xY#~9JI zx3?b|Ud!owO;hVQDqYy%2IZmdeCu=a(B{wGi%O+3M75INIh1s3f~0znAN+9Y`W*B2 zYFSHH*zMJT-gTef-zyY~$j*1CuC)_;*9A8gz*V^|uYx-Nq_)2&cB}^f_O_;`#Wz=Dmm0WGd_5vmZPn;Z@Y$?s-xl010-LVn-j7_WpUmV?gQ z#@BnsDCw;D-Mk{e0y63*g(>ik5-}JIM`rWR*c|KVbAjP(z>W_i1`*!8_i(%|;{uGC z=1*tRXf#K<;z00WJ9@QwgxE5?z#+KKmR3oohFArc09Du>_{D}=45RaiWSTAcoE0S( z@N0$7w#FA*`D6m3Ej=?Wu_-VQ{;qw(T^K2l4WQn_MPTm22Kq5Uga8S_V6a;oN&P@u zQzBZxL5Q(6h7b}0@Ff42os>5;w6y`Ds8kaR|6@St|4;V1Z*vQP`#GOQZH!5*#rSH(*E!w%R>-W{9c69(j2#gn5S*Pqeeq^v zzkL7CbksY8FY>ZH_y6!U8jYr2bRG(APR1>F*_YGqtw{Yg0`Hk*&pV0b&!3yS)ld!| zn-f5urNP6I+p~<`D6nDn7fewiT>32o*H`kl6t(#{?$F=*N%E5432(0YCHDnRmtM{%F+ZC$WQDv++M6`c7mUI8vfQsyf=ACU$>$DI+n##uKp{O$Xh-}+|U_|mnTX|Q;*F+<{u+T@*V3jZ|K z&~S*U?dR?=dYp2%b8#zklwvgU3(HA5ZJ*GQU#Pd#ydxV9O*j5)xBk^zxanB&!TRJbl+-sIOMSY7+S!-!q6vOvO6U|hJ<$tucw(e2>IopzU zf2Q#2*c**a=_FsApXeEHs+lu9>UQWW!OhK72-@dJnVPY@2A%?hObj3>@XYkT0K34m Aj{pDw literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/tutorial.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/tutorial.png new file mode 100644 index 0000000000000000000000000000000000000000..bc19737521daf3fdf8ba84693a6c1db275587a5c GIT binary patch literal 431 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vkfZXr^pAgre zprHL{KJDGRx2LCv!T8Mo|NkA*ZeG25wYa$W-Me?omMzQgdGzervomMTq@|^;S+i#5 z%$Y4ME$=`5xp(j0`I}#l9z7Zv8M$@qR-kNkbv01-`}gk!y^mPGos9)r!CBxDS#iRWF{)OWfrBD=NDxcEBHq2o~We) zR4WEj>s*wYSdy8arx22vo62BdqHkafM2UK~>Od6>JzX3_D(1wVzsPr3frB+*)nX0d z)r+?ozWcww_=ZWek(`gs#BPRvqA|;NeJ*kO*ruqfcq}a9c#C3L?KpBF@G1}eAg_> R{R!w;22WQ%mvv4FO#oMzwKo6& literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/tutorial_folder.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/tutorial_folder.png new file mode 100644 index 0000000000000000000000000000000000000000..2a468b2a06fa3424ba94773373637d424f91f7e0 GIT binary patch literal 572 zcmV-C0>k}@P)>~W@cuiqoe=KGyn8k-rnBK%*_ATKmXxKdU|^Q=uf|NmyHcL<7#inXPLp`VEqaE{#o000SaNLh0L01FZT01FZU z(%pXi0000MbVXQnLvm$dbZKvHAXI5>WdJZVFEBDMFf-YbT0#H-03dWlSaefwW^{L9 za%BKbVPkS{ZDnL>VIW3na%FdKa%*!SO<22;DkJ~^0HH}lK~#90Rm|HGfj|I&;Z-?S zTE~>lvDmU9)2vA$a-s45?_+lx7yird;s>}vSUUa%B5*H?0lB_-jxz$}S+Eu>Tci^} zf*_zRSBAc7nwO;j`bo#VVd?HJ70@Hv7$8pt&R;?fo08O0cTlDBo5&$ zS2)D&L_ip-Xv-c3iad`)mSr0V%M{(b3i`Z5_cW1MYXWTY*ZT`cP91=4{NC>X0000< KMNUMnLSTaQ$PWMj literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/up_button.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/images/up_button.png new file mode 100644 index 0000000000000000000000000000000000000000..ff36c59356d1d67cf8c4d12cef7b5aff7bf4dbc1 GIT binary patch literal 668 zcmV;N0%QG&P)%Pk4nVFe0X3Tq=+TY{p|NsA1fYZIby?c9mt*x!i*Xj57 z_j7Y|p0wcB-0AP{?>}zNjg5_FW@fduwWXz{lda&z#l@+-;@;%(Zjsl_%*=y>gJX); zOLx%L*4A8HT!y3E-rnA{#N%dWW|^6pp||AZ=k2Gu;O6G$tG?unrQUFp*;j$nOL)=N z-H!7B000SaNLh0L01m?d01m?e$8V@)0000WbVXQnQ*UN;cVTj608L?Ia&K*AWNBd_ zMrm?ocW-iQb0AGvyOAm+0000MbVXQnLvm$dbZKvHAXI5>WdJZVFEKJNFf-)xbMgQH z0aZyvK~#90eUl4s!XOZUanyCl+N~BSZdg%F=FV*U|Nm|WGzj(aC4Hp#g}ZVbsUwYZ z&Rzjil!QBIZEnCM*G;mFfhMO*Sgs&ijd4EZ4F>=mqdHh2`yC0Klf6aD**dot!!VqZ z1kM^tYtrbhSZY~S)mve)l_6jX>4Z|XyI6o$PsyzG!CTd_u;_}+68;72Gqbc*E#XaG z{1KHkUhfaBA749OLuPS0vpzyLTx|WwI-s@b{QWyw?8=I(yrMOhmdva(hL@P@CDfl= z3@+A)(FIx?d>#r*+a&qgfBjDR2CScBhYVBOmN=QV;cFbnb7;T&7X-qIrqsl*m$}d$CKcW835(Ow@m?{E zuz;N49J94VK$=2) { + this.childNodes[this.childNodes.length -2]._last = false; + } + while (root.parentNode) { root = root.parentNode; } + if (root.rendered) { + if (this.childNodes.length >= 2) { + document.getElementById(this.childNodes[this.childNodes.length -2].id + '-plus').src = ((this.childNodes[this.childNodes.length -2].folder)?webFXTreeConfig.tMinusIcon:webFXTreeConfig.tIcon); + if (this.childNodes[this.childNodes.length -2].folder) { + this.childNodes[this.childNodes.length -2].plusIcon = webFXTreeConfig.tPlusIcon; + this.childNodes[this.childNodes.length -2].minusIcon = webFXTreeConfig.tMinusIcon; + } + this.childNodes[this.childNodes.length -2]._last = false; + } + this._last = true; + var foo = this; + while (foo.parentNode) { + for (var i = 0; i < foo.parentNode.childNodes.length; i++) { + if (foo.id == foo.parentNode.childNodes[i].id) { break; } + } + if (++i == foo.parentNode.childNodes.length) { foo.parentNode._last = true; } + else { foo.parentNode._last = false; } + foo = foo.parentNode; + } + document.getElementById(this.id + '-cont').insertAdjacentHTML("beforeEnd", node.toString()); + if ((!this.folder) && (!this.openIcon)) { + this.icon = webFXTreeConfig.folderIcon; + this.openIcon = webFXTreeConfig.openFolderIcon; + } + this.folder = true; + this.indent(); + this.expand(); + } + return node; +} + +WebFXTreeAbstractNode.prototype.toggle = function() { + if (this.folder) { + if (this.open) { this.collapse(); } + else { this.expand(); } + } +} + +WebFXTreeAbstractNode.prototype.select = function() { + document.getElementById(this.id + '-anchor').focus(); +} + +WebFXTreeAbstractNode.prototype.focus = function() { + webFXTreeHandler.selected = this; + if ((this.openIcon) && (webFXTreeHandler.behavior != 'classic')) { document.getElementById(this.id + '-icon').src = this.openIcon; } + document.getElementById(this.id + '-anchor').style.backgroundColor = 'highlight'; + document.getElementById(this.id + '-anchor').style.color = 'highlighttext'; + document.getElementById(this.id + '-anchor').focus(); +} + +WebFXTreeAbstractNode.prototype.blur = function() { + if ((this.openIcon) && (webFXTreeHandler.behavior != 'classic')) { document.getElementById(this.id + '-icon').src = this.icon; } + document.getElementById(this.id + '-anchor').style.backgroundColor = 'transparent'; + document.getElementById(this.id + '-anchor').style.color = 'menutext'; +} + +WebFXTreeAbstractNode.prototype.doExpand = function() { + if (webFXTreeHandler.behavior == 'classic') { document.getElementById(this.id + '-icon').src = this.openIcon; } + if (this.childNodes.length) { document.getElementById(this.id + '-cont').style.display = 'block'; } + this.open = true; + webFXTreeHandler.cookies.setCookie(this.id.substr(18,this.id.length - 18), '1'); +} + +WebFXTreeAbstractNode.prototype.doCollapse = function() { + if (webFXTreeHandler.behavior == 'classic') { document.getElementById(this.id + '-icon').src = this.icon; } + if (this.childNodes.length) { document.getElementById(this.id + '-cont').style.display = 'none'; } + this.open = false; + webFXTreeHandler.cookies.setCookie(this.id.substr(18,this.id.length - 18), '0'); +} + +WebFXTreeAbstractNode.prototype.expandAll = function() { + this.expandChildren(); + if ((this.folder) && (!this.open)) { this.expand(); } +} + +WebFXTreeAbstractNode.prototype.expandChildren = function() { + for (var i = 0; i < this.childNodes.length; i++) { + this.childNodes[i].expandAll(); +} } + +WebFXTreeAbstractNode.prototype.collapseAll = function() { + if ((this.folder) && (this.open)) { this.collapse(); } + this.collapseChildren(); +} + +WebFXTreeAbstractNode.prototype.collapseChildren = function() { + for (var i = 0; i < this.childNodes.length; i++) { + this.childNodes[i].collapseAll(); +} } + +WebFXTreeAbstractNode.prototype.indent = function(lvl, del, last, level) { + /* + * Since we only want to modify items one level below ourself, + * and since the rightmost indentation position is occupied by + * the plus icon we set this to -2 + */ + if (lvl == null) { lvl = -2; } + var state = 0; + for (var i = this.childNodes.length - 1; i >= 0 ; i--) { + state = this.childNodes[i].indent(lvl + 1, del, last, level); + if (state) { return; } + } + if (del) { + if (level >= this._level) { + if (this.folder) { + document.getElementById(this.id + '-plus').src = (this.open)?webFXTreeConfig.lMinusIcon:webFXTreeConfig.lPlusIcon; + this.plusIcon = webFXTreeConfig.lPlusIcon; + this.minusIcon = webFXTreeConfig.lMinusIcon; + } + else { document.getElementById(this.id + '-plus').src = webFXTreeConfig.lIcon; } + return 1; + } + } + var foo = document.getElementById(this.id + '-indent-' + lvl); + if (foo) { + if ((del) && (last)) { foo._last = true; } + if (foo._last) { foo.src = webFXTreeConfig.blankIcon; } + else { foo.src = webFXTreeConfig.iIcon; } + } + return 0; +} + +/* + * WebFXTree class + */ + +function WebFXTree(sText, sAction, sBehavior, sIcon, sOpenIcon) { + this.base = WebFXTreeAbstractNode; + this.base(sText, sAction); + this.icon = sIcon || webFXTreeConfig.rootIcon; + this.openIcon = sOpenIcon || webFXTreeConfig.openRootIcon; + /* Defaults to open */ + this.open = (webFXTreeHandler.cookies.getCookie(this.id.substr(18,this.id.length - 18)) == '0')?false:true; + this.folder = true; + this.rendered = false; + if (!webFXTreeHandler.behavior) { webFXTreeHandler.behavior = sBehavior || webFXTreeConfig.defaultBehavior; } + this.targetWindow = 'right'; +} + +WebFXTree.prototype = new WebFXTreeAbstractNode; + +WebFXTree.prototype.setBehavior = function (sBehavior) { + webFXTreeHandler.behavior = sBehavior; +}; + +WebFXTree.prototype.getBehavior = function (sBehavior) { + return webFXTreeHandler.behavior; +}; + +WebFXTree.prototype.getSelected = function() { + if (webFXTreeHandler.selected) { return webFXTreeHandler.selected; } + else { return null; } +} + +WebFXTree.prototype.remove = function() { } + +WebFXTree.prototype.expand = function() { + this.doExpand(); +} + +WebFXTree.prototype.collapse = function() { + this.focus(); + this.doCollapse(); +} + +WebFXTree.prototype.getFirst = function() { + return null; +} + +WebFXTree.prototype.getLast = function() { + return null; +} + +WebFXTree.prototype.getNextSibling = function() { + return null; +} + +WebFXTree.prototype.getPreviousSibling = function() { + return null; +} + +WebFXTree.prototype.keydown = function(key) { + if (key == 39) { this.expand(); return false; } + if (key == 37) { this.collapse(); return false; } + if ((key == 40) && (this.open)) { this.childNodes[0].select(); return false; } + return true; +} + +WebFXTree.prototype.toString = function() { + var str = "
    "; + str += "" + this.text + "
    "; + str += "
    "; + for (var i = 0; i < this.childNodes.length; i++) { + str += this.childNodes[i].toString(i, this.childNodes.length); + } + str += "
    "; + this.rendered = true; + return str; +}; + +/* + * WebFXTreeItem class + */ + +function WebFXTreeItem(sText, sAction, eParent, sIcon, sOpenIcon) { + this.base = WebFXTreeAbstractNode; + this.base(sText, sAction); + /* Defaults to close */ + this.open = (webFXTreeHandler.cookies.getCookie(this.id.substr(18,this.id.length - 18)) == '1')?true:false; + if (eParent) { eParent.add(this); } + if (sIcon) { this.icon = sIcon; } + if (sOpenIcon) { this.openIcon = sOpenIcon; } +} + +WebFXTreeItem.prototype = new WebFXTreeAbstractNode; + +WebFXTreeItem.prototype.remove = function() { + var parentNode = this.parentNode; + var prevSibling = this.getPreviousSibling(true); + var nextSibling = this.getNextSibling(true); + var folder = this.parentNode.folder; + var last = ((nextSibling) && (nextSibling.parentNode) && (nextSibling.parentNode.id == parentNode.id))?false:true; + this.getPreviousSibling().focus(); + this._remove(); + if (parentNode.childNodes.length == 0) { + parentNode.folder = false; + parentNode.open = false; + } + if (last) { + if (parentNode.id == prevSibling.id) { + document.getElementById(parentNode.id + '-icon').src = webFXTreeConfig.fileIcon; + } + else { } + } + if ((!prevSibling.parentNode) || (prevSibling.parentNode != parentNode)) { + parentNode.indent(null, true, last, this._level); + } + if (document.getElementById(prevSibling.id + '-plus')) { + if (nextSibling) { + if ((parentNode == prevSibling) && (parentNode.getNextSibling)) { document.getElementById(prevSibling.id + '-plus').src = webFXTreeConfig.tIcon; } + else if (nextSibling.parentNode != prevSibling) { document.getElementById(prevSibling.id + '-plus').src = webFXTreeConfig.lIcon; } + } + else { document.getElementById(prevSibling.id + '-plus').src = webFXTreeConfig.lIcon; } + } +} + +WebFXTreeItem.prototype._remove = function() { + for (var i = this.childNodes.length - 1; i >= 0; i--) { + this.childNodes[i]._remove(); + } + for (var i = 0; i < this.parentNode.childNodes.length; i++) { + if (this.id == this.parentNode.childNodes[i].id) { + for (var j = i; j < this.parentNode.childNodes.length; j++) { + this.parentNode.childNodes[i] = this.parentNode.childNodes[i+1] + } + this.parentNode.childNodes.length = this.parentNode.childNodes.length - 1; + if (i + 1 == this.parentNode.childNodes.length) { this.parentNode._last = true; } + } + } + webFXTreeHandler.all[this.id] = null; + if (document.getElementById(this.id)) { + document.getElementById(this.id).innerHTML = ""; + document.getElementById(this.id).removeNode(); + } +} + +WebFXTreeItem.prototype.expand = function() { + this.doExpand(); + document.getElementById(this.id + '-plus').src = this.minusIcon; +} + +WebFXTreeItem.prototype.collapse = function() { + this.focus(); + this.doCollapse(); + document.getElementById(this.id + '-plus').src = this.plusIcon; +} + +WebFXTreeItem.prototype.getFirst = function() { + return this.childNodes[0]; +} + +WebFXTreeItem.prototype.getLast = function() { + if (this.childNodes[this.childNodes.length - 1].open) { return this.childNodes[this.childNodes.length - 1].getLast(); } + else { return this.childNodes[this.childNodes.length - 1]; } +} + +WebFXTreeItem.prototype.getNextSibling = function() { + for (var i = 0; i < this.parentNode.childNodes.length; i++) { + if (this == this.parentNode.childNodes[i]) { break; } + } + if (++i == this.parentNode.childNodes.length) { return this.parentNode.getNextSibling(); } + else { return this.parentNode.childNodes[i]; } +} + +WebFXTreeItem.prototype.getPreviousSibling = function(b) { + for (var i = 0; i < this.parentNode.childNodes.length; i++) { + if (this == this.parentNode.childNodes[i]) { break; } + } + if (i == 0) { return this.parentNode; } + else { + if ((this.parentNode.childNodes[--i].open) || (b && this.parentNode.childNodes[i].folder)) { return this.parentNode.childNodes[i].getLast(); } + else { return this.parentNode.childNodes[i]; } +} } + +WebFXTreeItem.prototype.keydown = function(key) { + if ((key == 39) && (this.folder)) { + if (!this.open) { this.expand(); return false; } + else { this.getFirst().select(); return false; } + } + else if (key == 37) { + if (this.open) { this.collapse(); return false; } + else { this.parentNode.select(); return false; } + } + else if (key == 40) { + if (this.open) { this.getFirst().select(); return false; } + else { + var sib = this.getNextSibling(); + if (sib) { sib.select(); return false; } + } } + else if (key == 38) { this.getPreviousSibling().select(); return false; } + return true; +} + +WebFXTreeItem.prototype.toString = function (nItem, nItemCount) { + var foo = this.parentNode; + var indent = ''; + if (nItem + 1 == nItemCount) { this.parentNode._last = true; } + var i = 0; + while (foo.parentNode) { + foo = foo.parentNode; + indent = "" + indent; + i++; + } + this._level = i; + if (this.childNodes.length) { this.folder = 1; } + else { this.open = false; } + if ((this.folder) || (webFXTreeHandler.behavior != 'classic')) { + if (!this.icon) { this.icon = webFXTreeConfig.folderIcon; } + if (!this.openIcon) { this.openIcon = webFXTreeConfig.openFolderIcon; } + } + else if (!this.icon) { this.icon = webFXTreeConfig.fileIcon; } + var label = this.text; + label = label.replace('<', '<'); + label = label.replace('>', '>'); + var str = "
    "; + str += indent; + str += "" + str += "" + label + "
    "; + str += "
    "; + for (var i = 0; i < this.childNodes.length; i++) { + str += this.childNodes[i].toString(i,this.childNodes.length); + } + str += "
    "; + this.plusIcon = ((this.parentNode._last)?webFXTreeConfig.lPlusIcon:webFXTreeConfig.tPlusIcon); + this.minusIcon = ((this.parentNode._last)?webFXTreeConfig.lMinusIcon:webFXTreeConfig.tMinusIcon); + return str; +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/stylesheet.css b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/stylesheet.css new file mode 100644 index 0000000..5b025a9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/media/stylesheet.css @@ -0,0 +1,181 @@ +a { color: #000090; text-decoration: none; } +a:hover, a:active, a:focus { color: highlighttext; background-color: highlight; text-decoration: none; } + +body { background : #FFFFFF; } +body, table { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10pt; } + +a img { border: 0px; } + +/* Page layout/boxes */ + +.info-box { } +.info-box-title { margin: 1em 0em 0em 0em; font-weight: normal; font-size: 14pt; color: #999999; border-bottom: 2px solid #999999; } +.info-box-body { border: 1px solid #999999; padding: .5em; } +.nav-bar { font-size: 8pt; white-space: nowrap; text-align: right; padding: .2em; margin: 0em 0em 1em 0em; } + +.oddrow { background-color: #F8F8F8; border: 1px solid #AAAAAA; padding: .5em; margin-bottom: 1em} +.evenrow { border: 1px solid #AAAAAA; padding: .5em; margin-bottom: 1em} + +.page-body { max-width: 800px; margin: auto; } +.tree { } + +/* Index formatting classes */ + +.index-item-body { margin-top: .5em; margin-bottom: .5em} +.index-item-description { margin-top: .25em } +.index-item-details { font-weight: normal; font-style: italic; font-size: 8pt } +.index-letter-section { background-color: #EEEEEE; border: 1px dotted #999999; padding: .5em; margin-bottom: 1em} +.index-letter-title { font-size: 12pt; font-weight: bold } +.index-letter-menu { text-align: center; margin: 1em } +.index-letter { font-size: 12pt } + +/* Docbook classes */ + +.description {} +.short-description { font-weight: bold; color: #666666; } +.tags { padding-left: 0em; margin-left: 3em; color: #666666; list-style-type: square; } +.parameters { padding-left: 0em; margin-left: 3em; color: #014fbe; list-style-type: square; } +.redefinitions { font-size: 8pt; padding-left: 0em; margin-left: 2em; } +.package { font-weight: bold; } +.package-title { font-weight: bold; font-size: 14pt; border-bottom: 1px solid black } +.sub-package { font-weight: bold; } +.tutorial { border-width: thin; border-color: #0066ff; } +.tutorial-nav-box { width: 100%; border: 1px solid #999999; background-color: #F8F8F8; } + +/* Generic formatting */ + +.field { font-weight: bold; } +.detail { font-size: 8pt; } +.notes { font-style: italic; font-size: 8pt; } +.separator { background-color: #999999; height: 2px; } +.warning { color: #FF6600; } +.disabled { font-style: italic; color: #999999; } + +/* Code elements */ + +.line-number { } + +.class-table { width: 100%; } +.class-table-header { border-bottom: 1px dotted #666666; text-align: left} +.class-name { color: #0000AA; font-weight: bold; } + +.method-summary { color: #009000; padding-left: 1em; font-size: 8pt; } +.method-header { } +.method-definition { margin-bottom: .2em } +.method-title { color: #009000; font-weight: bold; } +.method-name { font-weight: bold; } +.method-signature { font-size: 85%; color: #666666; margin: .5em 0em } +.method-result { font-style: italic; } + +.var-summary { padding-left: 1em; font-size: 8pt; } +.var-header { } +.var-title { color: #014fbe; margin-bottom: .3em } +.var-type { font-style: italic; } +.var-name { font-weight: bold; } +.var-default {} +.var-description { font-weight: normal; color: #000000; } + +.include-title { color: #014fbe;} +.include-type { font-style: italic; } +.include-name { font-weight: bold; } + +.const-title { color: #FF6600; } +.const-name { font-weight: bold; } + +/* Syntax highlighting */ + +.src-code { font-family: 'Courier New', Courier, monospace; font-weight: normal; } +.src-line { font-family: 'Courier New', Courier, monospace; font-weight: normal; } + +.src-code a:link { padding: 1px; text-decoration: underline; color: #0000DD; } +.src-code a:visited { text-decoration: underline; color: #0000DD; } +.src-code a:active { background-color: #FFFF66; color: #008000; } +.src-code a:hover { background-color: #FFFF66; text-decoration: overline underline; color: #008000; } + +.src-comm { color: #666666; } +.src-id { color: #FF6600; font-style: italic; } +.src-inc { color: #0000AA; font-weight: bold; } +.src-key { color: #0000AA; font-weight: bold; } +.src-num { color: #CC0000; } +.src-str { color: #CC0000; } +.src-sym { } +.src-var { } + +.src-php { font-weight: bold; } + +.src-doc { color: #666666; } +.src-doc-close-template { color: #666666 } +.src-doc-coretag { color: #008000; } +.src-doc-inlinetag {} +.src-doc-internal {} +.src-doc-tag { color: #0080CC; } +.src-doc-template { color: #666666 } +.src-doc-type { font-style: italic; color: #444444 } +.src-doc-var { color: #444444 } + +.tute-tag { color: #009999 } +.tute-attribute-name { color: #0000FF } +.tute-attribute-value { color: #0099FF } +.tute-entity { font-weight: bold; } +.tute-comment { font-style: italic } +.tute-inline-tag { color: #636311; font-weight: bold } + +/* tutorial */ + +.authors { } +.author { font-style: italic; font-weight: bold } +.author-blurb { margin: .5em 0em .5em 2em; font-size: 85%; font-weight: normal; font-style: normal } +.example { border: 1px dashed #999999; background-color: #EEEEEE; padding: .5em; } +.listing { border: 1px dashed #999999; background-color: #EEEEEE; padding: .5em; white-space: nowrap; } +.release-info { font-size: 85%; font-style: italic; margin: 1em 0em } +.ref-title-box { } +.ref-title { } +.ref-purpose { font-style: italic; color: #666666 } +.ref-synopsis { } +.title { font-weight: bold; border-bottom: 1px solid #999999; color: #999999; } +.cmd-synopsis { margin: 1em 0em } +.cmd-title { font-weight: bold } +.toc { margin-left: 2em; padding-left: 0em } + +/*------------------------------------------------------------------------------ + webfx-tree +------------------------------------------------------------------------------*/ + +.webfx-tree-container { + margin: 0px; + padding: 0px; + white-space: nowrap; + font: icon; +} + +.webfx-tree-item { + padding: 0px; + margin: 0px; + color: black; + white-space: nowrap; + font: icon; +} + +.webfx-tree-item a { + margin-left: 3px; + padding: 1px 2px 1px 2px; + color: black; + text-decoration: none; +} + +.webfx-tree-item a:hover, .webfx-tree-item a:active { + color: highlighttext; + background: highlight; + text-decoration: none +} + +.webfx-tree-item img { + vertical-align: middle; + border: 0px; +} + +.webfx-tree-icon { + width: 16px; + height: 16px; +} + diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/packages.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/packages.html new file mode 100644 index 0000000..599d146 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/packages.html @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/todolist.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/todolist.html new file mode 100644 index 0000000..401dcf6 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/api/todolist.html @@ -0,0 +1,20 @@ + + + + + + Todo List + + + +

    Todo List

    +

    bovigo_vfs

    +

    vfsStreamWrapper::rmdir()

    +
      +
    • consider $options with STREAM_MKDIR_RECURSIVE
    • +
    +

    + Documentation generated on Fri, 08 Oct 2010 12:16:44 +0200 by phpDocumentor 1.4.3 +

    + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/butter.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/butter.png new file mode 100644 index 0000000000000000000000000000000000000000..3c7e36f2da2e0557f70191ceb58b58187fa46292 GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1SBVv2j2ryoCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#8Y?HeiPce~l`DWkvL&t&CC>S|xv6<249-QVi6yBi3gww4844j8sS56%z5(x3 pRP%rec|2VlLpZJ{|M+}Ko`F@8$+T(TnfpL-22WQ%mvv4FO#nkKCNls4 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/chameleon.png b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/chameleon.png new file mode 100644 index 0000000000000000000000000000000000000000..68046070133a2c309839b9d340ced4c521fa9d3b GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1SBVv2j2ryoCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#8Y?HesrbxqN9F*9WJ_ElN}Tg^b5rw57@Uhz6H8K46v{J8G895GQWe}ieFNU7 psOA9`@_4#9hHzX@eo>Xe#K1g@abe4bR%xI(gQu&X%Q~loCID3dC3gS- literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/close12_1.gif b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/close12_1.gif new file mode 100644 index 0000000000000000000000000000000000000000..e2f67d72efc158da4e069822cbe338915761e396 GIT binary patch literal 85 zcmZ?wbhEHbz lf$Gy9znh?Y?^x%Bps9Cfw!UsJn!aoAS>7kV)`>G%0|4uCA&me4 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/container-min.js b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/container-min.js new file mode 100644 index 0000000..d36255e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/container-min.js @@ -0,0 +1,19 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +(function(){YAHOO.util.Config=function(D){if(D){this.init(D);}};var B=YAHOO.lang,C=YAHOO.util.CustomEvent,A=YAHOO.util.Config;A.CONFIG_CHANGED_EVENT="configChanged";A.BOOLEAN_TYPE="boolean";A.prototype={owner:null,queueInProgress:false,config:null,initialConfig:null,eventQueue:null,configChangedEvent:null,init:function(D){this.owner=D;this.configChangedEvent=this.createEvent(A.CONFIG_CHANGED_EVENT);this.configChangedEvent.signature=C.LIST;this.queueInProgress=false;this.config={};this.initialConfig={};this.eventQueue=[];},checkBoolean:function(D){return(typeof D==A.BOOLEAN_TYPE);},checkNumber:function(D){return(!isNaN(D));},fireEvent:function(D,F){var E=this.config[D];if(E&&E.event){E.event.fire(F);}},addProperty:function(E,D){E=E.toLowerCase();this.config[E]=D;D.event=this.createEvent(E,{scope:this.owner});D.event.signature=C.LIST;D.key=E;if(D.handler){D.event.subscribe(D.handler,this.owner);}this.setProperty(E,D.value,true);if(!D.suppressEvent){this.queueProperty(E,D.value);}},getConfig:function(){var D={},F=this.config,G,E;for(G in F){if(B.hasOwnProperty(F,G)){E=F[G];if(E&&E.event){D[G]=E.value;}}}return D;},getProperty:function(D){var E=this.config[D.toLowerCase()];if(E&&E.event){return E.value;}else{return undefined;}},resetProperty:function(D){D=D.toLowerCase();var E=this.config[D];if(E&&E.event){if(this.initialConfig[D]&&!B.isUndefined(this.initialConfig[D])){this.setProperty(D,this.initialConfig[D]);return true;}}else{return false;}},setProperty:function(E,G,D){var F;E=E.toLowerCase();if(this.queueInProgress&&!D){this.queueProperty(E,G);return true;}else{F=this.config[E];if(F&&F.event){if(F.validator&&!F.validator(G)){return false;}else{F.value=G;if(!D){this.fireEvent(E,G);this.configChangedEvent.fire([E,G]);}return true;}}else{return false;}}},queueProperty:function(S,P){S=S.toLowerCase();var R=this.config[S],K=false,J,G,H,I,O,Q,F,M,N,D,L,T,E;if(R&&R.event){if(!B.isUndefined(P)&&R.validator&&!R.validator(P)){return false;}else{if(!B.isUndefined(P)){R.value=P;}else{P=R.value;}K=false;J=this.eventQueue.length;for(L=0;L0){G=F-1;do{D=E.subscribers[G];if(D&&D.obj==I&&D.fn==H){return true;}}while(G--);}return false;};YAHOO.lang.augmentProto(A,YAHOO.util.EventProvider);}());(function(){YAHOO.widget.Module=function(R,Q){if(R){this.init(R,Q);}else{}};var F=YAHOO.util.Dom,D=YAHOO.util.Config,N=YAHOO.util.Event,M=YAHOO.util.CustomEvent,G=YAHOO.widget.Module,I=YAHOO.env.ua,H,P,O,E,A={"BEFORE_INIT":"beforeInit","INIT":"init","APPEND":"append","BEFORE_RENDER":"beforeRender","RENDER":"render","CHANGE_HEADER":"changeHeader","CHANGE_BODY":"changeBody","CHANGE_FOOTER":"changeFooter","CHANGE_CONTENT":"changeContent","DESTROY":"destroy","BEFORE_SHOW":"beforeShow","SHOW":"show","BEFORE_HIDE":"beforeHide","HIDE":"hide"},J={"VISIBLE":{key:"visible",value:true,validator:YAHOO.lang.isBoolean},"EFFECT":{key:"effect",suppressEvent:true,supercedes:["visible"]},"MONITOR_RESIZE":{key:"monitorresize",value:true},"APPEND_TO_DOCUMENT_BODY":{key:"appendtodocumentbody",value:false}};G.IMG_ROOT=null;G.IMG_ROOT_SSL=null;G.CSS_MODULE="yui-module";G.CSS_HEADER="hd";G.CSS_BODY="bd";G.CSS_FOOTER="ft";G.RESIZE_MONITOR_SECURE_URL="javascript:false;";G.RESIZE_MONITOR_BUFFER=1;G.textResizeEvent=new M("textResize");G.forceDocumentRedraw=function(){var Q=document.documentElement;if(Q){Q.className+=" ";Q.className=YAHOO.lang.trim(Q.className);}};function L(){if(!H){H=document.createElement("div");H.innerHTML=('
    '+'
    ');P=H.firstChild;O=P.nextSibling;E=O.nextSibling;}return H;}function K(){if(!P){L();}return(P.cloneNode(false));}function B(){if(!O){L();}return(O.cloneNode(false));}function C(){if(!E){L();}return(E.cloneNode(false));}G.prototype={constructor:G,element:null,header:null,body:null,footer:null,id:null,imageRoot:G.IMG_ROOT,initEvents:function(){var Q=M.LIST; +this.beforeInitEvent=this.createEvent(A.BEFORE_INIT);this.beforeInitEvent.signature=Q;this.initEvent=this.createEvent(A.INIT);this.initEvent.signature=Q;this.appendEvent=this.createEvent(A.APPEND);this.appendEvent.signature=Q;this.beforeRenderEvent=this.createEvent(A.BEFORE_RENDER);this.beforeRenderEvent.signature=Q;this.renderEvent=this.createEvent(A.RENDER);this.renderEvent.signature=Q;this.changeHeaderEvent=this.createEvent(A.CHANGE_HEADER);this.changeHeaderEvent.signature=Q;this.changeBodyEvent=this.createEvent(A.CHANGE_BODY);this.changeBodyEvent.signature=Q;this.changeFooterEvent=this.createEvent(A.CHANGE_FOOTER);this.changeFooterEvent.signature=Q;this.changeContentEvent=this.createEvent(A.CHANGE_CONTENT);this.changeContentEvent.signature=Q;this.destroyEvent=this.createEvent(A.DESTROY);this.destroyEvent.signature=Q;this.beforeShowEvent=this.createEvent(A.BEFORE_SHOW);this.beforeShowEvent.signature=Q;this.showEvent=this.createEvent(A.SHOW);this.showEvent.signature=Q;this.beforeHideEvent=this.createEvent(A.BEFORE_HIDE);this.beforeHideEvent.signature=Q;this.hideEvent=this.createEvent(A.HIDE);this.hideEvent.signature=Q;},platform:function(){var Q=navigator.userAgent.toLowerCase();if(Q.indexOf("windows")!=-1||Q.indexOf("win32")!=-1){return"windows";}else{if(Q.indexOf("macintosh")!=-1){return"mac";}else{return false;}}}(),browser:function(){var Q=navigator.userAgent.toLowerCase();if(Q.indexOf("opera")!=-1){return"opera";}else{if(Q.indexOf("msie 7")!=-1){return"ie7";}else{if(Q.indexOf("msie")!=-1){return"ie";}else{if(Q.indexOf("safari")!=-1){return"safari";}else{if(Q.indexOf("gecko")!=-1){return"gecko";}else{return false;}}}}}}(),isSecure:function(){if(window.location.href.toLowerCase().indexOf("https")===0){return true;}else{return false;}}(),initDefaultConfig:function(){this.cfg.addProperty(J.VISIBLE.key,{handler:this.configVisible,value:J.VISIBLE.value,validator:J.VISIBLE.validator});this.cfg.addProperty(J.EFFECT.key,{suppressEvent:J.EFFECT.suppressEvent,supercedes:J.EFFECT.supercedes});this.cfg.addProperty(J.MONITOR_RESIZE.key,{handler:this.configMonitorResize,value:J.MONITOR_RESIZE.value});this.cfg.addProperty(J.APPEND_TO_DOCUMENT_BODY.key,{value:J.APPEND_TO_DOCUMENT_BODY.value});},init:function(V,U){var S,W;this.initEvents();this.beforeInitEvent.fire(G);this.cfg=new D(this);if(this.isSecure){this.imageRoot=G.IMG_ROOT_SSL;}if(typeof V=="string"){S=V;V=document.getElementById(V);if(!V){V=(L()).cloneNode(false);V.id=S;}}this.id=F.generateId(V);this.element=V;W=this.element.firstChild;if(W){var R=false,Q=false,T=false;do{if(1==W.nodeType){if(!R&&F.hasClass(W,G.CSS_HEADER)){this.header=W;R=true;}else{if(!Q&&F.hasClass(W,G.CSS_BODY)){this.body=W;Q=true;}else{if(!T&&F.hasClass(W,G.CSS_FOOTER)){this.footer=W;T=true;}}}}}while((W=W.nextSibling));}this.initDefaultConfig();F.addClass(this.element,G.CSS_MODULE);if(U){this.cfg.applyConfig(U,true);}if(!D.alreadySubscribed(this.renderEvent,this.cfg.fireQueue,this.cfg)){this.renderEvent.subscribe(this.cfg.fireQueue,this.cfg,true);}this.initEvent.fire(G);},initResizeMonitor:function(){var R=(I.gecko&&this.platform=="windows");if(R){var Q=this;setTimeout(function(){Q._initResizeMonitor();},0);}else{this._initResizeMonitor();}},_initResizeMonitor:function(){var Q,S,U;function W(){G.textResizeEvent.fire();}if(!I.opera){S=F.get("_yuiResizeMonitor");var V=this._supportsCWResize();if(!S){S=document.createElement("iframe");if(this.isSecure&&G.RESIZE_MONITOR_SECURE_URL&&I.ie){S.src=G.RESIZE_MONITOR_SECURE_URL;}if(!V){U=[" + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    Current file:C:\dev\php\bovigo\vfs\trunk\src\main\php\org\bovigo\vfs\vfsStream.php
    Legend: + executed + not executed + dead code +
    +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     Coverage
     ClassesFunctions / MethodsLines
    Total + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%8 / 8 + + + + +
    100.00%100.00%
    +
    100.00%29 / 29
     
    vfsStream + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%8 / 8 + + + + +
    100.00%100.00%
    +
    100.00%29 / 29
     public static function url($path) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public static function path($url) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%5 / 5
     public static function umask($umask = null) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%5 / 5
     public static function setup($rootDirName = 'root', $permissions = null) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%4 / 4
     public static function newFile($name, $permissions = null) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public static function newDirectory($name, $permissions = null) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%11 / 11
     public static function getCurrentUser() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public static function getCurrentGroup() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
    +
    + +
    + + + + + + + + +

    +
    +       1                 : <?php                                                                                         
    +       2                 : /**                                                                                           
    +       3                 :  * Some utility methods for vfsStream.                                                        
    +       4                 :  *                                                                                            
    +       5                 :  * @package  bovigo_vfs                                                                       
    +       6                 :  * @version  $Id: vfsStream.php 211 2010-10-06 16:33:05Z google@frankkleine.de $              
    +       7                 :  */                                                                                           
    +       8                 : /**                                                                                           
    +       9                 :  * @ignore                                                                                    
    +      10                 :  */                                                                                           
    +      11                 : require_once dirname(__FILE__) . '/vfsStreamWrapper.php';                                     
    +      12                 : /**                                                                                           
    +      13                 :  * Some utility methods for vfsStream.                                                        
    +      14                 :  *                                                                                            
    +      15                 :  * @package  bovigo_vfs                                                                       
    +      16                 :  */                                                                                           
    +      17                 : class vfsStream                                                                               
    +      18                 : {                                                                                             
    +      19                 :     /**                                                                                       
    +      20                 :      * url scheme                                                                             
    +      21                 :      */                                                                                       
    +      22                 :     const SCHEME       = 'vfs';                                                               
    +      23                 :     /**                                                                                       
    +      24                 :      * owner: root                                                                            
    +      25                 :      */                                                                                       
    +      26                 :     const OWNER_ROOT   = 0;                                                                   
    +      27                 :     /**                                                                                       
    +      28                 :      * owner: user 1                                                                          
    +      29                 :      */                                                                                       
    +      30                 :     const OWNER_USER_1 = 1;                                                                   
    +      31                 :     /**                                                                                       
    +      32                 :      * owner: user 2                                                                          
    +      33                 :      */                                                                                       
    +      34                 :     const OWNER_USER_2 = 2;                                                                   
    +      35                 :     /**                                                                                       
    +      36                 :      * group: root                                                                            
    +      37                 :      */                                                                                       
    +      38                 :     const GROUP_ROOT   = 0;                                                                   
    +      39                 :     /**                                                                                       
    +      40                 :      * group: user 1                                                                          
    +      41                 :      */                                                                                       
    +      42                 :     const GROUP_USER_1 = 1;                                                                   
    +      43                 :     /**                                                                                       
    +      44                 :      * group: user 2                                                                          
    +      45                 :      */                                                                                       
    +      46                 :     const GROUP_USER_2 = 2;                                                                   
    +      47                 :     /**                                                                                       
    +      48                 :      * initial umask setting                                                                  
    +      49                 :      *                                                                                        
    +      50                 :      * @var  int                                                                              
    +      51                 :      */                                                                                       
    +      52                 :     protected static $umask = 0000;                                                           
    +      53                 :                                                                                               
    +      54                 :     /**                                                                                       
    +      55                 :      * prepends the scheme to the given URL                                                   
    +      56                 :      *                                                                                        
    +      57                 :      * @param   string  $path                                                                 
    +      58                 :      * @return  string                                                                        
    +      59                 :      */                                                                                       
    +      60                 :     public static function url($path)                                                         
    +      61                 :     {                                                                                         
    +      62              93 :         return self::SCHEME . '://' . str_replace('\\', '/', $path);                          
    +      63                 :     }                                                                                         
    +      64                 :                                                                                               
    +      65                 :     /**                                                                                       
    +      66                 :      * restores the path from the url                                                         
    +      67                 :      *                                                                                        
    +      68                 :      * @param   string  $url                                                                  
    +      69                 :      * @return  string                                                                        
    +      70                 :      */                                                                                       
    +      71                 :     public static function path($url)                                                         
    +      72                 :     {                                                                                         
    +      73                 :         // remove line feeds and trailing whitespaces                                         
    +      74              93 :         $path = trim($url, " \t\r\n\0\x0B/");                                                 
    +      75              93 :         $path = substr($path, strlen(self::SCHEME . '://'));                                  
    +      76              93 :         $path = str_replace('\\', '/', $path);                                                
    +      77                 :         // replace double slashes with single slashes                                         
    +      78              93 :         $path = str_replace('//', '/', $path);                                                
    +      79              93 :         return $path;                                                                         
    +      80                 :     }                                                                                         
    +      81                 :                                                                                               
    +      82                 :     /**                                                                                       
    +      83                 :      * sets new umask setting and returns previous umask setting                              
    +      84                 :      *                                                                                        
    +      85                 :      * If no value is given only the current umask setting is returned.                       
    +      86                 :      *                                                                                        
    +      87                 :      * @param   int  $umask  optional                                                         
    +      88                 :      * @return  int                                                                           
    +      89                 :      * @since   0.8.0                                                                         
    +      90                 :      */                                                                                       
    +      91                 :     public static function umask($umask = null)                                               
    +      92                 :     {                                                                                         
    +      93             131 :         $oldUmask = self::$umask;                                                             
    +      94             131 :         if (null !== $umask) {                                                                
    +      95              15 :             self::$umask = $umask;                                                            
    +      96              15 :         }                                                                                     
    +      97                 :                                                                                               
    +      98             131 :         return $oldUmask;                                                                     
    +      99                 :     }                                                                                         
    +     100                 :                                                                                               
    +     101                 :     /**                                                                                       
    +     102                 :      * helper method for setting up vfsStream in unit tests                                   
    +     103                 :      *                                                                                        
    +     104                 :      * Instead of                                                                             
    +     105                 :      * vfsStreamWrapper::register();                                                          
    +     106                 :      * vfsStreamWrapper::setRoot(vfsStream::newDirectory('root'));                            
    +     107                 :      * you can simply do                                                                      
    +     108                 :      * vfsStream::setup()                                                                     
    +     109                 :      * which yields the same result. Additionally, the method returns the                     
    +     110                 :      * freshly created root directory which you can use to make further                       
    +     111                 :      * adjustments to it.                                                                     
    +     112                 :      *                                                                                        
    +     113                 :      * @param   string              $rootDirName  optional  name of root directory            
    +     114                 :      * @param   int                 $permissions  optional  file permissions of root directory
    +     115                 :      * @return  vfsStreamDirectory                                                            
    +     116                 :      * @since   0.7.0                                                                         
    +     117                 :      */                                                                                       
    +     118                 :     public static function setup($rootDirName = 'root', $permissions = null)                  
    +     119                 :     {                                                                                         
    +     120              12 :         vfsStreamWrapper::register();                                                         
    +     121              12 :         $root = self::newDirectory($rootDirName, $permissions);                               
    +     122              12 :         vfsStreamWrapper::setRoot($root);                                                     
    +     123              12 :         return $root;                                                                         
    +     124                 :     }                                                                                         
    +     125                 :                                                                                               
    +     126                 :     /**                                                                                       
    +     127                 :      * returns a new file with given name                                                     
    +     128                 :      *                                                                                        
    +     129                 :      * @param   string         $name                                                          
    +     130                 :      * @param   int            $permissions  optional                                         
    +     131                 :      * @return  vfsStreamFile                                                                 
    +     132                 :      */                                                                                       
    +     133                 :     public static function newFile($name, $permissions = null)                                
    +     134                 :     {                                                                                         
    +     135              85 :         return new vfsStreamFile($name, $permissions);                                        
    +     136                 :     }                                                                                         
    +     137                 :                                                                                               
    +     138                 :     /**                                                                                       
    +     139                 :      * returns a new directory with given name                                                
    +     140                 :      *                                                                                        
    +     141                 :      * If the name contains slashes, a new directory structure will be created.               
    +     142                 :      * The returned directory will always be the parent directory of this                     
    +     143                 :      * directory structure.                                                                   
    +     144                 :      *                                                                                        
    +     145                 :      * @param   string              $name                                                     
    +     146                 :      * @param   int                 $permissions  optional                                    
    +     147                 :      * @return  vfsStreamDirectory                                                            
    +     148                 :      */                                                                                       
    +     149                 :     public static function newDirectory($name, $permissions = null)                           
    +     150                 :     {                                                                                         
    +     151              30 :         if ('/' === $name{0}) {                                                               
    +     152               5 :             $name = substr($name, 1);                                                         
    +     153               5 :         }                                                                                     
    +     154                 :                                                                                               
    +     155              30 :         $firstSlash = strpos($name, '/');                                                     
    +     156              30 :         if (false === $firstSlash) {                                                          
    +     157              30 :             return new vfsStreamDirectory($name, $permissions);                               
    +     158                 :         }                                                                                     
    +     159                 :                                                                                               
    +     160               9 :         $ownName   = substr($name, 0, $firstSlash);                                           
    +     161               9 :         $subDirs   = substr($name, $firstSlash + 1);                                          
    +     162               9 :         $directory = new vfsStreamDirectory($ownName, $permissions);                          
    +     163               9 :         self::newDirectory($subDirs, $permissions)->at($directory);                           
    +     164               9 :         return $directory;                                                                    
    +     165                 :     }                                                                                         
    +     166                 :                                                                                               
    +     167                 :     /**                                                                                       
    +     168                 :      * returns current user                                                                   
    +     169                 :      *                                                                                        
    +     170                 :      * If the system does not support posix_getuid() the current user will be root (0).       
    +     171                 :      *                                                                                        
    +     172                 :      * @return  int                                                                           
    +     173                 :      */                                                                                       
    +     174                 :     public static function getCurrentUser()                                                   
    +     175                 :     {                                                                                         
    +     176             155 :         return function_exists('posix_getuid') ? posix_getuid() : self::OWNER_ROOT;           
    +     177                 :     }                                                                                         
    +     178                 :                                                                                               
    +     179                 :     /**                                                                                       
    +     180                 :      * returns current group                                                                  
    +     181                 :      *                                                                                        
    +     182                 :      * If the system does not support posix_getgid() the current group will be root (0).      
    +     183                 :      *                                                                                        
    +     184                 :      * @return  int                                                                           
    +     185                 :      */                                                                                       
    +     186                 :     public static function getCurrentGroup()                                                  
    +     187                 :     {                                                                                         
    +     188             155 :         return function_exists('posix_getgid') ? posix_getgid() : self::GROUP_ROOT;           
    +     189                 :     }                                                                                         
    +     190                 : }                                                                                             
    +
    +
    +
    + + + + +
    Generated by PHPUnit 3.4.15 and Xdebug 2.0.5 using PHP 5.2.5 at Fri Oct 8 12:16:32 CEST 2010.
    + +
    + + + + diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamAbstractContent.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamAbstractContent.php.html new file mode 100644 index 0000000..72b1db9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamAbstractContent.php.html @@ -0,0 +1,1222 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    Current file:C:\dev\php\bovigo\vfs\trunk\src\main\php\org\bovigo\vfs\vfsStreamAbstractContent.php
    Legend: + executed + not executed + dead code +
    +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     Coverage
     ClassesFunctions / MethodsLines
    Total + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%20 / 20 + + + + +
    100.00%100.00%
    +
    100.00%55 / 55
     
    vfsStreamAbstractContent + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%20 / 20 + + + + +
    100.00%100.00%
    +
    100.00%55 / 55
     public function __construct($name, $permissions = null) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%9 / 9
     public function getName() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function rename($newName) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%2 / 2
     public function appliesTo($name) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%3 / 3
     public function getType() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function setFilemtime($filemtime) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function lastModified($filemtime) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%2 / 2
     public function filemtime() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function at(vfsStreamContainer $container) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%2 / 2
     public function chmod($permissions) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%3 / 3
     public function getPermissions() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function isReadable($user, $group) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%7 / 7
     public function isWritable($user, $group) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%7 / 7
     public function isExecutable($user, $group) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%7 / 7
     public function chown($user) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%2 / 2
     public function isOwnedByUser($user) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function getUser() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function chgrp($group) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%2 / 2
     public function isOwnedByGroup($group) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function getGroup() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
    +
    + +
    + + + + + + + + +

    +
    +       1                 : <?php                                                                                                  
    +       2                 : /**                                                                                                    
    +       3                 :  * Base stream contents container.                                                                     
    +       4                 :  *                                                                                                     
    +       5                 :  * @package  bovigo_vfs                                                                                
    +       6                 :  * @version  $Id: vfsStreamAbstractContent.php 214 2010-10-07 20:57:57Z google@frankkleine.de $        
    +       7                 :  */                                                                                                    
    +       8                 : /**                                                                                                    
    +       9                 :  * @ignore                                                                                             
    +      10                 :  */                                                                                                    
    +      11                 : require_once dirname(__FILE__) . '/vfsStreamContent.php';                                              
    +      12                 : /**                                                                                                    
    +      13                 :  * Base stream contents container.                                                                     
    +      14                 :  *                                                                                                     
    +      15                 :  * @package  bovigo_vfs                                                                                
    +      16                 :  */                                                                                                    
    +      17                 : abstract class vfsStreamAbstractContent implements vfsStreamContent                                    
    +      18                 : {                                                                                                      
    +      19                 :     /**                                                                                                
    +      20                 :      * name of the container                                                                           
    +      21                 :      *                                                                                                 
    +      22                 :      * @var  string                                                                                    
    +      23                 :      */                                                                                                
    +      24                 :     protected $name;                                                                                   
    +      25                 :     /**                                                                                                
    +      26                 :      * type of the container                                                                           
    +      27                 :      *                                                                                                 
    +      28                 :      * @var  string                                                                                    
    +      29                 :      */                                                                                                
    +      30                 :     protected $type;                                                                                   
    +      31                 :     /**                                                                                                
    +      32                 :      * timestamp of last modification                                                                  
    +      33                 :      *                                                                                                 
    +      34                 :      * @var  int                                                                                       
    +      35                 :      */                                                                                                
    +      36                 :     protected $lastModified;                                                                           
    +      37                 :     /**                                                                                                
    +      38                 :      * permissions for content                                                                         
    +      39                 :      *                                                                                                 
    +      40                 :      * @var  int                                                                                       
    +      41                 :      */                                                                                                
    +      42                 :     protected $permissions;                                                                            
    +      43                 :     /**                                                                                                
    +      44                 :      * owner of the file                                                                               
    +      45                 :      *                                                                                                 
    +      46                 :      * @var  int                                                                                       
    +      47                 :      */                                                                                                
    +      48                 :     protected $user;                                                                                   
    +      49                 :     /**                                                                                                
    +      50                 :      * owner group of the file                                                                         
    +      51                 :      *                                                                                                 
    +      52                 :      * @var  int                                                                                       
    +      53                 :      */                                                                                                
    +      54                 :     protected $group;                                                                                  
    +      55                 :                                                                                                        
    +      56                 :     /**                                                                                                
    +      57                 :      * constructor                                                                                     
    +      58                 :      *                                                                                                 
    +      59                 :      * @param  string  $name                                                                           
    +      60                 :      * @param  int     $permissions  optional                                                          
    +      61                 :      */                                                                                                
    +      62                 :     public function __construct($name, $permissions = null)                                            
    +      63                 :     {                                                                                                  
    +      64             155 :         $this->name         = $name;                                                                   
    +      65             155 :         $this->lastModified = time();                                                                  
    +      66             155 :         if (null === $permissions) {                                                                   
    +      67             129 :             $permissions = $this->getDefaultPermissions() & ~vfsStream::umask();                       
    +      68             129 :         }                                                                                              
    +      69                 :                                                                                                        
    +      70             155 :         $this->permissions  = $permissions;                                                            
    +      71             155 :         $this->user         = vfsStream::getCurrentUser();                                             
    +      72             155 :         $this->group        = vfsStream::getCurrentGroup();                                            
    +      73             155 :     }                                                                                                  
    +      74                 :                                                                                                        
    +      75                 :     /**                                                                                                
    +      76                 :      * returns default permissions for concrete implementation                                         
    +      77                 :      *                                                                                                 
    +      78                 :      * @return  int                                                                                    
    +      79                 :      * @since   0.8.0                                                                                  
    +      80                 :      */                                                                                                
    +      81                 :     protected abstract function getDefaultPermissions();                                               
    +      82                 :                                                                                                        
    +      83                 :     /**                                                                                                
    +      84                 :      * returns the file name of the content                                                            
    +      85                 :      *                                                                                                 
    +      86                 :      * @return  string                                                                                 
    +      87                 :      */                                                                                                
    +      88                 :     public function getName()                                                                          
    +      89                 :     {                                                                                                  
    +      90             106 :         return $this->name;                                                                            
    +      91                 :     }                                                                                                  
    +      92                 :                                                                                                        
    +      93                 :     /**                                                                                                
    +      94                 :      * renames the content                                                                             
    +      95                 :      *                                                                                                 
    +      96                 :      * @param  string  $newName                                                                        
    +      97                 :      */                                                                                                
    +      98                 :     public function rename($newName)                                                                   
    +      99                 :     {                                                                                                  
    +     100               8 :         $this->name = $newName;                                                                        
    +     101               8 :     }                                                                                                  
    +     102                 :                                                                                                        
    +     103                 :     /**                                                                                                
    +     104                 :      * checks whether the container can be applied to given name                                       
    +     105                 :      *                                                                                                 
    +     106                 :      * @param   string  $name                                                                          
    +     107                 :      * @return  bool                                                                                   
    +     108                 :      */                                                                                                
    +     109                 :     public function appliesTo($name)                                                                   
    +     110                 :     {                                                                                                  
    +     111              81 :         if ($name === $this->name) {                                                                   
    +     112              10 :             return true;                                                                               
    +     113                 :         }                                                                                              
    +     114                 :                                                                                                        
    +     115              80 :         return (substr($name, 0, strlen($this->name)) === $this->name && strpos($name, '/') !== false);
    +     116                 :     }                                                                                                  
    +     117                 :                                                                                                        
    +     118                 :     /**                                                                                                
    +     119                 :      * returns the type of the container                                                               
    +     120                 :      *                                                                                                 
    +     121                 :      * @return  int                                                                                    
    +     122                 :      */                                                                                                
    +     123                 :     public function getType()                                                                          
    +     124                 :     {                                                                                                  
    +     125              79 :         return $this->type;                                                                            
    +     126                 :     }                                                                                                  
    +     127                 :                                                                                                        
    +     128                 :     /**                                                                                                
    +     129                 :      * alias for lastModified()                                                                        
    +     130                 :      *                                                                                                 
    +     131                 :      * @param   int               $filemtime                                                           
    +     132                 :      * @return  vfsStreamContent                                                                       
    +     133                 :      * @see     lastModified()                                                                         
    +     134                 :      */                                                                                                
    +     135                 :     public function setFilemtime($filemtime)                                                           
    +     136                 :     {                                                                                                  
    +     137              81 :         return $this->lastModified($filemtime);                                                        
    +     138                 :     }                                                                                                  
    +     139                 :                                                                                                        
    +     140                 :     /**                                                                                                
    +     141                 :      * sets the last modification time of the stream content                                           
    +     142                 :      *                                                                                                 
    +     143                 :      * @param   int               $filemtime                                                           
    +     144                 :      * @return  vfsStreamContent                                                                       
    +     145                 :      */                                                                                                
    +     146                 :     public function lastModified($filemtime)                                                           
    +     147                 :     {                                                                                                  
    +     148              81 :         $this->lastModified = $filemtime;                                                              
    +     149              81 :         return $this;                                                                                  
    +     150                 :     }                                                                                                  
    +     151                 :                                                                                                        
    +     152                 :     /**                                                                                                
    +     153                 :      * returns the last modification time of the stream content                                        
    +     154                 :      *                                                                                                 
    +     155                 :      * @return  int                                                                                    
    +     156                 :      */                                                                                                
    +     157                 :     public function filemtime()                                                                        
    +     158                 :     {                                                                                                  
    +     159              42 :         return $this->lastModified;                                                                    
    +     160                 :     }                                                                                                  
    +     161                 :                                                                                                        
    +     162                 :     /**                                                                                                
    +     163                 :      * adds content to given container                                                                 
    +     164                 :      *                                                                                                 
    +     165                 :      * @param   vfsStreamContainer  $container                                                         
    +     166                 :      * @return  vfsStreamContent                                                                       
    +     167                 :      */                                                                                                
    +     168                 :     public function at(vfsStreamContainer $container)                                                  
    +     169                 :     {                                                                                                  
    +     170              31 :         $container->addChild($this);                                                                   
    +     171              31 :         return $this;                                                                                  
    +     172                 :     }                                                                                                  
    +     173                 :                                                                                                        
    +     174                 :     /**                                                                                                
    +     175                 :      * change file mode to given permissions                                                           
    +     176                 :      *                                                                                                 
    +     177                 :      * @param   int               $permissions                                                         
    +     178                 :      * @return  vfsStreamContent                                                                       
    +     179                 :      */                                                                                                
    +     180                 :     public function chmod($permissions)                                                                
    +     181                 :     {                                                                                                  
    +     182               9 :         $this->permissions = $permissions;                                                             
    +     183               9 :         clearstatcache();                                                                              
    +     184               9 :         return $this;                                                                                  
    +     185                 :     }                                                                                                  
    +     186                 :                                                                                                        
    +     187                 :     /**                                                                                                
    +     188                 :      * returns permissions                                                                             
    +     189                 :      *                                                                                                 
    +     190                 :      * @return  int                                                                                    
    +     191                 :      */                                                                                                
    +     192                 :     public function getPermissions()                                                                   
    +     193                 :     {                                                                                                  
    +     194              76 :         return $this->permissions;                                                                     
    +     195                 :     }                                                                                                  
    +     196                 :                                                                                                        
    +     197                 :     /**                                                                                                
    +     198                 :      * checks whether content is readable                                                              
    +     199                 :      *                                                                                                 
    +     200                 :      * @param   int   $user   id of user to check for                                                  
    +     201                 :      * @param   int   $group  id of group to check for                                                 
    +     202                 :      * @return  bool                                                                                   
    +     203                 :      */                                                                                                
    +     204                 :     public function isReadable($user, $group)                                                          
    +     205                 :     {                                                                                                  
    +     206              43 :         if ($this->user === $user) {                                                                   
    +     207              43 :             $check = 0400;                                                                             
    +     208              43 :         } elseif ($this->group === $group) {                                                           
    +     209              22 :             $check = 0040;                                                                             
    +     210              22 :         } else {                                                                                       
    +     211              22 :             $check = 0004;                                                                             
    +     212                 :         }                                                                                              
    +     213                 :                                                                                                        
    +     214              43 :         return (bool) ($this->permissions & $check);                                                   
    +     215                 :     }                                                                                                  
    +     216                 :                                                                                                        
    +     217                 :     /**                                                                                                
    +     218                 :      * checks whether content is writable                                                              
    +     219                 :      *                                                                                                 
    +     220                 :      * @param   int   $user   id of user to check for                                                  
    +     221                 :      * @param   int   $group  id of group to check for                                                 
    +     222                 :      * @return  bool                                                                                   
    +     223                 :      */                                                                                                
    +     224                 :     public function isWritable($user, $group)                                                          
    +     225                 :     {                                                                                                  
    +     226              58 :         if ($this->user === $user) {                                                                   
    +     227              57 :             $check = 0200;                                                                             
    +     228              58 :         } elseif ($this->group === $group) {                                                           
    +     229              22 :             $check = 0020;                                                                             
    +     230              22 :         } else {                                                                                       
    +     231              23 :             $check = 0002;                                                                             
    +     232                 :         }                                                                                              
    +     233                 :                                                                                                        
    +     234              58 :         return (bool) ($this->permissions & $check);                                                   
    +     235                 :     }                                                                                                  
    +     236                 :                                                                                                        
    +     237                 :     /**                                                                                                
    +     238                 :      * checks whether content is executable                                                            
    +     239                 :      *                                                                                                 
    +     240                 :      * @param   int   $user   id of user to check for                                                  
    +     241                 :      * @param   int   $group  id of group to check for                                                 
    +     242                 :      * @return  bool                                                                                   
    +     243                 :      */                                                                                                
    +     244                 :     public function isExecutable($user, $group)                                                        
    +     245                 :     {                                                                                                  
    +     246              22 :         if ($this->user === $user) {                                                                   
    +     247              22 :             $check = 0100;                                                                             
    +     248              22 :         } elseif ($this->group === $group) {                                                           
    +     249              22 :             $check = 0010;                                                                             
    +     250              22 :         } else {                                                                                       
    +     251              22 :             $check = 0001;                                                                             
    +     252                 :         }                                                                                              
    +     253                 :                                                                                                        
    +     254              22 :         return (bool) ($this->permissions & $check);                                                   
    +     255                 :     }                                                                                                  
    +     256                 :                                                                                                        
    +     257                 :     /**                                                                                                
    +     258                 :      * change owner of file to given user                                                              
    +     259                 :      *                                                                                                 
    +     260                 :      * @param   int               $user                                                                
    +     261                 :      * @return  vfsStreamContent                                                                       
    +     262                 :      */                                                                                                
    +     263                 :     public function chown($user)                                                                       
    +     264                 :     {                                                                                                  
    +     265               4 :         $this->user = $user;                                                                           
    +     266               4 :         return $this;                                                                                  
    +     267                 :     }                                                                                                  
    +     268                 :                                                                                                        
    +     269                 :     /**                                                                                                
    +     270                 :      * checks whether file is owned by given user                                                      
    +     271                 :      *                                                                                                 
    +     272                 :      * @param   int  $user                                                                             
    +     273                 :      * @return  bool                                                                                   
    +     274                 :      */                                                                                                
    +     275                 :     public function isOwnedByUser($user)                                                               
    +     276                 :     {                                                                                                  
    +     277               2 :         return $this->user === $user;                                                                  
    +     278                 :     }                                                                                                  
    +     279                 :                                                                                                        
    +     280                 :     /**                                                                                                
    +     281                 :      * returns owner of file                                                                           
    +     282                 :      *                                                                                                 
    +     283                 :      * @return  int                                                                                    
    +     284                 :      */                                                                                                
    +     285                 :     public function getUser()                                                                          
    +     286                 :     {                                                                                                  
    +     287              44 :         return $this->user;                                                                            
    +     288                 :     }                                                                                                  
    +     289                 :                                                                                                        
    +     290                 :     /**                                                                                                
    +     291                 :      * change owner group of file to given group                                                       
    +     292                 :      *                                                                                                 
    +     293                 :      * @param   int               $group                                                               
    +     294                 :      * @return  vfsStreamContent                                                                       
    +     295                 :      */                                                                                                
    +     296                 :     public function chgrp($group)                                                                      
    +     297                 :     {                                                                                                  
    +     298               4 :         $this->group = $group;                                                                         
    +     299               4 :         return $this;                                                                                  
    +     300                 :     }                                                                                                  
    +     301                 :                                                                                                        
    +     302                 :     /**                                                                                                
    +     303                 :      * checks whether file is owned by group                                                           
    +     304                 :      *                                                                                                 
    +     305                 :      * @param   int   $group                                                                           
    +     306                 :      * @return  bool                                                                                   
    +     307                 :      */                                                                                                
    +     308                 :     public function isOwnedByGroup($group)                                                             
    +     309                 :     {                                                                                                  
    +     310               2 :         return $this->group === $group;                                                                
    +     311                 :     }                                                                                                  
    +     312                 :                                                                                                        
    +     313                 :     /**                                                                                                
    +     314                 :      * returns owner group of file                                                                     
    +     315                 :      *                                                                                                 
    +     316                 :      * @return  int                                                                                    
    +     317                 :      */                                                                                                
    +     318                 :     public function getGroup()                                                                         
    +     319                 :     {                                                                                                  
    +     320              44 :         return $this->group;                                                                           
    +     321                 :     }                                                                                                  
    +     322                 : }                                                                                                      
    +
    +
    +
    + + + + +
    Generated by PHPUnit 3.4.15 and Xdebug 2.0.5 using PHP 5.2.5 at Fri Oct 8 12:16:32 CEST 2010.
    + +
    + + + + diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamContainerIterator.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamContainerIterator.php.html new file mode 100644 index 0000000..3efcffa --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamContainerIterator.php.html @@ -0,0 +1,485 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    Current file:C:\dev\php\bovigo\vfs\trunk\src\main\php\org\bovigo\vfs\vfsStreamContainerIterator.php
    Legend: + executed + not executed + dead code +
    +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     Coverage
     ClassesFunctions / MethodsLines
    Total + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%6 / 6 + + + + +
    100.00%100.00%
    +
    100.00%16 / 16
     
    vfsStreamContainerIterator + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%6 / 6 + + + + +
    100.00%100.00%
    +
    100.00%16 / 16
     public function __construct(array $children) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%3 / 3
     public function rewind() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%2 / 2
     public function current() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%4 / 4
     public function key() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%4 / 4
     public function next() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%2 / 2
     public function valid() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
    +
    + +
    + + + + + + + + +

    +
    +       1                 : <?php                                                                                            
    +       2                 : /**                                                                                              
    +       3                 :  * Iterator for children of a directory container.                                               
    +       4                 :  *                                                                                               
    +       5                 :  * @package  bovigo_vfs                                                                          
    +       6                 :  * @version  $Id: vfsStreamContainerIterator.php 132 2009-07-13 19:13:25Z google@frankkleine.de $
    +       7                 :  */                                                                                              
    +       8                 : /**                                                                                              
    +       9                 :  * Iterator for children of a directory container.                                               
    +      10                 :  *                                                                                               
    +      11                 :  * @package  bovigo_vfs                                                                          
    +      12                 :  */                                                                                              
    +      13                 : class vfsStreamContainerIterator implements Iterator                                             
    +      14                 : {                                                                                                
    +      15                 :     /**                                                                                          
    +      16                 :      * list of children from container to iterate over                                           
    +      17                 :      *                                                                                           
    +      18                 :      * @var  array<vfsStreamContent>                                                             
    +      19                 :      */                                                                                          
    +      20                 :     protected $children = array();                                                               
    +      21                 :                                                                                                  
    +      22                 :     /**                                                                                          
    +      23                 :      * constructor                                                                               
    +      24                 :      *                                                                                           
    +      25                 :      * @param  array<vfsStreamContent>  $children                                                
    +      26                 :      */                                                                                          
    +      27                 :     public function __construct(array $children)                                                 
    +      28                 :     {                                                                                            
    +      29               6 :         $this->children = $children;                                                             
    +      30               6 :         reset($this->children);                                                                  
    +      31               6 :     }                                                                                            
    +      32                 :                                                                                                  
    +      33                 :     /**                                                                                          
    +      34                 :      * resets children pointer                                                                   
    +      35                 :      */                                                                                          
    +      36                 :     public function rewind()                                                                     
    +      37                 :     {                                                                                            
    +      38               4 :         reset($this->children);                                                                  
    +      39               4 :     }                                                                                            
    +      40                 :                                                                                                  
    +      41                 :     /**                                                                                          
    +      42                 :      * returns the current child                                                                 
    +      43                 :      *                                                                                           
    +      44                 :      * @return  vfsStreamContent                                                                 
    +      45                 :      */                                                                                          
    +      46                 :     public function current()                                                                    
    +      47                 :     {                                                                                            
    +      48               6 :         $child = current($this->children);                                                       
    +      49               6 :         if (false === $child) {                                                                  
    +      50               5 :             return null;                                                                         
    +      51                 :         }                                                                                        
    +      52                 :                                                                                                  
    +      53               6 :         return $child;                                                                           
    +      54                 :     }                                                                                            
    +      55                 :                                                                                                  
    +      56                 :     /**                                                                                          
    +      57                 :      * returns the name of the current child                                                     
    +      58                 :      *                                                                                           
    +      59                 :      * @return  string                                                                           
    +      60                 :      */                                                                                          
    +      61                 :     public function key()                                                                        
    +      62                 :     {                                                                                            
    +      63               1 :         $child = current($this->children);                                                       
    +      64               1 :         if (false === $child) {                                                                  
    +      65               1 :             return null;                                                                         
    +      66                 :         }                                                                                        
    +      67                 :                                                                                                  
    +      68               1 :         return $child->getName();                                                                
    +      69                 :     }                                                                                            
    +      70                 :                                                                                                  
    +      71                 :     /**                                                                                          
    +      72                 :      * iterates to next child                                                                    
    +      73                 :      */                                                                                          
    +      74                 :     public function next()                                                                       
    +      75                 :     {                                                                                            
    +      76               6 :         next($this->children);                                                                   
    +      77               6 :     }                                                                                            
    +      78                 :                                                                                                  
    +      79                 :     /**                                                                                          
    +      80                 :      * checks if the current value is valid                                                      
    +      81                 :      *                                                                                           
    +      82                 :      * @return  bool                                                                             
    +      83                 :      */                                                                                          
    +      84                 :     public function valid()                                                                      
    +      85                 :     {                                                                                            
    +      86               1 :         return (false !== current($this->children));                                             
    +      87                 :     }                                                                                            
    +      88                 : }                                                                                                
    +
    +
    +
    + + + + +
    Generated by PHPUnit 3.4.15 and Xdebug 2.0.5 using PHP 5.2.5 at Fri Oct 8 12:16:32 CEST 2010.
    + +
    + + + + diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamDirectory.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamDirectory.php.html new file mode 100644 index 0000000..a7135ee --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamDirectory.php.html @@ -0,0 +1,892 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    Current file:C:\dev\php\bovigo\vfs\trunk\src\main\php\org\bovigo\vfs\vfsStreamDirectory.php
    Legend: + executed + not executed + dead code +
    +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     Coverage
     ClassesFunctions / MethodsLines
    Total + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%13 / 13 + + + + +
    100.00%100.00%
    +
    100.00%42 / 42
     
    vfsStreamDirectory + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%13 / 13 + + + + +
    100.00%100.00%
    +
    100.00%42 / 42
     public function __construct($name, $permissions = null) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%5 / 5
     protected function getDefaultPermissions() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function size() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function sizeSummarized() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%8 / 8
     public function rename($newName) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%4 / 4
     public function addChild(vfsStreamContent $child) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%2 / 2
     public function removeChild($name) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%6 / 6
     public function hasChild($name) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function getChild($name) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%8 / 8
     protected function getRealChildName($name) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%3 / 3
     protected static function getChildName($name, $ownName) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function getChildren() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function getIterator() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
    +
    + +
    + + + + + + + + +

    +
    +       1                 : <?php                                                                                             
    +       2                 : /**                                                                                               
    +       3                 :  * Directory container.                                                                           
    +       4                 :  *                                                                                                
    +       5                 :  * @package  bovigo_vfs                                                                           
    +       6                 :  * @version  $Id: vfsStreamDirectory.php 211 2010-10-06 16:33:05Z google@frankkleine.de $         
    +       7                 :  */                                                                                               
    +       8                 : /**                                                                                               
    +       9                 :  * @ignore                                                                                        
    +      10                 :  */                                                                                               
    +      11                 : require_once dirname(__FILE__) . '/vfsStreamAbstractContent.php';                                 
    +      12                 : require_once dirname(__FILE__) . '/vfsStreamContainer.php';                                       
    +      13                 : require_once dirname(__FILE__) . '/vfsStreamContainerIterator.php';                               
    +      14                 : require_once dirname(__FILE__) . '/vfsStreamException.php';                                       
    +      15                 : /**                                                                                               
    +      16                 :  * Directory container.                                                                           
    +      17                 :  *                                                                                                
    +      18                 :  * @package  bovigo_vfs                                                                           
    +      19                 :  */                                                                                               
    +      20                 : class vfsStreamDirectory extends vfsStreamAbstractContent implements vfsStreamContainer           
    +      21                 : {                                                                                                 
    +      22                 :     /**                                                                                           
    +      23                 :      * list of directory children                                                                 
    +      24                 :      *                                                                                            
    +      25                 :      * @var  array<string,vfsStreamContent>                                                       
    +      26                 :      */                                                                                           
    +      27                 :     protected $children = array();                                                                
    +      28                 :                                                                                                   
    +      29                 :     /**                                                                                           
    +      30                 :      * constructor                                                                                
    +      31                 :      *                                                                                            
    +      32                 :      * @param   string  $name                                                                     
    +      33                 :      * @param   int     $permissions  optional                                                    
    +      34                 :      * @throws  vfsStreamException                                                                
    +      35                 :      */                                                                                           
    +      36                 :     public function __construct($name, $permissions = null)                                       
    +      37                 :     {                                                                                             
    +      38             116 :         if (strstr($name, '/') !== false) {                                                       
    +      39               1 :             throw new vfsStreamException('Directory name can not contain /.');                    
    +      40                 :         }                                                                                         
    +      41                 :                                                                                                   
    +      42             116 :         $this->type = vfsStreamContent::TYPE_DIR;                                                 
    +      43             116 :         parent::__construct($name, $permissions);                                                 
    +      44             116 :     }                                                                                             
    +      45                 :                                                                                                   
    +      46                 :     /**                                                                                           
    +      47                 :      * returns default permissions for concrete implementation                                    
    +      48                 :      *                                                                                            
    +      49                 :      * @return  int                                                                               
    +      50                 :      * @since   0.8.0                                                                             
    +      51                 :      */                                                                                           
    +      52                 :     protected function getDefaultPermissions()                                                    
    +      53                 :     {                                                                                             
    +      54             113 :         return 0777;                                                                              
    +      55                 :     }                                                                                             
    +      56                 :                                                                                                   
    +      57                 :     /**                                                                                           
    +      58                 :      * returns size of directory                                                                  
    +      59                 :      *                                                                                            
    +      60                 :      * The size of a directory is always 0 bytes. To calculate the summarized                     
    +      61                 :      * size of all children in the directory use sizeSummarized().                                
    +      62                 :      *                                                                                            
    +      63                 :      * @return  int                                                                               
    +      64                 :      */                                                                                           
    +      65                 :     public function size()                                                                        
    +      66                 :     {                                                                                             
    +      67              24 :         return 0;                                                                                 
    +      68                 :     }                                                                                             
    +      69                 :                                                                                                   
    +      70                 :     /**                                                                                           
    +      71                 :      * returns summarized size of directory and its children                                      
    +      72                 :      *                                                                                            
    +      73                 :      * @return  int                                                                               
    +      74                 :      */                                                                                           
    +      75                 :     public function sizeSummarized()                                                              
    +      76                 :     {                                                                                             
    +      77               2 :         $size = 0;                                                                                
    +      78               2 :         foreach ($this->children as $child) {                                                     
    +      79               2 :             if ($child->getType() === vfsStreamContent::TYPE_DIR) {                               
    +      80               1 :                 $size += $child->sizeSummarized();                                                
    +      81               1 :             } else {                                                                              
    +      82               2 :                 $size += $child->size();                                                          
    +      83                 :             }                                                                                     
    +      84               2 :         }                                                                                         
    +      85                 :                                                                                                   
    +      86               2 :         return $size;                                                                             
    +      87                 :     }                                                                                             
    +      88                 :                                                                                                   
    +      89                 :     /**                                                                                           
    +      90                 :      * renames the content                                                                        
    +      91                 :      *                                                                                            
    +      92                 :      * @param   string  $newName                                                                  
    +      93                 :      * @throws  vfsStreamException                                                                
    +      94                 :      */                                                                                           
    +      95                 :     public function rename($newName)                                                              
    +      96                 :     {                                                                                             
    +      97               5 :         if (strstr($newName, '/') !== false) {                                                    
    +      98               1 :             throw new vfsStreamException('Directory name can not contain /.');                    
    +      99                 :         }                                                                                         
    +     100                 :                                                                                                   
    +     101               4 :         parent::rename($newName);                                                                 
    +     102               4 :     }                                                                                             
    +     103                 :                                                                                                   
    +     104                 :     /**                                                                                           
    +     105                 :      * adds child to the directory                                                                
    +     106                 :      *                                                                                            
    +     107                 :      * @param  vfsStreamContent  $child                                                           
    +     108                 :      */                                                                                           
    +     109                 :     public function addChild(vfsStreamContent $child)                                             
    +     110                 :     {                                                                                             
    +     111              99 :         $this->children[$child->getName()] = $child;                                              
    +     112              99 :     }                                                                                             
    +     113                 :                                                                                                   
    +     114                 :     /**                                                                                           
    +     115                 :      * removes child from the directory                                                           
    +     116                 :      *                                                                                            
    +     117                 :      * @param   string  $name                                                                     
    +     118                 :      * @return  bool                                                                              
    +     119                 :      */                                                                                           
    +     120                 :     public function removeChild($name)                                                            
    +     121                 :     {                                                                                             
    +     122              11 :         foreach ($this->children as $key => $child) {                                             
    +     123              11 :             if ($child->appliesTo($name) === true) {                                              
    +     124              10 :                 unset($this->children[$key]);                                                     
    +     125              10 :                 return true;                                                                      
    +     126                 :             }                                                                                     
    +     127               4 :         }                                                                                         
    +     128                 :                                                                                                   
    +     129               1 :         return false;                                                                             
    +     130                 :     }                                                                                             
    +     131                 :                                                                                                   
    +     132                 :     /**                                                                                           
    +     133                 :      * checks whether the container contains a child with the given name                          
    +     134                 :      *                                                                                            
    +     135                 :      * @param   string  $name                                                                     
    +     136                 :      * @return  bool                                                                              
    +     137                 :      */                                                                                           
    +     138                 :     public function hasChild($name)                                                               
    +     139                 :     {                                                                                             
    +     140              72 :         return ($this->getChild($name) !== null);                                                 
    +     141                 :     }                                                                                             
    +     142                 :                                                                                                   
    +     143                 :     /**                                                                                           
    +     144                 :      * returns the child with the given name                                                      
    +     145                 :      *                                                                                            
    +     146                 :      * @param   string  $name                                                                     
    +     147                 :      * @return  vfsStreamContent                                                                  
    +     148                 :      */                                                                                           
    +     149                 :     public function getChild($name)                                                               
    +     150                 :     {                                                                                             
    +     151              78 :         $childName = $this->getRealChildName($name);                                              
    +     152              78 :         foreach ($this->children as $child) {                                                     
    +     153              75 :             if ($child->getName() === $childName) {                                               
    +     154              69 :                 return $child;                                                                    
    +     155                 :             }                                                                                     
    +     156                 :                                                                                                   
    +     157              58 :             if ($child->appliesTo($childName) === true && $child->hasChild($childName) === true) {
    +     158              27 :                 return $child->getChild($childName);                                              
    +     159                 :             }                                                                                     
    +     160              60 :         }                                                                                         
    +     161                 :                                                                                                   
    +     162              39 :         return null;                                                                              
    +     163                 :     }                                                                                             
    +     164                 :                                                                                                   
    +     165                 :     /**                                                                                           
    +     166                 :      * helper method to detect the real child name                                                
    +     167                 :      *                                                                                            
    +     168                 :      * @param   string  $name                                                                     
    +     169                 :      * @return  string                                                                            
    +     170                 :      */                                                                                           
    +     171                 :     protected function getRealChildName($name)                                                    
    +     172                 :     {                                                                                             
    +     173              78 :         if ($this->appliesTo($name) === true) {                                                   
    +     174              64 :             return self::getChildName($name, $this->name);                                        
    +     175                 :         }                                                                                         
    +     176                 :                                                                                                   
    +     177              48 :         return $name;                                                                             
    +     178                 :     }                                                                                             
    +     179                 :                                                                                                   
    +     180                 :     /**                                                                                           
    +     181                 :      * helper method to calculate the child name                                                  
    +     182                 :      *                                                                                            
    +     183                 :      * @param   string  $name                                                                     
    +     184                 :      * @param   string  $ownName                                                                  
    +     185                 :      * @return  string                                                                            
    +     186                 :      */                                                                                           
    +     187                 :     protected static function getChildName($name, $ownName)                                       
    +     188                 :     {                                                                                             
    +     189              64 :         return substr($name, strlen($ownName) + 1);                                               
    +     190                 :     }                                                                                             
    +     191                 :                                                                                                   
    +     192                 :     /**                                                                                           
    +     193                 :      * returns a list of children for this directory                                              
    +     194                 :      *                                                                                            
    +     195                 :      * @return  array<vfsStreamContent>                                                           
    +     196                 :      */                                                                                           
    +     197                 :     public function getChildren()                                                                 
    +     198                 :     {                                                                                             
    +     199              19 :         return array_values($this->children);                                                     
    +     200                 :     }                                                                                             
    +     201                 :                                                                                                   
    +     202                 :     /**                                                                                           
    +     203                 :      * returns iterator for the children                                                          
    +     204                 :      *                                                                                            
    +     205                 :      * @return  vfsStreamContainerIterator                                                        
    +     206                 :      */                                                                                           
    +     207                 :     public function getIterator()                                                                 
    +     208                 :     {                                                                                             
    +     209               6 :         return new vfsStreamContainerIterator($this->children);                                   
    +     210                 :     }                                                                                             
    +     211                 : }                                                                                                 
    +
    +
    +
    + + + + +
    Generated by PHPUnit 3.4.15 and Xdebug 2.0.5 using PHP 5.2.5 at Fri Oct 8 12:16:32 CEST 2010.
    + +
    + + + + diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamFile.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamFile.php.html new file mode 100644 index 0000000..77f0607 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamFile.php.html @@ -0,0 +1,838 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    Current file:C:\dev\php\bovigo\vfs\trunk\src\main\php\org\bovigo\vfs\vfsStreamFile.php
    Legend: + executed + not executed + dead code +
    +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     Coverage
     ClassesFunctions / MethodsLines
    Total + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%13 / 13 + + + + +
    100.00%100.00%
    +
    100.00%33 / 33
     
    vfsStreamFile + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%13 / 13 + + + + +
    100.00%100.00%
    +
    100.00%33 / 33
     public function __construct($name, $permissions = null) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%3 / 3
     protected function getDefaultPermissions() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function appliesTo($name) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function setContent($content) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function withContent($content) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%2 / 2
     public function getContent() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function read($count) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%3 / 3
     public function readUntilEnd() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function write($data) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%5 / 5
     public function eof() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function getBytesRead() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function seek($offset, $whence) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%12 / 12
     public function size() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
    +
    + +
    + + + + + + + + +

    +
    +       1                 : <?php                                                                                                                                    
    +       2                 : /**                                                                                                                                      
    +       3                 :  * File container.                                                                                                                       
    +       4                 :  *                                                                                                                                       
    +       5                 :  * @package  bovigo_vfs                                                                                                                  
    +       6                 :  * @version  $Id: vfsStreamFile.php 211 2010-10-06 16:33:05Z google@frankkleine.de $                                                     
    +       7                 :  */                                                                                                                                      
    +       8                 : /**                                                                                                                                      
    +       9                 :  * @ignore                                                                                                                               
    +      10                 :  */                                                                                                                                      
    +      11                 : require_once dirname(__FILE__) . '/vfsStreamAbstractContent.php';                                                                        
    +      12                 : /**                                                                                                                                      
    +      13                 :  * File container.                                                                                                                       
    +      14                 :  *                                                                                                                                       
    +      15                 :  * @package  bovigo_vfs                                                                                                                  
    +      16                 :  */                                                                                                                                      
    +      17                 : class vfsStreamFile extends vfsStreamAbstractContent                                                                                     
    +      18                 : {                                                                                                                                        
    +      19                 :     /**                                                                                                                                  
    +      20                 :      * the real content of the file                                                                                                      
    +      21                 :      *                                                                                                                                   
    +      22                 :      * @var  string                                                                                                                      
    +      23                 :      */                                                                                                                                  
    +      24                 :     protected $content;                                                                                                                  
    +      25                 :     /**                                                                                                                                  
    +      26                 :      * amount of read bytes                                                                                                              
    +      27                 :      *                                                                                                                                   
    +      28                 :      * @var  int                                                                                                                         
    +      29                 :      */                                                                                                                                  
    +      30                 :     protected $bytes_read = 0;                                                                                                           
    +      31                 :                                                                                                                                          
    +      32                 :     /**                                                                                                                                  
    +      33                 :      * constructor                                                                                                                       
    +      34                 :      *                                                                                                                                   
    +      35                 :      * @param  string  $name                                                                                                             
    +      36                 :      * @param  int     $permissions  optional                                                                                            
    +      37                 :      */                                                                                                                                  
    +      38                 :     public function __construct($name, $permissions = null)                                                                              
    +      39                 :     {                                                                                                                                    
    +      40             100 :         $this->type = vfsStreamContent::TYPE_FILE;                                                                                       
    +      41             100 :         parent::__construct($name, $permissions);                                                                                        
    +      42             100 :     }                                                                                                                                    
    +      43                 :                                                                                                                                          
    +      44                 :     /**                                                                                                                                  
    +      45                 :      * returns default permissions for concrete implementation                                                                           
    +      46                 :      *                                                                                                                                   
    +      47                 :      * @return  int                                                                                                                      
    +      48                 :      * @since   0.8.0                                                                                                                    
    +      49                 :      */                                                                                                                                  
    +      50                 :     protected function getDefaultPermissions()                                                                                           
    +      51                 :     {                                                                                                                                    
    +      52              99 :         return 0666;                                                                                                                     
    +      53                 :     }                                                                                                                                    
    +      54                 :                                                                                                                                          
    +      55                 :     /**                                                                                                                                  
    +      56                 :      * checks whether the container can be applied to given name                                                                         
    +      57                 :      *                                                                                                                                   
    +      58                 :      * @param   string  $name                                                                                                            
    +      59                 :      * @return  bool                                                                                                                     
    +      60                 :      */                                                                                                                                  
    +      61                 :     public function appliesTo($name)                                                                                                     
    +      62                 :     {                                                                                                                                    
    +      63              34 :         return ($name === $this->name);                                                                                                  
    +      64                 :     }                                                                                                                                    
    +      65                 :                                                                                                                                          
    +      66                 :     /**                                                                                                                                  
    +      67                 :      * alias for withContent()                                                                                                           
    +      68                 :      *                                                                                                                                   
    +      69                 :      * @param   string  $content                                                                                                         
    +      70                 :      * @return  vfsStreamFile                                                                                                            
    +      71                 :      * @see     withContent()                                                                                                            
    +      72                 :      */                                                                                                                                  
    +      73                 :     public function setContent($content)                                                                                                 
    +      74                 :     {                                                                                                                                    
    +      75               8 :         return $this->withContent($content);                                                                                             
    +      76                 :     }                                                                                                                                    
    +      77                 :                                                                                                                                          
    +      78                 :     /**                                                                                                                                  
    +      79                 :      * sets the contents of the file                                                                                                     
    +      80                 :      *                                                                                                                                   
    +      81                 :      * Setting content with this method does not change the time when the file                                                           
    +      82                 :      * was last modified.                                                                                                                
    +      83                 :      *                                                                                                                                   
    +      84                 :      * @param   string  $content                                                                                                         
    +      85                 :      * @return  vfsStreamFile                                                                                                            
    +      86                 :      * @see     setContent()                                                                                                             
    +      87                 :      */                                                                                                                                  
    +      88                 :     public function withContent($content)                                                                                                
    +      89                 :     {                                                                                                                                    
    +      90              85 :         $this->content = $content;                                                                                                       
    +      91              85 :         return $this;                                                                                                                    
    +      92                 :     }                                                                                                                                    
    +      93                 :                                                                                                                                          
    +      94                 :     /**                                                                                                                                  
    +      95                 :      * returns the contents of the file                                                                                                  
    +      96                 :      *                                                                                                                                   
    +      97                 :      * @return  string                                                                                                                   
    +      98                 :      */                                                                                                                                  
    +      99                 :     public function getContent()                                                                                                         
    +     100                 :     {                                                                                                                                    
    +     101               4 :         return $this->content;                                                                                                           
    +     102                 :     }                                                                                                                                    
    +     103                 :                                                                                                                                          
    +     104                 :     /**                                                                                                                                  
    +     105                 :      * reads the given amount of bytes from content                                                                                      
    +     106                 :      *                                                                                                                                   
    +     107                 :      * @param   int     $count                                                                                                           
    +     108                 :      * @return  string                                                                                                                   
    +     109                 :      */                                                                                                                                  
    +     110                 :     public function read($count)                                                                                                         
    +     111                 :     {                                                                                                                                    
    +     112              16 :         $data = substr($this->content, $this->bytes_read, $count);                                                                       
    +     113              16 :         $this->bytes_read += $count;                                                                                                     
    +     114              16 :         return $data;                                                                                                                    
    +     115                 :     }                                                                                                                                    
    +     116                 :                                                                                                                                          
    +     117                 :     /**                                                                                                                                  
    +     118                 :      * returns the content until its end from current offset                                                                             
    +     119                 :      *                                                                                                                                   
    +     120                 :      * @return  string                                                                                                                   
    +     121                 :      */                                                                                                                                  
    +     122                 :     public function readUntilEnd()                                                                                                       
    +     123                 :     {                                                                                                                                    
    +     124               1 :         return substr($this->content, $this->bytes_read);                                                                                
    +     125                 :     }                                                                                                                                    
    +     126                 :                                                                                                                                          
    +     127                 :     /**                                                                                                                                  
    +     128                 :      * writes an amount of data                                                                                                          
    +     129                 :      *                                                                                                                                   
    +     130                 :      * Using this method changes the time when the file was last modified.                                                               
    +     131                 :      *                                                                                                                                   
    +     132                 :      * @param   string  $data                                                                                                            
    +     133                 :      * @return  amount of written bytes                                                                                                  
    +     134                 :      */                                                                                                                                  
    +     135                 :     public function write($data)                                                                                                         
    +     136                 :     {                                                                                                                                    
    +     137              14 :         $dataLen           = strlen($data);                                                                                              
    +     138              14 :         $this->content     = substr($this->content, 0, $this->bytes_read) . $data . substr($this->content, $this->bytes_read + $dataLen);
    +     139              14 :         $this->bytes_read += $dataLen;                                                                                                   
    +     140              14 :         $this->filemtime   = time();                                                                                                     
    +     141              14 :         return $dataLen;                                                                                                                 
    +     142                 :     }                                                                                                                                    
    +     143                 :                                                                                                                                          
    +     144                 :     /**                                                                                                                                  
    +     145                 :      * checks whether pointer is at end of file                                                                                          
    +     146                 :      *                                                                                                                                   
    +     147                 :      * @return  bool                                                                                                                     
    +     148                 :      */                                                                                                                                  
    +     149                 :     public function eof()                                                                                                                
    +     150                 :     {                                                                                                                                    
    +     151              17 :         return $this->bytes_read >= strlen($this->content);                                                                              
    +     152                 :     }                                                                                                                                    
    +     153                 :                                                                                                                                          
    +     154                 :     /**                                                                                                                                  
    +     155                 :      * returns the current position within the file                                                                                      
    +     156                 :      *                                                                                                                                   
    +     157                 :      * @return  int                                                                                                                      
    +     158                 :      */                                                                                                                                  
    +     159                 :     public function getBytesRead()                                                                                                       
    +     160                 :     {                                                                                                                                    
    +     161               9 :         return $this->bytes_read;                                                                                                        
    +     162                 :     }                                                                                                                                    
    +     163                 :                                                                                                                                          
    +     164                 :     /**                                                                                                                                  
    +     165                 :      * seeks to the given offset                                                                                                         
    +     166                 :      *                                                                                                                                   
    +     167                 :      * @param   int   $offset                                                                                                            
    +     168                 :      * @param   int   $whence                                                                                                            
    +     169                 :      * @return  bool                                                                                                                     
    +     170                 :      */                                                                                                                                  
    +     171                 :     public function seek($offset, $whence)                                                                                               
    +     172                 :     {                                                                                                                                    
    +     173                 :         switch ($whence) {                                                                                                               
    +     174              20 :             case SEEK_CUR:                                                                                                               
    +     175               4 :                 $this->bytes_read += $offset;                                                                                            
    +     176               4 :                 return true;                                                                                                             
    +     177                 :                                                                                                                                          
    +     178              20 :             case SEEK_END:                                                                                                               
    +     179               5 :                 $this->bytes_read = strlen($this->content) + $offset;                                                                    
    +     180               5 :                 return true;                                                                                                             
    +     181                 :                                                                                                                                          
    +     182              20 :             case SEEK_SET:                                                                                                               
    +     183              20 :                 $this->bytes_read = $offset;                                                                                             
    +     184              20 :                 return true;                                                                                                             
    +     185                 :                                                                                                                                          
    +     186               2 :             default:                                                                                                                     
    +     187               2 :                 return false;                                                                                                            
    +     188               2 :         }                                                                                                                                
    +     189                 :                                                                                                                                          
    +     190                 :         return false;                                                                                                                    
    +     191                 :     }                                                                                                                                    
    +     192                 :                                                                                                                                          
    +     193                 :     /**                                                                                                                                  
    +     194                 :      * returns size of content                                                                                                           
    +     195                 :      *                                                                                                                                   
    +     196                 :      * @return  int                                                                                                                      
    +     197                 :      */                                                                                                                                  
    +     198                 :     public function size()                                                                                                               
    +     199                 :     {                                                                                                                                    
    +     200              37 :         return strlen($this->content);                                                                                                   
    +     201                 :     }                                                                                                                                    
    +     202                 : }                                                                                                                                        
    +
    +
    +
    + + + + +
    Generated by PHPUnit 3.4.15 and Xdebug 2.0.5 using PHP 5.2.5 at Fri Oct 8 12:16:32 CEST 2010.
    + +
    + + + + diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamWrapper.php.html b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamWrapper.php.html new file mode 100644 index 0000000..f83f7b9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/vfsStreamWrapper.php.html @@ -0,0 +1,2572 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    Current file:C:\dev\php\bovigo\vfs\trunk\src\main\php\org\bovigo\vfs\vfsStreamWrapper.php
    Legend: + executed + not executed + dead code +
    +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     Coverage
     ClassesFunctions / MethodsLines
    Total + + + + +
    0.00%0.00%
    +
    0.00%0 / 1 + + + + +
    84.62%84.62%
    +
    84.62%22 / 26 + + + + +
    95.78%95.78%
    +
    95.78%227 / 237
     
    vfsStreamWrapper + + + + +
    0.00%0.00%
    +
    0.00%0 / 1 + + + + +
    84.62%84.62%
    +
    84.62%22 / 26 + + + + +
    95.78%95.78%
    +
    95.78%227 / 237
     public static function register() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%7 / 7
     public static function setRoot(vfsStreamContent $root) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%2 / 2
     public static function getRoot() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     protected function getContent($path) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%7 / 7
     protected function getContentOfType($path, $type) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%4 / 4
     protected function splitPath($path) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%6 / 6
     protected function resolvePath($path) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%10 / 10
     public function stream_open($path, $mode, $options, $opened_path) + + + + +
    0.00%0.00%
    +
    0.00%0 / 1 + + + + +
    92.31%92.31%
    +
    92.31%48 / 52
     protected function calculateMode($mode, $extended) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%5 / 5
     public function stream_close() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function stream_read($count) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%5 / 5
     public function stream_write($data) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%5 / 5
     public function stream_eof() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function stream_tell() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function stream_seek($offset, $whence) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function stream_flush() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function stream_stat() + + + + +
    0.00%0.00%
    +
    0.00%0 / 1 + + + + +
    93.33%93.33%
    +
    93.33%14 / 15
     public function unlink($path) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%14 / 14
     public function rename($path_from, $path_to) + + + + +
    0.00%0.00%
    +
    0.00%0 / 1 + + + + +
    88.89%88.89%
    +
    88.89%16 / 18
     public function mkdir($path, $mode, $options) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%29 / 29
     public function rmdir($path, $options) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%16 / 16
     public function dir_opendir($path, $options) + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%6 / 6
     public function dir_readdir() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%5 / 5
     public function dir_rewinddir() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%1 / 1
     public function dir_closedir() + + + + +
    100.00%100.00%
    +
    100.00%1 / 1 + + + + +
    100.00%100.00%
    +
    100.00%2 / 2
     public function url_stat($path, $flags) + + + + +
    0.00%0.00%
    +
    0.00%0 / 1 + + + + +
    86.36%86.36%
    +
    86.36%19 / 22
    +
    + +
    + + + + + + + + +

    +
    +       1                 : <?php                                                                                                                                        
    +       2                 : /**                                                                                                                                          
    +       3                 :  * Stream wrapper to mock file system requests.                                                                                              
    +       4                 :  *                                                                                                                                           
    +       5                 :  * @package  bovigo_vfs                                                                                                                      
    +       6                 :  * @version  $Id: vfsStreamWrapper.php 214 2010-10-07 20:57:57Z google@frankkleine.de $                                                      
    +       7                 :  */                                                                                                                                          
    +       8                 : /**                                                                                                                                          
    +       9                 :  * @ignore                                                                                                                                   
    +      10                 :  */                                                                                                                                          
    +      11                 : require_once dirname(__FILE__) . '/vfsStreamDirectory.php';                                                                                  
    +      12                 : require_once dirname(__FILE__) . '/vfsStreamFile.php';                                                                                       
    +      13                 : require_once dirname(__FILE__) . '/vfsStreamException.php';                                                                                  
    +      14                 : /**                                                                                                                                          
    +      15                 :  * Stream wrapper to mock file system requests.                                                                                              
    +      16                 :  *                                                                                                                                           
    +      17                 :  * @package  bovigo_vfs                                                                                                                      
    +      18                 :  */                                                                                                                                          
    +      19                 : class vfsStreamWrapper                                                                                                                       
    +      20                 : {                                                                                                                                            
    +      21                 :     /**                                                                                                                                      
    +      22                 :      * open file for reading                                                                                                                 
    +      23                 :      */                                                                                                                                      
    +      24                 :     const READ                   = 'r';                                                                                                      
    +      25                 :     /**                                                                                                                                      
    +      26                 :      * truncate file                                                                                                                         
    +      27                 :      */                                                                                                                                      
    +      28                 :     const TRUNCATE               = 'w';                                                                                                      
    +      29                 :     /**                                                                                                                                      
    +      30                 :      * set file pointer to end, append new data                                                                                              
    +      31                 :      */                                                                                                                                      
    +      32                 :     const APPEND                 = 'a';                                                                                                      
    +      33                 :     /**                                                                                                                                      
    +      34                 :      * set file pointer to start, overwrite existing data                                                                                    
    +      35                 :      */                                                                                                                                      
    +      36                 :     const WRITE                  = 'x';                                                                                                      
    +      37                 :     /**                                                                                                                                      
    +      38                 :      * file mode: read only                                                                                                                  
    +      39                 :      */                                                                                                                                      
    +      40                 :     const READONLY               = 0;                                                                                                        
    +      41                 :     /**                                                                                                                                      
    +      42                 :      * file mode: write only                                                                                                                 
    +      43                 :      */                                                                                                                                      
    +      44                 :     const WRITEONLY              = 1;                                                                                                        
    +      45                 :     /**                                                                                                                                      
    +      46                 :      * file mode: read and write                                                                                                             
    +      47                 :      */                                                                                                                                      
    +      48                 :     const ALL                    = 2;                                                                                                        
    +      49                 :     /**                                                                                                                                      
    +      50                 :      * switch whether class has already been registered as stream wrapper or not                                                             
    +      51                 :      *                                                                                                                                       
    +      52                 :      * @var  bool                                                                                                                            
    +      53                 :      */                                                                                                                                      
    +      54                 :     protected static $registered = false;                                                                                                    
    +      55                 :     /**                                                                                                                                      
    +      56                 :      * root content                                                                                                                          
    +      57                 :      *                                                                                                                                       
    +      58                 :      * @var  vfsStreamContent                                                                                                                
    +      59                 :      */                                                                                                                                      
    +      60                 :     protected static $root;                                                                                                                  
    +      61                 :     /**                                                                                                                                      
    +      62                 :      * file mode: read only, write only, all                                                                                                 
    +      63                 :      *                                                                                                                                       
    +      64                 :      * @var  int                                                                                                                             
    +      65                 :      */                                                                                                                                      
    +      66                 :     protected $mode;                                                                                                                         
    +      67                 :     /**                                                                                                                                      
    +      68                 :      * shortcut to file container                                                                                                            
    +      69                 :      *                                                                                                                                       
    +      70                 :      * @var  vfsStreamFile                                                                                                                   
    +      71                 :      */                                                                                                                                      
    +      72                 :     protected $content;                                                                                                                      
    +      73                 :     /**                                                                                                                                      
    +      74                 :      * shortcut to directory container                                                                                                       
    +      75                 :      *                                                                                                                                       
    +      76                 :      * @var  vfsStreamDirectory                                                                                                              
    +      77                 :      */                                                                                                                                      
    +      78                 :     protected $dir;                                                                                                                          
    +      79                 :     /**                                                                                                                                      
    +      80                 :      * shortcut to directory container iterator                                                                                              
    +      81                 :      *                                                                                                                                       
    +      82                 :      * @var  vfsStreamDirectory                                                                                                              
    +      83                 :      */                                                                                                                                      
    +      84                 :     protected $dirIterator;                                                                                                                  
    +      85                 :                                                                                                                                              
    +      86                 :     /**                                                                                                                                      
    +      87                 :      * method to register the stream wrapper                                                                                                 
    +      88                 :      *                                                                                                                                       
    +      89                 :      * Please be aware that a call to this method will reset the root element                                                                
    +      90                 :      * to null.                                                                                                                              
    +      91                 :      * If the stream is already registered the method returns silently. If there                                                             
    +      92                 :      * is already another stream wrapper registered for the scheme used by                                                                   
    +      93                 :      * vfsStream a vfsStreamException will be thrown.                                                                                        
    +      94                 :      *                                                                                                                                       
    +      95                 :      * @throws  vfsStreamException                                                                                                           
    +      96                 :      */                                                                                                                                      
    +      97                 :     public static function register()                                                                                                        
    +      98                 :     {                                                                                                                                        
    +      99              98 :         self::$root = null;                                                                                                                  
    +     100              98 :         if (true === self::$registered) {                                                                                                    
    +     101              95 :             return;                                                                                                                          
    +     102                 :         }                                                                                                                                    
    +     103                 :                                                                                                                                              
    +     104               3 :         if (@stream_wrapper_register(vfsStream::SCHEME, __CLASS__) === false) {                                                              
    +     105               1 :             throw new vfsStreamException('A handler has already been registered for the ' . vfsStream::SCHEME . ' protocol.');               
    +     106                 :         }                                                                                                                                    
    +     107                 :                                                                                                                                              
    +     108               2 :         self::$registered = true;                                                                                                            
    +     109               2 :     }                                                                                                                                        
    +     110                 :                                                                                                                                              
    +     111                 :     /**                                                                                                                                      
    +     112                 :      * sets the root content                                                                                                                 
    +     113                 :      *                                                                                                                                       
    +     114                 :      * @param  vfsStreamContent  $root                                                                                                       
    +     115                 :      */                                                                                                                                      
    +     116                 :     public static function setRoot(vfsStreamContent $root)                                                                                   
    +     117                 :     {                                                                                                                                        
    +     118              93 :         self::$root = $root;                                                                                                                 
    +     119              93 :     }                                                                                                                                        
    +     120                 :                                                                                                                                              
    +     121                 :     /**                                                                                                                                      
    +     122                 :      * returns the root content                                                                                                              
    +     123                 :      *                                                                                                                                       
    +     124                 :      * @return  vfsStreamContent                                                                                                             
    +     125                 :      */                                                                                                                                      
    +     126                 :     public static function getRoot()                                                                                                         
    +     127                 :     {                                                                                                                                        
    +     128              19 :         return self::$root;                                                                                                                  
    +     129                 :     }                                                                                                                                        
    +     130                 :                                                                                                                                              
    +     131                 :     /**                                                                                                                                      
    +     132                 :      * returns content for given path                                                                                                        
    +     133                 :      *                                                                                                                                       
    +     134                 :      * @param   string            $path                                                                                                      
    +     135                 :      * @return  vfsStreamContent                                                                                                             
    +     136                 :      */                                                                                                                                      
    +     137                 :     protected function getContent($path)                                                                                                     
    +     138                 :     {                                                                                                                                        
    +     139              84 :         if (null === self::$root) {                                                                                                          
    +     140               7 :             return null;                                                                                                                     
    +     141                 :         }                                                                                                                                    
    +     142                 :                                                                                                                                              
    +     143              79 :         if (self::$root->getName() === $path) {                                                                                              
    +     144              58 :             return self::$root;                                                                                                              
    +     145                 :         }                                                                                                                                    
    +     146                 :                                                                                                                                              
    +     147              61 :         if (self::$root->hasChild($path) === true) {                                                                                         
    +     148              49 :             return self::$root->getChild($path);                                                                                             
    +     149                 :         }                                                                                                                                    
    +     150                 :                                                                                                                                              
    +     151              32 :         return null;                                                                                                                         
    +     152                 :     }                                                                                                                                        
    +     153                 :                                                                                                                                              
    +     154                 :     /**                                                                                                                                      
    +     155                 :      * returns content for given path but only when it is of given type                                                                      
    +     156                 :      *                                                                                                                                       
    +     157                 :      * @param   string            $path                                                                                                      
    +     158                 :      * @param   int               $type                                                                                                      
    +     159                 :      * @return  vfsStreamContent                                                                                                             
    +     160                 :      */                                                                                                                                      
    +     161                 :     protected function getContentOfType($path, $type)                                                                                        
    +     162                 :     {                                                                                                                                        
    +     163              39 :         $content = $this->getContent($path);                                                                                                 
    +     164              39 :         if (null !== $content && $content->getType() === $type) {                                                                            
    +     165              34 :             return $content;                                                                                                                 
    +     166                 :         }                                                                                                                                    
    +     167                 :                                                                                                                                              
    +     168              18 :         return null;                                                                                                                         
    +     169                 :     }                                                                                                                                        
    +     170                 :                                                                                                                                              
    +     171                 :     /**                                                                                                                                      
    +     172                 :      * splits path into its dirname and the basename                                                                                         
    +     173                 :      *                                                                                                                                       
    +     174                 :      * @param   string  $path                                                                                                                
    +     175                 :      * @return  array                                                                                                                        
    +     176                 :      */                                                                                                                                      
    +     177                 :     protected function splitPath($path)                                                                                                      
    +     178                 :     {                                                                                                                                        
    +     179              40 :         $lastSlashPos = strrpos($path, '/');                                                                                                 
    +     180              40 :         if (false === $lastSlashPos) {                                                                                                       
    +     181              16 :             return array('dirname' => '', 'basename' => $path);                                                                              
    +     182                 :         }                                                                                                                                    
    +     183                 :                                                                                                                                              
    +     184              38 :         return array('dirname'  => substr($path, 0, $lastSlashPos),                                                                          
    +     185              38 :                      'basename' => substr($path, $lastSlashPos + 1)                                                                          
    +     186              38 :                );                                                                                                                            
    +     187                 :     }                                                                                                                                        
    +     188                 :                                                                                                                                              
    +     189                 :     /**                                                                                                                                      
    +     190                 :      * helper method to resolve a path from /foo/bar/. to /foo/bar                                                                           
    +     191                 :      *                                                                                                                                       
    +     192                 :      * @param   string  $path                                                                                                                
    +     193                 :      * @return  string                                                                                                                       
    +     194                 :      */                                                                                                                                      
    +     195                 :     protected function resolvePath($path)                                                                                                    
    +     196                 :     {                                                                                                                                        
    +     197              70 :         $newPath  = array();                                                                                                                 
    +     198              70 :         foreach (explode('/', $path) as $pathPart) {                                                                                         
    +     199              70 :             if ('.' !== $pathPart) {                                                                                                         
    +     200              70 :                 if ('..' !== $pathPart) {                                                                                                    
    +     201              70 :                     $newPath[] = $pathPart;                                                                                                  
    +     202              70 :                 } else {                                                                                                                     
    +     203               1 :                     array_pop($newPath);                                                                                                     
    +     204                 :                 }                                                                                                                            
    +     205              70 :             }                                                                                                                                
    +     206              70 :         }                                                                                                                                    
    +     207                 :                                                                                                                                              
    +     208              70 :         return implode('/', $newPath);                                                                                                       
    +     209                 :     }                                                                                                                                        
    +     210                 :                                                                                                                                              
    +     211                 :     /**                                                                                                                                      
    +     212                 :      * open the stream                                                                                                                       
    +     213                 :      *                                                                                                                                       
    +     214                 :      * @param   string  $path         the path to open                                                                                       
    +     215                 :      * @param   string  $mode         mode for opening                                                                                       
    +     216                 :      * @param   string  $options      options for opening                                                                                    
    +     217                 :      * @param   string  $opened_path  full path that was actually opened                                                                     
    +     218                 :      * @return  bool                                                                                                                         
    +     219                 :      */                                                                                                                                      
    +     220                 :     public function stream_open($path, $mode, $options, $opened_path)                                                                        
    +     221                 :     {                                                                                                                                        
    +     222              25 :         $extended = ((strstr($mode, '+') !== false) ? (true) : (false));                                                                     
    +     223              25 :         $mode     = str_replace(array('b', '+'), '', $mode);                                                                                 
    +     224              25 :         if (in_array($mode, array('r', 'w', 'a', 'x')) === false) {                                                                          
    +     225               1 :             if (!($options & STREAM_REPORT_ERRORS)) {                                                                                        
    +     226               1 :                 trigger_error('Illegal mode ' . $mode . ', use r, w, a  or x, flavoured with b and/or +', E_USER_WARNING);                   
    +     227               1 :             }                                                                                                                                
    +     228                 :                                                                                                                                              
    +     229               1 :             return false;                                                                                                                    
    +     230                 :         }                                                                                                                                    
    +     231                 :                                                                                                                                              
    +     232              24 :         $this->mode    = $this->calculateMode($mode, $extended);                                                                             
    +     233              24 :         $path          = $this->resolvePath(vfsStream::path($path));                                                                         
    +     234              24 :         $this->content = $this->getContentOfType($path, vfsStreamContent::TYPE_FILE);                                                        
    +     235              24 :         if (null !== $this->content) {                                                                                                       
    +     236              17 :             if (self::WRITE === $mode) {                                                                                                     
    +     237               1 :                 if (!($options & STREAM_REPORT_ERRORS)) {                                                                                    
    +     238               1 :                     trigger_error('File ' . $path . ' already exists, can not open with mode x', E_USER_WARNING);                            
    +     239               1 :                 }                                                                                                                            
    +     240                 :                                                                                                                                              
    +     241               1 :                 return false;                                                                                                                
    +     242                 :             }                                                                                                                                
    +     243                 :                                                                                                                                              
    +     244              17 :             $this->content->seek(0, SEEK_SET);                                                                                               
    +     245              17 :             if (self::TRUNCATE === $mode && $this->content->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === true) {
    +     246               4 :                 $this->content->setContent(''); // truncate                                                                                  
    +     247              17 :             } elseif (self::APPEND === $mode) {                                                                                              
    +     248               2 :                 $this->content->seek(0, SEEK_END);                                                                                           
    +     249               2 :             }                                                                                                                                
    +     250                 :                                                                                                                                              
    +     251              17 :             return true;                                                                                                                     
    +     252                 :         }                                                                                                                                    
    +     253                 :                                                                                                                                              
    +     254              14 :         $names = $this->splitPath($path);                                                                                                    
    +     255              14 :         if (empty($names['dirname']) === true) {                                                                                             
    +     256               3 :             if (!($options & STREAM_REPORT_ERRORS)) {                                                                                        
    +     257               3 :                 trigger_error('File ' . $names['basename'] . ' does not exist', E_USER_WARNING);                                             
    +     258               2 :             }                                                                                                                                
    +     259                 :                                                                                                                                              
    +     260               2 :             return false;                                                                                                                    
    +     261                 :         }                                                                                                                                    
    +     262                 :                                                                                                                                              
    +     263              13 :         $dir = $this->getContentOfType($names['dirname'], vfsStreamContent::TYPE_DIR);                                                       
    +     264              13 :         if (null === $dir) {                                                                                                                 
    +     265               0 :             if (!($options & STREAM_REPORT_ERRORS)) {                                                                                        
    +     266               0 :                 trigger_error('Directory ' . $names['dirname'] . ' does not exist', E_USER_WARNING);                                         
    +     267               0 :             }                                                                                                                                
    +     268                 :                                                                                                                                              
    +     269               0 :             return false;                                                                                                                    
    +     270              13 :         } elseif ($dir->hasChild($names['basename']) === true) {                                                                             
    +     271               2 :             if (!($options & STREAM_REPORT_ERRORS)) {                                                                                        
    +     272               2 :                 trigger_error('Directory ' . $names['dirname'] . ' already contains a director named ' . $names['basename'], E_USER_WARNING);
    +     273               2 :             }                                                                                                                                
    +     274                 :                                                                                                                                              
    +     275               2 :             return false;                                                                                                                    
    +     276                 :         }                                                                                                                                    
    +     277                 :                                                                                                                                              
    +     278              11 :         if (self::READ === $mode) {                                                                                                          
    +     279               2 :             if (!($options & STREAM_REPORT_ERRORS)) {                                                                                        
    +     280               2 :                 trigger_error('Can not open non-existing file ' . $path . ' for reading', E_USER_WARNING);                                   
    +     281               2 :             }                                                                                                                                
    +     282                 :                                                                                                                                              
    +     283               2 :             return false;                                                                                                                    
    +     284                 :         }                                                                                                                                    
    +     285                 :                                                                                                                                              
    +     286               9 :         if ($dir->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {                                         
    +     287               1 :             if (!($options & STREAM_REPORT_ERRORS)) {                                                                                        
    +     288               1 :                 trigger_error('Can not create new file in non-writable path ' . $names['dirname'], E_USER_WARNING);                          
    +     289               1 :             }                                                                                                                                
    +     290                 :                                                                                                                                              
    +     291               1 :             return false;                                                                                                                    
    +     292                 :         }                                                                                                                                    
    +     293                 :                                                                                                                                              
    +     294               8 :         $this->content = vfsStream::newFile($names['basename'])->at($dir);                                                                   
    +     295               8 :         return true;                                                                                                                         
    +     296                 :     }                                                                                                                                        
    +     297                 :                                                                                                                                              
    +     298                 :     /**                                                                                                                                      
    +     299                 :      * calculates the file mode                                                                                                              
    +     300                 :      *                                                                                                                                       
    +     301                 :      * @param   string  $mode      opening mode: r, w, a or x                                                                                
    +     302                 :      * @param   bool    $extended  true if + was set with opening mode                                                                       
    +     303                 :      * @return  int                                                                                                                          
    +     304                 :      */                                                                                                                                      
    +     305                 :     protected function calculateMode($mode, $extended)                                                                                       
    +     306                 :     {                                                                                                                                        
    +     307              24 :         if (true === $extended) {                                                                                                            
    +     308               1 :             return self::ALL;                                                                                                                
    +     309                 :         }                                                                                                                                    
    +     310                 :                                                                                                                                              
    +     311              23 :         if (self::READ === $mode) {                                                                                                          
    +     312              18 :             return self::READONLY;                                                                                                           
    +     313                 :         }                                                                                                                                    
    +     314                 :                                                                                                                                              
    +     315              14 :         return self::WRITEONLY;                                                                                                              
    +     316                 :     }                                                                                                                                        
    +     317                 :                                                                                                                                              
    +     318                 :     /**                                                                                                                                      
    +     319                 :      * closes the stream                                                                                                                     
    +     320                 :      */                                                                                                                                      
    +     321                 :     public function stream_close()                                                                                                           
    +     322                 :     {                                                                                                                                        
    +     323                 :         // nothing to do                                                                                                                     
    +     324              20 :     }                                                                                                                                        
    +     325                 :                                                                                                                                              
    +     326                 :     /**                                                                                                                                      
    +     327                 :      * read the stream up to $count bytes                                                                                                    
    +     328                 :      *                                                                                                                                       
    +     329                 :      * @param   int     $count  amount of bytes to read                                                                                      
    +     330                 :      * @return  string                                                                                                                       
    +     331                 :      */                                                                                                                                      
    +     332                 :     public function stream_read($count)                                                                                                      
    +     333                 :     {                                                                                                                                        
    +     334              15 :         if (self::WRITEONLY === $this->mode) {                                                                                               
    +     335               3 :             return '';                                                                                                                       
    +     336                 :         }                                                                                                                                    
    +     337                 :                                                                                                                                              
    +     338              15 :         if ($this->content->isReadable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {                               
    +     339               1 :             return '';                                                                                                                       
    +     340                 :         }                                                                                                                                    
    +     341                 :                                                                                                                                              
    +     342              14 :         return $this->content->read($count);                                                                                                 
    +     343                 :     }                                                                                                                                        
    +     344                 :                                                                                                                                              
    +     345                 :     /**                                                                                                                                      
    +     346                 :      * writes data into the stream                                                                                                           
    +     347                 :      *                                                                                                                                       
    +     348                 :      * @param   string  $data                                                                                                                
    +     349                 :      * @return  int     amount of bytes written                                                                                              
    +     350                 :      */                                                                                                                                      
    +     351                 :     public function stream_write($data)                                                                                                      
    +     352                 :     {                                                                                                                                        
    +     353              14 :         if (self::READONLY === $this->mode) {                                                                                                
    +     354               1 :             return 0;                                                                                                                        
    +     355                 :         }                                                                                                                                    
    +     356                 :                                                                                                                                              
    +     357              13 :         if ($this->content->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {                               
    +     358               1 :             return 0;                                                                                                                        
    +     359                 :         }                                                                                                                                    
    +     360                 :                                                                                                                                              
    +     361              12 :         return $this->content->write($data);                                                                                                 
    +     362                 :     }                                                                                                                                        
    +     363                 :                                                                                                                                              
    +     364                 :     /**                                                                                                                                      
    +     365                 :      * checks whether stream is at end of file                                                                                               
    +     366                 :      *                                                                                                                                       
    +     367                 :      * @return  bool                                                                                                                         
    +     368                 :      */                                                                                                                                      
    +     369                 :     public function stream_eof()                                                                                                             
    +     370                 :     {                                                                                                                                        
    +     371              15 :         return $this->content->eof();                                                                                                        
    +     372                 :     }                                                                                                                                        
    +     373                 :                                                                                                                                              
    +     374                 :     /**                                                                                                                                      
    +     375                 :      * returns the current position of the stream                                                                                            
    +     376                 :      *                                                                                                                                       
    +     377                 :      * @return  int                                                                                                                          
    +     378                 :      */                                                                                                                                      
    +     379                 :     public function stream_tell()                                                                                                            
    +     380                 :     {                                                                                                                                        
    +     381               5 :         return $this->content->getBytesRead();                                                                                               
    +     382                 :     }                                                                                                                                        
    +     383                 :                                                                                                                                              
    +     384                 :     /**                                                                                                                                      
    +     385                 :      * seeks to the given offset                                                                                                             
    +     386                 :      *                                                                                                                                       
    +     387                 :      * @param   int   $offset                                                                                                                
    +     388                 :      * @param   int   $whence                                                                                                                
    +     389                 :      * @return  bool                                                                                                                         
    +     390                 :      */                                                                                                                                      
    +     391                 :     public function stream_seek($offset, $whence)                                                                                            
    +     392                 :     {                                                                                                                                        
    +     393               5 :         return $this->content->seek($offset, $whence);                                                                                       
    +     394                 :     }                                                                                                                                        
    +     395                 :                                                                                                                                              
    +     396                 :     /**                                                                                                                                      
    +     397                 :      * flushes unstored data into storage                                                                                                    
    +     398                 :      *                                                                                                                                       
    +     399                 :      * @return  bool                                                                                                                         
    +     400                 :      */                                                                                                                                      
    +     401                 :     public function stream_flush()                                                                                                           
    +     402                 :     {                                                                                                                                        
    +     403              20 :         return true;                                                                                                                         
    +     404                 :     }                                                                                                                                        
    +     405                 :                                                                                                                                              
    +     406                 :     /**                                                                                                                                      
    +     407                 :      * returns status of stream                                                                                                              
    +     408                 :      *                                                                                                                                       
    +     409                 :      * @return  array                                                                                                                        
    +     410                 :      */                                                                                                                                      
    +     411                 :     public function stream_stat()                                                                                                            
    +     412                 :     {                                                                                                                                        
    +     413              15 :         $fileStat = array('dev'     => 0,                                                                                                    
    +     414              15 :                           'ino'     => 0,                                                                                                    
    +     415              15 :                           'mode'    => $this->content->getType() | $this->content->getPermissions(),                                         
    +     416              15 :                           'nlink'   => 0,                                                                                                    
    +     417              15 :                           'uid'     => $this->content->getUser(),                                                                            
    +     418              15 :                           'gid'     => $this->content->getGroup(),                                                                           
    +     419              15 :                           'rdev'    => 0,                                                                                                    
    +     420              15 :                           'size'    => $this->content->size(),                                                                               
    +     421              15 :                           'atime'   => $this->content->filemtime(),                                                                          
    +     422              15 :                           'mtime'   => $this->content->filemtime(),                                                                          
    +     423              15 :                           'ctime'   => $this->content->filemtime(),                                                                          
    +     424              15 :                           'blksize' => -1,                                                                                                   
    +     425               0 :                           'blocks'  => -1                                                                                                    
    +     426              15 :                     );                                                                                                                       
    +     427              15 :         return array_merge(array_values($fileStat), $fileStat);                                                                              
    +     428                 :     }                                                                                                                                        
    +     429                 :                                                                                                                                              
    +     430                 :     /**                                                                                                                                      
    +     431                 :      * remove the data under the given path                                                                                                  
    +     432                 :      *                                                                                                                                       
    +     433                 :      * @param   string  $path                                                                                                                
    +     434                 :      * @return  bool                                                                                                                         
    +     435                 :      */                                                                                                                                      
    +     436                 :     public function unlink($path)                                                                                                            
    +     437                 :     {                                                                                                                                        
    +     438               8 :         $realPath = $this->resolvePath(vfsStream::path($path));                                                                              
    +     439               8 :         $content  = $this->getContent($realPath);                                                                                            
    +     440               8 :         if (null === $content || $content->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {                
    +     441               3 :             return false;                                                                                                                    
    +     442                 :         }                                                                                                                                    
    +     443                 :                                                                                                                                              
    +     444               6 :         if (self::$root->getName() === $realPath) {                                                                                          
    +     445                 :             // delete root? very brave. :)                                                                                                   
    +     446               1 :             self::$root = null;                                                                                                              
    +     447               1 :             clearstatcache();                                                                                                                
    +     448               1 :             return true;                                                                                                                     
    +     449                 :         }                                                                                                                                    
    +     450                 :                                                                                                                                              
    +     451               6 :         $names   = $this->splitPath($realPath);                                                                                              
    +     452               6 :         $content = $this->getContent($names['dirname']);                                                                                     
    +     453               6 :         if ($content->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {                                     
    +     454               1 :             return false;                                                                                                                    
    +     455                 :         }                                                                                                                                    
    +     456                 :                                                                                                                                              
    +     457               5 :         clearstatcache();                                                                                                                    
    +     458               5 :         return $content->removeChild($names['basename']);                                                                                    
    +     459                 :     }                                                                                                                                        
    +     460                 :                                                                                                                                              
    +     461                 :     /**                                                                                                                                      
    +     462                 :      * rename from one path to another                                                                                                       
    +     463                 :      *                                                                                                                                       
    +     464                 :      * @param   string  $path_from                                                                                                           
    +     465                 :      * @param   string  $path_to                                                                                                             
    +     466                 :      * @return  bool                                                                                                                         
    +     467                 :      * @author  Benoit Aubuchon                                                                                                              
    +     468                 :      */                                                                                                                                      
    +     469                 :     public function rename($path_from, $path_to)                                                                                             
    +     470                 :     {                                                                                                                                        
    +     471               8 :         $srcRealPath = $this->resolvePath(vfsStream::path($path_from));                                                                      
    +     472               8 :         $dstRealPath = vfsStream::path($path_to);                                                                                            
    +     473               8 :         $srcContent  = $this->getContent($srcRealPath);                                                                                      
    +     474               8 :         if (null == $srcContent) {                                                                                                           
    +     475               2 :             trigger_error(' No such file or directory', E_USER_WARNING);                                                                     
    +     476               1 :             return false;                                                                                                                    
    +     477                 :         }                                                                                                                                    
    +     478                 :                                                                                                                                              
    +     479               6 :         $dstContent = clone $srcContent;                                                                                                     
    +     480               6 :         $dstNames   = $this->splitPath($dstRealPath);                                                                                        
    +     481                 :         // Renaming the filename                                                                                                             
    +     482               6 :         $dstContent->rename($dstNames['basename']);                                                                                          
    +     483                 :         // Copying to the destination                                                                                                        
    +     484               6 :         $dstParentContent = $this->getContent($dstNames['dirname']);                                                                         
    +     485               6 :         if (null == $dstParentContent) {                                                                                                     
    +     486               1 :             trigger_error('No such file or directory', E_USER_WARNING);                                                                      
    +     487               0 :             return false;                                                                                                                    
    +     488                 :         }                                                                                                                                    
    +     489                 :                                                                                                                                              
    +     490               5 :         if ($dstParentContent->getType() !== vfsStreamContent::TYPE_DIR) {                                                                   
    +     491               1 :             trigger_error('Target is not a directory', E_USER_WARNING);                                                                      
    +     492               0 :             return false;                                                                                                                    
    +     493                 :         }                                                                                                                                    
    +     494                 :                                                                                                                                              
    +     495               4 :         $dstParentContent->addChild($dstContent);                                                                                            
    +     496                 :         // Removing the source                                                                                                               
    +     497               4 :         return $this->unlink($path_from);                                                                                                    
    +     498                 :     }                                                                                                                                        
    +     499                 :                                                                                                                                              
    +     500                 :     /**                                                                                                                                      
    +     501                 :      * creates a new directory                                                                                                               
    +     502                 :      *                                                                                                                                       
    +     503                 :      * @param   string  $path                                                                                                                
    +     504                 :      * @param   int     $mode                                                                                                                
    +     505                 :      * @param   int     $options                                                                                                             
    +     506                 :      * @return  bool                                                                                                                         
    +     507                 :      */                                                                                                                                      
    +     508                 :     public function mkdir($path, $mode, $options)                                                                                            
    +     509                 :     {                                                                                                                                        
    +     510              18 :         $umask = vfsStream::umask();                                                                                                         
    +     511              18 :         if (0 < $umask) {                                                                                                                    
    +     512               4 :             $permissions = $mode & ~$umask;                                                                                                  
    +     513               4 :         } else {                                                                                                                             
    +     514              14 :             $permissions = $mode;                                                                                                            
    +     515                 :         }                                                                                                                                    
    +     516                 :                                                                                                                                              
    +     517              18 :         $path = vfsStream::path($path);                                                                                                      
    +     518              18 :         if (null === self::$root) {                                                                                                          
    +     519               3 :             self::$root = vfsStream::newDirectory($path, $permissions);                                                                      
    +     520               3 :             return true;                                                                                                                     
    +     521                 :         }                                                                                                                                    
    +     522                 :                                                                                                                                              
    +     523              15 :         $maxDepth = count(explode('/', $path));                                                                                              
    +     524              15 :         $names    = $this->splitPath($path);                                                                                                 
    +     525              15 :         $newDirs  = $names['basename'];                                                                                                      
    +     526              15 :         $dir      = null;                                                                                                                    
    +     527              15 :         $i        = 0;                                                                                                                       
    +     528              15 :         while ($dir === null && $i < $maxDepth) {                                                                                            
    +     529              15 :             $dir     = $this->getContent($names['dirname']);                                                                                 
    +     530              15 :             $names   = $this->splitPath($names['dirname']);                                                                                  
    +     531              15 :             $newDirs = $names['basename'] . '/' . $newDirs;                                                                                  
    +     532              15 :             $i++;                                                                                                                            
    +     533              15 :         }                                                                                                                                    
    +     534                 :                                                                                                                                              
    +     535                 :         if (null === $dir                                                                                                                    
    +     536              15 :           || $dir->getType() !== vfsStreamContent::TYPE_DIR                                                                                  
    +     537              15 :           || $dir->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {                                        
    +     538               5 :             return false;                                                                                                                    
    +     539                 :         }                                                                                                                                    
    +     540                 :                                                                                                                                              
    +     541              10 :         $newDirs = str_replace($dir->getName() . '/', '', $newDirs);                                                                         
    +     542              10 :         $recursive = ((STREAM_MKDIR_RECURSIVE & $options) !== 0) ? (true) : (false);                                                         
    +     543              10 :         if (strpos($newDirs, '/') !== false && false === $recursive) {                                                                       
    +     544               1 :             return false;                                                                                                                    
    +     545                 :         }                                                                                                                                    
    +     546                 :                                                                                                                                              
    +     547              10 :         vfsStream::newDirectory($newDirs, $permissions)->at($dir);                                                                           
    +     548              10 :         return true;                                                                                                                         
    +     549                 :     }                                                                                                                                        
    +     550                 :                                                                                                                                              
    +     551                 :     /**                                                                                                                                      
    +     552                 :      * removes a directory                                                                                                                   
    +     553                 :      *                                                                                                                                       
    +     554                 :      * @param   string  $path                                                                                                                
    +     555                 :      * @param   int     $options                                                                                                             
    +     556                 :      * @return  bool                                                                                                                         
    +     557                 :      * @todo    consider $options with STREAM_MKDIR_RECURSIVE                                                                                
    +     558                 :      */                                                                                                                                      
    +     559                 :     public function rmdir($path, $options)                                                                                                   
    +     560                 :     {                                                                                                                                        
    +     561               8 :         $path  = $this->resolvePath(vfsStream::path($path));                                                                                 
    +     562               8 :         $child = $this->getContentOfType($path, vfsStreamContent::TYPE_DIR);                                                                 
    +     563               8 :         if (null === $child) {                                                                                                               
    +     564               3 :             return false;                                                                                                                    
    +     565                 :         }                                                                                                                                    
    +     566                 :                                                                                                                                              
    +     567                 :         // can only remove empty directories                                                                                                 
    +     568               5 :         if (count($child->getChildren()) > 0) {                                                                                              
    +     569               1 :             return false;                                                                                                                    
    +     570                 :         }                                                                                                                                    
    +     571                 :                                                                                                                                              
    +     572               4 :         if (self::$root->getName() === $path) {                                                                                              
    +     573                 :             // delete root? very brave. :)                                                                                                   
    +     574               1 :             self::$root = null;                                                                                                              
    +     575               1 :             clearstatcache();                                                                                                                
    +     576               1 :             return true;                                                                                                                     
    +     577                 :         }                                                                                                                                    
    +     578                 :                                                                                                                                              
    +     579               3 :         $names = $this->splitPath($path);                                                                                                    
    +     580               3 :         $dir   = $this->getContentOfType($names['dirname'], vfsStreamContent::TYPE_DIR);                                                     
    +     581               3 :         if ($dir->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {                                         
    +     582               1 :             return false;                                                                                                                    
    +     583                 :         }                                                                                                                                    
    +     584                 :                                                                                                                                              
    +     585               2 :         clearstatcache();                                                                                                                    
    +     586               2 :         return $dir->removeChild($child->getName());                                                                                         
    +     587                 :     }                                                                                                                                        
    +     588                 :                                                                                                                                              
    +     589                 :     /**                                                                                                                                      
    +     590                 :      * opens a directory                                                                                                                     
    +     591                 :      *                                                                                                                                       
    +     592                 :      * @param   string  $path                                                                                                                
    +     593                 :      * @param   int     $options                                                                                                             
    +     594                 :      * @return  bool                                                                                                                         
    +     595                 :      */                                                                                                                                      
    +     596                 :     public function dir_opendir($path, $options)                                                                                             
    +     597                 :     {                                                                                                                                        
    +     598               7 :         $path      = $this->resolvePath(vfsStream::path($path));                                                                             
    +     599               7 :         $this->dir = $this->getContentOfType($path, vfsStreamContent::TYPE_DIR);                                                             
    +     600               7 :         if (null === $this->dir || $this->dir->isReadable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {            
    +     601               2 :             return false;                                                                                                                    
    +     602                 :         }                                                                                                                                    
    +     603                 :                                                                                                                                              
    +     604               5 :         $this->dirIterator = $this->dir->getIterator();                                                                                      
    +     605               5 :         return true;                                                                                                                         
    +     606                 :     }                                                                                                                                        
    +     607                 :                                                                                                                                              
    +     608                 :     /**                                                                                                                                      
    +     609                 :      * reads directory contents                                                                                                              
    +     610                 :      *                                                                                                                                       
    +     611                 :      * @return  string                                                                                                                       
    +     612                 :      */                                                                                                                                      
    +     613                 :     public function dir_readdir()                                                                                                            
    +     614                 :     {                                                                                                                                        
    +     615               5 :         $dir = $this->dirIterator->current();                                                                                                
    +     616               5 :         if (null === $dir) {                                                                                                                 
    +     617               4 :             return false;                                                                                                                    
    +     618                 :         }                                                                                                                                    
    +     619                 :                                                                                                                                              
    +     620               5 :         $this->dirIterator->next();                                                                                                          
    +     621               5 :         return $dir->getName();                                                                                                              
    +     622                 :     }                                                                                                                                        
    +     623                 :                                                                                                                                              
    +     624                 :     /**                                                                                                                                      
    +     625                 :      * reset directory iteration                                                                                                             
    +     626                 :      *                                                                                                                                       
    +     627                 :      * @return  bool                                                                                                                         
    +     628                 :      */                                                                                                                                      
    +     629                 :     public function dir_rewinddir()                                                                                                          
    +     630                 :     {                                                                                                                                        
    +     631               3 :         return $this->dirIterator->rewind();                                                                                                 
    +     632                 :     }                                                                                                                                        
    +     633                 :                                                                                                                                              
    +     634                 :     /**                                                                                                                                      
    +     635                 :      * closes directory                                                                                                                      
    +     636                 :      *                                                                                                                                       
    +     637                 :      * @return  bool                                                                                                                         
    +     638                 :      */                                                                                                                                      
    +     639                 :     public function dir_closedir()                                                                                                           
    +     640                 :     {                                                                                                                                        
    +     641               5 :         $this->dirIterator = null;                                                                                                           
    +     642               5 :         return true;                                                                                                                         
    +     643                 :     }                                                                                                                                        
    +     644                 :                                                                                                                                              
    +     645                 :     /**                                                                                                                                      
    +     646                 :      * returns status of url                                                                                                                 
    +     647                 :      *                                                                                                                                       
    +     648                 :      * @param   string  $path   path of url to return status for                                                                             
    +     649                 :      * @param   ?       $flags  flags set by the stream API                                                                                  
    +     650                 :      * @return  array                                                                                                                        
    +     651                 :      */                                                                                                                                      
    +     652                 :     public function url_stat($path, $flags)                                                                                                  
    +     653                 :     {                                                                                                                                        
    +     654              31 :         $path    = $this->resolvePath(vfsStream::path($path));                                                                               
    +     655              31 :         $content = $this->getContent($path);                                                                                                 
    +     656              31 :         if (null === $content) {                                                                                                             
    +     657              13 :             if (!($flags & STREAM_URL_STAT_QUIET)) {                                                                                         
    +     658               0 :                 trigger_error(' No such file or directory', E_USER_WARNING);                                                                 
    +     659               0 :             }                                                                                                                                
    +     660              13 :             return false;                                                                                                                    
    +     661                 :                                                                                                                                              
    +     662                 :         }                                                                                                                                    
    +     663                 :                                                                                                                                              
    +     664              28 :         $fileStat = array('dev'     => 0,                                                                                                    
    +     665              28 :                           'ino'     => 0,                                                                                                    
    +     666              28 :                           'mode'    => $content->getType() | $content->getPermissions(),                                                     
    +     667              28 :                           'nlink'   => 0,                                                                                                    
    +     668              28 :                           'uid'     => $content->getUser(),                                                                                  
    +     669              28 :                           'gid'     => $content->getGroup(),                                                                                 
    +     670              28 :                           'rdev'    => 0,                                                                                                    
    +     671              28 :                           'size'    => $content->size(),                                                                                     
    +     672              28 :                           'atime'   => $content->filemtime(),                                                                                
    +     673              28 :                           'mtime'   => $content->filemtime(),                                                                                
    +     674              28 :                           'ctime'   => $content->filemtime(),                                                                                
    +     675              28 :                           'blksize' => -1,                                                                                                   
    +     676               0 :                           'blocks'  => -1                                                                                                    
    +     677              28 :                     );                                                                                                                       
    +     678              28 :         return array_merge(array_values($fileStat), $fileStat);                                                                              
    +     679                 :     }                                                                                                                                        
    +     680                 : }                                                                                                                                            
    +
    +
    +
    + + + + +
    Generated by PHPUnit 3.4.15 and Xdebug 2.0.5 using PHP 5.2.5 at Fri Oct 8 12:16:32 CEST 2010.
    + +
    + + + + diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/yahoo-dom-event.js b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/yahoo-dom-event.js new file mode 100644 index 0000000..68586b2 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/coverage/yahoo-dom-event.js @@ -0,0 +1,14 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +if(typeof YAHOO=="undefined"||!YAHOO){var YAHOO={};}YAHOO.namespace=function(){var A=arguments,E=null,C,B,D;for(C=0;C0)?B.dump(I[K],N-1):Q);}else{P.push(I[K]);}P.push(O);}if(P.length>1){P.pop();}P.push("]");}else{P.push("{");for(K in I){if(B.hasOwnProperty(I,K)){P.push(K+L);if(B.isObject(I[K])){P.push((N>0)?B.dump(I[K],N-1):Q);}else{P.push(I[K]);}P.push(O);}}if(P.length>1){P.pop();}P.push("}");}return P.join("");},substitute:function(Y,J,R){var N,M,L,U,V,X,T=[],K,O="dump",S=" ",I="{",W="}",Q,P;for(;;){N=Y.lastIndexOf(I);if(N<0){break;}M=Y.indexOf(W,N);if(N+1>=M){break;}K=Y.substring(N+1,M);U=K;X=null;L=U.indexOf(S);if(L>-1){X=U.substring(L+1);U=U.substring(0,L);}V=J[U];if(R){V=R(U,V,X);}if(B.isObject(V)){if(B.isArray(V)){V=B.dump(V,parseInt(X,10));}else{X=X||"";Q=X.indexOf(O);if(Q>-1){X=X.substring(4);}P=V.toString();if(P===G||Q>-1){V=B.dump(V,parseInt(X,10));}else{V=P;}}}else{if(!B.isString(V)&&!B.isNumber(V)){V="~-"+T.length+"-~";T[T.length]=K;}}Y=Y.substring(0,N)+V+Y.substring(M+1);}for(N=T.length-1;N>=0;N=N-1){Y=Y.replace(new RegExp("~-"+N+"-~"),"{"+T[N]+"}","g");}return Y;},trim:function(I){try{return I.replace(/^\s+|\s+$/g,"");}catch(J){return I;}},merge:function(){var L={},J=arguments,I=J.length,K;for(K=0;K519)?true:false);while((G=G[u])){z[0]+=G[b];z[1]+=G[P];if(AC){z=E.Dom._calcBorders(G,z);}}if(E.Dom._getStyle(y,p)!==f){G=y;while((G=G[Z])&&G[C]){AA=G[i];AB=G[O];if(H&&(E.Dom._getStyle(G,"overflow")!=="visible")){z=E.Dom._calcBorders(G,z);}if(AA||AB){z[0]-=AB;z[1]-=AA;}}z[0]+=x;z[1]+=Y;}else{if(D){z[0]-=x;z[1]-=Y;}else{if(I||H){z[0]+=x;z[1]+=Y;}}}z[0]=Math.floor(z[0]);z[1]=Math.floor(z[1]);}else{}return z;};}}(),getX:function(G){var Y=function(x){return E.Dom.getXY(x)[0];};return E.Dom.batch(G,Y,E.Dom,true);},getY:function(G){var Y=function(x){return E.Dom.getXY(x)[1];};return E.Dom.batch(G,Y,E.Dom,true);},setXY:function(G,x,Y){E.Dom.batch(G,E.Dom._setXY,{pos:x,noRetry:Y});},_setXY:function(G,z){var AA=E.Dom._getStyle(G,p),y=E.Dom.setStyle,AD=z.pos,Y=z.noRetry,AB=[parseInt(E.Dom.getComputedStyle(G,j),10),parseInt(E.Dom.getComputedStyle(G,o),10)],AC,x;if(AA=="static"){AA=V;y(G,p,AA);}AC=E.Dom._getXY(G);if(!AD||AC===false){return false;}if(isNaN(AB[0])){AB[0]=(AA==V)?0:G[b];}if(isNaN(AB[1])){AB[1]=(AA==V)?0:G[P];}if(AD[0]!==null){y(G,j,AD[0]-AC[0]+AB[0]+"px");}if(AD[1]!==null){y(G,o,AD[1]-AC[1]+AB[1]+"px");}if(!Y){x=E.Dom._getXY(G);if((AD[0]!==null&&x[0]!=AD[0])||(AD[1]!==null&&x[1]!=AD[1])){E.Dom._setXY(G,{pos:AD,noRetry:true});}}},setX:function(Y,G){E.Dom.setXY(Y,[G,null]);},setY:function(G,Y){E.Dom.setXY(G,[null,Y]);},getRegion:function(G){var Y=function(x){var y=false;if(E.Dom._canPosition(x)){y=E.Region.getRegion(x);}else{}return y;};return E.Dom.batch(G,Y,E.Dom,true);},getClientWidth:function(){return E.Dom.getViewportWidth();},getClientHeight:function(){return E.Dom.getViewportHeight();},getElementsByClassName:function(AB,AF,AC,AE,x,AD){AF=AF||"*";AC=(AC)?E.Dom.get(AC):null||K;if(!AC){return[];}var Y=[],G=AC.getElementsByTagName(AF),z=E.Dom.hasClass;for(var y=0,AA=G.length;y-1;}}else{}return G;},addClass:function(Y,G){return E.Dom.batch(Y,E.Dom._addClass,G);},_addClass:function(x,Y){var G=false,y;if(x&&Y){y=E.Dom._getAttribute(x,F)||J;if(!E.Dom._hasClass(x,Y)){E.Dom.setAttribute(x,F,A(y+B+Y));G=true;}}else{}return G;},removeClass:function(Y,G){return E.Dom.batch(Y,E.Dom._removeClass,G);},_removeClass:function(y,x){var Y=false,AA,z,G;if(y&&x){AA=E.Dom._getAttribute(y,F)||J;E.Dom.setAttribute(y,F,AA.replace(E.Dom._getClassRegex(x),J));z=E.Dom._getAttribute(y,F);if(AA!==z){E.Dom.setAttribute(y,F,A(z));Y=true;if(E.Dom._getAttribute(y,F)===""){G=(y.hasAttribute&&y.hasAttribute(g))?g:F; +y.removeAttribute(G);}}}else{}return Y;},replaceClass:function(x,Y,G){return E.Dom.batch(x,E.Dom._replaceClass,{from:Y,to:G});},_replaceClass:function(y,x){var Y,AB,AA,G=false,z;if(y&&x){AB=x.from;AA=x.to;if(!AA){G=false;}else{if(!AB){G=E.Dom._addClass(y,x.to);}else{if(AB!==AA){z=E.Dom._getAttribute(y,F)||J;Y=(B+z.replace(E.Dom._getClassRegex(AB),B+AA)).split(E.Dom._getClassRegex(AA));Y.splice(1,0,B+AA);E.Dom.setAttribute(y,F,A(Y.join(J)));G=true;}}}}else{}return G;},generateId:function(G,x){x=x||"yui-gen";var Y=function(y){if(y&&y.id){return y.id;}var z=x+YAHOO.env._id_counter++;if(y){if(y[e]&&y[e].getElementById(z)){return E.Dom.generateId(y,z+x);}y.id=z;}return z;};return E.Dom.batch(G,Y,E.Dom,true)||Y.apply(E.Dom,arguments);},isAncestor:function(Y,x){Y=E.Dom.get(Y);x=E.Dom.get(x);var G=false;if((Y&&x)&&(Y[l]&&x[l])){if(Y.contains&&Y!==x){G=Y.contains(x);}else{if(Y.compareDocumentPosition){G=!!(Y.compareDocumentPosition(x)&16);}}}else{}return G;},inDocument:function(G,Y){return E.Dom._inDoc(E.Dom.get(G),Y);},_inDoc:function(Y,x){var G=false;if(Y&&Y[C]){x=x||Y[e];G=E.Dom.isAncestor(x[v],Y);}else{}return G;},getElementsBy:function(Y,AF,AB,AD,y,AC,AE){AF=AF||"*";AB=(AB)?E.Dom.get(AB):null||K;if(!AB){return[];}var x=[],G=AB.getElementsByTagName(AF);for(var z=0,AA=G.length;z=8&&K.documentElement.hasAttribute){E.Dom.DOT_ATTRIBUTES.type=true;}})();YAHOO.util.Region=function(C,D,A,B){this.top=C;this.y=C;this[1]=C;this.right=D;this.bottom=A;this.left=B;this.x=B;this[0]=B; +this.width=this.right-this.left;this.height=this.bottom-this.top;};YAHOO.util.Region.prototype.contains=function(A){return(A.left>=this.left&&A.right<=this.right&&A.top>=this.top&&A.bottom<=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(E){var C=Math.max(this.top,E.top),D=Math.min(this.right,E.right),A=Math.min(this.bottom,E.bottom),B=Math.max(this.left,E.left);if(A>=C&&D>=B){return new YAHOO.util.Region(C,D,A,B);}else{return null;}};YAHOO.util.Region.prototype.union=function(E){var C=Math.min(this.top,E.top),D=Math.max(this.right,E.right),A=Math.max(this.bottom,E.bottom),B=Math.min(this.left,E.left);return new YAHOO.util.Region(C,D,A,B);};YAHOO.util.Region.prototype.toString=function(){return("Region {"+"top: "+this.top+", right: "+this.right+", bottom: "+this.bottom+", left: "+this.left+", height: "+this.height+", width: "+this.width+"}");};YAHOO.util.Region.getRegion=function(D){var F=YAHOO.util.Dom.getXY(D),C=F[1],E=F[0]+D.offsetWidth,A=F[1]+D.offsetHeight,B=F[0];return new YAHOO.util.Region(C,E,A,B);};YAHOO.util.Point=function(A,B){if(YAHOO.lang.isArray(A)){B=A[1];A=A[0];}YAHOO.util.Point.superclass.constructor.call(this,B,A,B,A);};YAHOO.extend(YAHOO.util.Point,YAHOO.util.Region);(function(){var B=YAHOO.util,A="clientTop",F="clientLeft",J="parentNode",K="right",W="hasLayout",I="px",U="opacity",L="auto",D="borderLeftWidth",G="borderTopWidth",P="borderRightWidth",V="borderBottomWidth",S="visible",Q="transparent",N="height",E="width",H="style",T="currentStyle",R=/^width|height$/,O=/^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,M={get:function(X,Z){var Y="",a=X[T][Z];if(Z===U){Y=B.Dom.getStyle(X,U);}else{if(!a||(a.indexOf&&a.indexOf(I)>-1)){Y=a;}else{if(B.Dom.IE_COMPUTED[Z]){Y=B.Dom.IE_COMPUTED[Z](X,Z);}else{if(O.test(a)){Y=B.Dom.IE.ComputedStyle.getPixel(X,Z);}else{Y=a;}}}}return Y;},getOffset:function(Z,e){var b=Z[T][e],X=e.charAt(0).toUpperCase()+e.substr(1),c="offset"+X,Y="pixel"+X,a="",d;if(b==L){d=Z[c];if(d===undefined){a=0;}a=d;if(R.test(e)){Z[H][e]=d;if(Z[c]>d){a=d-(Z[c]-d);}Z[H][e]=L;}}else{if(!Z[H][Y]&&!Z[H][e]){Z[H][e]=b;}a=Z[H][Y];}return a+I;},getBorderWidth:function(X,Z){var Y=null;if(!X[T][W]){X[H].zoom=1;}switch(Z){case G:Y=X[A];break;case V:Y=X.offsetHeight-X.clientHeight-X[A];break;case D:Y=X[F];break;case P:Y=X.offsetWidth-X.clientWidth-X[F];break;}return Y+I;},getPixel:function(Y,X){var a=null,b=Y[T][K],Z=Y[T][X];Y[H][K]=Z;a=Y[H].pixelRight;Y[H][K]=b;return a+I;},getMargin:function(Y,X){var Z;if(Y[T][X]==L){Z=0+I;}else{Z=B.Dom.IE.ComputedStyle.getPixel(Y,X);}return Z;},getVisibility:function(Y,X){var Z;while((Z=Y[T])&&Z[X]=="inherit"){Y=Y[J];}return(Z)?Z[X]:S;},getColor:function(Y,X){return B.Dom.Color.toRGB(Y[T][X])||Q;},getBorderColor:function(Y,X){var Z=Y[T],a=Z[X]||Z.color;return B.Dom.Color.toRGB(B.Dom.Color.toHex(a));}},C={};C.top=C.right=C.bottom=C.left=C[E]=C[N]=M.getOffset;C.color=M.getColor;C[G]=C[P]=C[V]=C[D]=M.getBorderWidth;C.marginTop=C.marginRight=C.marginBottom=C.marginLeft=M.getMargin;C.visibility=M.getVisibility;C.borderColor=C.borderTopColor=C.borderRightColor=C.borderBottomColor=C.borderLeftColor=M.getBorderColor;B.Dom.IE_COMPUTED=C;B.Dom.IE_ComputedStyle=M;})();(function(){var C="toString",A=parseInt,B=RegExp,D=YAHOO.util;D.Dom.Color={KEYWORDS:{black:"000",silver:"c0c0c0",gray:"808080",white:"fff",maroon:"800000",red:"f00",purple:"800080",fuchsia:"f0f",green:"008000",lime:"0f0",olive:"808000",yellow:"ff0",navy:"000080",blue:"00f",teal:"008080",aqua:"0ff"},re_RGB:/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,re_hex:/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,re_hex3:/([0-9A-F])/gi,toRGB:function(E){if(!D.Dom.Color.re_RGB.test(E)){E=D.Dom.Color.toHex(E);}if(D.Dom.Color.re_hex.exec(E)){E="rgb("+[A(B.$1,16),A(B.$2,16),A(B.$3,16)].join(", ")+")";}return E;},toHex:function(H){H=D.Dom.Color.KEYWORDS[H]||H;if(D.Dom.Color.re_RGB.exec(H)){var G=(B.$1.length===1)?"0"+B.$1:Number(B.$1),F=(B.$2.length===1)?"0"+B.$2:Number(B.$2),E=(B.$3.length===1)?"0"+B.$3:Number(B.$3);H=[G[C](16),F[C](16),E[C](16)].join("");}if(H.length<6){H=H.replace(D.Dom.Color.re_hex3,"$1$1");}if(H!=="transparent"&&H.indexOf("#")<0){H="#"+H;}return H.toLowerCase();}};}());YAHOO.register("dom",YAHOO.util.Dom,{version:"2.8.0r4",build:"2449"});YAHOO.util.CustomEvent=function(D,C,B,A,E){this.type=D;this.scope=C||window;this.silent=B;this.fireOnce=E;this.fired=false;this.firedWith=null;this.signature=A||YAHOO.util.CustomEvent.LIST;this.subscribers=[];if(!this.silent){}var F="_YUICEOnSubscribe";if(D!==F){this.subscribeEvent=new YAHOO.util.CustomEvent(F,this,true);}this.lastError=null;};YAHOO.util.CustomEvent.LIST=0;YAHOO.util.CustomEvent.FLAT=1;YAHOO.util.CustomEvent.prototype={subscribe:function(B,C,D){if(!B){throw new Error("Invalid callback for subscriber to '"+this.type+"'");}if(this.subscribeEvent){this.subscribeEvent.fire(B,C,D);}var A=new YAHOO.util.Subscriber(B,C,D);if(this.fireOnce&&this.fired){this.notify(A,this.firedWith);}else{this.subscribers.push(A);}},unsubscribe:function(D,F){if(!D){return this.unsubscribeAll();}var E=false;for(var B=0,A=this.subscribers.length;B0){H=C[0];}try{B=F.fn.call(E,H,F.obj);}catch(G){this.lastError=G;if(A){throw G;}}}else{try{B=F.fn.call(E,this.type,C,F.obj);}catch(D){this.lastError=D;if(A){throw D;}}}return B;},unsubscribeAll:function(){var A=this.subscribers.length,B;for(B=A-1;B>-1;B--){this._delete(B);}this.subscribers=[];return A;},_delete:function(A){var B=this.subscribers[A];if(B){delete B.fn;delete B.obj;}this.subscribers.splice(A,1);},toString:function(){return"CustomEvent: "+"'"+this.type+"', "+"context: "+this.scope;}};YAHOO.util.Subscriber=function(A,B,C){this.fn=A;this.obj=YAHOO.lang.isUndefined(B)?null:B;this.overrideContext=C;};YAHOO.util.Subscriber.prototype.getScope=function(A){if(this.overrideContext){if(this.overrideContext===true){return this.obj;}else{return this.overrideContext;}}return A;};YAHOO.util.Subscriber.prototype.contains=function(A,B){if(B){return(this.fn==A&&this.obj==B);}else{return(this.fn==A);}};YAHOO.util.Subscriber.prototype.toString=function(){return"Subscriber { obj: "+this.obj+", overrideContext: "+(this.overrideContext||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var G=false,H=[],J=[],A=0,E=[],B=0,C={63232:38,63233:40,63234:37,63235:39,63276:33,63277:34,25:9},D=YAHOO.env.ua.ie,F="focusin",I="focusout";return{POLL_RETRYS:500,POLL_INTERVAL:40,EL:0,TYPE:1,FN:2,WFN:3,UNLOAD_OBJ:3,ADJ_SCOPE:4,OBJ:5,OVERRIDE:6,CAPTURE:7,lastError:null,isSafari:YAHOO.env.ua.webkit,webkit:YAHOO.env.ua.webkit,isIE:D,_interval:null,_dri:null,_specialTypes:{focusin:(D?"focusin":"focus"),focusout:(D?"focusout":"blur")},DOMReady:false,throwErrors:false,startInterval:function(){if(!this._interval){this._interval=YAHOO.lang.later(this.POLL_INTERVAL,this,this._tryPreloadAttach,null,true);}},onAvailable:function(Q,M,O,P,N){var K=(YAHOO.lang.isString(Q))?[Q]:Q;for(var L=0;L-1;M--){S=(this.removeListener(L[M],K,R)&&S);}return S;}}if(!R||!R.call){return this.purgeElement(L,false,K);}if("unload"==K){for(M=J.length-1;M>-1;M--){U=J[M];if(U&&U[0]==L&&U[1]==K&&U[2]==R){J.splice(M,1);return true;}}return false;}var N=null;var O=arguments[3];if("undefined"===typeof O){O=this._getCacheIndex(H,L,K,R);}if(O>=0){N=H[O];}if(!L||!N){return false;}var T=N[this.CAPTURE]===true?true:false;try{this._simpleRemove(L,K,N[this.WFN],T);}catch(Q){this.lastError=Q;return false;}delete H[O][this.WFN];delete H[O][this.FN];H.splice(O,1);return true;},getTarget:function(M,L){var K=M.target||M.srcElement;return this.resolveTextNode(K);},resolveTextNode:function(L){try{if(L&&3==L.nodeType){return L.parentNode;}}catch(K){}return L;},getPageX:function(L){var K=L.pageX;if(!K&&0!==K){K=L.clientX||0;if(this.isIE){K+=this._getScrollLeft();}}return K;},getPageY:function(K){var L=K.pageY;if(!L&&0!==L){L=K.clientY||0;if(this.isIE){L+=this._getScrollTop();}}return L;},getXY:function(K){return[this.getPageX(K),this.getPageY(K)];},getRelatedTarget:function(L){var K=L.relatedTarget;if(!K){if(L.type=="mouseout"){K=L.toElement; +}else{if(L.type=="mouseover"){K=L.fromElement;}}}return this.resolveTextNode(K);},getTime:function(M){if(!M.time){var L=new Date().getTime();try{M.time=L;}catch(K){this.lastError=K;return L;}}return M.time;},stopEvent:function(K){this.stopPropagation(K);this.preventDefault(K);},stopPropagation:function(K){if(K.stopPropagation){K.stopPropagation();}else{K.cancelBubble=true;}},preventDefault:function(K){if(K.preventDefault){K.preventDefault();}else{K.returnValue=false;}},getEvent:function(M,K){var L=M||window.event;if(!L){var N=this.getEvent.caller;while(N){L=N.arguments[0];if(L&&Event==L.constructor){break;}N=N.caller;}}return L;},getCharCode:function(L){var K=L.keyCode||L.charCode||0;if(YAHOO.env.ua.webkit&&(K in C)){K=C[K];}return K;},_getCacheIndex:function(M,P,Q,O){for(var N=0,L=M.length;N0&&E.length>0);}var P=[];var R=function(T,U){var S=T;if(U.overrideContext){if(U.overrideContext===true){S=U.obj;}else{S=U.overrideContext;}}U.fn.call(S,U.obj);};var L,K,O,N,M=[];for(L=0,K=E.length;L-1;L--){O=E[L];if(!O||!O.id){E.splice(L,1);}}this.startInterval();}else{if(this._interval){this._interval.cancel();this._interval=null;}}this.locked=false;},purgeElement:function(O,P,R){var M=(YAHOO.lang.isString(O))?this.getEl(O):O;var Q=this.getListeners(M,R),N,K;if(Q){for(N=Q.length-1;N>-1;N--){var L=Q[N];this.removeListener(M,L.type,L.fn);}}if(P&&M&&M.childNodes){for(N=0,K=M.childNodes.length;N-1;N--){M=H[N];if(M){L.removeListener(M[L.EL],M[L.TYPE],M[L.FN],N);}}M=null;}L._simpleRemove(window,"unload",L._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var K=document.documentElement,L=document.body;if(K&&(K.scrollTop||K.scrollLeft)){return[K.scrollTop,K.scrollLeft];}else{if(L){return[L.scrollTop,L.scrollLeft];}else{return[0,0];}}},regCE:function(){},_simpleAdd:function(){if(window.addEventListener){return function(M,N,L,K){M.addEventListener(N,L,(K));};}else{if(window.attachEvent){return function(M,N,L,K){M.attachEvent("on"+N,L);};}else{return function(){};}}}(),_simpleRemove:function(){if(window.removeEventListener){return function(M,N,L,K){M.removeEventListener(N,L,(K));};}else{if(window.detachEvent){return function(L,M,K){L.detachEvent("on"+M,K);};}else{return function(){};}}}()};}();(function(){var EU=YAHOO.util.Event;EU.on=EU.addListener;EU.onFocus=EU.addFocusListener;EU.onBlur=EU.addBlurListener; +/* DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */ +if(EU.isIE){if(self!==self.top){document.onreadystatechange=function(){if(document.readyState=="complete"){document.onreadystatechange=null;EU._ready();}};}else{YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event,true);var n=document.createElement("p");EU._dri=setInterval(function(){try{n.doScroll("left");clearInterval(EU._dri);EU._dri=null;EU._ready();n=null;}catch(ex){}},EU.POLL_INTERVAL);}}else{if(EU.webkit&&EU.webkit<525){EU._dri=setInterval(function(){var rs=document.readyState;if("loaded"==rs||"complete"==rs){clearInterval(EU._dri);EU._dri=null;EU._ready();}},EU.POLL_INTERVAL);}else{EU._simpleAdd(document,"DOMContentLoaded",EU._ready);}}EU._simpleAdd(window,"load",EU._load);EU._simpleAdd(window,"unload",EU._unload);EU._tryPreloadAttach();})();}YAHOO.util.EventProvider=function(){};YAHOO.util.EventProvider.prototype={__yui_events:null,__yui_subscribers:null,subscribe:function(A,C,F,E){this.__yui_events=this.__yui_events||{};var D=this.__yui_events[A];if(D){D.subscribe(C,F,E);}else{this.__yui_subscribers=this.__yui_subscribers||{};var B=this.__yui_subscribers;if(!B[A]){B[A]=[];}B[A].push({fn:C,obj:F,overrideContext:E});}},unsubscribe:function(C,E,G){this.__yui_events=this.__yui_events||{};var A=this.__yui_events;if(C){var F=A[C];if(F){return F.unsubscribe(E,G);}}else{var B=true;for(var D in A){if(YAHOO.lang.hasOwnProperty(A,D)){B=B&&A[D].unsubscribe(E,G);}}return B;}return false;},unsubscribeAll:function(A){return this.unsubscribe(A); +},createEvent:function(B,G){this.__yui_events=this.__yui_events||{};var E=G||{},D=this.__yui_events,F;if(D[B]){}else{F=new YAHOO.util.CustomEvent(B,E.scope||this,E.silent,YAHOO.util.CustomEvent.FLAT,E.fireOnce);D[B]=F;if(E.onSubscribeCallback){F.subscribeEvent.subscribe(E.onSubscribeCallback);}this.__yui_subscribers=this.__yui_subscribers||{};var A=this.__yui_subscribers[B];if(A){for(var C=0;C + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/pmd-cpd.xml b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/pmd-cpd.xml new file mode 100644 index 0000000..2fe1c4e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/pmd-cpd.xml @@ -0,0 +1,2 @@ + + diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/pmd.xml b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/pmd.xml new file mode 100644 index 0000000..16bb737 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/docs/pmd.xml @@ -0,0 +1,11 @@ + + + + The cyclomatic complexity is 20. +Complexity is determined by the number of decision points in a function or method plus one for the function or method entry. The decision points are "if", "for", "foreach", "while", "case", "catch", "&&", "||", and "?:". Generally, 1-4 is low complexity, 5-7 indicates moderate complexity, 8-10 is high complexity, and 11+ is very high complexity. + The NPath complexity is 18954. +The NPath complexity of a function or method is the number of acyclic execution paths through that method. A threshold of 200 is generally considered the point where measures should be taken to reduce complexity. + The NPath complexity is 544. +The NPath complexity of a function or method is the number of acyclic execution paths through that method. A threshold of 200 is generally considered the point where measures should be taken to reduce complexity. + + diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/Example.php b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/Example.php new file mode 100644 index 0000000..42a4ce1 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/Example.php @@ -0,0 +1,55 @@ +id = $id; + } + + /** + * sets the directory + * + * @param string $directory + */ + public function setDirectory($directory) + { + $this->directory = $directory . DIRECTORY_SEPARATOR . $this->id; + if (file_exists($this->directory) === false) { + mkdir($this->directory, 0700, true); + } + } + + // more source code here... +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/ExampleTestCaseOldWay.php b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/ExampleTestCaseOldWay.php new file mode 100644 index 0000000..71b93c5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/ExampleTestCaseOldWay.php @@ -0,0 +1,50 @@ +assertFalse(file_exists(dirname(__FILE__) . '/id')); + $example->setDirectory(dirname(__FILE__)); + $this->assertTrue(file_exists(dirname(__FILE__) . '/id')); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/ExampleTestCaseWithVfsStream.php b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/ExampleTestCaseWithVfsStream.php new file mode 100644 index 0000000..2e1a2a0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/ExampleTestCaseWithVfsStream.php @@ -0,0 +1,39 @@ +assertFalse(vfsStreamWrapper::getRoot()->hasChild('id')); + $example->setDirectory(vfsStream::url('exampleDir')); + $this->assertTrue(vfsStreamWrapper::getRoot()->hasChild('id')); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FailureExample.php b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FailureExample.php new file mode 100644 index 0000000..eba4c24 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FailureExample.php @@ -0,0 +1,51 @@ +filename = $filename; + } + + /** + * sets the directory + * + * @param string $directory + */ + public function writeData($data) + { + $bytes = @file_put_contents($this->filename, $data); + if (false === $bytes) { + return 'could not write data'; + } + + return 'ok'; + } + + // more source code here... +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FailureExampleTestCase.php b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FailureExampleTestCase.php new file mode 100644 index 0000000..dead1a8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FailureExampleTestCase.php @@ -0,0 +1,60 @@ +assertSame('ok', $example->writeData('testdata')); + $this->assertTrue($root->hasChild('test.txt')); + $this->assertSame('testdata', $root->getChild('test.txt')->getContent()); + } + + /** + * can't write to file + */ + public function testNoWrite() + { + $root = new vfsStreamDirectory('exampleDir'); + $file = $this->getMock('vfsStreamFile', array('write'), array('test.txt')); + $file->setContent('notoverwritten'); + $file->expects($this->once()) + ->method('write') + ->will($this->returnValue(false)); + $root->addChild($file); + vfsStreamWrapper::setRoot($root); + $example = new FailureExample(vfsStream::url('exampleDir/test.txt')); + $this->assertSame('could not write data', $example->writeData('testdata')); + $this->assertTrue($root->hasChild('test.txt')); + $this->assertSame('notoverwritten', $root->getChild('test.txt')->getContent()); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FileModeExampleTestCaseOldWay.php b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FileModeExampleTestCaseOldWay.php new file mode 100644 index 0000000..303df90 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FileModeExampleTestCaseOldWay.php @@ -0,0 +1,69 @@ +setDirectory(dirname(__FILE__)); + if (DIRECTORY_SEPARATOR === '\\') { + // can not really test on windows, filemode from mkdir() is ignored + $this->assertEquals(40777, decoct(fileperms(dirname(__FILE__) . '/id'))); + } else { + $this->assertEquals(40700, decoct(fileperms(dirname(__FILE__) . '/id'))); + } + } + + /** + * test correct file mode for created directory + */ + public function testDirectoryHasCorrectDifferentFilePermissions() + { + $example = new FilemodeExample('id', 0755); + $example->setDirectory(dirname(__FILE__)); + if (DIRECTORY_SEPARATOR === '\\') { + // can not really test on windows, filemode from mkdir() is ignored + $this->assertEquals(40777, decoct(fileperms(dirname(__FILE__) . '/id'))); + } else { + $this->assertEquals(40755, decoct(fileperms(dirname(__FILE__) . '/id'))); + } + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilePermissionsExample.php b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilePermissionsExample.php new file mode 100644 index 0000000..69e20c6 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilePermissionsExample.php @@ -0,0 +1,30 @@ + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilePermissionsExampleTestCase.php b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilePermissionsExampleTestCase.php new file mode 100644 index 0000000..d0b19f2 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilePermissionsExampleTestCase.php @@ -0,0 +1,46 @@ +writeConfig(array('foo' => 'bar'), + vfsStream::url('exampleDir/writable.ini') + ); + + // assertions here + } + + /** + * @test + */ + public function directoryNotWritable() + { + vfsStream::setup('exampleDir', 0444); + $example = new FilePermissionsExample(); + $example->writeConfig(array('foo' => 'bar'), + vfsStream::url('exampleDir/notWritable.ini') + ); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilemodeExample.php b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilemodeExample.php new file mode 100644 index 0000000..0178576 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilemodeExample.php @@ -0,0 +1,63 @@ +id = $id; + $this->fileMode = $fileMode; + } + + /** + * sets the directory + * + * @param string $directory + */ + public function setDirectory($directory) + { + $this->directory = $directory . DIRECTORY_SEPARATOR . $this->id; + if (file_exists($this->directory) === false) { + mkdir($this->directory, $this->fileMode, true); + } + } + + // more source code here... +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilemodeExampleTestCaseWithVfsStream.php b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilemodeExampleTestCaseWithVfsStream.php new file mode 100644 index 0000000..c698097 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/docs/vfsStream/examples/FilemodeExampleTestCaseWithVfsStream.php @@ -0,0 +1,48 @@ +setDirectory(vfsStream::url('exampleDir')); + $this->assertEquals(0700, vfsStreamWrapper::getRoot()->getChild('id')->getPermissions()); + } + + /** + * test that the directory is created + */ + public function testDirectoryIsCreatedWithGivenPermissions() + { + $example = new FilemodeExample('id', 0755); + $example->setDirectory(vfsStream::url('exampleDir')); + $this->assertEquals(0755, vfsStreamWrapper::getRoot()->getChild('id')->getPermissions()); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/base.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/base.php new file mode 100644 index 0000000..925faf6 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/base.php @@ -0,0 +1,658 @@ +array) + */ + protected static $repositoryDirs = array(); + + /** + * This variable stores all the elements from the autoload arrays. When a + * new autoload file is loaded, their files are added to this array. + * + * @var array(string=>string) + */ + protected static $autoloadArray = array(); + + /** + * This variable stores all the elements from the autoload arrays for + * external repositories. When a new autoload file is loaded, their files + * are added to this array. + * + * @var array(string=>string) + */ + protected static $externalAutoloadArray = array(); + + /** + * Options for the ezcBase class. + * + * @var ezcBaseOptions + */ + static private $options; + + /** + * Associates an option object with this static class. + * + * @param ezcBaseAutoloadOptions $options + */ + static public function setOptions( ezcBaseAutoloadOptions $options ) + { + self::$options = $options; + } + + /** + * Tries to autoload the given className. If the className could be found + * this method returns true, otherwise false. + * + * This class caches the requested class names (including the ones who + * failed to load). + * + * @param string $className The name of the class that should be loaded. + * + * @return bool + */ + public static function autoload( $className ) + { + ezcBase::setPackageDir(); + + // Check whether the classname is already in the cached autoloadArray. + if ( array_key_exists( $className, ezcBase::$autoloadArray ) ) + { + // Is it registered as 'unloadable'? + if ( ezcBase::$autoloadArray[$className] == false ) + { + return false; + } + ezcBase::loadFile( ezcBase::$autoloadArray[$className] ); + + return true; + } + + // Check whether the classname is already in the cached autoloadArray + // for external repositories. + if ( array_key_exists( $className, ezcBase::$externalAutoloadArray ) ) + { + // Is it registered as 'unloadable'? + if ( ezcBase::$externalAutoloadArray[$className] == false ) + { + return false; + } + ezcBase::loadExternalFile( ezcBase::$externalAutoloadArray[$className] ); + + return true; + } + + // Not cached, so load the autoload from the package. + // Matches the first and optionally the second 'word' from the classname. + $fileNames = array(); + if ( preg_match( "/^([a-z0-9]*)([A-Z][a-z0-9]*)?([A-Z][a-z0-9]*)?/", $className, $matches ) !== false ) + { + $autoloadFile = ""; + // Try to match with both names, if available. + switch ( sizeof( $matches ) ) + { + case 4: + // check for x_y_autoload.php + $autoloadFile = strtolower( "{$matches[2]}_{$matches[3]}_autoload.php" ); + $fileNames[] = $autoloadFile; + if ( ezcBase::requireFile( $autoloadFile, $className, $matches[1] ) ) + { + return true; + } + // break intentionally missing. + + case 3: + // check for x_autoload.php + $autoloadFile = strtolower( "{$matches[2]}_autoload.php" ); + $fileNames[] = $autoloadFile; + if ( ezcBase::requireFile( $autoloadFile, $className, $matches[1] ) ) + { + return true; + } + // break intentionally missing. + + case 2: + // check for autoload.php + $autoloadFile = 'autoload.php'; + $fileNames[] = $autoloadFile; + if ( ezcBase::requireFile( $autoloadFile, $className, $matches[1] ) ) + { + return true; + } + break; + } + + // Maybe there is another autoload available. + // Register this classname as false. + ezcBase::$autoloadArray[$className] = false; + } + + $path = ezcBase::$packageDir . 'autoload/'; + $realPath = realpath( $path ); + + if ( $realPath == '' ) + { + // Can not be tested, because if this happens, then the autoload + // environment has not been set-up correctly. + trigger_error( "Couldn't find autoload directory '$path'", E_USER_ERROR ); + } + + $dirs = self::getRepositoryDirectories(); + if ( ezcBase::$options && ezcBase::$options->debug ) + { + throw new ezcBaseAutoloadException( $className, $fileNames, $dirs ); + } + + return false; + } + + /** + * Sets the current working directory to $directory. + * + * @param string $directory + */ + public static function setWorkingDirectory( $directory ) + { + self::$libraryMode = 'custom'; + self::$currentWorkingDirectory = $directory; + } + + /** + * Figures out the base path of the eZ Components installation. + * + * It stores the path that it finds in a static member variable. The path + * depends on the installation method of the eZ Components. The SVN version + * has a different path than the PEAR installed version. + */ + protected static function setPackageDir() + { + if ( ezcBase::$packageDir !== null ) + { + return; + } + + // Get the path to the components. + $baseDir = dirname( __FILE__ ); + + switch ( ezcBase::$libraryMode ) + { + case "custom": + ezcBase::$packageDir = self::$currentWorkingDirectory . '/'; + break; + case "devel": + case "tarball": + ezcBase::$packageDir = $baseDir. "/../../"; + break; + case "pear"; + ezcBase::$packageDir = $baseDir. "/../"; + break; + } + } + + /** + * Tries to load the autoload array and, if loaded correctly, includes the class. + * + * @param string $fileName Name of the autoload file. + * @param string $className Name of the class that should be autoloaded. + * @param string $prefix The prefix of the class repository. + * + * @return bool True is returned when the file is correctly loaded. + * Otherwise false is returned. + */ + protected static function requireFile( $fileName, $className, $prefix ) + { + $autoloadDir = ezcBase::$packageDir . "autoload/"; + + // We need the full path to the fileName. The method file_exists() doesn't + // automatically check the (php.ini) library paths. Therefore: + // file_exists( "ezc/autoload/$fileName" ) doesn't work. + if ( $prefix === 'ezc' && file_exists( "$autoloadDir$fileName" ) ) + { + $array = require( "$autoloadDir$fileName" ); + + if ( is_array( $array) && array_key_exists( $className, $array ) ) + { + // Add the array to the cache, and include the requested file. + ezcBase::$autoloadArray = array_merge( ezcBase::$autoloadArray, $array ); + if ( ezcBase::$options !== null && ezcBase::$options->preload && !preg_match( '/Exception$/', $className ) ) + { + foreach ( $array as $loadClassName => $file ) + { + if ( $loadClassName !== 'ezcBase' && !class_exists( $loadClassName, false ) && !interface_exists( $loadClassName, false ) && !preg_match( '/Exception$/', $loadClassName ) /*&& !class_exists( $loadClassName, false ) && !interface_exists( $loadClassName, false )*/ ) + { + ezcBase::loadFile( ezcBase::$autoloadArray[$loadClassName] ); + } + } + } + else + { + ezcBase::loadFile( ezcBase::$autoloadArray[$className] ); + } + return true; + } + } + + // It is not in components autoload/ dir. + // try to search in additional dirs. + foreach ( ezcBase::$repositoryDirs as $repositoryPrefix => $extraDir ) + { + if ( gettype( $repositoryPrefix ) === 'string' && $repositoryPrefix !== $prefix ) + { + continue; + } + + if ( file_exists( $extraDir['autoloadDirPath'] . '/' . $fileName ) ) + { + $array = array(); + $originalArray = require( $extraDir['autoloadDirPath'] . '/' . $fileName ); + + // Building paths. + // Resulting path to class definition file consists of: + // path to extra directory with autoload file + + // basePath provided for current extra directory + + // path to class definition file stored in autoload file. + foreach ( $originalArray as $class => $classPath ) + { + $array[$class] = $extraDir['basePath'] . '/' . $classPath; + } + + if ( is_array( $array ) && array_key_exists( $className, $array ) ) + { + // Add the array to the cache, and include the requested file. + ezcBase::$externalAutoloadArray = array_merge( ezcBase::$externalAutoloadArray, $array ); + ezcBase::loadExternalFile( ezcBase::$externalAutoloadArray[$className] ); + return true; + } + } + } + + // Nothing found :-(. + return false; + } + + /** + * Loads, require(), the given file name. If we are in development mode, + * "/src/" is inserted into the path. + * + * @param string $file The name of the file that should be loaded. + */ + protected static function loadFile( $file ) + { + switch ( ezcBase::$libraryMode ) + { + case "devel": + case "tarball": + list( $first, $second ) = explode( '/', $file, 2 ); + $file = $first . "/src/" . $second; + break; + + case "custom": + list( $first, $second ) = explode( '/', $file, 2 ); + // Add the "src/" after the package name. + if ( $first == 'Base' || $first == 'UnitTest' ) + { + list( $first, $second ) = explode( '/', $file, 2 ); + $file = $first . "/src/" . $second; + } + else + { + list( $first, $second, $third ) = explode( '/', $file, 3 ); + $file = $first . '/' . $second . "/src/" . $third; + } + break; + + case "pear": + /* do nothing, it's already correct */ + break; + } + + if ( file_exists( ezcBase::$packageDir . $file ) ) + { + require( ezcBase::$packageDir . $file ); + } + else + { + // Can not be tested, because if this happens, then one of the + // components has a broken autoload file. + throw new ezcBaseFileNotFoundException( ezcBase::$packageDir.$file ); + } + } + + /** + * Loads, require(), the given file name from an external package. + * + * @param string $file The name of the file that should be loaded. + */ + protected static function loadExternalFile( $file ) + { + if ( file_exists( $file ) ) + { + require( $file ); + } + else + { + throw new ezcBaseFileNotFoundException( $file ); + } + } + + /** + * Checks for dependencies on PHP versions or extensions + * + * The function as called by the $component component checks for the $type + * dependency. The dependency $type is compared against the $value. The + * function aborts the script if the dependency is not matched. + * + * @param string $component + * @param int $type + * @param mixed $value + */ + public static function checkDependency( $component, $type, $value ) + { + switch ( $type ) + { + case self::DEP_PHP_EXTENSION: + if ( extension_loaded( $value ) ) + { + return; + } + else + { + // Can not be tested as it would abort the PHP script. + die( "\nThe {$component} component depends on the default PHP extension '{$value}', which is not loaded.\n" ); + } + break; + + case self::DEP_PHP_VERSION: + $phpVersion = phpversion(); + if ( version_compare( $phpVersion, $value, '>=' ) ) + { + return; + } + else + { + // Can not be tested as it would abort the PHP script. + die( "\nThe {$component} component depends on the PHP version '{$value}', but the current version is '{$phpVersion}'.\n" ); + } + break; + } + } + + /** + * Return the list of directories that contain class repositories. + * + * The path to the eZ components directory is always included in the result + * array. Each element in the returned array has the format of: + * packageDirectory => ezcBaseRepositoryDirectory + * + * @return array(string=>ezcBaseRepositoryDirectory) + */ + public static function getRepositoryDirectories() + { + $autoloadDirs = array(); + ezcBase::setPackageDir(); + $repositoryDir = self::$currentWorkingDirectory ? self::$currentWorkingDirectory : ( realpath( dirname( __FILE__ ) . '/../../' ) ); + $autoloadDirs['ezc'] = new ezcBaseRepositoryDirectory( ezcBaseRepositoryDirectory::TYPE_INTERNAL, $repositoryDir, $repositoryDir . "/autoload" ); + + foreach ( ezcBase::$repositoryDirs as $extraDirKey => $extraDirArray ) + { + $repositoryDirectory = new ezcBaseRepositoryDirectory( ezcBaseRepositoryDirectory::TYPE_EXTERNAL, realpath( $extraDirArray['basePath'] ), realpath( $extraDirArray['autoloadDirPath'] ) ); + $autoloadDirs[$extraDirKey] = $repositoryDirectory; + } + + return $autoloadDirs; + } + + /** + * Adds an additional class repository. + * + * Used for adding class repositoryies outside the eZ components to be + * loaded by the autoload system. + * + * This function takes two arguments: $basePath is the base path for the + * whole class repository and $autoloadDirPath the path where autoload + * files for this repository are found. The paths in the autoload files are + * relative to the package directory as specified by the $basePath + * argument. I.e. class definition file will be searched at location + * $basePath + path to the class definition file as stored in the autoload + * file. + * + * addClassRepository() should be called somewhere in code before external classes + * are used. + * + * Example: + * Take the following facts: + *
      + *
    • there is a class repository stored in the directory "./repos"
    • + *
    • autoload files for that repository are stored in "./repos/autoloads"
    • + *
    • there are two components in this repository: "Me" and "You"
    • + *
    • the "Me" component has the classes "erMyClass1" and "erMyClass2"
    • + *
    • the "You" component has the classes "erYourClass1" and "erYourClass2"
    • + *
    + * + * In this case you would need to create the following files in + * "./repos/autoloads". Please note that the part before _autoload.php in + * the filename is the first part of the classname, not considering + * the all lower-case letter prefix. + * + * "my_autoload.php": + * + * 'Me/myclass1.php', + * 'erMyClass2' => 'Me/myclass2.php', + * ); + * ?> + * + * + * "your_autoload.php": + * + * 'You/yourclass1.php', + * 'erYourClass2' => 'You/yourclass2.php', + * ); + * ?> + * + * + * The directory structure for the external repository is then: + * + * ./repos/autoloads/my_autoload.php + * ./repos/autoloads/you_autoload.php + * ./repos/Me/myclass1.php + * ./repos/Me/myclass2.php + * ./repos/You/yourclass1.php + * ./repos/You/yourclass2.php + * + * + * To use this repository with the autoload mechanism you have to use the + * following code: + * + * + * + * + * @throws ezcBaseFileNotFoundException if $autoloadDirPath or $basePath do not exist. + * @param string $basePath + * @param string $autoloadDirPath + * @param string $prefix + */ + public static function addClassRepository( $basePath, $autoloadDirPath = null, $prefix = null ) + { + // check if base path exists + if ( !is_dir( $basePath ) ) + { + throw new ezcBaseFileNotFoundException( $basePath, 'base directory' ); + } + + // calculate autoload path if it wasn't given + if ( is_null( $autoloadDirPath ) ) + { + $autoloadDirPath = $basePath . '/autoload'; + } + + // check if autoload dir exists + if ( !is_dir( $autoloadDirPath ) ) + { + throw new ezcBaseFileNotFoundException( $autoloadDirPath, 'autoload directory' ); + } + + // add info to $repositoryDirs + if ( $prefix === null ) + { + $array = array( 'basePath' => $basePath, 'autoloadDirPath' => $autoloadDirPath ); + + // add info to the list of extra dirs + ezcBase::$repositoryDirs[] = $array; + } + else + { + if ( array_key_exists( $prefix, ezcBase::$repositoryDirs ) ) + { + throw new ezcBaseDoubleClassRepositoryPrefixException( $prefix, $basePath, $autoloadDirPath ); + } + + // add info to the list of extra dirs, and use the prefix to identify the new repository. + ezcBase::$repositoryDirs[$prefix] = array( 'basePath' => $basePath, 'autoloadDirPath' => $autoloadDirPath ); + } + } + + /** + * Returns the base path of the eZ Components installation + * + * This method returns the base path, including a trailing directory + * separator. + * + * @return string + */ + public static function getInstallationPath() + { + self::setPackageDir(); + + $path = realpath( self::$packageDir ); + if ( substr( $path, -1 ) !== DIRECTORY_SEPARATOR ) + { + $path .= DIRECTORY_SEPARATOR; + } + return $path; + } + + /** + * Sets the development mode to the one specified. + * + * @param int $runMode + */ + public static function setRunMode( $runMode ) + { + if ( !in_array( $runMode, array( ezcBase::MODE_PRODUCTION, ezcBase::MODE_DEVELOPMENT ) ) ) + { + throw new ezcBaseValueException( 'runMode', $runMode, 'ezcBase::MODE_PRODUCTION or ezcBase::MODE_DEVELOPMENT' ); + } + + self::$runMode = $runMode; + } + + /** + * Returns the current development mode. + * + * @return int + */ + public static function getRunMode() + { + return self::$runMode; + } + + /** + * Returns true when we are in development mode. + * + * @return bool + */ + public static function inDevMode() + { + return self::$runMode == ezcBase::MODE_DEVELOPMENT; + } + + /** + * Returns the installation method + * + * Possible return values are 'custom', 'devel', 'tarball' and 'pear'. Only + * 'tarball' and 'pear' are returned for user-installed versions. + * + * @return string + */ + public static function getInstallMethod() + { + return self::$libraryMode; + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/base_autoload.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/base_autoload.php new file mode 100644 index 0000000..b6575e0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/base_autoload.php @@ -0,0 +1,47 @@ + 'Base/exceptions/exception.php', + 'ezcBaseFileException' => 'Base/exceptions/file_exception.php', + 'ezcBaseAutoloadException' => 'Base/exceptions/autoload.php', + 'ezcBaseDoubleClassRepositoryPrefixException' => 'Base/exceptions/double_class_repository_prefix.php', + 'ezcBaseExtensionNotFoundException' => 'Base/exceptions/extension_not_found.php', + 'ezcBaseFileIoException' => 'Base/exceptions/file_io.php', + 'ezcBaseFileNotFoundException' => 'Base/exceptions/file_not_found.php', + 'ezcBaseFilePermissionException' => 'Base/exceptions/file_permission.php', + 'ezcBaseFunctionalityNotSupportedException' => 'Base/exceptions/functionality_not_supported.php', + 'ezcBaseInitCallbackConfiguredException' => 'Base/exceptions/init_callback_configured.php', + 'ezcBaseInitInvalidCallbackClassException' => 'Base/exceptions/invalid_callback_class.php', + 'ezcBaseInvalidParentClassException' => 'Base/exceptions/invalid_parent_class.php', + 'ezcBasePropertyNotFoundException' => 'Base/exceptions/property_not_found.php', + 'ezcBasePropertyPermissionException' => 'Base/exceptions/property_permission.php', + 'ezcBaseSettingNotFoundException' => 'Base/exceptions/setting_not_found.php', + 'ezcBaseSettingValueException' => 'Base/exceptions/setting_value.php', + 'ezcBaseValueException' => 'Base/exceptions/value.php', + 'ezcBaseWhateverException' => 'Base/exceptions/whatever.php', + 'ezcBaseOptions' => 'Base/options.php', + 'ezcBaseStruct' => 'Base/struct.php', + 'ezcBase' => 'Base/base.php', + 'ezcBaseAutoloadOptions' => 'Base/options/autoload.php', + 'ezcBaseConfigurationInitializer' => 'Base/interfaces/configuration_initializer.php', + 'ezcBaseExportable' => 'Base/interfaces/exportable.php', + 'ezcBaseFeatures' => 'Base/features.php', + 'ezcBaseFile' => 'Base/file.php', + 'ezcBaseFileFindContext' => 'Base/structs/file_find_context.php', + 'ezcBaseInit' => 'Base/init.php', + 'ezcBaseMetaData' => 'Base/metadata.php', + 'ezcBaseMetaDataPearReader' => 'Base/metadata/pear.php', + 'ezcBaseMetaDataTarballReader' => 'Base/metadata/tarball.php', + 'ezcBasePersistable' => 'Base/interfaces/persistable.php', + 'ezcBaseRepositoryDirectory' => 'Base/structs/repository_directory.php', +); +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/autoload.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/autoload.php new file mode 100644 index 0000000..e993896 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/autoload.php @@ -0,0 +1,38 @@ +autoloadPath ); + } + parent::__construct( "Could not find a class to file mapping for '{$className}'. Searched for ". implode( ', ', $files ) . " in: " . implode( ', ', $paths ) ); + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/double_class_repository_prefix.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/double_class_repository_prefix.php new file mode 100644 index 0000000..71ca49e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/double_class_repository_prefix.php @@ -0,0 +1,34 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/exception.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/exception.php new file mode 100644 index 0000000..00c54f7 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/exception.php @@ -0,0 +1,43 @@ +originalMessage = $message; + + if ( php_sapi_name() == 'cli' ) + { + parent::__construct( $message ); + } + else + { + parent::__construct( htmlspecialchars( $message ) ); + } + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/extension_not_found.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/extension_not_found.php new file mode 100644 index 0000000..7aa7aa6 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/extension_not_found.php @@ -0,0 +1,38 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_exception.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_exception.php new file mode 100644 index 0000000..72905de --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_exception.php @@ -0,0 +1,25 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_io.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_io.php new file mode 100644 index 0000000..8b274ad --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_io.php @@ -0,0 +1,50 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_not_found.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_not_found.php new file mode 100644 index 0000000..e2a8c39 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_not_found.php @@ -0,0 +1,43 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_permission.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_permission.php new file mode 100644 index 0000000..e7b15df --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/file_permission.php @@ -0,0 +1,63 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/functionality_not_supported.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/functionality_not_supported.php new file mode 100644 index 0000000..0ba8959 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/functionality_not_supported.php @@ -0,0 +1,31 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/init_callback_configured.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/init_callback_configured.php new file mode 100644 index 0000000..db47ef0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/init_callback_configured.php @@ -0,0 +1,31 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/invalid_callback_class.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/invalid_callback_class.php new file mode 100644 index 0000000..0aff341 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/invalid_callback_class.php @@ -0,0 +1,31 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/invalid_parent_class.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/invalid_parent_class.php new file mode 100644 index 0000000..febe410 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/invalid_parent_class.php @@ -0,0 +1,29 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/property_not_found.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/property_not_found.php new file mode 100644 index 0000000..a16eb1d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/property_not_found.php @@ -0,0 +1,30 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/property_permission.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/property_permission.php new file mode 100644 index 0000000..1632e08 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/property_permission.php @@ -0,0 +1,42 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/setting_not_found.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/setting_not_found.php new file mode 100644 index 0000000..91673aa --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/setting_not_found.php @@ -0,0 +1,29 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/setting_value.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/setting_value.php new file mode 100644 index 0000000..be7b50a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/setting_value.php @@ -0,0 +1,42 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/value.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/value.php new file mode 100644 index 0000000..2f46b41 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/value.php @@ -0,0 +1,43 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/whatever.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/whatever.php new file mode 100644 index 0000000..8043ec0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/exceptions/whatever.php @@ -0,0 +1,40 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/ezc_bootstrap.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/ezc_bootstrap.php new file mode 100644 index 0000000..e3864f2 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/ezc_bootstrap.php @@ -0,0 +1,40 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/features.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/features.php new file mode 100644 index 0000000..e1fd85e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/features.php @@ -0,0 +1,365 @@ + + * + * + * + * @package Base + * @version 1.8 + */ +class ezcBaseFeatures +{ + /** + * Used to store the path of the ImageMagick convert utility. + * + * It is initialized in the {@link getImageConvertExecutable()} function. + * + * @var string + */ + private static $imageConvert = null; + + /** + * Used to store the path of the ImageMagick identify utility. + * + * It is initialized in the {@link getImageIdentifyExecutable()} function. + * + * @var string + */ + private static $imageIdentify = null; + + /** + * Used to store the operating system. + * + * It is initialized in the {@link os()} function. + * + * @var string + */ + private static $os = null; + + /** + * Determines if hardlinks are supported. + * + * @return bool + */ + public static function supportsLink() + { + return function_exists( 'link' ); + } + + /** + * Determines if symlinks are supported. + * + * @return bool + */ + public static function supportsSymLink() + { + return function_exists( 'symlink' ); + } + + /** + * Determines if posix uids are supported. + * + * @return bool + */ + public static function supportsUserId() + { + return function_exists( 'posix_getpwuid' ); + } + + /** + * Determines if the ImageMagick convert utility is installed. + * + * @return bool + */ + public static function hasImageConvert() + { + return !is_null( self::getImageConvertExecutable() ); + } + + /** + * Returns the path to the ImageMagick convert utility. + * + * On Linux, Unix,... it will return something like: /usr/bin/convert + * On Windows it will return something like: C:\Windows\System32\convert.exe + * + * @return string + */ + public static function getImageConvertExecutable() + { + if ( !is_null( self::$imageConvert ) ) + { + return self::$imageConvert; + } + return ( self::$imageConvert = self::findExecutableInPath( 'convert' ) ); + } + + /** + * Determines if the ImageMagick identify utility is installed. + * + * @return bool + */ + public static function hasImageIdentify() + { + return !is_null( self::getImageIdentifyExecutable() ); + } + + /** + * Returns the path to the ImageMagick identify utility. + * + * On Linux, Unix,... it will return something like: /usr/bin/identify + * On Windows it will return something like: C:\Windows\System32\identify.exe + * + * @return string + */ + public static function getImageIdentifyExecutable() + { + if ( !is_null( self::$imageIdentify ) ) + { + return self::$imageIdentify; + } + return ( self::$imageIdentify = self::findExecutableInPath( 'identify' ) ); + } + + /** + * Determines if the specified extension is loaded. + * + * If $version is specified, the specified extension will be tested also + * against the version of the loaded extension. + * + * Examples: + * + * hasExtensionSupport( 'gzip' ); + * + * will return true if gzip extension is loaded. + * + * + * hasExtensionSupport( 'pdo_mysql', '1.0.2' ); + * + * will return true if pdo_mysql extension is loaded and its version is at least 1.0.2. + * + * @param string $extension + * @param string $version + * @return bool + */ + public static function hasExtensionSupport( $extension, $version = null ) + { + if ( is_null( $version ) ) + { + return extension_loaded( $extension ); + } + return extension_loaded( $extension ) && version_compare( phpversion( $extension ), $version, ">=" ) ; + } + + /** + * Determines if the specified function is available. + * + * Examples: + * + * ezcBaseFeatures::hasFunction( 'imagepstext' ); + * + * will return true if support for Type 1 fonts is available with your GD + * extension. + * + * @param string $functionName + * @return bool + */ + public static function hasFunction( $functionName ) + { + return function_exists( $functionName ); + } + + /** + * Returns if a given class exists. + * Checks for a given class name and returns if this class exists or not. + * Catches the ezcBaseAutoloadException and returns false, if it was thrown. + * + * @param string $className The class to check for. + * @param bool $autoload True to use __autoload(), otherwise false. + * @return bool True if the class exists. Otherwise false. + */ + public static function classExists( $className, $autoload = true ) + { + try + { + if ( class_exists( $className, $autoload ) ) + { + return true; + } + return false; + } + catch ( ezcBaseAutoloadException $e ) + { + return false; + } + } + + /** + * Returns the operating system on which PHP is running. + * + * This method returns a sanitized form of the OS name, example + * return values are "Windows", "Mac", "Linux" and "FreeBSD". In + * all other cases it returns the value of the internal PHP constant + * PHP_OS. + * + * @return string + */ + public static function os() + { + if ( is_null( self::$os ) ) + { + $uname = php_uname( 's' ); + if ( substr( $uname, 0, 7 ) == 'Windows' ) + { + self::$os = 'Windows'; + } + elseif ( substr( $uname, 0, 3 ) == 'Mac' ) + { + self::$os = 'Mac'; + } + elseif ( strtolower( $uname ) == 'linux' ) + { + self::$os = 'Linux'; + } + elseif ( strtolower( substr( $uname, 0, 7 ) ) == 'freebsd' ) + { + self::$os = 'FreeBSD'; + } + else + { + self::$os = PHP_OS; + } + } + return self::$os; + } + + /** + * Returns the path of the specified executable, if it can be found in the system's path. + * + * It scans the PATH enviroment variable based on the OS to find the + * $fileName. For Windows, the path is with \, not /. If $fileName is not + * found, it returns null. + * + * @todo consider using getenv( 'PATH' ) instead of $_ENV['PATH'] + * (but that won't work under IIS) + * + * @param string $fileName + * @return string + */ + public static function findExecutableInPath( $fileName ) + { + if ( array_key_exists( 'PATH', $_ENV ) ) + { + $envPath = trim( $_ENV['PATH'] ); + } + else if ( ( $envPath = getenv( 'PATH' ) ) !== false ) + { + $envPath = trim( $envPath ); + } + if ( is_string( $envPath ) && strlen( trim( $envPath ) ) == 0 ) + { + $envPath = false; + } + + switch ( self::os() ) + { + case 'Unix': + case 'FreeBSD': + case 'Mac': + case 'MacOS': + case 'Darwin': + case 'Linux': + case 'SunOS': + if ( $envPath ) + { + $dirs = explode( ':', $envPath ); + foreach ( $dirs as $dir ) + { + // The @-operator is used here mainly to avoid + // open_basedir warnings. If open_basedir (or any other + // circumstance) prevents the desired file from being + // accessed, it is fine for file_exists() to return + // false, since it is useless for use then, anyway. + if ( file_exists( "{$dir}/{$fileName}" ) ) + { + return "{$dir}/{$fileName}"; + } + } + } + // The @-operator is used here mainly to avoid open_basedir + // warnings. If open_basedir (or any other circumstance) + // prevents the desired file from being accessed, it is fine + // for file_exists() to return false, since it is useless for + // use then, anyway. + elseif ( @file_exists( "./{$fileName}" ) ) + { + return $fileName; + } + break; + case 'Windows': + if ( $envPath ) + { + $dirs = explode( ';', $envPath ); + foreach ( $dirs as $dir ) + { + // The @-operator is used here mainly to avoid + // open_basedir warnings. If open_basedir (or any other + // circumstance) prevents the desired file from being + // accessed, it is fine for file_exists() to return + // false, since it is useless for use then, anyway. + if ( @file_exists( "{$dir}\\{$fileName}.exe" ) ) + { + return "{$dir}\\{$fileName}.exe"; + } + } + } + // The @-operator is used here mainly to avoid open_basedir + // warnings. If open_basedir (or any other circumstance) + // prevents the desired file from being accessed, it is fine + // for file_exists() to return false, since it is useless for + // use then, anyway. + elseif ( @file_exists( "{$fileName}.exe" ) ) + { + return "{$fileName}.exe"; + } + break; + } + return null; + } + + /** + * Reset the cached information. + * + * @return void + * @access private + * @ignore + */ + public static function reset() + { + self::$imageIdentify = null; + self::$imageConvert = null; + self::$os = null; + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/file.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/file.php new file mode 100644 index 0000000..843399c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/file.php @@ -0,0 +1,495 @@ + + * + * + * + * @package Base + * @version 1.8 + * @mainclass + */ +class ezcBaseFile +{ + /** + * This is the callback used by findRecursive to collect data. + * + * This callback method works together with walkRecursive() and is called + * for every file/and or directory. The $context is a callback specific + * container in which data can be stored and shared between the different + * calls to the callback function. The walkRecursive() function also passes + * in the full absolute directory in $sourceDir, the filename in $fileName + * and file information (such as size, modes, types) as an array as + * returned by PHP's stat() in the $fileInfo parameter. + * + * @param ezcBaseFileFindContext $context + * @param string $sourceDir + * @param string $fileName + * @param array(stat) $fileInfo + */ + static protected function findRecursiveCallback( ezcBaseFileFindContext $context, $sourceDir, $fileName, $fileInfo ) + { + // ignore if we have a directory + if ( $fileInfo['mode'] & 0x4000 ) + { + return; + } + + // update the statistics + $context->elements[] = $sourceDir . DIRECTORY_SEPARATOR . $fileName; + $context->count++; + $context->size += $fileInfo['size']; + } + + /** + * Walks files and directories recursively on a file system + * + * This method walks over a directory and calls a callback from every file + * and directory it finds. You can use $includeFilters to include only + * specific files, and $excludeFilters to exclude certain files from being + * returned. The function will always go into subdirectories even if the + * entry would not have passed the filters. + * + * The callback is passed in the $callback parameter, and the + * $callbackContext will be send to the callback function/method as + * parameter so that you can store data in there that persists with all the + * calls and recursive calls to this method. It's up to the callback method + * to do something useful with this. The callback function's parameters are + * in order: + * + *
      + *
    • ezcBaseFileFindContext $context
    • + *
    • string $sourceDir
    • + *
    • string $fileName
    • + *
    • array(stat) $fileInfo
    • + *
    + * + * See {@see findRecursiveCallback()} for an example of a callback function. + * + * Filters are regular expressions and are therefore required to have + * starting and ending delimiters. The Perl Compatible syntax is used as + * regular expression language. + * + * @param string $sourceDir + * @param array(string) $includeFilters + * @param array(string) $excludeFilters + * @param callback $callback + * @param mixed $callbackContext + * + * @throws ezcBaseFileNotFoundException if the $sourceDir directory is not + * a directory or does not exist. + * @throws ezcBaseFilePermissionException if the $sourceDir directory could + * not be opened for reading. + * @return array + */ + static public function walkRecursive( $sourceDir, array $includeFilters = array(), array $excludeFilters = array(), $callback, &$callbackContext ) + { + if ( !is_dir( $sourceDir ) ) + { + throw new ezcBaseFileNotFoundException( $sourceDir, 'directory' ); + } + $elements = array(); + $d = @dir( $sourceDir ); + if ( !$d ) + { + throw new ezcBaseFilePermissionException( $sourceDir, ezcBaseFileException::READ ); + } + + while ( ( $entry = $d->read() ) !== false ) + { + if ( $entry == '.' || $entry == '..' ) + { + continue; + } + + $fileInfo = @stat( $sourceDir . DIRECTORY_SEPARATOR . $entry ); + if ( !$fileInfo ) + { + $fileInfo = array( 'size' => 0, 'mode' => 0 ); + } + + if ( $fileInfo['mode'] & 0x4000 ) + { + // We need to ignore the Permission exceptions here as it can + // be normal that a directory can not be accessed. We only need + // the exception if the top directory could not be read. + try + { + call_user_func_array( $callback, array( $callbackContext, $sourceDir, $entry, $fileInfo ) ); + $subList = self::walkRecursive( $sourceDir . DIRECTORY_SEPARATOR . $entry, $includeFilters, $excludeFilters, $callback, $callbackContext ); + $elements = array_merge( $elements, $subList ); + } + catch ( ezcBaseFilePermissionException $e ) + { + } + } + else + { + // By default a file is included in the return list + $ok = true; + // Iterate over the $includeFilters and prohibit the file from + // being returned when atleast one of them does not match + foreach ( $includeFilters as $filter ) + { + if ( !preg_match( $filter, $sourceDir . DIRECTORY_SEPARATOR . $entry ) ) + { + $ok = false; + break; + } + } + // Iterate over the $excludeFilters and prohibit the file from + // being returns when atleast one of them matches + foreach ( $excludeFilters as $filter ) + { + if ( preg_match( $filter, $sourceDir . DIRECTORY_SEPARATOR . $entry ) ) + { + $ok = false; + break; + } + } + + // If everything's allright, call the callback and add the + // entry to the elements array + if ( $ok ) + { + call_user_func( $callback, $callbackContext, $sourceDir, $entry, $fileInfo ); + $elements[] = $sourceDir . DIRECTORY_SEPARATOR . $entry; + } + } + } + sort( $elements ); + return $elements; + } + + /** + * Finds files recursively on a file system + * + * With this method you can scan the file system for files. You can use + * $includeFilters to include only specific files, and $excludeFilters to + * exclude certain files from being returned. The function will always go + * into subdirectories even if the entry would not have passed the filters. + * It uses the {@see walkRecursive()} method to do the actually recursion. + * + * Filters are regular expressions and are therefore required to have + * starting and ending delimiters. The Perl Compatible syntax is used as + * regular expression language. + * + * If you pass an empty array to the $statistics argument, the function + * will in details about the number of files found into the 'count' array + * element, and the total filesize in the 'size' array element. Because this + * argument is passed by reference, you *have* to pass a variable and you + * can not pass a constant value such as "array()". + * + * @param string $sourceDir + * @param array(string) $includeFilters + * @param array(string) $excludeFilters + * @param array() $statistics + * + * @throws ezcBaseFileNotFoundException if the $sourceDir directory is not + * a directory or does not exist. + * @throws ezcBaseFilePermissionException if the $sourceDir directory could + * not be opened for reading. + * @return array + */ + static public function findRecursive( $sourceDir, array $includeFilters = array(), array $excludeFilters = array(), &$statistics = null ) + { + // init statistics array + if ( !is_array( $statistics ) || !array_key_exists( 'size', $statistics ) || !array_key_exists( 'count', $statistics ) ) + { + $statistics['size'] = 0; + $statistics['count'] = 0; + } + + // create the context, and then start walking over the array + $context = new ezcBaseFileFindContext; + self::walkRecursive( $sourceDir, $includeFilters, $excludeFilters, array( 'ezcBaseFile', 'findRecursiveCallback' ), $context ); + + // collect the statistics + $statistics['size'] = $context->size; + $statistics['count'] = $context->count; + + // return the found and pattern-matched files + sort( $context->elements ); + return $context->elements; + } + + + /** + * Removes files and directories recursively from a file system + * + * This method recursively removes the $directory and all its contents. + * You should be extremely careful with this method as it has the + * potential to erase everything that the current user has access to. + * + * @param string $directory + */ + static public function removeRecursive( $directory ) + { + $sourceDir = realpath( $directory ); + if ( !$sourceDir ) + { + throw new ezcBaseFileNotFoundException( $directory, 'directory' ); + } + $d = @dir( $sourceDir ); + if ( !$d ) + { + throw new ezcBaseFilePermissionException( $directory, ezcBaseFileException::READ ); + } + // check if we can remove the dir + $parentDir = realpath( $directory . DIRECTORY_SEPARATOR . '..' ); + if ( !is_writable( $parentDir ) ) + { + throw new ezcBaseFilePermissionException( $parentDir, ezcBaseFileException::WRITE ); + } + // loop over contents + while ( ( $entry = $d->read() ) !== false ) + { + if ( $entry == '.' || $entry == '..' ) + { + continue; + } + + if ( is_dir( $sourceDir . DIRECTORY_SEPARATOR . $entry ) ) + { + self::removeRecursive( $sourceDir . DIRECTORY_SEPARATOR . $entry ); + } + else + { + if ( @unlink( $sourceDir . DIRECTORY_SEPARATOR . $entry ) === false ) + { + throw new ezcBaseFilePermissionException( $directory . DIRECTORY_SEPARATOR . $entry, ezcBaseFileException::REMOVE ); + } + } + } + $d->close(); + rmdir( $sourceDir ); + } + + /** + * Recursively copy a file or directory. + * + * Recursively copy a file or directory in $source to the given + * destination. If a depth is given, the operation will stop, if the given + * recursion depth is reached. A depth of -1 means no limit, while a depth + * of 0 means, that only the current file or directory will be copied, + * without any recursion. + * + * You may optionally define modes used to create files and directories. + * + * @throws ezcBaseFileNotFoundException + * If the $sourceDir directory is not a directory or does not exist. + * @throws ezcBaseFilePermissionException + * If the $sourceDir directory could not be opened for reading, or the + * destination is not writeable. + * + * @param string $source + * @param string $destination + * @param int $depth + * @param int $dirMode + * @param int $fileMode + * @return void + */ + static public function copyRecursive( $source, $destination, $depth = -1, $dirMode = 0775, $fileMode = 0664 ) + { + // Check if source file exists at all. + if ( !is_file( $source ) && !is_dir( $source ) ) + { + throw new ezcBaseFileNotFoundException( $source ); + } + + // Destination file should NOT exist + if ( is_file( $destination ) || is_dir( $destination ) ) + { + throw new ezcBaseFilePermissionException( $destination, ezcBaseFileException::WRITE ); + } + + // Skip non readable files in source directory + if ( !is_readable( $source ) ) + { + return; + } + + // Copy + if ( is_dir( $source ) ) + { + mkdir( $destination ); + // To ignore umask, umask() should not be changed with + // multithreaded servers... + chmod( $destination, $dirMode ); + } + elseif ( is_file( $source ) ) + { + copy( $source, $destination ); + chmod( $destination, $fileMode ); + } + + if ( ( $depth === 0 ) || + ( !is_dir( $source ) ) ) + { + // Do not recurse (any more) + return; + } + + // Recurse + $dh = opendir( $source ); + while ( ( $file = readdir( $dh ) ) !== false ) + { + if ( ( $file === '.' ) || + ( $file === '..' ) ) + { + continue; + } + + self::copyRecursive( + $source . '/' . $file, + $destination . '/' . $file, + $depth - 1, $dirMode, $fileMode + ); + } + } + + /** + * Calculates the relative path of the file/directory '$path' to a given + * $base path. + * + * $path and $base should be fully absolute paths. This function returns the + * answer of "How do I go from $base to $path". If the $path and $base are + * the same path, the function returns '.'. This method does not touch the + * filesystem. + * + * @param string $path + * @param string $base + * @return string + */ + static public function calculateRelativePath( $path, $base ) + { + // Sanitize the paths to use the correct directory separator for the platform + $path = strtr( $path, '\\/', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR ); + $base = strtr( $base, '\\/', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR ); + + $base = explode( DIRECTORY_SEPARATOR, $base ); + $path = explode( DIRECTORY_SEPARATOR, $path ); + + // If the paths are the same we return + if ( $base === $path ) + { + return '.'; + } + + $result = ''; + + $pathPart = array_shift( $path ); + $basePart = array_shift( $base ); + while ( $pathPart == $basePart ) + { + $pathPart = array_shift( $path ); + $basePart = array_shift( $base ); + } + + if ( $pathPart != null ) + { + array_unshift( $path, $pathPart ); + } + if ( $basePart != null ) + { + array_unshift( $base, $basePart ); + } + + $result = str_repeat( '..' . DIRECTORY_SEPARATOR, count( $base ) ); + // prevent a trailing DIRECTORY_SEPARATOR in case there is only a .. + if ( count( $path ) == 0 ) + { + $result = substr( $result, 0, -strlen( DIRECTORY_SEPARATOR ) ); + } + $result .= join( DIRECTORY_SEPARATOR, $path ); + + return $result; + } + + /** + * Returns whether the passed $path is an absolute path, giving the current $os. + * + * With the $os parameter you can tell this function to use the semantics + * for a different operating system to determine whether a path is + * absolute. The $os argument defaults to the OS that the script is running + * on. + * + * @param string $path + * @param string $os + * @return bool + */ + public static function isAbsolutePath( $path, $os = null ) + { + if ( $os === null ) + { + $os = ezcBaseFeatures::os(); + } + + // Stream wrapper like phar can also be considered absolute paths + if ( preg_match( '(^[a-z]{3,}://)S', $path ) ) + { + return true; + } + + switch ( $os ) + { + case 'Windows': + // Sanitize the paths to use the correct directory separator for the platform + $path = strtr( $path, '\\/', '\\\\' ); + + // Absolute paths with drive letter: X:\ + if ( preg_match( '@^[A-Z]:\\\\@i', $path ) ) + { + return true; + } + + // Absolute paths with network paths: \\server\share\ + if ( preg_match( '@^\\\\\\\\[A-Z]+\\\\[^\\\\]@i', $path ) ) + { + return true; + } + break; + case 'Mac': + case 'Linux': + case 'FreeBSD': + default: + // Sanitize the paths to use the correct directory separator for the platform + $path = strtr( $path, '\\/', '//' ); + + if ( $path[0] == '/' ) + { + return true; + } + } + return false; + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/init.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/init.php new file mode 100644 index 0000000..507c989 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/init.php @@ -0,0 +1,125 @@ + + * + * + * + * You will also need to configure which callback class to call. This you do + * with the ezcBaseInit::setCallback() method. The following examples sets the + * callback classname for the configuration identifier + * 'ezcInitConfigurationManager' to 'cfgConfigurationManager': + * + * + * + * + * + * The class 'cfgConfigurationManager' is required to implement the + * ezcBaseConfigurationInitializer interface, which defines only one method: + * configureObject(). An example on how to implement such a class could be: + * + * + * init( 'ezcConfigurationIniReader', 'settings', array( 'useComments' => true ) ); + * } + * } + * ?> + * + * + * Of course the implementation of this callback class is up to the application + * developer that uses the component (in this example the Configuration + * component's class ezcConfigurationManager). + * + * @package Base + * @version 1.8 + */ +class ezcBaseInit +{ + /** + * Contains the callback where the identifier is the key of the array, and the classname to callback to the value. + * + * @var array(string=>string) + */ + static private $callbackMap = array(); + + /** + * Adds the classname $callbackClassname as callback for the identifier $identifier. + * + * @param string $identifier + * @param string $callbackClassname + */ + public static function setCallback( $identifier, $callbackClassname ) + { + if ( array_key_exists( $identifier, self::$callbackMap ) ) + { + throw new ezcBaseInitCallbackConfiguredException( $identifier, self::$callbackMap[$identifier] ); + } + else + { + // Check if the passed classname actually exists + if ( !ezcBaseFeatures::classExists( $callbackClassname, true ) ) + { + throw new ezcBaseInitInvalidCallbackClassException( $callbackClassname ); + } + + // Check if the passed classname actually implements the interface. + if ( !in_array( 'ezcBaseConfigurationInitializer', class_implements( $callbackClassname ) ) ) + { + throw new ezcBaseInitInvalidCallbackClassException( $callbackClassname ); + } + + self::$callbackMap[$identifier] = $callbackClassname; + } + } + + /** + * Uses the configured callback belonging to $identifier to configure the $object. + * + * The method will return the return value of the callback method, or null + * in case there was no callback set for the specified $identifier. + * + * @param string $identifier + * @param object $object + * @return mixed + */ + public static function fetchConfig( $identifier, $object ) + { + if ( isset( self::$callbackMap[$identifier] ) ) + { + $callbackClassname = self::$callbackMap[$identifier]; + return call_user_func( array( $callbackClassname, 'configureObject' ), $object ); + } + return null; + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/interfaces/configuration_initializer.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/interfaces/configuration_initializer.php new file mode 100644 index 0000000..e3e3045 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/interfaces/configuration_initializer.php @@ -0,0 +1,32 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/interfaces/exportable.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/interfaces/exportable.php new file mode 100644 index 0000000..83d76bf --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/interfaces/exportable.php @@ -0,0 +1,33 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/interfaces/persistable.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/interfaces/persistable.php new file mode 100644 index 0000000..703ae8f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/interfaces/persistable.php @@ -0,0 +1,40 @@ +mixed) + */ + public function getState(); + + /** + * Accepts an array containing data for one or more of the class' properties. + * + * @param array $properties + */ + public function setState( array $properties ); +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/metadata.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/metadata.php new file mode 100644 index 0000000..bf5da65 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/metadata.php @@ -0,0 +1,120 @@ +reader = new ezcBaseMetaDataTarballReader; + break; + case 'pear': + $this->reader = new ezcBaseMetaDataPearReader; + break; + default: + throw new ezcBaseMetaDataReaderException( "Unknown install method '$installMethod'." ); + break; + } + } + + /** + * Returns the version string for the installed eZ Components bundle. + * + * A version string such as "2008.2.2" is returned. + * + * @return string + */ + public function getBundleVersion() + { + return $this->reader->getBundleVersion(); + } + + /** + * Returns a PHP version string that describes the required PHP version for + * this installed eZ Components bundle. + * + * @return string + */ + public function getRequiredPhpVersion() + { + return $this->reader->getRequiredPhpVersion(); + } + + /** + * Returns whether $componentName is installed + * + * If installed with PEAR, it checks the PEAR registry whether the + * component is there. In case the tarball installation method is used, it + * will return true for every component that exists (because all of them + * are then available). + * + * @return bool + */ + public function isComponentInstalled( $componentName ) + { + return $this->reader->isComponentInstalled( $componentName ); + } + + /** + * Returns the version string of the available $componentName or false when + * the component is not installed. + * + * @return string + */ + public function getComponentVersion( $componentName ) + { + return $this->reader->getComponentVersion( $componentName ); + } + + /** + * Returns a list of components that $componentName depends on. + * + * If $componentName is left empty, all installed components are returned. + * + * The returned array has as keys the component names, and as values the + * version of the components. + * + * @return array(string=>string). + */ + public function getComponentDependencies( $componentName = null ) + { + if ( $componentName === null ) + { + return $this->reader->getComponentDependencies(); + } + else + { + return $this->reader->getComponentDependencies( $componentName ); + } + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/metadata/pear.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/metadata/pear.php new file mode 100644 index 0000000..321670a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/metadata/pear.php @@ -0,0 +1,129 @@ +registry = new PEAR_Registry; + } + + /** + * Returns the version string for the installed eZ Components bundle. + * + * A version string such as "2008.2.2" is returned. + * + * @return string + */ + public function getBundleVersion() + { + @$packageInfo = $this->registry->packageInfo( 'ezcomponents', null, 'components.ez.no' ); + return $packageInfo['version']['release']; + } + + /** + * Returns a PHP version string that describes the required PHP version for + * this installed eZ Components bundle. + * + * @return string + */ + public function getRequiredPhpVersion() + { + @$packageInfo = $this->registry->packageInfo( 'ezcomponents', null, 'components.ez.no' ); + if ( array_key_exists( 'required', $packageInfo['dependencies'] ) ) + { + return $packageInfo['dependencies']['required']['php']['min']; + } + return $packageInfo['dependencies']['php']['min']; + } + + /** + * Returns whether $componentName is installed + * + * Checks the PEAR registry whether the component is there. + * + * @return bool + */ + public function isComponentInstalled( $componentName ) + { + @$packageInfo = $this->registry->packageInfo( $componentName, null, 'components.ez.no' ); + return is_array( $packageInfo ); + } + + /** + * Returns the version string of the available $componentName or false when + * the component is not installed. + * + * @return string + */ + public function getComponentVersion( $componentName ) + { + @$packageInfo = $this->registry->packageInfo( $componentName, null, 'components.ez.no' ); + $release = $packageInfo['version']['release']; + return $release === null ? false : $release; + } + + /** + * Returns a list of components that $componentName depends on. + * + * If $componentName is left empty, all installed components are returned. + * + * The returned array has as keys the component names, and as values the + * version of the components. + * + * @return array(string=>string). + */ + public function getComponentDependencies( $componentName = 'ezcomponents' ) + { + @$packageInfo = $this->registry->packageInfo( $componentName, 'dependencies', 'components.ez.no' ); + if ( isset( $packageInfo['required']['package'] ) ) + { + $deps = array(); + if ( isset( $packageInfo['required']['package']['name'] ) ) + { + $deps[$packageInfo['required']['package']['name']] = $packageInfo['required']['package']['min']; + } + else + { + foreach ( $packageInfo['required']['package'] as $package ) + { + $deps[$package['name']] = $package['min']; + } + } + return $deps; + } + return array(); + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/metadata/tarball.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/metadata/tarball.php new file mode 100644 index 0000000..5e671fa --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/metadata/tarball.php @@ -0,0 +1,153 @@ +xml = simplexml_load_file( $filename ); + } + + /** + * Returns the version string for the installed eZ Components bundle. + * + * A version string such as "2008.2.2" is returned. + * + * @return string + */ + public function getBundleVersion() + { + return (string) $this->xml->version; + } + + /** + * Returns a PHP version string that describes the required PHP version for + * this installed eZ Components bundle. + * + * @return string + */ + public function getRequiredPhpVersion() + { + return (string) $this->xml->deps->php; + } + + /** + * Returns whether $componentName is installed + * + * Returns true for every component that exists (because all of them are + * then available). + * + * @return bool + */ + public function isComponentInstalled( $componentName ) + { + $root = $this->xml->deps->packages->package; + + foreach ( $root as $package ) + { + if ( (string) $package['name'] == $componentName ) + { + return true; + } + } + return false; + } + + /** + * Returns the version string of the available $componentName or false when + * the component is not installed. + * + * @return string + */ + public function getComponentVersion( $componentName ) + { + $root = $this->xml->deps->packages->package; + + foreach ( $root as $package ) + { + if ( (string) $package['name'] == $componentName ) + { + return (string) $package['version']; + } + } + return false; + } + + /** + * Returns a list of components that $componentName depends on. + * + * If $componentName is left empty, all installed components are returned. + * + * The returned array has as keys the component names, and as values the + * version of the components. It returns null of the $componentName + * is not found. + * + * @return array(string=>string). + */ + public function getComponentDependencies( $componentName = null ) + { + $baseVersion = false; + $root = $this->xml->deps->packages; + $found = $componentName === null ? true : false; + + // in case $componentName != null, we loop through all the components + // in the file, and figure out the new root that we can list dependency + // packages from. + foreach ( $root->package as $package ) + { + if ( (string) $package['name'] == 'Base' ) + { + $baseVersion = $package['version']; + } + if ( !$found && (string) $package['name'] == $componentName ) + { + $root = $package->deps; + $found = true; + } + } + + if ( !$found ) + { + return null; + } + + // We always add the Base dependency even though it's not in the dependency file. + $deps = array(); + $deps['Base'] = (string) $baseVersion; + + if ( !isset( $root->package ) ) + { + return $deps; + } + foreach ( $root->package as $package ) + { + $deps[(string) $package['name']] = (string) $package['version']; + } + return $deps; + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/options.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/options.php new file mode 100644 index 0000000..b1f879d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/options.php @@ -0,0 +1,174 @@ +mixed) + */ + protected $properties; + + /** + * Construct a new options object. + * Options are constructed from an option array by default. The constructor + * automatically passes the given options to the __set() method to set them + * in the class. + * + * @throws ezcBasePropertyNotFoundException + * If trying to access a non existent property. + * @throws ezcBaseValueException + * If the value for a property is out of range. + * @param array(string=>mixed) $options The initial options to set. + */ + public function __construct( array $options = array() ) + { + foreach ( $options as $option => $value ) + { + $this->__set( $option, $value ); + } + } + + /** + * Merge an array into the actual options object. + * This method merges an array of new options into the actual options object. + * + * @throws ezcBasePropertyNotFoundException + * If trying to access a non existent property. + * @throws ezcBaseValueException + * If the value for a property is out of range. + * @param array(string=>mixed) $newOptions The new options. + */ + public function merge( array $newOptions ) + { + foreach ( $newOptions as $key => $value ) + { + $this->__set( $key, $value ); + } + } + + /** + * Property get access. + * Simply returns a given option. + * + * @throws ezcBasePropertyNotFoundException + * If a the value for the property options is not an instance of + * @param string $propertyName The name of the option to get. + * @return mixed The option value. + * @ignore + * + * @throws ezcBasePropertyNotFoundException + * if the given property does not exist. + * @throws ezcBasePropertyPermissionException + * if the property to be set is a write-only property. + */ + public function __get( $propertyName ) + { + if ( $this->__isset( $propertyName ) === true ) + { + return $this->properties[$propertyName]; + } + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + + /** + * Sets an option. + * This method is called when an option is set. + * + * @param string $propertyName The name of the option to set. + * @param mixed $propertyValue The option value. + * @ignore + * + * @throws ezcBasePropertyNotFoundException + * if the given property does not exist. + * @throws ezcBaseValueException + * if the value to be assigned to a property is invalid. + * @throws ezcBasePropertyPermissionException + * if the property to be set is a read-only property. + */ + abstract public function __set( $propertyName, $propertyValue ); + + /** + * Returns if a option exists. + * + * @param string $propertyName Option name to check for. + * @return bool Whether the option exists. + * @ignore + */ + public function __isset( $propertyName ) + { + return array_key_exists( $propertyName, $this->properties ); + } + + /** + * Returns if an option exists. + * Allows isset() using ArrayAccess. + * + * @param string $propertyName The name of the option to get. + * @return bool Whether the option exists. + */ + public function offsetExists( $propertyName ) + { + return $this->__isset( $propertyName ); + } + + /** + * Returns an option value. + * Get an option value by ArrayAccess. + * + * @throws ezcBasePropertyNotFoundException + * If $propertyName is not a key in the $properties array. + * @param string $propertyName The name of the option to get. + * @return mixed The option value. + */ + public function offsetGet( $propertyName ) + { + return $this->__get( $propertyName ); + } + + /** + * Set an option. + * Sets an option using ArrayAccess. + * + * @throws ezcBasePropertyNotFoundException + * If $propertyName is not a key in the $properties array. + * @throws ezcBaseValueException + * If the value for a property is out of range. + * @param string $propertyName The name of the option to set. + * @param mixed $propertyValue The value for the option. + */ + public function offsetSet( $propertyName, $propertyValue ) + { + $this->__set( $propertyName, $propertyValue ); + } + + /** + * Unset an option. + * Unsets an option using ArrayAccess. + * + * @throws ezcBasePropertyNotFoundException + * If $propertyName is not a key in the $properties array. + * @throws ezcBaseValueException + * If a the value for a property is out of range. + * @param string $propertyName The name of the option to unset. + */ + public function offsetUnset( $propertyName ) + { + $this->__set( $propertyName, null ); + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/options/autoload.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/options/autoload.php new file mode 100644 index 0000000..61503fc --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/options/autoload.php @@ -0,0 +1,75 @@ +mixed) $options + */ + public function __construct( array $options = array() ) + { + $this->preload = false; + $this->debug = false; + + parent::__construct( $options ); + } + + /** + * Sets the option $name to $value. + * + * @throws ezcBasePropertyNotFoundException + * if the property $name is not defined + * @throws ezcBaseValueException + * if $value is not correct for the property $name + * @param string $name + * @param mixed $value + * @ignore + */ + public function __set( $name, $value ) + { + switch ( $name ) + { + case 'debug': + case 'preload': + if ( !is_bool( $value ) ) + { + throw new ezcBaseValueException( $name, $value, 'bool' ); + } + $this->properties[$name] = $value; + break; + + default: + throw new ezcBasePropertyNotFoundException( $name ); + } + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/struct.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/struct.php new file mode 100644 index 0000000..1a1900b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/struct.php @@ -0,0 +1,42 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/structs/file_find_context.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/structs/file_find_context.php new file mode 100644 index 0000000..579b928 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/structs/file_find_context.php @@ -0,0 +1,72 @@ +elements = $elements; + $this->count = $count; + $this->size = $size; + } + + /** + * Returns a new instance of this class with the data specified by $array. + * + * $array contains all the data members of this class in the form: + * array('member_name'=>value). + * + * __set_state makes this class exportable with var_export. + * var_export() generates code, that calls this method when it + * is parsed with PHP. + * + * @param array(string=>mixed) $array + * @return ezcBaseFileFindContext + */ + static public function __set_state( array $array ) + { + return new ezcBaseFileFindContext( $array['elements'], $array['count'], $array['size'] ); + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/Base/structs/repository_directory.php b/typo3conf/ext/phpunit/PEAR/ezc/Base/structs/repository_directory.php new file mode 100644 index 0000000..74e290e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/Base/structs/repository_directory.php @@ -0,0 +1,83 @@ +type = $type; + $this->basePath = $basePath; + $this->autoloadPath = $autoloadPath; + } + + /** + * Returns a new instance of this class with the data specified by $array. + * + * $array contains all the data members of this class in the form: + * array('member_name'=>value). + * + * __set_state makes this class exportable with var_export. + * var_export() generates code, that calls this method when it + * is parsed with PHP. + * + * @param array(string=>mixed) $array + * @return ezcBaseRepositoryDirectory + */ + static public function __set_state( array $array ) + { + return new ezcBaseRepositoryDirectory( $array['type'], $array['basePath'], $array['autoloadPath'] ); + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/console_autoload.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/console_autoload.php new file mode 100644 index 0000000..4d44e02 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/console_autoload.php @@ -0,0 +1,76 @@ + 'ConsoleTools/exceptions/exception.php', + 'ezcConsoleArgumentException' => 'ConsoleTools/exceptions/argument.php', + 'ezcConsoleOptionException' => 'ConsoleTools/exceptions/option.php', + 'ezcConsoleArgumentAlreadyRegisteredException' => 'ConsoleTools/exceptions/argument_already_registered.php', + 'ezcConsoleArgumentMandatoryViolationException' => 'ConsoleTools/exceptions/argument_mandatory_violation.php', + 'ezcConsoleArgumentTypeViolationException' => 'ConsoleTools/exceptions/argument_type_violation.php', + 'ezcConsoleDialogAbortException' => 'ConsoleTools/exceptions/dialog_abort.php', + 'ezcConsoleInvalidOptionNameException' => 'ConsoleTools/exceptions/invalid_option_name.php', + 'ezcConsoleInvalidOutputTargetException' => 'ConsoleTools/exceptions/invalid_output_target.php', + 'ezcConsoleNoPositionStoredException' => 'ConsoleTools/exceptions/no_position_stored.php', + 'ezcConsoleNoValidDialogResultException' => 'ConsoleTools/exceptions/no_valid_dialog_result.php', + 'ezcConsoleOptionAlreadyRegisteredException' => 'ConsoleTools/exceptions/option_already_registered.php', + 'ezcConsoleOptionArgumentsViolationException' => 'ConsoleTools/exceptions/option_arguments_violation.php', + 'ezcConsoleOptionDependencyViolationException' => 'ConsoleTools/exceptions/option_dependency_violation.php', + 'ezcConsoleOptionExclusionViolationException' => 'ConsoleTools/exceptions/option_exclusion_violation.php', + 'ezcConsoleOptionMandatoryViolationException' => 'ConsoleTools/exceptions/option_mandatory_violation.php', + 'ezcConsoleOptionMissingValueException' => 'ConsoleTools/exceptions/option_missing_value.php', + 'ezcConsoleOptionNoAliasException' => 'ConsoleTools/exceptions/option_no_alias.php', + 'ezcConsoleOptionNotExistsException' => 'ConsoleTools/exceptions/option_not_exists.php', + 'ezcConsoleOptionStringNotWellformedException' => 'ConsoleTools/exceptions/option_string_not_wellformed.php', + 'ezcConsoleOptionTooManyValuesException' => 'ConsoleTools/exceptions/option_too_many_values.php', + 'ezcConsoleOptionTypeViolationException' => 'ConsoleTools/exceptions/option_type_violation.php', + 'ezcConsoleTooManyArgumentsException' => 'ConsoleTools/exceptions/argument_too_many.php', + 'ezcConsoleDialogValidator' => 'ConsoleTools/interfaces/dialog_validator.php', + 'ezcConsoleQuestionDialogValidator' => 'ConsoleTools/interfaces/question_dialog_validator.php', + 'ezcConsoleDialog' => 'ConsoleTools/interfaces/dialog.php', + 'ezcConsoleDialogOptions' => 'ConsoleTools/options/dialog.php', + 'ezcConsoleInputHelpGenerator' => 'ConsoleTools/interfaces/input_help_generator.php', + 'ezcConsoleInputValidator' => 'ConsoleTools/interfaces/input_validator.php', + 'ezcConsoleMenuDialogValidator' => 'ConsoleTools/interfaces/menu_dialog_validator.php', + 'ezcConsoleQuestionDialogCollectionValidator' => 'ConsoleTools/dialog/validators/question_dialog_collection.php', + 'ezcConsoleArgument' => 'ConsoleTools/input/argument.php', + 'ezcConsoleArguments' => 'ConsoleTools/input/arguments.php', + 'ezcConsoleDialogViewer' => 'ConsoleTools/dialog_viewer.php', + 'ezcConsoleInput' => 'ConsoleTools/input.php', + 'ezcConsoleInputStandardHelpGenerator' => 'ConsoleTools/input/help_generators/standard.php', + 'ezcConsoleMenuDialog' => 'ConsoleTools/dialog/menu_dialog.php', + 'ezcConsoleMenuDialogDefaultValidator' => 'ConsoleTools/dialog/validators/menu_dialog_default.php', + 'ezcConsoleMenuDialogOptions' => 'ConsoleTools/options/menu_dialog.php', + 'ezcConsoleOption' => 'ConsoleTools/input/option.php', + 'ezcConsoleOptionRule' => 'ConsoleTools/structs/option_rule.php', + 'ezcConsoleOutput' => 'ConsoleTools/output.php', + 'ezcConsoleOutputFormat' => 'ConsoleTools/structs/output_format.php', + 'ezcConsoleOutputFormats' => 'ConsoleTools/structs/output_formats.php', + 'ezcConsoleOutputOptions' => 'ConsoleTools/options/output.php', + 'ezcConsoleProgressMonitor' => 'ConsoleTools/progressmonitor.php', + 'ezcConsoleProgressMonitorOptions' => 'ConsoleTools/options/progressmonitor.php', + 'ezcConsoleProgressbar' => 'ConsoleTools/progressbar.php', + 'ezcConsoleProgressbarOptions' => 'ConsoleTools/options/progressbar.php', + 'ezcConsoleQuestionDialog' => 'ConsoleTools/dialog/question_dialog.php', + 'ezcConsoleQuestionDialogMappingValidator' => 'ConsoleTools/dialog/validators/question_dialog_mapping.php', + 'ezcConsoleQuestionDialogOptions' => 'ConsoleTools/options/question_dialog.php', + 'ezcConsoleQuestionDialogRegexValidator' => 'ConsoleTools/dialog/validators/question_dialog_regex.php', + 'ezcConsoleQuestionDialogTypeValidator' => 'ConsoleTools/dialog/validators/question_dialog_type.php', + 'ezcConsoleStandardInputValidator' => 'ConsoleTools/input/validators/standard.php', + 'ezcConsoleStatusbar' => 'ConsoleTools/statusbar.php', + 'ezcConsoleStatusbarOptions' => 'ConsoleTools/options/statusbar.php', + 'ezcConsoleStringTool' => 'ConsoleTools/tools/string.php', + 'ezcConsoleTable' => 'ConsoleTools/table.php', + 'ezcConsoleTableCell' => 'ConsoleTools/table/cell.php', + 'ezcConsoleTableOptions' => 'ConsoleTools/options/table.php', + 'ezcConsoleTableRow' => 'ConsoleTools/table/row.php', +); +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/menu_dialog.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/menu_dialog.php new file mode 100644 index 0000000..f99a73c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/menu_dialog.php @@ -0,0 +1,217 @@ + null, + "output" => null, + ); + + /** + * Creates a new menu dialog. + * Creates a new question dialog to be displayed to the user. All behaviour is + * defined through the $options parameter. The $output parameter is used to + * display the dialog in the {@link display()} method. + * + * @param ezcConsoleOutput $output Output object. + * @param ezcConsoleMenuDialogOptions $options The options. + * @return void + */ + public function __construct( ezcConsoleOutput $output, ezcConsoleMenuDialogOptions $options = null ) + { + $this->output = $output; + $this->options = $options === null ? new ezcConsoleMenuDialogOptions() : $options; + } + + /** + * Returns if the dialog retrieved a valid result. + * If a valid result has already been received, this method returns true, + * otherwise false. + * + * @return bool If a valid result was retrieved. + */ + public function hasValidResult() + { + return ( $this->result !== null ); + } + + /** + * Returns the result retrieved. + * If no valid result was retreived, yet, this method throws an + * ezcConsoleNoValidDialogResultException. Use {@link hasValidResult()} to + * avoid this. + * + * @return mixed The retreived result. + * + * @throws ezcDialogNoValidResultException + * if this method is called without a valid result being retrieved + * by the object. Use {@link hasValidResult()} to avoid this + * exception. + */ + public function getResult() + { + if ( $this->result === null ) + { + throw new ezcConsoleNoValidDialogResultException(); + } + return $this->result; + } + + /** + * Displays the dialog and retreives a value from the user. + * Displays the dialog and retreives the desired answer from the user. If + * the a valid result is retrieved, it can be obtained using {@link + * getResult()}. The method {@link hasValidResult()} can be used to check + * if a valid result is available. + * + * @return void + * @throws ezcConsoleDialogAbortException + * if the user closes STDIN using -D. + */ + public function display() + { + $this->reset(); + + $text = "{$this->options->text}\n"; + foreach ( $this->options->validator->getElements() as $key => $entry ) + { + $text .= sprintf( + $this->options->formatString, + $key, + $entry + ); + } + $text .= "\n{$this->options->selectText}{$this->options->validator->getResultString()} "; + + $this->output->outputText( $text, $this->options->format ); + + $result = $this->options->validator->fixup( + ezcConsoleDialogViewer::readLine() + ); + if ( $this->options->validator->validate( $result ) ) + { + $this->result = $result; + } + } + + /** + * Reset the dialog. + * Resets a possibly received result and all changes made to the dialog + * during {@link display()}. After that, the dialog can be re-used. All + * option values are kept. + * + * @return void + */ + public function reset() + { + $this->result = null; + } + + /** + * Property read access. + * + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * + * @param string $propertyName Name of the property. + * @return mixed Value of the property or null. + * @ignore + */ + public function __get( $propertyName ) + { + if ( array_key_exists( $propertyName, $this->properties ) ) + { + return $this->properties[$propertyName]; + } + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + + /** + * Property write access. + * + * @param string $propertyName Name of the property. + * @param mixed $propertyValue The value for the property. + * + * @throws ezcBasePropertyPermissionException + * If the property you try to access is read-only. + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * @ignore + */ + public function __set( $propertyName, $propertyValue ) + { + switch ( $propertyName ) + { + case "options": + if ( ( $propertyValue instanceof ezcConsoleMenuDialogOptions ) === false ) + { + throw new ezcBaseValueException( + $propertyName, + ( is_object( $propertyValue ) ? get_class( $propertyValue ) : gettype( $propertyValue ) ), + "instance of ezcConsoleMenuDialogOptions" + ); + } + break; + case "output": + if ( ( $propertyValue instanceof ezcConsoleOutput ) === false ) + { + throw new ezcBaseValueException( + $propertyName, + ( is_object( $propertyValue ) ? get_class( $propertyValue ) : gettype( $propertyValue ) ), + "instance of ezcConsoleOutput" + ); + } + break; + default: + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + $this->properties[$propertyName] = $propertyValue; + } + + /** + * Property isset access. + * + * @param string $propertyName Name of the property to check. + * @return bool If the property exists or not. + * @ignore + */ + public function __isset( $propertyName ) + { + return array_key_exists( $propertyName, $this->properties ); + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/question_dialog.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/question_dialog.php new file mode 100644 index 0000000..c44ec8b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/question_dialog.php @@ -0,0 +1,251 @@ + null, + "output" => null, + ); + + /** + * Creates a new question dialog. + * Creates a new menu dialog to be displayed to the user. All behaviour is + * defined through the $options parameter. The $output parameter is used to + * display the dialog in the {@link display()} method. + * + * @param ezcConsoleOutput $output Output object. + * @param ezcConsoleQuestionDialogOptions $options Options. + * @return void + */ + public function __construct( ezcConsoleOutput $output, ezcConsoleQuestionDialogOptions $options = null ) + { + $this->output = $output; + $this->options = $options === null ? new ezcConsoleQuestionDialogOptions() : $options; + } + + /** + * Returns if the dialog retrieved a valid result. + * If a valid result has already been received, this method returns true, + * otherwise false. + * + * @return bool If a valid result was retrieved. + */ + public function hasValidResult() + { + return $this->result !== null; + } + + /** + * Returns the result retrieved. + * If no valid result was retreived, yet, this method should throw an + * ezcConsoleNoValidDialogResultException. + * + * If no valid result was retreived, yet, this method throws an + * ezcConsoleNoValidDialogResultException. Use {@link hasValidResult()} to + * avoid this. + * + * @return mixed The retreived result. + * + * @throws ezcDialogNoValidResultException + * if this method is called without a valid result being retrieved + * by the object. Use {@link hasValidResult()} to avoid this + * exception. + */ + public function getResult() + { + if ( $this->result === null ) + { + throw new ezcConsoleNoValidDialogResultException(); + } + return $this->result; + } + + /** + * Displays the dialog and retreives a value from the user. + * Displays the dialog and retreives the desired answer from the user. If + * the a valid result is retrieved, it can be obtained using {@link + * getResult()}. The method {@link hasValidResult()} can be used to check + * if a valid result is available. + * + * @return void + * @throws ezcConsoleDialogAbortException + * if the user closes STDIN using -D. + */ + public function display() + { + $this->reset(); + + $this->output->outputText( + $this->options->text . ( $this->options->showResults === true ? " " . $this->options->validator->getResultString() : "" ) . " ", + $this->options->format + ); + $result = $this->options->validator->fixup( ezcConsoleDialogViewer::readLine() ); + if ( $this->options->validator->validate( $result ) ) + { + $this->result = $result; + } + } + + /** + * Reset the dialog. + * Resets a possibly received result and all changes made to the dialog + * during {@link display()}. After that, the dialog can be re-used. All + * option values are kept. + * + * @return void + */ + public function reset() + { + $this->result = null; + } + + /** + * Returns a ready to use yes/no question dialog. + * Returns a question dialog, which requests the answers "y" for "yes" or + * "n" for "no" from the user. The answer is converted to lower-case. + * + * + * // Would you like to proceed? (y/n) + * $dialog = ezcConsoleDialog( $out, "Would you like to proceed?" ); + * + * // Would you like to proceed? (y/n) [n] + * $dialog = ezcConsoleDialog( $out, "Would you like to proceed?", "n" ); + * + * + * @param ezcConsoleOutput $out Output object. + * @param string $questionString Question string. + * @param string $default "y" or "n", if default value is desired. + * @return ezcConsoleQuestionDialog The created dialog. + */ + public static function YesNoQuestion( ezcConsoleOutput $out, $questionString, $default = null ) + { + $opts = new ezcConsoleQuestionDialogOptions(); + $opts->text = $questionString; + $opts->showResults = true; + $opts->validator = new ezcConsoleQuestionDialogMappingValidator( + array( "y", "n" ), + $default, + ezcConsoleQuestionDialogCollectionValidator::CONVERT_LOWER, + array( + 'yes' => 'y', + 'no' => 'n', + ) + ); + + return new ezcConsoleQuestionDialog( $out, $opts ); + } + + /** + * Property read access. + * + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * + * @param string $propertyName Name of the property. + * @return mixed Value of the property or null. + * @ignore + */ + public function __get( $propertyName ) + { + if ( array_key_exists( $propertyName, $this->properties ) ) + { + return $this->properties[$propertyName]; + } + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + + /** + * Property write access. + * + * @param string $propertyName Name of the property. + * @param mixed $propertyValue The value for the property. + * + * @throws ezcBasePropertyPermissionException + * If the property you try to access is read-only. + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * @ignore + */ + public function __set( $propertyName, $propertyValue ) + { + switch ( $propertyName ) + { + case "options": + if ( ( $propertyValue instanceof ezcConsoleQuestionDialogOptions ) === false ) + { + throw new ezcBaseValueException( + $propertyName, + ( is_object( $propertyValue ) ? get_class( $propertyValue ) : gettype( $propertyValue ) ), + "instance of ezcConsoleQuestionDialogOptions" + ); + } + break; + case "output": + if ( ( $propertyValue instanceof ezcConsoleOutput ) === false ) + { + throw new ezcBaseValueException( + $propertyName, + ( is_object( $propertyValue ) ? get_class( $propertyValue ) : gettype( $propertyValue ) ), + "instance of ezcConsoleOutput" + ); + } + break; + default: + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + $this->properties[$propertyName] = $propertyValue; + } + + /** + * Property isset access. + * + * @param string $propertyName Name of the property to check. + * @return bool If the property exists or not. + * @ignore + */ + public function __isset( $propertyName ) + { + return array_key_exists( $propertyName, $this->properties ); + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/menu_dialog_default.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/menu_dialog_default.php new file mode 100644 index 0000000..8a14faa --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/menu_dialog_default.php @@ -0,0 +1,199 @@ + array(), + "default" => null, + "conversion" => self::CONVERT_NONE, + ); + + /** + * Creates a new menu default validator. + * Creates a validator specified by the given parameters. The $elements + * array specifies the possible menu items to select from. The item + * identifier (the key of the array) is used to validate the result. The + * assigned text is displayed as the menu item text. If no result is + * provided and an optionally provided default value is used. The + * $conversion parameter can be used to get a conversion applied to the + * result before validating it. + * + * @param array $elements The elements of the menu. + * @param mixed $default The default value. + * @param int $conversion The conversion to apply. + * @return void + */ + public function __construct( array $elements = array(), $default = null, $conversion = self::CONVERT_NONE ) + { + $this->elements = $elements; + $this->default = $default; + $this->conversion = $conversion; + } + + /** + * Returns if the given result is valid. + * Checks if the given result is a valid key in the $elements property. + * + * @param mixed $result The received result. + * @return bool If the result is valid. + */ + public function validate( $result ) + { + return isset( $this->elements[$result] ); + } + + /** + * Returns a fixed version of the result, if possible. + * Converts the given result according to the conversion defined in the + * $conversion property. + * + * @param mixed $result The received result. + * @return mixed The manipulated result. + */ + public function fixup( $result ) + { + if ( $result === "" && $this->default !== null ) + { + return $this->default; + + } + switch ( $this->conversion ) + { + case self::CONVERT_LOWER: + return strtolower( $result ); + case self::CONVERT_UPPER: + return strtoupper( $result ); + case self::CONVERT_NONE: + default: + return $result; + } + } + + /** + * Returns a string representing the default value. + * For example "[y]" to indicate that "y" is the preselected result and + * will be chosen if no result is provided. + * + * @return string The result string. + */ + public function getResultString() + { + return $this->default === null ? "" : "[{$this->default}]"; + } + + /** + * Returns an array of the elements to display. + * + * @return array(string=>string) Elements to display. + */ + public function getElements() + { + return $this->elements; + } + + /** + * Property read access. + * + * @param string $propertyName Name of the property. + * @return mixed Value of the property or null. + * + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * @ignore + */ + public function __get( $propertyName ) + { + if ( isset( $this->$propertyName ) ) + { + return $this->properties[$propertyName]; + } + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + + /** + * Property write access. + * + * @param string $propertyName Name of the property. + * @param mixed $propertyValue The value for the property. + * + * @throws ezcBasePropertyNotFoundException + * If a the value for the property options is not an instance of + * @throws ezcBaseValueException + * If a the value for a property is out of range. + * @ignore + */ + public function __set( $propertyName, $propertyValue ) + { + switch ( $propertyName ) + { + case "elements": + if ( is_array( $propertyValue ) === false ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "array" ); + } + break; + case "default": + if ( is_scalar( $propertyValue ) === false && $propertyValue !== null ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "scalar" ); + } + break; + case "conversion": + if ( $propertyValue !== self::CONVERT_NONE && $propertyValue !== self::CONVERT_UPPER && $propertyValue !== self::CONVERT_LOWER ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "ezcConsoleMenuDialogDefaultValidator::CONVERT_*" ); + } + break; + default: + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + $this->properties[$propertyName] = $propertyValue; + } + + /** + * Property isset access. + * + * @param string $propertyName Name of the property. + * @return bool True is the property is set, otherwise false. + * @ignore + */ + public function __isset( $propertyName ) + { + return array_key_exists( $propertyName, $this->properties ); + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_collection.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_collection.php new file mode 100644 index 0000000..b381be6 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_collection.php @@ -0,0 +1,186 @@ + array(), + "default" => null, + "conversion" => self::CONVERT_NONE, + ); + + /** + * Creates a new question dialog collection validator. + * Creates a new question dialog collection validator, which validates the + * result specified by the user against an array of valid results + * ($collection). If not value is provided by the user a possibly set + * $default value is used instead. The $conversion parameter can optionally + * define a conversion to be performed on the result before validating it. + * Valid conversions are defined by the CONVERT_* constants in this class. + * + * @param array $collection The collection of valid results. + * @param mixed $default Optional default value. + * @param int $conversion CONVERT_* constant. + * @return void + */ + public function __construct( array $collection, $default = null, $conversion = self::CONVERT_NONE ) + { + $this->collection = $collection; + $this->default = $default; + $this->conversion = $conversion; + } + + /** + * Returns if the given result is valid. + * Returns if the result is in the $collection array. + * + * @param mixed $result The received result. + * @return bool If the result is valid. + */ + public function validate( $result ) + { + return in_array( $result, $this->collection ); + } + + /** + * Returns a fixed version of the result, if possible. + * Converts the given result according to the conversion defined in the + * $conversion property. + * + * @param mixed $result The received result. + * @return mixed The manipulated result. + */ + public function fixup( $result ) + { + if ( $result === "" && $this->default !== null ) + { + return $this->default; + } + switch ( $this->conversion ) + { + case self::CONVERT_UPPER: + return strtoupper( $result ); + case self::CONVERT_LOWER: + return strtolower( $result ); + default: + return $result; + } + } + + /** + * Returns a string representing valid results. + * Returns the string that will be displayed with the question to + * indicate valid results to the user and a possibly set default, if + * available. + * + * @return string + */ + public function getResultString() + { + return "(" . implode( "/", $this->collection ) . ")" . ( $this->default !== null ? " [{$this->default}]" : "" ); + } + + /** + * Property read access. + * + * @param string $propertyName Name of the property. + * @return mixed Value of the property or null. + * + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * @ignore + */ + public function __get( $propertyName ) + { + if ( isset( $this->$propertyName ) ) + { + return $this->properties[$propertyName]; + } + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + + /** + * Property write access. + * + * @param string $propertyName Name of the property. + * @param mixed $propertyValue The value for the property. + * + * @throws ezcBasePropertyNotFoundException + * If a the value for the property options is not an instance of + * @throws ezcBaseValueException + * If a the value for a property is out of range. + * @ignore + */ + public function __set( $propertyName, $propertyValue ) + { + switch ( $propertyName ) + { + case "collection": + if ( is_array( $propertyValue ) === false ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "array" ); + } + break; + case "default": + if ( is_scalar( $propertyValue ) === false && $propertyValue !== null ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "scalar" ); + } + break; + case "conversion": + if ( $propertyValue !== self::CONVERT_NONE && $propertyValue !== self::CONVERT_UPPER && $propertyValue !== self::CONVERT_LOWER ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "ezcConsoleQuestionDialogCollectionValidator::CONVERT_*" ); + } + break; + default: + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + $this->properties[$propertyName] = $propertyValue; + } + + /** + * Property isset access. + * + * @param string $propertyName Name of the property. + * @return bool True is the property is set, otherwise false. + * @ignore + */ + public function __isset( $propertyName ) + { + return array_key_exists( $propertyName, $this->properties ); + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_mapping.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_mapping.php new file mode 100644 index 0000000..41af09a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_mapping.php @@ -0,0 +1,142 @@ + + * array( + * 'yes' => 'y', + * 'no' => 'n', + * '1' => 'y', + * '0' => 'n' + * ) + * + * While the corresponding collection of valid answers would look like + * this: + * + * array( + * 'y', 'n' + * ) + * + * If the answer 'yes' is received by the validator, it is mapped to 'y', + * therefore considered valid and 'y' is returned as the received value. + * + * @package ConsoleTools + * @version 1.6.1 + * + * @property array(string) $collection + * The collection of valid answers. + * @property mixed $default + * Default value. + * @property int $conversion + * ezcConsoleDialogValidator::CONVERT_NONE (default) or + * ezcConsoleDialogValidator::CONVERT_LOWER or + * ezcConsoleDialogValidator::CONVERT_UPPER. + * @property array(string=>string) $map + * Mapping of answers to valid answers (e.g. array('yes' => 'y') to + * map 'yes' to 'y' while 'y' must be in $collection). + */ +class ezcConsoleQuestionDialogMappingValidator extends ezcConsoleQuestionDialogCollectionValidator +{ + /** + * Creates a new question dialog mapping validator. + * Creates a new question dialog mapping validator, which validates the + * result specified by the user against an array of valid results + * ($collection). If not value is provided by the user a possibly set + * $default value is used instead. The $conversion parameter can optionally + * define a conversion to be performed on the result before validating it. + * Valid conversions are defined by the CONVERT_* constants in this class. + * + * While this functionality is already provided by {@link + * ezcConsoleQuestionDialogCollectionValidator}, the additional $map + * paramater allows the sepcification of a map of result values. These + * mapping is then checked for matches, before a received answer is + * validated against the collection. + * + * @param array(string) $collection The collection of valid results. + * @param mixed $default Optional default value. + * @param int $conversion CONVERT_* constant. + * @param array(string=>string) $map + * @return void + */ + public function __construct( array $collection, $default = null, $conversion = self::CONVERT_NONE, array $map = array() ) + { + // Initialize additional property + $this->properties['map'] = $map; + + parent::__construct( $collection, $default, $conversion ); + } + + /** + * Returns a fixed version of the result, if possible. + * Converts the given result according to the conversion defined in the + * $conversion property. + * + * @param mixed $result The received result. + * @return mixed The manipulated result. + */ + public function fixup( $result ) + { + if ( $result === "" && $this->default !== null ) + { + return $this->default; + } + switch ( $this->conversion ) + { + case self::CONVERT_UPPER: + $result = strtoupper( $result ); + break; + case self::CONVERT_LOWER: + $result = strtolower( $result ); + break; + } + return ( isset( $this->map[$result] ) ? $this->map[$result] : $result ); + } + + /** + * Property write access. + * + * @param string $propertyName Name of the property. + * @param mixed $propertyValue The value for the property. + * + * @throws ezcBasePropertyNotFoundException + * If a the value for the property options is not an instance of + * @throws ezcBaseValueException + * If a the value for a property is out of range. + * @ignore + */ + public function __set( $propertyName, $propertyValue ) + { + switch ( $propertyName ) + { + case "map": + if ( is_array( $propertyValue ) === false ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "array" ); + } + break; + default: + return parent::__set( $propertyName, $propertyValue ); + } + $this->properties[$propertyName] = $propertyValue; + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_regex.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_regex.php new file mode 100644 index 0000000..f6b6b8c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_regex.php @@ -0,0 +1,169 @@ +mixed) + */ + protected $properties = array( + "pattern" => null, + "default" => null, + ); + + /** + * Create a new question dialog regex validator. + * Create a new question dialog regex validator, which validates the result + * specified against a given regular expression. The delimiters and + * eventual modifiers must be included in the pattern. If not value is + * provided by the user a possibly set $default value is used instead. + * + * + * @param string $pattern Pattern to validate against. + * @param mixed $default Default value. + * @return void + */ + public function __construct( $pattern, $default = null ) + { + $this->pattern = $pattern; + $this->default = $default; + } + + /** + * Returns if the given result is valid. + * Returns if the result matches the regular expression. + * + * @param mixed $result The received result. + * @return bool If the result is valid. + */ + public function validate( $result ) + { + if ( $result === "" ) + { + return $this->default !== null; + } + return preg_match( $this->pattern, $result ) > 0; + } + + /** + * Returns a fixed version of the result, if possible. + * If no result was provided by the user, the default value will be + * returned, if set. + * + * @param mixed $result The received result. + * @return mixed The manipulated result. + */ + public function fixup( $result ) + { + if ( $result === "" && $this->default !== null ) + { + return $this->default; + } + return $result; + } + + /** + * Returns a string representing valid results. + * Returns the string that will be displayed with the question to + * indicate valid results to the user and a possibly set default, if + * available. + * + * @return string + */ + public function getResultString() + { + return "(match {$this->pattern})" . ( $this->default !== null ? " [{$this->default}]" : "" ); + } + + /** + * Property read access. + * + * @param string $propertyName Name of the property. + * @return mixed Value of the property or null. + * + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * @ignore + */ + public function __get( $propertyName ) + { + if ( $this->__isset( $propertyName ) ) + { + return $this->properties[$propertyName]; + } + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + + /** + * Property write access. + * + * @param string $propertyName Name of the property. + * @param mixed $propertyValue The value for the property. + * + * @throws ezcBasePropertyNotFoundException + * If a the value for the property options is not an instance of + * @throws ezcBaseValueException + * If a the value for a property is out of range. + * @ignore + */ + public function __set( $propertyName, $propertyValue ) + { + switch ( $propertyName ) + { + case "pattern": + if ( is_string( $propertyValue ) === false || strlen( $propertyValue ) < 2 ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "string, length > 1" ); + } + break; + case "default": + if ( is_scalar( $propertyValue ) === false && $propertyValue !== null ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "scalar" ); + } + break; + default: + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + $this->properties[$propertyName] = $propertyValue; + } + + /** + * Property isset access. + * + * @param string $propertyName Name of the property. + * @return bool True is the property is set, otherwise false. + * @ignore + */ + public function __isset( $propertyName ) + { + return array_key_exists( $propertyName, $this->properties ); + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_type.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_type.php new file mode 100644 index 0000000..e14371d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_type.php @@ -0,0 +1,227 @@ + self::TYPE_STRING, + "default" => null, + ); + + /** + * Creates a new question dialog type validator. + * Creates a new question dialog type validator, which validates the result + * specified to be of a certaon type. The $type must be one of the TYPE_* + * constants in this class. If no value is provided by the user a possibly + * set $default value is used instead. + * + * @param int $type One of ezcConsoleQuestionDialogTypeValidator::TYPE_*. + * @param mixed $default Default value according to $type. + * @return void + */ + public function __construct( $type = self::TYPE_STRING, $default = null ) + { + $this->type = $type; + $this->default = $default; + } + + /** + * Returns if the given result is valid. + * Returns if the result is of the given type. + * + * @param mixed $result The result to check. + * @return bool True if the result is valid. Otherwise false. + */ + public function validate( $result ) + { + if ( $result === "" ) + { + return $this->default !== null; + } + switch ( $this->type ) + { + case self::TYPE_INT: + return is_int( $result ); + case self::TYPE_FLOAT: + return is_float( $result ); + case self::TYPE_BOOL: + return is_bool( $result ); + case self::TYPE_STRING: + default: + return is_string( $result ); + } + } + + /** + * Returns a fixed version of the result, if possible. + * Returns the value casted into the correct type or the default value, if + * it exists and the result is empty. + * + * @param mixed $result The result received. + * @return mixed The manipulated result. + */ + public function fixup( $result ) + { + if ( $result === "" && $this->default !== null ) + { + return $this->default; + } + switch ( $this->type ) + { + case self::TYPE_INT: + return ( preg_match( "/^[0-9\-]+$/", $result ) !== 0 ) ? (int) $result : $result; + case self::TYPE_FLOAT: + return ( preg_match( "/^[0-9.E\-]+$/i", $result ) !== 0 ) ? (float) $result : $result; + case self::TYPE_BOOL: + switch ( $result ) + { + case "1": + case "true": + return true; + case "0": + case "false": + return false; + } + case self::TYPE_STRING: + default: + return $result; + } + } + + /** + * Returns a string representing valid results. + * Returns the string that can will be displayed with the question to + * indicate valid results to the user and a possibly set default, if + * available. + * + * @return string + */ + public function getResultString() + { + $res = "(<%s>)" . ( $this->default !== null ? " [{$this->default}]" : "" ); + switch ( $this->type ) + { + case self::TYPE_INT: + return sprintf( $res, "int" ); + case self::TYPE_FLOAT: + return sprintf( $res, "float" ); + case self::TYPE_BOOL: + return sprintf( $res, "bool" ); + case self::TYPE_STRING: + default: + return sprintf( $res, "string" ); + } + } + + /** + * Property read access. + * + * @param string $propertyName Name of the property. + * @return mixed Value of the property or null. + * + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * @ignore + */ + public function __get( $propertyName ) + { + if ( isset( $this->$propertyName ) ) + { + return $this->properties[$propertyName]; + } + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + + /** + * Property write access. + * + * @param string $propertyName Name of the property. + * @param mixed $propertyValue The value for the property. + * + * @throws ezcBasePropertyNotFoundException + * If a the value for the property options is not an instance of + * @throws ezcBaseValueException + * If a the value for a property is out of range. + * @ignore + */ + public function __set( $propertyName, $propertyValue ) + { + switch ( $propertyName ) + { + case "type": + if ( $propertyValue !== self::TYPE_STRING && $propertyValue !== self::TYPE_INT && $propertyValue !== self::TYPE_FLOAT && $propertyValue !== self::TYPE_BOOL ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "ezcConsoleQuestionDialogTypeValidator::TYPE_*" ); + } + break; + case "default": + if ( is_scalar( $propertyValue ) === false && $propertyValue !== null ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "scalar" ); + } + break; + default: + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + $this->properties[$propertyName] = $propertyValue; + } + + /** + * Property isset access. + * + * @param string $propertyName Name of the property. + * @return bool True is the property is set, otherwise false. + * @ignore + */ + public function __isset( $propertyName ) + { + return array_key_exists( $propertyName, $this->properties ); + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog_viewer.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog_viewer.php new file mode 100644 index 0000000..15a9a89 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/dialog_viewer.php @@ -0,0 +1,68 @@ + + * // Instatiate dialog in $dialog ... + * ezcConsoleDialogViewer::displayDialog( $dialog ); + * + * + * For implementing a custom dialog, the method {@link readLine()} method can be + * used to read a line of input from the user. + * + * @package ConsoleTools + * @version 1.6.1 + */ +class ezcConsoleDialogViewer +{ + /** + * Displays a dialog and returns a valid result from it. + * This methods displays a dialog in a loop, until it received a valid + * result from it and returns this result. + * + * @param ezcConsoleDialog $dialog The dialog to display. + * @return mixed The result from this dialog. + */ + public static function displayDialog( ezcConsoleDialog $dialog ) + { + do + { + $dialog->display(); + } + while ( $dialog->hasValidResult() === false ); + return $dialog->getResult(); + } + + /** + * Returns a line from STDIN. + * The returned line is fully trimmed. + * + * @return string + * @throws ezcConsoleDialogAbortException + * if the user closes STDIN using -D. + */ + public static function readLine() + { + $res = trim( fgets( STDIN ) ); + if ( feof( STDIN ) ) + { + throw new ezcConsoleDialogAbortException(); + } + return $res; + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument.php new file mode 100644 index 0000000..55f958a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument.php @@ -0,0 +1,23 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_already_registered.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_already_registered.php new file mode 100644 index 0000000..662b3b9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_already_registered.php @@ -0,0 +1,54 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_mandatory_violation.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_mandatory_violation.php new file mode 100644 index 0000000..9345c46 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_mandatory_violation.php @@ -0,0 +1,33 @@ +name}' is mandatory but was not submitted." ); + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_too_many.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_too_many.php new file mode 100644 index 0000000..36442a9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_too_many.php @@ -0,0 +1,33 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_type_violation.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_type_violation.php new file mode 100644 index 0000000..e2dc116 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/argument_type_violation.php @@ -0,0 +1,40 @@ +type ) + { + case ezcConsoleInput::TYPE_INT: + $typeName = 'int'; + break; + } + parent::__construct( "The argument '{$arg->name}' expects a value of type '{$typeName}', but received the value '{$value}'." ); + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/dialog_abort.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/dialog_abort.php new file mode 100644 index 0000000..1dc84c9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/dialog_abort.php @@ -0,0 +1,30 @@ +-D to a dialog instead of a valid answer. + * + * @package ConsoleTools + * @version 1.6.1 + */ +class ezcConsoleDialogAbortException extends ezcConsoleException +{ + /** + * Creates a new exception object. + * + * @param string $name Name of the already existing option. + * @return void + */ + public function __construct() + { + parent::__construct( "User send EOF." ); + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/exception.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/exception.php new file mode 100644 index 0000000..e3b3bac --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/exception.php @@ -0,0 +1,20 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/invalid_option_name.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/invalid_option_name.php new file mode 100644 index 0000000..7315bdf --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/invalid_option_name.php @@ -0,0 +1,32 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/invalid_output_target.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/invalid_output_target.php new file mode 100644 index 0000000..097d83a --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/invalid_output_target.php @@ -0,0 +1,32 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/no_position_stored.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/no_position_stored.php new file mode 100644 index 0000000..18b4c6f --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/no_position_stored.php @@ -0,0 +1,30 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/no_valid_dialog_result.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/no_valid_dialog_result.php new file mode 100644 index 0000000..5dc5d3e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/no_valid_dialog_result.php @@ -0,0 +1,32 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option.php new file mode 100644 index 0000000..78cfd1d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option.php @@ -0,0 +1,22 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_already_registered.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_already_registered.php new file mode 100644 index 0000000..0ebcc85 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_already_registered.php @@ -0,0 +1,31 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_arguments_violation.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_arguments_violation.php new file mode 100644 index 0000000..8f1c84d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_arguments_violation.php @@ -0,0 +1,32 @@ +long}' excludes the usage of arguments, but arguments have been submitted." ); + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_dependency_violation.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_dependency_violation.php new file mode 100644 index 0000000..0965848 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_dependency_violation.php @@ -0,0 +1,39 @@ +long}' depends on the option '{$dependantOption->long}' "; + if ( $valueRange !== null ) + { + $message .= "to have a value in '{$valueRange}' "; + } + $message .= "but this one was not submitted."; + parent::__construct( $message ); + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_exclusion_violation.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_exclusion_violation.php new file mode 100644 index 0000000..ead5774 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_exclusion_violation.php @@ -0,0 +1,39 @@ +long}' excludes the option '{$excludedOption->long}'"; + if ( $valueRange !== null ) + { + $message .= " to have a value in '{$valueRange}'"; + } + $message .= " but this one was submitted."; + parent::__construct( $message ); + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_mandatory_violation.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_mandatory_violation.php new file mode 100644 index 0000000..676d7ac --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_mandatory_violation.php @@ -0,0 +1,32 @@ +long}' is mandatory but was not submitted." ); + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_missing_value.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_missing_value.php new file mode 100644 index 0000000..fad8d9e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_missing_value.php @@ -0,0 +1,32 @@ +long}' expects a value, but none was submitted." ); + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_no_alias.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_no_alias.php new file mode 100644 index 0000000..464cc5e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_no_alias.php @@ -0,0 +1,31 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_not_exists.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_not_exists.php new file mode 100644 index 0000000..c9ed4dc --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_not_exists.php @@ -0,0 +1,31 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_string_not_wellformed.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_string_not_wellformed.php new file mode 100644 index 0000000..87159e5 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_string_not_wellformed.php @@ -0,0 +1,31 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_too_many_values.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_too_many_values.php new file mode 100644 index 0000000..d93e5b3 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_too_many_values.php @@ -0,0 +1,32 @@ +long}' expects a single value, but multiple were submitted." ); + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_type_violation.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_type_violation.php new file mode 100644 index 0000000..98c3aad --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/exceptions/option_type_violation.php @@ -0,0 +1,42 @@ +type ) + { + case ezcConsoleInput::TYPE_NONE: + $typeName = 'none'; + break; + case ezcConsoleInput::TYPE_INT: + $typeName = 'int'; + break; + } + parent::__construct( "The option '{$option->long}' expects a value of type '{$typeName}', but received the value '{$value}'." ); + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input.php new file mode 100644 index 0000000..33bfd77 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input.php @@ -0,0 +1,1396 @@ + + * $optionHandler = new ezcConsoleInput(); + * + * // Register simple parameter -h/--help + * $optionHandler->registerOption( new ezcConsoleOption( 'h', 'help' ) ); + * + * // Register complex parameter -f/--file + * $file = new ezcConsoleOption( + * 'f', + * 'file', + * ezcConsoleInput::TYPE_STRING, + * null, + * false, + * 'Process a file.', + * 'Processes a single file.' + * ); + * $optionHandler->registerOption( $file ); + * + * // Manipulate parameter -f/--file after registration + * $file->multiple = true; + * + * // Register another complex parameter that depends on -f and excludes -h + * $dir = new ezcConsoleOption( + * 'd', + * 'dir', + * ezcConsoleInput::TYPE_STRING, + * null, + * true, + * 'Process a directory.', + * 'Processes a complete directory.', + * array( new ezcConsoleOptionRule( $optionHandler->getOption( 'f' ) ) ), + * array( new ezcConsoleOptionRule( $optionHandler->getOption( 'h' ) ) ) + * ); + * $optionHandler->registerOption( $dir ); + * + * // Register an alias for this parameter + * $optionHandler->registerAlias( 'e', 'extended-dir', $dir ); + * + * // Process registered parameters and handle errors + * try + * { + * $optionHandler->process( array( 'example_input.php', '-h' ) ); + * } + * catch ( ezcConsoleOptionException $e ) + * { + * echo $e->getMessage(); + * exit( 1 ); + * } + * + * // Process a single parameter + * $file = $optionHandler->getOption( 'f' ); + * if ( $file->value === false ) + * { + * echo "Parameter -{$file->short}/--{$file->long} was not submitted.\n"; + * } + * elseif ( $file->value === true ) + * { + * echo "Parameter -{$file->short}/--{$file->long} was submitted without value.\n"; + * } + * else + * { + * echo "Parameter -{$file->short}/--{$file->long} was submitted with value '".var_export($file->value, true)."'.\n"; + * } + * + * // Process all parameters at once: + * foreach ( $optionHandler->getOptionValues() as $paramShort => $val ) + * { + * switch ( true ) + * { + * case $val === false: + * echo "Parameter $paramShort was not submitted.\n"; + * break; + * case $val === true: + * echo "Parameter $paramShort was submitted without a value.\n"; + * break; + * case is_array( $val ): + * echo "Parameter $paramShort was submitted multiple times with value: '".implode(', ', $val)."'.\n"; + * break; + * default: + * echo "Parameter $paramShort was submitted with value: '$val'.\n"; + * break; + * } + * } + * + * + * @package ConsoleTools + * @version 1.6.1 + * @mainclass + * + * @property ezcConsoleArguments $argumentDefinition Optional argument definition. + */ +class ezcConsoleInput +{ + /** + * Option does not carry a value. + */ + const TYPE_NONE = 1; + + /** + * Option takes an integer value. + */ + const TYPE_INT = 2; + + /** + * Option takes a string value. + */ + const TYPE_STRING = 3; + + /** + * Array of option definitions, indexed by number. + * + * This array stores the ezcConsoleOption objects representing + * the options. + * + * For lookup of an option after its short or long values the attributes + * {@link ezcConsoleInput::$optionShort} + * {@link ezcConsoleInput::$optionLong} + * are used. + * + * @var array(array) + */ + private $options = array(); + + /** + * Short option names. + * + * Each references a key in {@link ezcConsoleInput::$options}. + * + * @var array(string=>int) + */ + private $optionShort = array(); + + /** + * Long option names. + * + * Each references a key in {@link ezcConsoleInput::$options}. + * + * @var array(string=>int) + */ + private $optionLong = array(); + + /** + * Arguments, if submitted, are stored here. + * + * @var array(string) + */ + private $arguments = array(); + + /** + * Wether the process() method has already been called. + * + * @var bool + */ + private $processed = false; + + /** + * Indicates if an option was submitted, that has the isHelpOption flag set. + * + * @var bool + */ + private $helpOptionSet = false; + + /** + * Tool object for multi-byte encoding safe string operations. + * + * @var ezcConsoleStringTool + */ + private $stringTool; + + /** + * Input validator. + * + * @var ezcConsoleInputValidator + */ + private $validator; + + /** + * Help generator. + * + * @var ezcConsoleInputHelpGenerator + */ + private $helpGenerator; + + /** + * Collection of properties. + * + * @var array(string=>mixed) + */ + protected $properties = array(); + + /** + * Creates an input handler. + */ + public function __construct() + { + $this->argumentDefinition = null; + $this->stringTool = new ezcConsoleStringTool(); + + // @TODO Verify interface and make plugable + $this->validator = new ezcConsoleStandardInputValidator(); + $this->helpGenerator = new ezcConsoleInputStandardHelpGenerator( $this ); + } + + /** + * Registers the new option $option. + * + * This method adds the new option $option to your option collection. If + * already an option with the assigned short or long value exists, an + * exception will be thrown. + * + * @see ezcConsoleInput::unregisterOption() + * + * @param ezcConsoleOption $option + * + * @return ezcConsoleOption The recently registered option. + */ + public function registerOption( ezcConsoleOption $option ) + { + foreach ( $this->optionShort as $short => $ref ) + { + if ( $short === $option->short ) + { + throw new ezcConsoleOptionAlreadyRegisteredException( $short ); + } + } + foreach ( $this->optionLong as $long => $ref ) + { + if ( $long === $option->long ) + { + throw new ezcConsoleOptionAlreadyRegisteredException( $long ); + } + } + $this->options[] = $option; + $this->optionLong[$option->long] = $option; + if ( $option->short !== "" ) + { + $this->optionShort[$option->short] = $option; + } + return $option; + } + + /** + * Registers an alias for an option. + * + * Registers a new alias for an existing option. Aliases can + * be used as if they were a normal option. + * + * The alias is registered with the short option name $short and the + * long option name $long. The alias references to the existing + * option $option. + * + * @see ezcConsoleInput::unregisterAlias() + * + * @param string $short + * @param string $long + * @param ezcConsoleOption $option + * + * + * @throws ezcConsoleOptionNotExistsException + * If the referenced option is not registered. + * @throws ezcConsoleOptionAlreadyRegisteredException + * If another option/alias has taken the provided short or long name. + * @return void + */ + public function registerAlias( $short, $long, ezcConsoleOption $option ) + { + if ( !isset( $this->optionShort[$option->short] ) || !isset( $this->optionLong[$option->long] ) ) + { + throw new ezcConsoleOptionNotExistsException( $option->long ); + } + if ( isset( $this->optionShort[$short] ) || isset( $this->optionLong[$long] ) ) + { + throw new ezcConsoleOptionAlreadyRegisteredException( isset( $this->optionShort[$short] ) ? "-$short" : "--$long" ); + } + $this->optionShort[$short] = $option; + $this->optionLong[$long] = $option; + } + + /** + * Registers options according to a string specification. + * + * Accepts a string to define parameters and registers all parameters as + * options accordingly. String definition, specified in $optionDef, looks + * like this: + * + * + * [s:|size:][u:|user:][a:|all:] + * + * + * This string registers 3 parameters: + * -s / --size + * -u / --user + * -a / --all + * + * @param string $optionDef + * @return void + * + * @throws ezcConsoleOptionStringNotWellformedException + * If provided string does not have the correct format. + */ + public function registerOptionString( $optionDef ) + { + $regex = '\[([a-z0-9-]+)([:?*+])?([^|]*)\|([a-z0-9-]+)([:?*+])?\]'; + // Check string for wellformedness + if ( preg_match( "/^($regex)+$/", $optionDef ) == 0 ) + { + throw new ezcConsoleOptionStringNotWellformedException( "Option definition not wellformed: \"$optionDef\"" ); + } + if ( preg_match_all( "/$regex/", $optionDef, $matches ) ) + { + foreach ( $matches[1] as $id => $short ) + { + $option = null; + $option = new ezcConsoleOption( $short, $matches[4][$id] ); + if ( !empty( $matches[2][$id] ) || !empty( $matches[5][$id] ) ) + { + switch ( !empty( $matches[2][$id] ) ? $matches[2][$id] : $matches[5][$id] ) + { + case '*': + // Allows 0 or more occurances + $option->multiple = true; + break; + case '+': + // Allows 1 or more occurances + $option->multiple = true; + $option->type = self::TYPE_STRING; + break; + case '?': + $option->type = self::TYPE_STRING; + $option->default = ''; + break; + default: + break; + } + } + if ( !empty( $matches[3][$id] ) ) + { + $option->default = $matches[3][$id]; + } + $this->registerOption( $option ); + } + } + } + + /** + * Removes an option. + * + * This function removes an option. All dependencies to that + * specific option are removed completely from every other registered + * option. + * + * @see ezcConsoleInput::registerOption() + * + * @param ezcConsoleOption $option The option object to unregister. + * + * @throws ezcConsoleOptionNotExistsException + * If requesting a not registered option. + * @return void + */ + public function unregisterOption( ezcConsoleOption $option ) + { + $found = false; + foreach ( $this->options as $id => $existParam ) + { + if ( $existParam === $option ) + { + $found = true; + unset( $this->options[$id] ); + continue; + } + $existParam->removeAllExclusions( $option ); + $existParam->removeAllDependencies( $option ); + } + if ( $found === false ) + { + throw new ezcConsoleOptionNotExistsException( $option->long ); + } + foreach ( $this->optionLong as $name => $existParam ) + { + if ( $existParam === $option ) + { + unset( $this->optionLong[$name] ); + } + } + foreach ( $this->optionShort as $name => $existParam ) + { + if ( $existParam === $option ) + { + unset( $this->optionShort[$name] ); + } + } + } + + /** + * Removes an alias to an option. + * + * This function removes an alias with the short name $short and long + * name $long. + * + * @see ezcConsoleInput::registerAlias() + * + * @throws ezcConsoleOptionNoAliasException + * If the requested short/long name belongs to a real parameter instead. + * + * @param string $short + * @param string $long + * @return void + * + * @todo Check if $short and $long refer to the same option! + */ + public function unregisterAlias( $short, $long ) + { + foreach ( $this->options as $id => $option ) + { + if ( $option->short === $short ) + { + throw new ezcConsoleOptionNoAliasException( $short ); + } + if ( $option->long === $long ) + { + throw new ezcConsoleOptionNoAliasException( $long ); + } + } + if ( isset( $this->optionShort[$short] ) ) + { + unset( $this->optionShort[$short] ); + } + if ( isset( $this->optionLong[$long] ) ) + { + unset( $this->optionLong[$long] ); + } + } + + /** + * Returns the definition object for the option with the name $name. + * + * This method receives the long or short name of an option and + * returns the ezcConsoleOption object. + * + * @param string $name Short or long name of the option (without - or --). + * @return ezcConsoleOption + * + * @throws ezcConsoleOptionNotExistsException + * If requesting a not registered parameter. + */ + public function getOption( $name ) + { + $name = $name; + if ( isset( $this->optionShort[$name] ) ) + { + return $this->optionShort[$name]; + } + if ( isset( $this->optionLong[$name] ) ) + { + return $this->optionLong[$name]; + } + throw new ezcConsoleOptionNotExistsException( $name ); + } + + /** + * Process the input parameters. + * + * Actually process the input options and arguments according to the actual + * settings. + * + * Per default this method uses $argc and $argv for processing. You can + * override this setting with your own input, if necessary, using the + * parameters of this method. (Attention, first argument is always the pro + * gram name itself!) + * + * All exceptions thrown by this method contain an additional attribute "option" + * which specifies the parameter on which the error occurred. + * + * @param array(string) $args The arguments + * @return void + * + * @throws ezcConsoleOptionNotExistsException + * If an option that was submitted does not exist. + * @throws ezcConsoleOptionDependencyViolationException + * If a dependency rule was violated. + * @throws ezcConsoleOptionExclusionViolationException + * If an exclusion rule was violated. + * @throws ezcConsoleOptionTypeViolationException + * If the type of a submitted value violates the options type rule. + * @throws ezcConsoleOptionArgumentsViolationException + * If arguments are passed although a parameter disallowed them. + * + * @see ezcConsoleOptionException + */ + public function process( array $args = null ) + { + if ( $this->processed ) + { + $this->reset(); + } + $this->processed = true; + + if ( !isset( $args ) ) + { + $args = isset( $argv ) ? $argv : isset( $_SERVER['argv'] ) ? $_SERVER['argv'] : array(); + } + + $nextIndex = $this->processOptions( $args ); + + if ( $this->helpOptionSet() ) + { + // No need to parse arguments + return; + } + + $this->processArguments( $args, $nextIndex ); + + $this->checkRules(); + + $this->setOptionDefaults(); + } + + /** + * Sets defaults for options that have not been submitted. + * + * Checks all options if they have been submited. If not and a default + * values is present, this is set as the options value. + */ + private function setOptionDefaults() + { + foreach ( $this->options as $option ) + { + if ( $option->value === false || $option->value === array() ) + { + // Default value to set? + if ( $option->default !== null ) + { + $option->value = $option->default; + } + } + } + } + + /** + * Reads the submitted options from $args array. + * + * Returns the next index to check for arguments. + * + * @param array(string) $args + * @returns int + * + * @throws ezcConsoleOptionNotExistsException + * if a submitted option does not exist. + * @throws ezcConsoleOptionTooManyValuesException + * if an option that expects only a single value was submitted + * with multiple values. + * @throws ezcConsoleOptionTypeViolationException + * if an option was submitted with a value of the wrong type. + * @throws ezcConsoleOptionMissingValueException + * if an option thats expects a value was submitted without. + */ + private function processOptions( array $args ) + { + $numArgs = count( $args ); + $i = 1; + + while ( $i < $numArgs ) + { + if ( $args[$i] === '--' ) + { + break; + } + + // Equalize parameter handling (long params with =) + if ( iconv_substr( $args[$i], 0, 2, 'UTF-8' ) == '--' ) + { + $this->preprocessLongOption( $args, $i ); + // Update number of args, changed by preprocessLongOption() + $numArgs = count( $args ); + } + + // Check for parameter + if ( iconv_substr( $args[$i], 0, 1, 'UTF-8' ) === '-' ) + { + if ( !$this->hasOption( preg_replace( '/^-*/', '', $args[$i] ) ) ) + { + throw new ezcConsoleOptionNotExistsException( $args[$i] ); + } + $this->processOption( $args, $i ); + } + // Must be the arguments + else + { + break; + } + } + + // Move pointer over argument sign + isset( $args[$i] ) && $args[$i] == '--' ? ++$i : $i; + + return $i; + } + + /** + * Resets all option and argument values. + * + * This method is called automatically by {@link process()}, if this method + * is called twice or more, and may also be used to manually reset the + * values of all registered {@ezcConsoleOption} and {@link + * ezcConsoleArgument} objects. + */ + public function reset() + { + foreach ( $this->options as $option ) + { + $option->value = false; + } + if ( $this->argumentDefinition !== null ) + { + foreach ( $this->argumentDefinition as $argument ) + { + $argument->value = null; + } + } + $this->arguments = array(); + } + + /** + * Returns true if an option with the given name exists, otherwise false. + * + * Checks if an option with the given name is registered. + * + * @param string $name Short or long name of the option. + * @return bool True if option exists, otherwise false. + */ + public function hasOption( $name ) + { + try + { + $param = $this->getOption( $name ); + } + catch ( ezcConsoleOptionNotExistsException $e ) + { + return false; + } + return true; + } + + /** + * Returns an array of all registered options. + * + * Returns an array of all registered options in the following format: + * + * array( + * 0 => ezcConsoleOption, + * 1 => ezcConsoleOption, + * 2 => ezcConsoleOption, + * ... + * ); + * + * + * @return array(string=>ezcConsoleOption) Registered options. + */ + public function getOptions() + { + return $this->options; + } + + /** + * Returns the values of all submitted options. + * + * Returns an array of all values submitted to the options. The array is + * indexed by the parameters short name (excluding the '-' prefix). The array + * does not contain any parameter, which value is 'false' (meaning: the + * parameter was not submitted). + * + * @param bool $longnames Wheather to use longnames for indexing. + * @return array(string=>mixed) + */ + public function getOptionValues( $longnames = false ) + { + $res = array(); + foreach ( $this->options as $param ) + { + if ( $param->value !== false ) + { + $res[( $longnames === true ) ? $param->long : $param->short] = $param->value; + } + } + return $res; + } + + /** + * Returns arguments provided to the program. + * + * This method returns all arguments provided to a program in an + * int indexed array. Arguments are sorted in the way + * they are submitted to the program. You can disable arguments + * through the 'arguments' flag of a parameter, if you want + * to disallow arguments. + * + * Arguments are either the last part of the program call (if the + * last parameter is not a 'multiple' one) or divided via the '--' + * method which is commonly used on Unix (if the last parameter + * accepts multiple values this is required). + * + * @return array(string) Arguments. + */ + public function getArguments() + { + return $this->arguments; + } + + /** + * Get help information for your options. + * + * This method returns an array of help information for your options, + * indexed by int. Each help info has 2 fields: + * + * 0 => The options names (" / ") + * 1 => The help text (depending on the $long parameter) + * + * The $long options determines if you want to get the short or long help + * texts. The array returned can be used by {@link ezcConsoleTable}. + * + * If using the second options, you can filter the options shown in the + * help output (e.g. to show short help for related options). Provide + * as simple number indexed array of short and/or long values to set a filter. + * + * The $paramGrouping option can be used to group options in the help + * output. The structure of this array parameter is as follows: + * + * + * array( + * 'First section' => array( + * 'input', + * 'output' + * 'overwrite', + * ), + * 'Second section' => array( + * 'v', + * 'h', + * ), + * ) + * + * + * As can be seen, short option names are possible as well as long ones. + * The key of the first array level is the name of the section, which is + * assigned to an array of options to group under this section. The $params + * parameter still influences if an option is displayed at all. + * + * @param bool $long + * @param array(string) $params + * @param array(string=>array(string)) $paramGrouping + * @return array(array(string)) Table structure as explained. + * + * @apichange In future versions, the default values of $params will change + * to null instead of an empty array. Giving an empty array for + * these will then be taken literally. + */ + public function getHelp( $long = false, array $params = array(), array $paramGrouping = null ) + { + // New handling + $params = ( $params === array() || $params === null ? null : $params ); + + $help = array(); + if ( $paramGrouping === null ) + { + // Original handling + $help = $this->getOptionHelpWithoutGrouping( $long, $params ); + } + else + { + $help = $this->getOptionHelpWithGrouping( $long, $params, $paramGrouping ); + } + + if ( $this->argumentDefinition !== null ) + { + $help[] = array( "Arguments:", '' ); + + $argumentsHelp = $this->helpGenerator->generateArgumentHelp( $long ); + if ( $argumentsHelp === array() ) + { + $help[] = array( '', "No arguments available." ); + } + else + { + $help = array_merge( $help, $argumentsHelp ); + } + } + + return $help; + } + + /** + * Creates the option help array in the original, ungrouped way. + * + * Creates the original help array generated by {@link getHelp()}. The + * $long and $params options are the same as they are for this method. + * + * @param bool $long + * @param array $params + * @return array + */ + private function getOptionHelpWithoutGrouping( $long, $params ) + { + return $this->helpGenerator->generateUngroupedOptionHelp( + $long, + $params + ); + } + + /** + * Generates options helo array with ordering and grouping. + * + * @param mixed $long + * @param mixed $params + * @param mixed $paramGrouping + * @return array() + */ + private function getOptionHelpWithGrouping( $long, $params, $paramGrouping ) + { + $rawHelp = $this->helpGenerator->generateGroupedOptionHelp( + $paramGrouping, + $long, + $params + ); + + $help = array(); + $first = true; + foreach ( $rawHelp as $category => $optionsHelp ) + { + if ( !$first ) + { + $help[] = array( '', '' ); + } + else + { + $first = false; + } + + $help[] = array( $category, '' ); + $help = array_merge( $help, $optionsHelp ); + } + return $help; + } + + + /** + * Get help information for your options as a table. + * + * This method provides the information returned by + * {@link ezcConsoleInput::getHelp()} in a table. + * + * The $paramGrouping option can be used to group options in the help + * output. The structure of this array parameter is as follows: + * + * + * array( + * 'First section' => array( + * 'input', + * 'output' + * 'overwrite', + * ), + * 'Second section' => array( + * 'v', + * 'h', + * ), + * ) + * + * + * As can be seen, short option names are possible as well as long ones. + * The key of the first array level is the name of the section, which is + * assigned to an array of options to group under this section. The $params + * parameter still influences if an option as displayed at all. + * + * @param ezcConsoleTable $table The table object to fill. + * @param bool $long Set this to true for getting the + * long help version. + * @param array(string) $params Set of option names to generate help + * for, default is all. + * @param array(string=>array(string)) $paramGrouping + * @return ezcConsoleTable The filled table. + */ + public function getHelpTable( ezcConsoleTable $table, $long = false, array $params = array(), $paramGrouping = null ) + { + $help = $this->getHelp( $long, $params, $paramGrouping ); + $i = 0; + foreach ( $help as $row ) + { + $table[$i][0]->content = $row[0]; + $table[$i++][1]->content = $row[1]; + } + return $table; + } + + /** + * Returns a standard help output for your program. + * + * This method generates a help text as it's commonly known from Unix + * command line programs. The output will contain the synopsis, your + * provided program description and the selected parameter help + * as also provided by {@link ezcConsoleInput::getHelp()}. The returned + * string can directly be printed to the console. + * + * The $paramGrouping option can be used to group options in the help + * output. The structure of this array parameter is as follows: + * + * + * array( + * 'First section' => array( + * 'input', + * 'output' + * 'overwrite', + * ), + * 'Second section' => array( + * 'v', + * 'h', + * ), + * ) + * + * + * As can be seen, short option names are possible as well as long ones. + * The key of the first array level is the name of the section, which is + * assigned to an array of options to group under this section. The $params + * parameter still influences if an option as displayed at all. + * + * @param string $programDesc The description of your program. + * @param int $width The width to adjust the output text to. + * @param bool $long Set this to true for getting the long + * help version. + * @param array(string) $params Set of option names to generate help + * for, default is all. + * @param array(string=>array(string)) $paramGrouping + * @return string The generated help text. + */ + public function getHelpText( $programDesc, $width = 80, $long = false, array $params = null, $paramGrouping = null ) + { + $help = $this->getHelp( $long, ( $params == null ? array() : $params ), $paramGrouping ); + + // Determine max length of first column text. + $maxLength = 0; + foreach ( $help as $row ) + { + $maxLength = max( $maxLength, iconv_strlen( $row[0], 'UTF-8' ) ); + } + + // Width of left column + $leftColWidth = $maxLength + 2; + // Width of righ column + $rightColWidth = $width - $leftColWidth; + + $res = 'Usage: ' . $this->getSynopsis( $params ) . PHP_EOL; + $res .= $this->stringTool->wordwrap( $programDesc, $width, PHP_EOL ); + $res .= PHP_EOL . PHP_EOL; + foreach ( $help as $row ) + { + $rowParts = explode( + "\n", + $this->stringTool->wordwrap( $row[1], $rightColWidth ) + ); + + $res .= $this->stringTool->strPad( $row[0], $leftColWidth, ' ' ); + $res .= $rowParts[0] . PHP_EOL; + // @TODO: Fix function call in loop header + for ( $i = 1; $i < sizeof( $rowParts ); $i++ ) + { + $res .= str_repeat( ' ', $leftColWidth ) . $rowParts[$i] . PHP_EOL; + } + } + return $res; + } + + /** + * Returns the synopsis string for the program. + * + * This gives you a synopsis definition for the options and arguments + * defined with this instance of ezcConsoleInput. You can filter the + * options named in the synopsis by submitting their short names in an + * array as the parameter of this method. If the parameter $optionNames + * is set, only those options are listed in the synopsis. + * + * @param array(string) $optionNames + * @return string + */ + public function getSynopsis( array $optionNames = null ) + { + return $this->helpGenerator->generateSynopsis( $optionNames ); + } + + /** + * Returns if a help option was set. + * This method returns if an option was submitted, which was defined to be + * a help option, using the isHelpOption flag. + * + * @return bool If a help option was set. + */ + public function helpOptionSet() + { + return $this->helpOptionSet; + } + + /** + * Property read access. + * + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * + * @param string $propertyName Name of the property. + * @return mixed Value of the property or null. + * @ignore + */ + public function __get( $propertyName ) + { + if ( !isset( $this->$propertyName ) ) + { + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + return $this->properties[$propertyName]; + } + + /** + * Property set access. + * + * @param string $propertyName + * @param string $propertyValue + * @ignore + * @return void + */ + public function __set( $propertyName, $propertyValue ) + { + switch ( $propertyName ) + { + case "argumentDefinition": + if ( ( $propertyValue instanceof ezcConsoleArguments ) === false && $propertyValue !== null ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "ezcConsoleArguments" ); + } + break; + default: + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + $this->properties[$propertyName] = $propertyValue; + } + + /** + * Property isset access. + * + * @param string $propertyName Name of the property. + * @return bool True if the property is set, otherwise false. + * @ignore + */ + public function __isset( $propertyName ) + { + return array_key_exists( $propertyName, $this->properties ); + } + + /** + * Returns the synopsis string for a single option and its dependencies. + * + * This method returns a part of the program synopsis, specifically for a + * certain parameter. The method recursively adds depending parameters up + * to the 2nd depth level to the synopsis. The second parameter is used + * to store the short names of all options that have already been used in + * the synopsis (to avoid adding an option twice). The 3rd parameter + * determines the actual deps in the option dependency recursion to + * terminate that after 2 recursions. + * + * @param ezcConsoleOption $option The option to include. + * @param array(string) $usedOptions Array of used option short names. + * @param int $depth Current recursion depth. + * @return string The synopsis for this parameter. + * + * @apichange This method is deprecates. Implement your own {@link + * ezcConsoleInputHelpGenerator} instead, as soon as the + * interface is made public. + */ + protected function createOptionSynopsis( ezcConsoleOption $option, &$usedOptions, $depth = 0 ) + { + $synopsis = ''; + + // Break after a nesting level of 2 + if ( $depth++ > 2 || ( in_array( $option->short, $usedOptions['short'] ) && in_array( $option->long, $usedOptions['long'] ) ) ) return $synopsis; + + $usedOptions['short'][] = $option->short; + $usedOptions['long'][] = $option->long; + + $synopsis .= $option->short !== "" ? "-{$option->short}" : "--{$option->long}"; + + if ( isset( $option->default ) ) + { + $synopsis .= " " . ( $option->type === ezcConsoleInput::TYPE_STRING ? '"' : '' ) . $option->default . ( $option->type === ezcConsoleInput::TYPE_STRING ? '"' : '' ); + } + else if ( $option->type !== ezcConsoleInput::TYPE_NONE ) + { + $synopsis .= " "; + switch ( $option->type ) + { + case ezcConsoleInput::TYPE_STRING: + $synopsis .= ""; + break; + case ezcConsoleInput::TYPE_INT: + $synopsis .= ""; + break; + } + } + + foreach ( $option->getDependencies() as $rule ) + { + $deeperSynopsis = $this->createOptionSynopsis( $rule->option, $usedOptions, $depth ); + $synopsis .= ( iconv_strlen( trim( $deeperSynopsis ), 'UTF-8' ) > 0 + ? ' ' . $deeperSynopsis + : '' + ); + } + + if ( $option->arguments === false ) + { + $allowsArgs = false; + } + + // Make the whole thing optional? + if ( $option->mandatory === false ) + { + $synopsis = "[$synopsis]"; + } + + return $synopsis . ' '; + } + + /** + * Process an option. + * + * This method does the processing of a single option. + * + * @param array(string) $args The arguments array. + * @param int $i The current position in the arguments array. + * @return void + * + * @throws ezcConsoleOptionTooManyValuesException + * If an option that expects only a single value was submitted + * with multiple values. + * @throws ezcConsoleOptionTypeViolationException + * If an option was submitted with a value of the wrong type. + * @throws ezcConsoleOptionMissingValueException + * If an option thats expects a value was submitted without. + */ + private function processOption( array $args, &$i ) + { + $option = $this->getOption( preg_replace( '/^-+/', '', $args[$i++] ) ); + + // Is the actual option a help option? + if ( $option->isHelpOption === true ) + { + $this->helpOptionSet = true; + } + // No value expected + if ( $option->type === ezcConsoleInput::TYPE_NONE ) + { + // No value expected + if ( isset( $args[$i] ) && iconv_substr( $args[$i], 0, 1, 'UTF-8' ) !== '-' && sizeof( $args ) > ( $i + 1 ) ) + { + // But one found + throw new ezcConsoleOptionTypeViolationException( $option, $args[$i] ); + } + // Multiple occurance possible + if ( $option->multiple === true ) + { + $option->value[] = true; + } + else + { + $option->value = true; + } + // Everything fine, nothing to do + return $i; + } + // Value expected, check for it + if ( isset( $args[$i] ) && iconv_substr( $args[$i], 0, 1, 'UTF-8' ) !== '-' ) + { + // Type check + if ( $this->isCorrectType( $option->type, $args[$i] ) === false ) + { + throw new ezcConsoleOptionTypeViolationException( $option, $args[$i] ); + } + // Multiple values possible + if ( $option->multiple === true ) + { + $option->value[] = $args[$i]; + } + // Only single value expected, check for multiple + elseif ( isset( $option->value ) && $option->value !== false ) + { + throw new ezcConsoleOptionTooManyValuesException( $option ); + } + else + { + $option->value = $args[$i]; + } + $i++; + } + // Value found? If not, use default, if available + if ( !isset( $option->value ) || $option->value === false || ( is_array( $option->value ) && count( $option->value ) === 0) ) + { + throw new ezcConsoleOptionMissingValueException( $option ); + } + } + + /** + * Process arguments given to the program. + * + * @param array(string) $args The arguments array. + * @param int $i Current index in arguments array. + * @return void + */ + private function processArguments( array $args, &$i ) + { + $numArgs = count( $args ); + if ( $this->argumentDefinition === null || $this->argumentsAllowed() === false ) + { + // Old argument handling, also used of a set option sets disallowing arguments + while ( $i < $numArgs ) + { + $this->arguments[] = $args[$i++]; + } + } + else + { + $mandatory = true; + foreach ( $this->argumentDefinition as $arg ) + { + // Check if all followinga arguments are optional + if ( $arg->mandatory === false ) + { + $mandatory = false; + } + + // Check if the current argument is present and mandatory + if ( $mandatory === true ) + { + if ( !isset( $args[$i] ) ) + { + throw new ezcConsoleArgumentMandatoryViolationException( $arg ); + } + } + else + { + // Arguments are optional, if no more left: return. + if ( !isset( $args[$i] ) ) + { + // Optional and no more arguments left, assign default + $arg->value = $arg->default; + continue; + } + } + + if ( $arg->multiple === true ) + { + $arg->value = array(); + for ( $i = $i; $i < $numArgs; ++$i ) + { + if ( $this->isCorrectType( $arg->type, $args[$i] ) === false ) + { + throw new ezcConsoleArgumentTypeViolationException( $arg, $args[$i] ); + } + $arg->value = array_merge( $arg->value, array( $args[$i] ) ); + // Keep old handling, too + $this->arguments[] = $args[$i]; + } + return; + } + else + { + if ( $this->isCorrectType( $arg->type, $args[$i] ) === false ) + { + throw new ezcConsoleArgumentTypeViolationException( $arg, $args[$i] ); + } + $arg->value = $args[$i]; + // Keep old handling, too + $this->arguments[] = $args[$i]; + } + ++$i; + } + + if ( $i < $numArgs ) + { + throw new ezcConsoleTooManyArgumentsException( $args, $i ); + } + } + } + + /** + * Returns if arguments are allowed with the current option submition. + * + * @return bool If arguments allowed. + */ + protected function argumentsAllowed() + { + foreach ( $this->options as $id => $option ) + { + if ( $option->value !== false && $option->arguments === false ) + { + return false; + } + } + return true; + } + + /** + * Check the rules that may be associated with an option. + * + * Options are allowed to have rules associated for dependencies to other + * options and exclusion of other options or arguments. This method + * processes the checks. + * + * @throws ezcConsoleException + * in case validation fails. + */ + private function checkRules() + { + // If a help option is set, skip rule checking + if ( $this->helpOptionSet === true ) + { + return; + } + $this->validator->validateOptions( + $this->options, + ( $this->arguments !== array() ) + ); + } + + /** + * Checks if a value is of a given type. Converts the value to the + * correct PHP type on success. + * + * @param int $type The type to check for. One of self::TYPE_*. + * @param string $val The value to check. Will possibly altered! + * @return bool True on succesful check, otherwise false. + */ + private function isCorrectType( $type, &$val ) + { + $res = false; + switch ( $type ) + { + case ezcConsoleInput::TYPE_STRING: + $res = true; + $val = preg_replace( '/^(["\'])(.*)\1$/', '\2', $val ); + break; + case ezcConsoleInput::TYPE_INT: + $res = preg_match( '/^[0-9]+$/', $val ) ? true : false; + if ( $res ) + { + $val = ( int ) $val; + } + break; + } + return $res; + } + + /** + * Split parameter and value for long option names. + * + * This method checks for long options, if the value is passed using =. If + * this is the case parameter and value get split and replaced in the + * arguments array. + * + * @param array(string) $args The arguments array + * @param int $i Current arguments array position + * @return void + */ + private function preprocessLongOption( array &$args, $i ) + { + // Value given? + if ( preg_match( '/^--\w+\=[^ ]/i', $args[$i] ) ) + { + // Split param and value and replace current param + $parts = explode( '=', $args[$i], 2 ); + array_splice( $args, $i, 1, $parts ); + } + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/argument.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/argument.php new file mode 100644 index 0000000..b032e94 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/argument.php @@ -0,0 +1,180 @@ + null, + "type" => ezcConsoleInput::TYPE_STRING, + "shorthelp" => "No help available.", + "longhelp" => "There is no help for this argument available.", + "mandatory" => true, + "multiple" => false, + "default" => null, + "value" => null, + ); + + /** + * Creates a new console argument object. + * Creates a new console argument object, which represents a single + * argument on the shell. Arguments are stored insiede + * {@link ezcConsoleArguments} which is used with {@link ezcConsoleInput}. + * + * For the type property see {@link ezcConsoleInput::TYPE_STRING} and + * {@link ezcConsoleInput::TYPE_INT}. If 1 argument is defined as optional + * ($mandatory = false), all following arguments are autolamtically + * considered optional, too. + * + * @param string $name The name for the argument. Must be unique. + * @param int $type The value type. + * @param string $shorthelp A short help text. + * @param string $longhelp A long help text- + * @param bool $mandatory Whether the argument is mandatory. + * @param bool $multiple Whether the argument accepts multiple values. + * @param mixed $default A default value, if not mandatory. + * @return void + */ + public function __construct( + $name = null, + $type = ezcConsoleInput::TYPE_STRING, + $shorthelp = "No help available.", + $longhelp = "There is no help for this argument available.", + $mandatory = true, + $multiple = false, + $default = null + ) + { + if ( !is_string( $name ) || strlen( $name ) < 1 ) + { + throw new ezcBaseValueException( "name", $name, "string, length > 0" ); + } + $this->properties["name"] = $name; + + $this->type = $type; + $this->shorthelp = $shorthelp; + $this->longhelp = $longhelp; + $this->mandatory = $mandatory; + $this->multiple = $multiple; + $this->default = $default; + } + + /** + * Property set access. + * + * @param string $propertyName Name of the property. + * @param string $propertyValue Valze for the property. + * @return void + * @ignore + */ + public function __set( $propertyName, $propertyValue ) + { + switch ( $propertyName ) + { + case "name": + throw new ezcBasePropertyPermissionException( $propertyName, ezcBasePropertyPermissionException::READ ); + break; + case "type": + if ( $propertyValue !== ezcConsoleInput::TYPE_INT && $propertyValue !== ezcConsoleInput::TYPE_STRING ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "string, length > 0" ); + } + break; + case "shorthelp": + case "longhelp": + if ( is_string( $propertyValue ) === false ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "string" ); + } + break; + case "mandatory": + case "multiple": + if ( is_bool( $propertyValue ) === false ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "bool" ); + } + break; + case "default": + if ( is_scalar( $propertyValue ) === false && is_array( $propertyValue ) === false && $propertyValue !== null ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "array, scalar or null" ); + } + break; + case "value": + if ( is_scalar( $propertyValue ) === false && is_array( $propertyValue ) === false && $propertyValue !== null ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, "string or null" ); + } + break; + default: + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + $this->properties[$propertyName] = $propertyValue; + } + + /** + * Property read access. + * + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * + * @param string $propertyName Name of the property. + * @return mixed Value of the property or null. + * @ignore + */ + public function __get( $propertyName ) + { + if ( isset( $this->$propertyName ) ) + { + return $this->properties[$propertyName]; + } + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + + /** + * Property isset access. + * + * @param string $propertyName Name of the property. + * @return bool True is the property is set, otherwise false. + * @ignore + */ + public function __isset( $propertyName ) + { + return array_key_exists( $propertyName, $this->properties ); + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/arguments.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/arguments.php new file mode 100644 index 0000000..1a4f56b --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/arguments.php @@ -0,0 +1,246 @@ +ezcConsoleArgument) + */ + protected $named = array(); + + /** + * Returns if the given offset exists. + * This method is part of the ArrayAccess interface to allow access to the + * data of this object as if it was an array. Valid offsets are integers or + * strings. If an integer is used, it refers to the position in the command + * line. A string refers to the arguments name property. + * + * @param mixed $offset The offset to check. + * @return bool True when the offset exists, otherwise false. + * + * @throws ezcBaseValueException + * If the provided offset is neither an integer, nor a string. + */ + public function offsetExists( $offset ) + { + switch ( gettype( $offset ) ) + { + case "string": + return array_key_exists( $offset, $this->named ); + case "integer": + return array_key_exists( $offset, $this->ordered ); + default: + throw new ezcBaseValueException( "offset", $offset, "string or int" ); + } + } + + /** + * Returns the element with the given offset. + * This method is part of the ArrayAccess interface to allow access to the + * data of this object as if it was an array. Valid offsets are integers or + * strings. If an integer is used, it refers to the position in the command + * line. A string refers to the arguments name property. + * + * @param string|integer $offset The offset to check. + * @return ezcConsoleArgument + * + * @throws ezcBaseValueException + * If the provided offset is neither an integer, nor a string. + */ + public function offsetGet( $offset ) + { + switch ( gettype( $offset ) ) + { + case "string": + if ( isset( $this[$offset] ) ) + { + return $this->named[$offset]; + } + break; + case "integer": + if ( isset( $this[$offset] ) ) + { + return $this->ordered[$offset]; + } + break; + default: + throw new ezcBaseValueException( "offset", $offset, "string or int" ); + } + throw new ezcBasePropertyNotFoundException( $offset ); + } + + /** + * Set the element with the given offset. + * This method is part of the ArrayAccess interface to allow access to the + * data of this object as if it was an array. In contrast to the other + * ArrayAccess implementations of this class, this method allows only integer + * keys. + * + * @param int $offset The offset to assign an item to. + * @param ezcConsoleArgument $value The argument object to register. + * @return void + * + * @throws ezcBaseValueException + * If a non integer offset is provided. + * @throws ezcBaseValueException + * If the provided value is not of type {@ling ezcConsoleTableRow}. + * @throws ezcConsoleArgumentAlreadyRegisteredException + * If an argument with the given offset or name is already registered. + */ + public function offsetSet( $offset, $value ) + { + // Determine key if not set (using $obj[] = ...) + if ( $offset === null ) + { + $offset = count( $this->ordered ) === 0 ? 0 : max( array_keys( $this->ordered ) ) + 1; + } + + // Set access only allowed with integer values + if ( !is_int( $offset ) ) + { + throw new ezcBaseValueException( "offset", $offset, "int" ); + } + + switch ( true ) + { + case ( $value instanceof ezcConsoleArgument ): + if ( isset( $this->ordered[$offset] ) ) + { + throw new ezcConsoleArgumentAlreadyRegisteredException( $offset, ezcConsoleArgumentAlreadyRegisteredException::ORDERED ); + } + if ( isset( $this->named[$value->name] ) ) + { + throw new ezcConsoleArgumentAlreadyRegisteredException( $value->name, ezcConsoleArgumentAlreadyRegisteredException::NAMED ); + } + + $this->named[$value->name] = $value; + $this->ordered[$offset] = $value; + break; + case ( $value === null ): + // Aliasing unset() with assignement to null + unset( $this->named[$this->ordered[$offset]->name] ); + unset( $this->ordered[$offset] ); + break; + default: + throw new ezcBaseValueException( "value", $value, "ezcConsoleArgument or null" ); + } + } + + /** + * Unset the element with the given offset. + * This method is part of the ArrayAccess interface to allow access to the + * data of this object as if it was an array. In contrast to the other + * ArrayAccess implementations of this class, this method allows only integer + * keys. + * + * @param int $offset The offset to unset the value for. + * @return void + * + * @throws ezcBaseValueException + * If a non numeric row offset is used. + */ + public function offsetUnset( $offset ) + { + // Set access only allowed with integer values + if ( is_int( $offset ) === false ) + { + throw new ezcBaseValueException( "offset", $offset, "int" ); + } + + unset( $this->named[$this->ordered[$offset]->name] ); + unset( $this->ordered[$offset] ); + } + + /** + * Returns the currently selected argument from the list. + * Used by foreach-Loops. + * + * @return ezcConsoleArgument + */ + public function current() + { + return current( $this->ordered ); + } + + /** + * Returns the key of the currently selected argument from the list. + * Used by foreach-Loops. In contrast to the iteration direction, which is + * defined by the ordered list of arguments, this is the name of the + * argument. + * + * @return string + */ + public function key() + { + return key( $this->ordered ); + } + + /** + * Advances the internal pointer to the next argument and returns it. + * Used by foreach-Loops. + * + * @return ezcConsoleArgument + */ + public function next() + { + return next( $this->ordered ); + } + + /** + * Rewinds the internal pointer to the first argument and returns it. + * Used by foreach-Loops. + * + * @return ezcConsoleArgument + */ + public function rewind() + { + // Called before foreach + ksort( $this->ordered ); + return reset( $this->ordered ); + } + + /** + * Checks if the current position is valid. + * Used by foreach-Loops. + * + * @return bool + */ + public function valid() + { + return ( current( $this->ordered ) !== false ); + } + + /** + * Returns the number of registered arguments. + * + * @return int + */ + public function count() + { + return count( $this->ordered ); + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/help_generators/standard.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/help_generators/standard.php new file mode 100644 index 0000000..9922722 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/help_generators/standard.php @@ -0,0 +1,391 @@ +input = $input; + } + + /** + * Generates help information as a multidimensional array. + * + * This method generates a tabular view on the help information of a + * program. The returned array has the following structure: + * + * + * array( + * 0 => ' + * + * Each row of the array represents the help information for a single option. + * The first cell of a row contains the option name (maybe short, long or + * both), the second cell contains the help text of the option. + * + * The returned array is used by {@link ezcConsoleInput} for different + * purposes. + * For example, the user can retrieve it raw through the + * {@link ezcConsoleInput::getHelp()} method, he can generate a help + * {@link ezcConsoleTable} through {@link ezcConsoleInput::getHelpTable()} + * are can generate a printable help text through {@link + * ezcConsoleInput::getHelpText()}. + * + * The parameter $long defines if the long or short help text of the + * options should be used in the second cell of the returned array. The + * $optionsFilter parameter is used to restrict the generated help to a certain + * sub-set of options. It consists of an array of short or long names of + * the options to include. + * + * @param bool $long + * @param array(string) $optionsFilter + * @return array(array(string)) + */ + public function generateUngroupedOptionHelp( $long = false, array $optionsFilter = null ) + { + $help = array(); + foreach ( $this->input->getOptions() as $id => $param ) + { + if ( $optionsFilter === null || in_array( $param->short, $optionsFilter ) || in_array( $param->long, $optionsFilter ) ) + { + $help[] = $this->getOptionHelpRow( $long, $param ); + } + } + return $help; + } + + /** + * Generates help information as a multidimensional array, grouped in categories. + * + * This method behaves similar to {@link generateUngroupedOptionHelp()}. In + * contrast to the latter one, this method returns an array with 1 + * dimension more, grouping options into categories. The $groups parameter + * defines the categories to generate. Each category may contain an + * arbitrary number of options, options might occur in different + * categories. + * + * The returned array has the follorwing format: + * + * + * ' => array( + * 0 => array( + * 0 => ' + * + * The $long parameter, as in {@link generateUngroupedOptionHelp()} + * determines if the options short or long help is to be used. The + * $params array can in addition be used to determine if a parameter + * is displayed at all. If $optionsFilter is submitted and is not null, + * only options listed in it will be shown in the help at all. + * + * @param array(string=>array(string)) $groups + * @param bool $long + * @param array(string) $params + * @return array(string=>array(array(string))) + */ + public function generateGroupedOptionHelp( array $groups, $long = false, array $optionsFilter = null ) + { + $help = array(); + foreach ( $groups as $groupName => $groupOptions ) + { + foreach ( $groupOptions as $optionName ) + { + $option = $this->input->getOption( $optionName ); + if ( $optionsFilter === null || in_array( $option->short, $optionsFilter ) || in_array( $option->long, $optionsFilter ) ) + { + $help[$groupName][] = $this->getOptionHelpRow( + $long, + $option + ); + } + } + } + return $help; + } + + /** + * Generates help information as a multi-dimensonal array for the given $argumentDefinition. + * + * This method generates a tabular help information for the given + * $argumentDefinition in the following format: + * + * + * array( + * 0 => '', + * 1 => '' + * ), + * 1 => array( + * 0 => '', + * 1 => '' + * ), + * // ... + * ) + * ?> + * + * + * The $long parameter defines if the long of short help text should be + * used. + * + * @param bool $long + * @return array(array(string)) + */ + public function generateArgumentHelp( $long = false ) + { + $help = array(); + if ( $this->input->argumentDefinition !== null ) + { + foreach ( $this->input->argumentDefinition as $arg ) + { + $argSynopsis = "<%s:%s>"; + switch ( $arg->type ) + { + case ezcConsoleInput::TYPE_INT: + $type = "int"; + break; + case ezcConsoleInput::TYPE_STRING: + $type = "string"; + break; + } + $argSynopsis = sprintf( $argSynopsis, $type, $arg->name ); + $help[] = ( $long === true ) + ? array( + $argSynopsis, + $arg->longhelp . ( $arg->mandatory === false + ? ' (optional' . ( $arg->default !== null + ? ', default = ' . ( is_array( $arg->default ) + ? "'" . implode( "' '", $arg->default ) . "'" + : "'$arg->default'" + ) + : '' + ) . ')' + : '' + ) + ) + : array( $argSynopsis, $arg->shorthelp ); + } + } + return $help; + } + + /** + * Creates 1 text row for displaying options help. + * + * Returns a single array entry for the {@link getOptionHelpRow()} method. + * + * @param bool $long + * @param ezcConsoleOption $param + * @return string + */ + private function getOptionHelpRow( $long, ezcConsoleOption $param ) + { + return array( + ( $param->short !== "" ? '-' . $param->short . ' / ' : "" ) . '--' . $param->long, + $long == false ? $param->shorthelp : $param->longhelp, + ); + } + + /** + * Generates a command line synopsis for the options and arguments. + * + * This method generates a synopsis string that lists the options and + * parameters available, indicating their usage. If $optionsFilter is + * submitted, only the options named in this array (short or long variant) + * will be included in the synopsis. + * + * @param array(string) $optionsFilter + * @return string + */ + public function generateSynopsis( array $optionFilter = null ) + { + $usedOptions = array( 'short' => array(), 'long' => array() ); + $allowsArgs = true; + $synopsis = '$ ' . ( isset( $argv ) && sizeof( $argv ) > 0 ? $argv[0] : $_SERVER['argv'][0] ) . ' '; + foreach ( $this->input->getOptions() as $option ) + { + if ( $optionFilter === null || in_array( $option->short, $optionFilter ) || in_array( $option->long, $optionFilter ) ) + { + $synopsis .= $this->createOptionSynopsis( $option, $usedOptions, $allowsArgs ); + } + } + if ( $this->input->argumentDefinition === null ) + { + // Old handling + $synopsis .= " [[--] ]"; + } + else + { + $synopsis .= "[--] " . $this->createArgumentsSynopsis(); + } + return $synopsis; + } + + /** + * Returns the synopsis string for a single option and its dependencies. + * + * This method returns a part of the program synopsis, specifically for a + * certain parameter. The method recursively adds depending parameters up + * to the 2nd depth level to the synopsis. The second parameter is used + * to store the short names of all options that have already been used in + * the synopsis (to avoid adding an option twice). The 3rd parameter + * determines the actual deps in the option dependency recursion to + * terminate that after 2 recursions. + * + * @param ezcConsoleOption $option The option to include. + * @param array(string) $usedOptions Array of used option short names. + * @param int $depth Current recursion depth. + * @return string The synopsis for this parameter. + */ + private function createOptionSynopsis( ezcConsoleOption $option, &$usedOptions, $depth = 0 ) + { + $synopsis = ''; + + // Break after a nesting level of 2 + if ( $depth++ > 2 || ( in_array( $option->short, $usedOptions['short'] ) && in_array( $option->long, $usedOptions['long'] ) ) ) return $synopsis; + + $usedOptions['short'][] = $option->short; + $usedOptions['long'][] = $option->long; + + $synopsis .= $option->short !== "" ? "-{$option->short}" : "--{$option->long}"; + + if ( isset( $option->default ) ) + { + $synopsis .= " " . ( $option->type === ezcConsoleInput::TYPE_STRING ? '"' : '' ) . $option->default . ( $option->type === ezcConsoleInput::TYPE_STRING ? '"' : '' ); + } + else if ( $option->type !== ezcConsoleInput::TYPE_NONE ) + { + $synopsis .= " "; + switch ( $option->type ) + { + case ezcConsoleInput::TYPE_STRING: + $synopsis .= ""; + break; + case ezcConsoleInput::TYPE_INT: + $synopsis .= ""; + break; + } + } + + foreach ( $option->getDependencies() as $rule ) + { + $deeperSynopsis = $this->createOptionSynopsis( $rule->option, $usedOptions, $depth ); + $synopsis .= ( iconv_strlen( trim( $deeperSynopsis ), 'UTF-8' ) > 0 + ? ' ' . $deeperSynopsis + : '' + ); + } + + if ( $option->arguments === false ) + { + $allowsArgs = false; + } + + // Make the whole thing optional? + if ( $option->mandatory === false ) + { + $synopsis = "[$synopsis]"; + } + + return $synopsis . ' '; + } + + /** + * Generate synopsis for arguments. + * + * @return string The synopsis string. + */ + private function createArgumentsSynopsis() + { + $mandatory = true; + $synopsises = array(); + foreach ( $this->input->argumentDefinition as $arg ) + { + $argSynopsis = ""; + if ( $arg->mandatory === false ) + { + $mandatory = false; + } + $argSynopsis .= "<%s:%s>"; + switch ( $arg->type ) + { + case ezcConsoleInput::TYPE_INT: + $type = "int"; + break; + case ezcConsoleInput::TYPE_STRING: + $type = "string"; + break; + } + $argSynopsis = sprintf( $argSynopsis, $type, $arg->name ); + $synopsises[] = $mandatory === false ? "[$argSynopsis]" : $argSynopsis; + if ( $arg->multiple === true ) + { + $synopsises[] = "[$argSynopsis ...]"; + break; + } + } + return implode( " ", $synopsises ); + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/option.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/option.php new file mode 100644 index 0000000..447688e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/option.php @@ -0,0 +1,585 @@ +mixed) + */ + protected $properties; + + /** + * Dependency rules of this parameter. + * + * @see ezcConsoleOption::addDependency() + * @see ezcConsoleOption::removeDependency() + * @see ezcConsoleOption::hasDependency() + * @see ezcConsoleOption::getDependencies() + * @see ezcConsoleOption::resetDependencies() + * + * @var array(string=>ezcConsoleParamemterRule) + */ + protected $dependencies = array(); + + /** + * Exclusion rules of this parameter. + * + * @see ezcConsoleOption::addExclusion() + * @see ezcConsoleOption::removeExclusion() + * @see ezcConsoleOption::hasExclusion() + * @see ezcConsoleOption::getExclusions() + * @see ezcConsoleOption::resetExclusions() + * + * @var array(string=>ezcConsoleParamemterRule) + */ + protected $exclusions = array(); + + /** + * The value the parameter was assigned to when being submitted. + * Boolean false indicates the parameter was not submitted, boolean + * true means the parameter was submitted, but did not have a value. + * In any other case, this caries the submitted value. + * + * @var mixed + */ + public $value = false; + + /** + * Create a new parameter struct. + * Creates a new basic parameter struct with the base information "$short" + * (the short name of the parameter) and "$long" (the long version). You + * simply apply these parameters as strings (without '-' or '--'). So + * + * + * $param = new ezcConsoleOption( 'f', 'file' ); + * + * + * will result in a parameter that can be accessed using + * + * + * $ mytool -f + * + * + * or + * + * + * $ mytool --file + * + * . + * + * The newly created parameter contains only it's 2 names and each other + * attribute is set to it's default value. You can simply manipulate + * those attributes by accessing them directly. + * + * @param string $short Short name of the parameter without '-' (eg. 'f'). + * @param string $long Long name of the parameter without '--' (eg. 'file'). + * @param int $type Value type of the parameter. One of ezcConsoleInput::TYPE_*. + * @param mixed $default Default value the parameter holds if not submitted. + * @param bool $multiple If the parameter may be submitted multiple times. + * @param string $shorthelp Short help text. + * @param string $longhelp Long help text. + * @param array(ezcConsoleOptionRule) $dependencies Dependency rules. + * @param array(ezcConsoleOptionRule) $exclusions Exclusion rules. + * @param bool $arguments Whether supplying arguments is allowed when this parameter is set. + * @param bool $mandatory Whether the parameter must be always submitted. + * @param bool $isHelpOption Indicates that the given parameter is a help + * option. If a help option is set, all rule + * checking is skipped (dependency/exclusion/ + * mandatory). + * + * @throws ezcConsoleInvalidOptionNameException If the option names start with a "-" + * sign or contain whitespaces. + */ + public function __construct( + $short = '', + $long, + $type = ezcConsoleInput::TYPE_NONE, + $default = null, + $multiple = false, + $shorthelp = 'No help available.', + $longhelp = 'Sorry, there is no help text available for this parameter.', + array $dependencies = array(), + array $exclusions = array(), + $arguments = true, + $mandatory = false, + $isHelpOption = false + ) + { + $this->properties['short'] = ''; + $this->properties['long'] = ''; + $this->properties['arguments'] = $arguments; + + if ( !self::validateOptionName( $short ) ) + { + throw new ezcConsoleInvalidOptionNameException( $short ); + } + $this->properties['short'] = $short; + + if ( !self::validateOptionName( $long ) ) + { + throw new ezcConsoleInvalidOptionNameException( $long ); + } + $this->properties['long'] = $long; + + $this->__set( "type", $type !== null ? $type : ezcConsoleInput::TYPE_NONE ); + $this->__set( "multiple", $multiple !== null ? $multiple : false ); + $this->__set( "default", $default !== null ? $default : null ); + $this->__set( "shorthelp", $shorthelp !== null ? $shorthelp : 'No help available.' ); + $this->__set( "longhelp", $longhelp !== null ? $longhelp : 'Sorry, there is no help text available for this parameter.' ); + + $dependencies = $dependencies !== null && is_array( $dependencies ) ? $dependencies : array(); + foreach ( $dependencies as $dep ) + { + $this->addDependency( $dep ); + } + + $exclusions = $exclusions !== null && is_array( $exclusions ) ? $exclusions : array(); + foreach ( $exclusions as $exc ) + { + $this->addExclusion( $exc ); + } + + $this->__set( "mandatory", $mandatory !== null ? $mandatory : false ); + $this->__set( "isHelpOption", $isHelpOption !== null ? $isHelpOption : false ); + } + + /** + * Add a new dependency for a parameter. + * This registeres a new dependency rule with the parameter. If you try + * to add an already registered rule it will simply be ignored. Else, + * the submitted rule will be added to the parameter as a dependency. + * + * @param ezcConsoleOptionRule $rule The rule to add. + * @return void + */ + public function addDependency( ezcConsoleOptionRule $rule ) + { + foreach ( $this->dependencies as $existRule ) + { + if ( $rule == $existRule ) + { + return; + } + } + $this->dependencies[] = $rule; + } + + /** + * Remove a dependency rule from a parameter. + * This removes a given rule from a parameter, if it exists. If the rule is + * not registered with the parameter, the method call will simply be ignored. + * + * @param ezcConsoleOptionRule $rule The rule to be removed. + * @return void + */ + public function removeDependency( ezcConsoleOptionRule $rule ) + { + foreach ( $this->dependencies as $id => $existRule ) + { + if ( $rule == $existRule ) + { + unset( $this->dependencies[$id] ); + } + } + } + + /** + * Remove all dependency rule referring to a parameter. + * This removes all dependency rules from a parameter, that refer to as specific + * parameter. If no rule is registered with this parameter as reference, the + * method call will simply be ignored. + * + * @param ezcConsoleOption $param The param to be check for rules. + * @return void + */ + public function removeAllDependencies( ezcConsoleOption $param ) + { + foreach ( $this->dependencies as $id => $rule ) + { + if ( $rule->option == $param ) + { + unset( $this->dependencies[$id] ); + } + } + } + + /** + * Returns if a dependency to the given option exists. + * Returns true if a dependency rule to the given option is registered, + * otherwise false. + * + * @param ezcConsoleOption $param The param to check if a dependency exists to. + * @return bool True if rule is registered, otherwise false. + */ + public function hasDependency( ezcConsoleOption $param ) + { + foreach ( $this->dependencies as $id => $rule ) + { + if ( $rule->option == $param ) + { + return true; + } + } + return false; + } + + /** + * Returns the dependency rules registered with this parameter. + * Returns an array of registered dependencies. + * + * For example: + * + * array( + * 0 => ezcConsoleOptionRule, + * 1 => ezcConsoleOptionRule, + * 2 => ezcConsoleOptionRule, + * ); + * + * + * @return array(ezcConsoleOptionRule) Dependency definition. + */ + public function getDependencies() + { + return $this->dependencies; + } + + /** + * Reset existing dependency rules. + * Deletes all registered dependency rules from the option definition. + * + * @return void + */ + public function resetDependencies() + { + $this->dependencies = array(); + } + + /** + * Add a new exclusion for an option. + * This registeres a new exclusion rule with the option. If you try + * to add an already registered rule it will simply be ignored. Else, + * the submitted rule will be added to the option as a exclusion. + * + * @param ezcConsoleOptionRule $rule The rule to add. + * @return void + */ + public function addExclusion( ezcConsoleOptionRule $rule ) + { + foreach ( $this->exclusions as $existRule ) + { + if ( $rule == $existRule ) + { + return; + } + } + $this->exclusions[] = $rule; + } + + /** + * Remove a exclusion rule from a option. + * This removes a given rule from a option, if it exists. If the rule is + * not registered with the option, the method call will simply be ignored. + * + * @param ezcConsoleOptionRule $rule The rule to be removed. + * @return void + */ + public function removeExclusion( ezcConsoleOptionRule $rule ) + { + foreach ( $this->exclusions as $id => $existRule ) + { + if ( $rule == $existRule ) + { + unset( $this->exclusions[$id] ); + } + } + } + + /** + * Remove all exclusion rule referring to a option. + * This removes all exclusion rules from a option, that refer to as specific + * option. If no rule is registered with this option as reference, the + * method call will simply be ignored. + * + * @param ezcConsoleOption $param The option to remove rule for. + * @return void + */ + public function removeAllExclusions( ezcConsoleOption $param ) + { + foreach ( $this->exclusions as $id => $rule ) + { + if ( $rule->option == $param ) + { + unset( $this->exclusions[$id] ); + } + } + } + + /** + * Returns if a given exclusion rule is registered with the option. + * Returns true if a exclusion rule to the given option is registered, + * otherwise false. + * + * @param ezcConsoleOption $param The param to check if exclusions exist for. + * @return bool True if rule is registered, otherwise false. + */ + public function hasExclusion( ezcConsoleOption $param ) + { + foreach ( $this->exclusions as $id => $rule ) + { + if ( $rule->option == $param ) + { + return true; + } + } + return false; + } + + /** + * Returns the exclusion rules registered with this parameter. + * Returns an array of registered exclusions. + * + * For example: + * + * array( + * 0 => ezcConsoleOptionRule, + * 1 => ezcConsoleOptionRule, + * 2 => ezcConsoleOptionRule, + * ); + * + * + * @return array(ezcConsoleOptionRule) Exclusions definition. + */ + public function getExclusions() + { + return $this->exclusions; + } + + /** + * Reset existing exclusion rules. + * Deletes all registered exclusion rules from the option definition. + * + * @return void + */ + public function resetExclusions() + { + $this->exclusions = array(); + } + + /** + * Property read access. + * Provides read access to the properties of the object. + * + * @param string $key The name of the property. + * @return mixed The value if property exists and isset, otherwise null. + * @ignore + */ + public function __get( $key ) + { + switch ( $key ) + { + case 'short': + case 'long': + case 'type': + case 'default': + case 'multiple': + case 'shorthelp': + case 'longhelp': + case 'arguments': + case 'isHelpOption': + case 'mandatory': + return $this->properties[$key]; + case 'dependencies': + default: + throw new ezcBasePropertyNotFoundException( $key ); + } + } + + /** + * Property write access. + * + * @param string $key Name of the property. + * @param mixed $val The value for the property. + * + * @throws ezcBasePropertyPermissionException + * If the property you try to access is read-only. + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * @ignore + */ + public function __set( $key, $val ) + { + switch ( $key ) + { + case 'type': + if ( $val !== ezcConsoleInput::TYPE_NONE + && $val !== ezcConsoleInput::TYPE_INT + && $val !== ezcConsoleInput::TYPE_STRING ) + { + throw new ezcBaseValueException( + $key, + $val, + 'ezcConsoleInput::TYPE_STRING, ezcConsoleInput::TYPE_INT or ezcConsoleInput::TYPE_NONE' + ); + } + break; + case 'default': + if ( ( is_scalar( $val ) === false && $val !== null ) ) + { + // Newly allow arrays, if multiple is true + if ( $this->multiple === true && is_array( $val ) === true ) + { + break; + } + throw new ezcBaseValueException( $key, $val, 'a string or a number, if multiple == true also an array' ); + } + break; + case 'multiple': + if ( !is_bool( $val ) ) + { + throw new ezcBaseValueException( $key, $val, 'bool' ); + } + break; + case 'shorthelp': + if ( !is_string( $val ) ) + { + throw new ezcBaseValueException( $key, $val, 'string' ); + } + break; + case 'longhelp': + if ( !is_string( $val ) ) + { + throw new ezcBaseValueException( $key, $val, 'string' ); + } + break; + case 'arguments': + if ( !is_bool( $val ) ) + { + throw new ezcBaseValueException( $key, $val, 'bool' ); + } + break; + case 'mandatory': + if ( !is_bool( $val ) ) + { + throw new ezcBaseValueException( $key, $val, 'bool' ); + } + break; + case 'isHelpOption': + if ( !is_bool( $val ) ) + { + throw new ezcBaseValueException( $key, $val, 'bool' ); + } + break; + case 'long': + case 'short': + throw new ezcBasePropertyPermissionException( $key, ezcBasePropertyPermissionException::READ ); + break; + default: + throw new ezcBasePropertyNotFoundException( $key ); + break; + } + $this->properties[$key] = $val; + } + + /** + * Property isset access. + * + * @param string $key Name of the property. + * @return bool True is the property is set, otherwise false. + * @ignore + */ + public function __isset( $key ) + { + switch ( $key ) + { + case 'short': + case 'long': + case 'type': + case 'default': + case 'multiple': + case 'shorthelp': + case 'longhelp': + case 'arguments': + case 'isHelpOption': + case 'mandatory': + return ( $this->properties[$key] !== null ); + } + return false; + } + + /** + * Returns if a given name if valid for use as a parameter name a parameter. + * Checks if a given parameter name is generally valid for use. It checks a) + * that the name does not start with '-' or '--' and b) if it contains + * whitespaces. Note, that this method does not check any conflicts with already + * used parameter names. + * + * @param string $name The name to check. + * @return bool True if the name is valid, otherwise false. + */ + public static function validateOptionName( $name ) + { + if ( substr( $name, 0, 1 ) === '-' || strpos( $name, ' ' ) !== false ) + { + return false; + } + return true; + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/validators/standard.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/validators/standard.php new file mode 100644 index 0000000..633bcc9 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/input/validators/standard.php @@ -0,0 +1,171 @@ + $option ) + { + if ( $option->mandatory === true && $option->value === false ) + { + throw new ezcConsoleOptionMandatoryViolationException( $option ); + } + + $this->validateDependencies( $option ); + $this->validateExclusions( $option ); + + if ( $option->arguments === false && $option->value !== false && $hasArguments ) + { + throw new ezcConsoleOptionArgumentsViolationException( $option ); + } + } + } + + /** + * Validated option dependencies. + * + * Validates dependencies by $option. + * + * @param ezcConsoleOption $option. + */ + private function validateDependencies( ezcConsoleOption $option ) + { + $optSet = ( $option->value !== false + && ( !is_array( $option->value ) || $option->value !== array() ) ); + + foreach ( $option->getDependencies() as $dep ) + { + if ( $dep->ifSet === $optSet ) + { + $this->validateDependency( $option, $dep ); + } + } + } + + /** + * Validates a single dependency. + * + * Validates the dependency $dep, which is set in the $srcOpt. + * + * @param ezcConsoleOption $srcOpt + * @param ezcConsoleOptionRule $dep + */ + private function validateDependency( ezcConsoleOption $srcOpt, ezcConsoleOptionRule $dep ) + { + $optValue = $dep->option->value; + + if ( $optValue === false || $optValue === array() ) + { + throw new ezcConsoleOptionDependencyViolationException( + $srcOpt, + $dep->option + ); + } + + if ( $dep->values !== array() ) + { + $optVals = ( is_array( $optValue ) ? $optValue : array( $optValue) ); + $unrecognizedVals = array_diff( $optVals, $dep->values ); + if ( $unrecognizedVals !== array() ) + { + throw new ezcConsoleOptionDependencyViolationException( + $srcOpt, + $dep->option, + implode( ', ', $dep->values ) + ); + } + } + } + + /** + * Validated option exclusions. + * + * Validates exclusions by $option. + * + * @param ezcConsoleOption $option. + */ + private function validateExclusions( ezcConsoleOption $option ) + { + $optSet = ( $option->value !== false + && ( !is_array( $option->value ) || $option->value !== array() ) ); + + foreach ( $option->getExclusions() as $excl ) + { + if ( $excl->ifSet === $optSet ) + { + $this->validateExclusion( $option, $excl ); + } + } + } + + /** + * Validates a single exclusion. + * + * Validates the exclusion $excl, which is set in the $srcOpt. + * + * @param ezcConsoleOption $srcOpt + * @param ezcConsoleOptionRule $excl + */ + private function validateExclusion( ezcConsoleOption $srcOpt, ezcConsoleOptionRule $excl ) + { + $optValue = $excl->option->value; + + if ( $optValue !== false && $optValue !== array() && $excl->values === array() ) + { + throw new ezcConsoleOptionExclusionViolationException( + $srcOpt, + $excl->option + ); + } + + $optVals = ( is_array( $optValue ) ? $optValue : array( $optValue ) ); + $forbiddenVals = array_intersect( $optVals, $excl->values ); + if ( $forbiddenVals !== array() ) + { + throw new ezcConsoleOptionExclusionViolationException( + $srcOpt, + $excl->option, + implode( ', ', $excl->values ) + ); + } + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/interfaces/dialog.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/interfaces/dialog.php new file mode 100644 index 0000000..8ec6f55 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/interfaces/dialog.php @@ -0,0 +1,82 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/interfaces/dialog_validator.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/interfaces/dialog_validator.php new file mode 100644 index 0000000..b43b8f3 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/interfaces/dialog_validator.php @@ -0,0 +1,57 @@ + diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/interfaces/input_help_generator.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/interfaces/input_help_generator.php new file mode 100644 index 0000000..7f13f1c --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/interfaces/input_help_generator.php @@ -0,0 +1,170 @@ + + * array( + * 0 => '
    +

    Class Structures_Graph

    + +
    +
    +
    Description
    + +
    + +

    The Structures_Graph class represents a graph data structure.

    +

    A Graph is a data structure composed by a set of nodes, connected by arcs. Graphs may either be directed or undirected. In a directed graph, arcs are directional, and can be traveled only one way. In an undirected graph, arcs are bidirectional, and can be traveled both ways.

    + +

    + Located in /Structures/Graph.php (line 56) +

    + + +
    
    +	
    +			
    +
    + + + + +
    +
    Method Summary
    + +
    +
    + +
    + Structures_Graph + Structures_Graph + ([boolean $directed = true]) +
    + +
    + void + addNode + (Structures_Graph_Node &$newNode) +
    + +
    + array + &getNodes + () +
    + +
    + boolean + isDirected + () +
    + +
    + void + removeNode + (Structures_Graph_Node &$node) +
    +
    +
    +
    + + + +
    +
    Methods
    + +
    + + +
    + +
    + Constructor Structures_Graph (line 76) +
    + + +

    Constructor

    +
      +
    • access: public
    • +
    + +
    + Structures_Graph + + Structures_Graph + + ([boolean $directed = true]) +
    + +
      +
    • + boolean + $directed: Set to true if the graph is directed. Set to false if it is not directed. (Optional, defaults to true)
    • +
    + + +
    + +
    + +
    + addNode (line 102) +
    + + +

    Add a Node to the Graph

    +
      +
    • access: public
    • +
    + +
    + void + + addNode + + (Structures_Graph_Node &$newNode) +
    + + + + +
    + +
    + +
    + getNodes (line 151) +
    + + +

    Return the node set, in no particular order. For ordered node sets, use a Graph Manipulator insted.

    + + +
    + array + + &getNodes + + () +
    + + + +
    + +
    + +
    + isDirected (line 89) +
    + + +

    Return true if a graph is directed

    +
      +
    • return: true if the graph is directed
    • +
    • access: public
    • +
    + +
    + boolean + + isDirected + + () +
    + + + +
    + +
    + +
    + removeNode (line 138) +
    + + +

    Remove a Node from the Graph

    +
      +
    • access: public
    • +
    • todo: This is unimplemented
    • +
    + +
    + void + + removeNode + + (Structures_Graph_Node &$node) +
    + + + + +
    + +
    +
    + +

    + Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by phpDocumentor 1.2.3 +

    +
    ezcConsoleOption, contains the parameter that this rule refers to. + * - values array(string), contains a list of values that are accepted. + * + * @see ezcConsoleOption + * + * @package ConsoleTools + * @version 1.6.1 + */ +class ezcConsoleOptionRule +{ + /** + * Properties. + * + * @var array + */ + protected $properties = array( + 'option' => null, + 'values' => array(), + 'ifSet' => true + ); + + /** + * Creates a new option rule. + * + * Creates a new option rule. Per default the $values parameter + * is an empty array, which determines that the option may accept any + * value. To indicate that a option may only have certain values, + * place them inside tha $values array. For example to indicate an option + * may have the values 'a', 'b' and 'c' use: + * + * + * $rule = new ezcConsoleOptionRule( $option, array( 'a', 'b', 'c' ) ); + * + * + * If you want to allow only 1 specific value for an option, you do not + * need to wrap this into an array, when creating the rule. Simply use + * + * + * $rule = new ezcConsoleOptionRule( $option, 'a' ); + * + * + * to create a rule, that allows the desired option only to accept the + * value 'a'. + * + * The $ifSet parameter determines, if the rule is validated when its option + * is set or left out. If $ifSet is true, the rule is validated when the + * option is set. Otherwise the rule is validated if the option was not set + * by the user. + * + * @param ezcConsoleOption $option The option to refer to. + * @param mixed $values The affected values. + * @param bool $ifSet + */ + public function __construct( ezcConsoleOption $option, array $values = array(), $ifSet = true ) + { + $this->__set( 'option', $option ); + $this->__set( 'values', $values ); + $this->__set( 'ifSet', $ifSet ); + } + + /** + * Property read access. + * + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * + * @param string $propertyName Name of the property. + * @return mixed Value of the property or null. + * @ignore + */ + public function __get( $propertyName ) + { + switch ( $propertyName ) + { + case 'option': + return $this->properties['option']; + case 'values': + return $this->properties['values']; + case 'ifSet': + return $this->properties['ifSet']; + } + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + + /** + * Property write access. + * + * @param string $propertyName Name of the property. + * @param mixed $propertyValue The value for the property. + * + * @throws ezcBasePropertyPermissionException + * If the property you try to access is read-only. + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * @ignore + */ + public function __set( $propertyName, $propertyValue ) + { + switch ( $propertyName ) + { + case 'option': + if ( !( $propertyValue instanceof ezcConsoleOption ) ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcConsoleOption' ); + } + $this->properties['option'] = $propertyValue; + return; + case 'values': + if ( !is_array( $propertyValue ) ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, 'array' ); + } + $this->properties['values'] = $propertyValue; + return; + case 'ifSet': + if ( !is_bool( $propertyValue ) ) + { + throw new ezcBaseValueException( $propertyName, $propertyValue, 'bool' ); + } + $this->properties['ifSet'] = $propertyValue; + return; + } + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + + /** + * Property isset access. + * + * @param string $propertyName Name of the property to check. + * @return bool If the property exists or not. + * @ignore + */ + public function __isset( $propertyName ) + { + switch ( $propertyName ) + { + case 'option': + case 'values': + case 'ifSet': + return true; + } + return false; + } + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/structs/output_format.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/structs/output_format.php new file mode 100644 index 0000000..54ab906 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/structs/output_format.php @@ -0,0 +1,186 @@ +mixed) + */ + protected $properties = array( + 'color' => 'default', + 'style' => array( 'default' ), + 'bgcolor' => 'default', + 'target' => ezcConsoleOutput::TARGET_OUTPUT, + ); + + /** + * Create a new ezcConsoleOutputFormat object. + * Creates a new object of this class. + * + * @param string $color Name of a color value. + * @param array(string) $style Names of style values. + * @param string $bgcolor Name of a bgcolor value. + * @param string $target Target output stream. + */ + public function __construct( $color = 'default', array $style = null, $bgcolor = 'default', $target = ezcConsoleOutput::TARGET_OUTPUT ) + { + $this->__set( 'color', $color ); + $this->__set( 'style', isset( $style ) ? $style : array( 'default' ) ); + $this->__set( 'bgcolor', $bgcolor ); + $this->__set( 'target', $target ); + } + + /** + * Overloaded __get() method to gain read-only access to some attributes. + * + * @param string $propertyName Name of the property to read. + * @return mixed Desired value if exists, otherwise null. + * @ignore + */ + public function __get( $propertyName ) + { + switch ( $propertyName ) + { + case 'style': + return (array) $this->properties[$propertyName]; + case 'color': + case 'bgcolor': + case 'target': + return $this->properties[$propertyName]; + default: + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + } + + /** + * Overloaded __set() method to gain read-only access to properties. + * It also performs checks on setting others. + * + * @throws ezcBasePropertyNotFoundException + * If the setting you try to access does not exists + * @throws ezcBaseValueException + * If trying to set an invalid value for a setting. + * + * @param string $propertyName Name of the attrinbute to access. + * @param string $val The value to set. + * @ignore + */ + public function __set( $propertyName, $val ) + { + if ( !isset( $this->properties[$propertyName] ) ) + { + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + // Extry handling of multi styles + if ( $propertyName === 'style' ) + { + if ( !is_array( $val ) ) $val = array( $val ); + foreach ( $val as $style ) + { + if ( !ezcConsoleOutput::isValidFormatCode( $propertyName, $style ) ) + { + throw new ezcBaseValueException( $propertyName, $style, 'valid ezcConsoleOutput format code' ); + } + } + $this->properties['style'] = $val; + return; + } + // Continue normal handling + if ( ( $propertyName === "color" || $propertyName === "bgcolor" ) + && !ezcConsoleOutput::isValidFormatCode( $propertyName, $val ) ) + { + throw new ezcBaseValueException( $propertyName, $val, 'valid ezcConsoleOutput format code' ); + } + $this->properties[$propertyName] = $val; + } + + /** + * Property isset access. + * + * @param string $propertyName Name of the property. + * @return bool True is the property is set, otherwise false. + * @ignore + */ + public function __isset( $propertyName ) + { + return isset( $this->properties[$propertyName] ); + } + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/structs/output_formats.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/structs/output_formats.php new file mode 100644 index 0000000..11b4de0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/structs/output_formats.php @@ -0,0 +1,181 @@ + + * // New ezcConsoleOutput + * // $output->format is instance of ezcConsoleOutputFormats. + * $output = new ezcConsoleOutput(); + * + * // Default format - color = blue + * $output->formats->default->color = 'blue'; + * // Default format - weight = bold + * $output->formats->default->style = array( 'bold' ); + * + * // New format "important" - color = red + * $output->formats->important->color = 'red'; + * // Format "important" - background color = black + * $output->formats->important->bgcolor = 'black'; + * + * + * @package ConsoleTools + * @version 1.6.1 + */ +class ezcConsoleOutputFormats implements Iterator, Countable +{ + /** + * Array of ezcConsoleOutputFormat. + * + * @var array(ezcConsoleOutputFormat) + */ + protected $formats = array(); + + /** + * Create a new ezcConsoleOutputFormats object. + * + * Creates a new, empty object of this class. It also adds a default + * format. + */ + public function __construct() + { + $this->formats['default'] = new ezcConsoleOutputFormat(); + $this->formats['success'] = new ezcConsoleOutputFormat(); + $this->formats['success']->color = 'green'; + $this->formats['success']->style = array( 'bold' ); + $this->formats['failure'] = new ezcConsoleOutputFormat(); + $this->formats['failure']->color = 'red'; + $this->formats['failure']->style = array( 'bold' ); + } + + /** + * Returns the current Iterator value. + * + * Implementation of {@link Iterator::current()}. + * + * @return ezcConsoleOutputFormat + */ + public function current() + { + return current( $this->formats ); + } + + /** + * Advances the Iterator to the next element. + * + * Implementation of {@link Iterator::next()}. + * + * @return ezcConsoleOutputFormat|bool + */ + public function next() + { + return next( $this->formats ); + } + + /** + * Returns the current Iterator key. + * + * Implementation of {@link Iterator::key()}. + * + * @return string + */ + public function key() + { + return key( $this->formats ); + } + + /** + * Resets the Iterator to the first element. + * + * Implementation of {@link Iterator::rewind()}. + * + * @return ezcConsoleOutputFormat + */ + public function rewind() + { + return reset( $this->formats ); + } + + /** + * Checks if the current Iterator position is still valid. + * + * Implementation of {@link Iterator::valid()}. + * + * @return bool + */ + public function valid() + { + return ( current( $this->formats ) !== false ); + } + + /** + * Returns the number of registered formats. + * + * Implementation of {@link Countable::count()}. + * + * @return void + */ + public function count() + { + return count( $this->formats ); + } + + /** + * Read access to the formats. + * + * Formats are accessed directly like properties of this object. If a + * format does not exist, it is created on the fly (using default values), + * + * @param string $formatName + * @return ezcConsoleOutputFormat The format. + */ + public function __get( $formatName ) + { + if ( !isset( $this->formats[$formatName] ) ) + { + $this->formats[$formatName] = new ezcConsoleOutputFormat(); + } + return $this->formats[$formatName]; + } + + /** + * Write access to the formats. + * + * Formats are accessed directly like properties of this object. If a + * format does not exist, it is created on the fly (using default values), + * + * @param string $formatName + * @param ezcConsoleOutputFormat $val The format defintion. + * @return void + */ + public function __set( $formatName, ezcConsoleOutputFormat $val ) + { + $this->formats[$formatName] = $val; + } + + /** + * Property isset access. + * + * @param string $formatName Name of the property. + * @return bool True is the property is set, otherwise false. + */ + public function __isset( $formatName ) + { + return isset( $this->formats[$formatName] ); + } + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/table.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/table.php new file mode 100644 index 0000000..4b7f211 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/table.php @@ -0,0 +1,875 @@ +format. The second dimension gives + * you direct access to the cells of your table, like $table[0][0] accesses the + * first cell in the first row of your table. You can access its properties + * diretly here, too. This works like e.g. $table[0][0]->format. Table row and + * cell objects are created on the fly, when you access them for the first time. + * You can also create them as if you simply create new array elements. E.g. + * $table[] creates a new row in the table. + * + * + * // Initialize the console output handler + * $out = new ezcConsoleOutput(); + * // Define a new format "headline" + * $out->formats->headline->color = 'red'; + * $out->formats->headline->style = array( 'bold' ); + * // Define a new format "sum" + * $out->formats->sum->color = 'blue'; + * $out->formats->sum->style = array( 'negative' ); + * + * // Create a new table + * $table = new ezcConsoleTable( $out, 60 ); + * + * // Create first row and in it the first cell + * $table[0][0]->content = 'Headline 1'; + * + * // Create 3 more cells in row 0 + * for ( $i = 2; $i < 5; $i++ ) + * { + * $table[0][]->content = "Headline $i"; + * } + * + * $data = array( 1, 2, 3, 4 ); + * + * // Create some more data in the table... + * foreach ( $data as $value ) + * { + * // Create a new row each time and set it's contents to the actual value + * $table[][0]->content = $value; + * } + * + * // Set another border format for our headline row + * $table[0]->borderFormat = 'headline'; + * + * // Set the content format for all cells of the 3rd row to "sum" + * $table[2]->format = 'sum'; + * + * $table->outputTable(); + * + * + * @property ezcConsoleTableOptions $options + * Contains the options for this class. + * @property int $width + * Width of the table. + * + * @see ezcConsoleOutput + * @package ConsoleTools + * @version 1.6.1 + * @mainclass + */ +class ezcConsoleTable implements Countable, Iterator, ArrayAccess +{ + /** + * Automatically wrap text to fit into a column. + * @see ezcConsoleTable::$options + */ + const WRAP_AUTO = 1; + + /** + * Do not wrap text. Columns will be extended to fit the largest text. + * ATTENTION: This is risky! + * @see ezcConsoleTable::$options + */ + const WRAP_NONE = 2; + + /** + * Text will be cut to fit into a column. + * @see ezcConsoleTable::$options + */ + const WRAP_CUT = 3; + + /** + * Align text in the default direction. + */ + const ALIGN_DEFAULT = -1; + /** + * Align text in cells to the right. + */ + const ALIGN_LEFT = STR_PAD_RIGHT; + /** + * Align text in cells to the left. + */ + const ALIGN_RIGHT = STR_PAD_LEFT; + /** + * Align text in cells to the center. + */ + const ALIGN_CENTER = STR_PAD_BOTH; + + /** + * The width given by settings must be used even if the data allows it smaller. + */ + const WIDTH_FIXED = 1; + /** + * The width given by settings is a maximum value, if data allows it, the table gets smaller. + */ + const WIDTH_MAX = 2; + + /** + * Container to hold the properties + * + * @var array(string=>mixed) + */ + protected $properties; + + /** + * The ezcConsoleOutput object to use. + * + * @var ezcConsoleOutput + */ + protected $outputHandler; + + /** + * Collection of the rows that are contained in the table. + * + * @var array(ezcConsoleTableRow) + */ + protected $rows; + + /** + * Tool object for multi-byte encoding safe string operations. + * + * @var ezcConsoleStringTool + */ + private $stringTool; + + /** + * Creates a new table. + * + * @param ezcConsoleOutput $outHandler Output handler to utilize + * @param int $width Overall width of the table (chars). + * @param array $options Options + * + * @see ezcConsoleTable::$options + * + * @throws ezcBaseValueException On an invalid setting. + */ + public function __construct( ezcConsoleOutput $outHandler, $width, $options = array() ) + { + $this->rows = array(); + $this->outputHandler = $outHandler; + $this->stringTool = new ezcConsoleStringTool(); + + $this->__set( 'width', $width ); + if ( $options instanceof ezcConsoleTableOptions ) + { + $this->properties['options'] = $options; + } + else if ( is_array( $options ) ) + { + $this->properties['options'] = new ezcConsoleTableOptions( $options ); + } + else + { + throw new ezcBaseValueException( "options", $options, "array" ); + } + } + + /** + * Set new options. + * This method allows you to change the options of the table. + * + * @param ezcConsoleTableOptions $options The options to set. + * + * @throws ezcBaseSettingNotFoundException + * If you tried to set a non-existent option value. + * @throws ezcBaseSettingValueException + * If the value is not valid for the desired option. + * @throws ezcBaseValueException + * If you submit neither an array nor an instance of + * ezcConsoleTableOptions. + */ + public function setOptions( $options = array() ) + { + if ( is_array( $options ) ) + { + $this->properties['options']->merge( $options ); + } + else if ( $options instanceof ezcConsoleTableOptions ) + { + $this->properties['options'] = $options; + } + else + { + throw new ezcBaseValueException( "options", $options, "instance of ezcConsoleTableOptions" ); + } + } + + /** + * Returns the current options. + * Returns the options currently set for this table. + * + * @return ezcConsoleTableOptions The current options. + */ + public function getOptions() + { + return $this->properties['options']; + } + + /** + * Returns the table in an array. + * + * Returns the entire table as an array of printable lines. Each element of + * the array represents a physical line of the drawn table, including all + * borders and stuff, so you can simply print the table using + * + * echo implode( "\n" , $table->getTable() ): + * + * which is basically what {@link ezcConsoleTable::outputTable()} does. + * + * @return array An array representation of the table. + */ + public function getTable() + { + return $this->generateTable(); + } + + /** + * Output the table. + * Prints the complete table to the console. + * + * @return void + */ + public function outputTable() + { + echo implode( PHP_EOL, $this->generateTable() ); + } + + /** + * Returns the table in a string. + * + * @return string + */ + public function __toString() + { + return implode( PHP_EOL, $this->generateTable() ); + } + + /** + * Returns if the given offset exists. + * This method is part of the ArrayAccess interface to allow access to the + * data of this object as if it was an array. + * + * @param int $offset The offset to check. + * @return bool True when the offset exists, otherwise false. + * + * @throws ezcBaseValueException + * If a non numeric row ID is requested. + */ + public function offsetExists( $offset ) + { + if ( !is_int( $offset ) || $offset < 0 ) + { + throw new ezcBaseValueException( 'offset', $offset, 'int >= 0' ); + } + return isset( $this->rows[$offset] ); + } + + // From here only interface method implementations follow, which are not intended for direct usage + + /** + * Returns the element with the given offset. + * This method is part of the ArrayAccess interface to allow access to the + * data of this object as if it was an array. In case of the + * ezcConsoleTable class this method always returns a valid row object + * since it creates them on the fly, if a given item does not exist. + * + * @param int $offset The offset to check. + * @return ezcConsoleTableCell + * + * @throws ezcBaseValueException + * If a non numeric row ID is requested. + */ + public function offsetGet( $offset ) + { + $offset = ( $offset === null ) ? count( $this->rows ) : $offset; + if ( !is_int( $offset ) || $offset < 0 ) + { + throw new ezcBaseValueException( 'offset', $offset, 'int >= 0 or null' ); + } + if ( !isset( $this->rows[$offset] ) ) + { + $this->rows[$offset] = new ezcConsoleTableRow(); + } + return $this->rows[$offset]; + } + + /** + * Set the element with the given offset. + * This method is part of the ArrayAccess interface to allow access to the + * data of this object as if it was an array. + * + * @param int $offset The offset to assign an item to. + * @param ezcConsoleTableRow $value The row to assign. + * @return void + * + * @throws ezcBaseValueException + * If a non numeric row ID is requested. + * @throws ezcBaseValueException + * If the provided value is not of type {@link ezcConsoleTableRow}. + */ + public function offsetSet( $offset, $value ) + { + if ( !( $value instanceof ezcConsoleTableRow ) ) + { + throw new ezcBaseValueException( 'value', $value, 'ezcConsoleTableRow' ); + } + if ( !isset( $offset ) ) + { + $offset = count( $this ); + } + if ( !is_int( $offset ) || $offset < 0 ) + { + throw new ezcBaseValueException( 'offset', $offset, 'int >= 0' ); + } + $this->rows[$offset] = $value; + } + + /** + * Unset the element with the given offset. + * This method is part of the ArrayAccess interface to allow access to the + * data of this object as if it was an array. + * + * @param int $offset The offset to unset the value for. + * @return void + * + * @throws ezcBaseValueException + * If a non numeric row ID is requested. + */ + public function offsetUnset( $offset ) + { + if ( !is_int( $offset ) || $offset < 0 ) + { + throw new ezcBaseValueException( 'offset', $offset, 'int >= 0' ); + } + if ( isset( $this->rows[$offset] ) ) + { + unset( $this->rows[$offset] ); + } + } + + /** + * Returns the number of cells in the row. + * This method is part of the Countable interface to allow the usage of + * PHP's count() function to check how many cells this row has. + * + * @return int Number of cells in this row. + */ + public function count() + { + $keys = array_keys( $this->rows ); + return count( $keys ) > 0 ? ( end( $keys ) + 1 ) : 0; + } + + /** + * Returns the currently selected cell. + * This method is part of the Iterator interface to allow access to the + * cells of this row by iterating over it like an array (e.g. using + * foreach). + * + * @return ezcConsoleTableCell The currently selected cell. + */ + public function current() + { + return current( $this->rows ); + } + + /** + * Returns the key of the currently selected cell. + * This method is part of the Iterator interface to allow access to the + * cells of this row by iterating over it like an array (e.g. using + * foreach). + * + * @return int The key of the currently selected cell. + */ + public function key() + { + return key( $this->rows ); + } + + /** + * Returns the next cell and selects it or false on the last cell. + * This method is part of the Iterator interface to allow access to the + * cells of this row by iterating over it like an array (e.g. using + * foreach). + * + * @return mixed ezcConsoleTableCell if the next cell exists, or false. + */ + public function next() + { + return next( $this->rows ); + } + + /** + * Selects the very first cell and returns it. + * This method is part of the Iterator interface to allow access to the + * cells of this row by iterating over it like an array (e.g. using + * foreach). + * + * @return ezcConsoleTableCell The very first cell of this row. + */ + public function rewind() + { + return reset( $this->rows ); + } + + /** + * Returns if the current cell is valid. + * This method is part of the Iterator interface to allow access to the + * cells of this row by iterating over it like an array (e.g. using + * foreach). + * + * @return ezcConsoleTableCell The very first cell of this row. + */ + public function valid() + { + return current( $this->rows ) !== false; + } + + /** + * Property read access. + * + * @param string $key Name of the property. + * @return mixed Value of the property or null. + * + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * @ignore + */ + public function __get( $key ) + { + switch ( $key ) + { + case 'options': + case 'width': + return $this->properties[$key]; + default: + break; + } + throw new ezcBasePropertyNotFoundException( $key ); + } + + /** + * Property write access. + * + * @param string $key Name of the property. + * @param mixed $val The value for the property. + * + * @throws ezcBasePropertyNotFoundException + * If a the value for the property options is not an instance of + * @throws ezcBaseValueException + * If a the value for a property is out of range. + * @ignore + */ + public function __set( $key, $val ) + { + switch ( $key ) + { + case 'options': + if ( !( $val instanceof ezcConsoleTableOptions ) ) + { + throw new ezcBaseValueException( $key, $val, 'ezcConsoleTableOptions' ); + } + $this->properties['options'] = $val; + return; + case 'width': + if ( $val < 1 ) + { + throw new ezcBaseValueException( $key, $val, 'int > 0' ); + } + $this->properties[$key] = $val; + return; + default: + break; + } + throw new ezcBasePropertyNotFoundException( $key ); + } + + /** + * Property isset access. + * + * @param string $key Name of the property. + * @return bool True is the property is set, otherwise false. + * @ignore + */ + public function __isset( $key ) + { + switch ( $key ) + { + case 'options': + case 'width': + case 'cols': + return true; + } + return false; + } + + /** + * Generate the complete table as an array. + * + * @return array(string) The table. + */ + private function generateTable() + { + $colWidth = $this->getColWidths(); + $table = array(); + + if ( $this->options->lineVertical !== null ) + { + $table[] = $this->generateBorder( + $colWidth, + ( isset( $this[0] ) ? $this[0]->borderFormat : 'default' ) + ); + } + + // Rows submitted by the user + for ( $i = 0; $i < count( $this->rows ); $i++ ) + { + // Auto broken rows + foreach ( $this->breakRows( $this->rows[$i], $colWidth ) as $brkRow => $brkCells ) + { + $table[] = $this->generateRow( $brkCells, $colWidth, $this->rows[$i] ); + } + $afterBorderFormat = isset( $this->rows[$i + 1] ) && $this->rows[$i + 1]->borderFormat != 'default' ? $this->rows[$i + 1]->borderFormat : $this->rows[$i]->borderFormat; + if ( $this->options->lineVertical !== null ) + { + $table[] = $this->generateBorder( $colWidth, $afterBorderFormat ); + } + } + + // Empty tables need closing border + if ( $this->options->lineVertical !== null && count( $this->rows ) == null ) + { + $table[] = $this->generateBorder( $colWidth, 'default' ); + } + + return $table; + } + + /** + * Generate top/bottom borders of rows. + * + * @param array(int) $colWidth Array of column width. + * @param string $format Format name. + * @return string The Border string. + */ + private function generateBorder( $colWidth, $format ) + { + $border = ''; + foreach ( $colWidth as $col => $width ) + { + $border .= ( $this->options->lineHorizontal !== null ? $this->properties['options']->corner : '' ) + . str_repeat( + $this->properties['options']->lineVertical, + $width + ( + 2 * iconv_strlen( $this->properties['options']->colPadding, 'UTF-8' ) + ) + ); + } + $border .= ( $this->options->lineHorizontal !== null ? $this->properties['options']->corner : '' ); + + return $this->formatText( $border, $format ); + } + + /** + * Generate a single physical row. + * This method generates the string for a single physical table row. + * + * @param array(string) $cells Cells of the row. + * @param array(int) $colWidth Calculated columns widths. + * @param ezcConsoleTableRow $row The row to generate. + * @return string The row. + */ + private function generateRow( $cells, $colWidth, $row ) + { + $rowData = ''; + for ( $cell = 0; $cell < count( $colWidth ); $cell++ ) + { + $align = $this->determineAlign( $row, $cell ); + $format = $this->determineFormat( $row, $cell ); + $borderFormat = $this->determineBorderFormat( $row ); + + $data = isset( $cells[$cell] ) ? $cells[$cell] : ''; + $rowData .= $this->formatText( + $this->properties['options']->lineHorizontal, + $borderFormat + ); + $rowData .= $this->properties['options']->colPadding; + $rowData .= $this->formatText( + $this->stringTool->strPad( $data, $colWidth[$cell], ' ', $align ), + $format + ); + $rowData .= $this->properties['options']->colPadding; + } + $rowData .= $this->formatText( $this->properties['options']->lineHorizontal, $row->borderFormat ); + return $rowData; + } + + /** + * Determine the alignment of a cell. + * Walks the inheritance path upwards to determine the alignment of a + * cell. Checks first, if the cell has it's own alignment (apart from + * ezcConsoleTable::ALIGN_DEFAULT). If not, checks the row for an + * alignment setting and uses the default alignment if not found. + * + * @param ezcConsoleTableRow $row The row this cell belongs to. + * @param int $cellId Index of the desired cell. + * @return int An alignement constant (ezcConsoleTable::ALIGN_*). + */ + private function determineAlign( $row, $cellId = 0 ) + { + return ( $row[$cellId]->align !== ezcConsoleTable::ALIGN_DEFAULT + ? $row[$cellId]->align + : ( $row->align !== ezcConsoleTable::ALIGN_DEFAULT + ? $row->align + : ( $this->properties['options']->defaultAlign !== ezcConsoleTable::ALIGN_DEFAULT + ? $this->properties['options']->defaultAlign + : ezcConsoleTable::ALIGN_LEFT ) ) ); + } + + /** + * Determine the format of a cells content. + * Walks the inheritance path upwards to determine the format of a + * cells content. Checks first, if the cell has it's own format (apart + * from 'default'). If not, checks the row for a format setting and + * uses the default format if not found. + * + * @param ezcConsoleTableRow $row The row this cell belongs to. + * @param int $cellId Index of the desired cell. + * @return string A format name. + */ + private function determineFormat( $row, $cellId ) + { + return ( $row[$cellId]->format != 'default' + ? $row[$cellId]->format + : ( $row->format !== 'default' + ? $row->format + : $this->properties['options']->defaultFormat ) ); + } + + /** + * Determine the format of a rows border. + * Walks the inheritance path upwards to determine the format of a + * rows border. Checks first, if the row has it's own format (apart + * from 'default'). If not, uses the default format. + * + * @param ezcConsoleTableRow $row The row this cell belongs to. + * @return string A format name. + */ + private function determineBorderFormat( $row ) + { + return $row->borderFormat !== 'default' + ? $row->borderFormat + : $this->properties['options']->defaultBorderFormat; + } + + /** + * Returns auto broken rows from an array of cells. + * The data provided by a user may not fit into a cell calculated by the + * class. In this case, the data can be automatically wrapped. The table + * row then spans over multiple physical console lines. + * + * @param array(string) $cells Array of cells in one row. + * @param array(int) $colWidth Columns widths array. + * @return array(string) Physical rows generated out of this row. + */ + private function breakRows( $cells, $colWidth ) + { + $rows = array(); + // Iterate through cells of the row + foreach ( $colWidth as $cell => $width ) + { + $data = $cells[$cell]->content; + // Physical row id, start with 0 for each row + $row = 0; + // Split into multiple physical rows if manual breaks exist + $dataLines = explode( "\n", $data ); + foreach ( $dataLines as $dataLine ) + { + // Does the physical row fit? + if ( iconv_strlen( $dataLine, 'UTF-8' ) > ( $colWidth[$cell] ) ) + { + switch ( $this->properties['options']->colWrap ) + { + case ezcConsoleTable::WRAP_AUTO: + $subLines = explode( + "\n", + $this->stringTool->wordwrap( $dataLine, $colWidth[$cell], "\n", true ) + ); + foreach ( $subLines as $lineNo => $line ) + { + $rows[$row++][$cell] = $line; + } + break; + case ezcConsoleTable::WRAP_CUT: + $rows[$row++][$cell] = iconv_substr( $dataLine, 0, $colWidth[$cell], 'UTF-8' ); + break; + case ezcConsoleTable::WRAP_NONE: + default: + $rows[$row++][$cell] = $dataLine; + break; + } + } + else + { + $rows[$row++][$cell] = $dataLine; + } + } + } + return $rows; + } + + /** + * Determine width of each single column. + * + * @return void + */ + private function getColWidths() + { + if ( is_array( $this->properties['options']->colWidth ) ) + { + return $this->properties['options']->colWidth; + } + + // Determine number of columns: + $colCount = 0; + foreach ( $this->rows as $row ) + { + $colCount = max( sizeof( $row ), $colCount ); + } + + if ( $colCount === 0 ) + { + return array( $this->width ); + } + + $borderWidth = iconv_strlen( + $this->properties['options']->lineHorizontal, + 'UTF-8' + ); + + // Subtract border and padding chars from global width + $globalWidth = $this->width + - ( + // Per column: 2 * border padding + 1 border + $colCount * ( + 2 * iconv_strlen( $this->properties['options']->colPadding, 'UTF-8' ) + + $borderWidth + ) + // 1 Additional border + ) - $borderWidth; + + // Width of a column if each is made equal + $colNormWidth = round( $globalWidth / $colCount ); + $colMaxWidth = array(); + + // Determine the longest data for each column + foreach ( $this->rows as $row => $cells ) + { + foreach ( $cells as $col => $cell ) + { + $contentLength = 0; + foreach ( explode( PHP_EOL, $cell->content ) as $contentRow ) + { + $contentLength = max( + $contentLength, + iconv_strlen( $contentRow, 'UTF-8' ) + ); + } + $colMaxWidth[$col] = isset( $colMaxWidth[$col] ) ? max( $colMaxWidth[$col], $contentLength ) : $contentLength; + } + } + $colWidth = array(); + $colWidthOverflow = array(); + $spareWidth = 0; + + // Make columns best fit + foreach ( $colMaxWidth as $col => $maxWidth ) + { + // Does the largest data of the column fit into the average size + // + what we have in spare from earlier columns? + if ( $maxWidth <= ( $colNormWidth + $spareWidth ) ) + { + // We fit in, make the column as large as necessary + $colWidth[$col] = $maxWidth; + $spareWidth += ( $colNormWidth - $maxWidth ); + } + else + { + // Does not fit, use maximal possible width + $colWidth[$col] = $colNormWidth + $spareWidth; + $spareWidth = 0; + // Store overflow for second processing step + $colWidthOverflow[$col] = $maxWidth - $colWidth[$col]; + } + } + + // Do we have spare to give to the columns again? + if ( $spareWidth > 0 ) + { + // Second processing step + if ( count( $colWidthOverflow ) > 0 ) + { + $overflowSum = array_sum( $colWidthOverflow ); + foreach ( $colWidthOverflow as $col => $overflow ); + { + $colWidth[$col] += floor( $overflow / $overflowSum * $spareWidth ); + } + } + elseif ( $this->properties['options']->widthType === ezcConsoleTable::WIDTH_FIXED ) + { + $widthSum = array_sum( $colWidth ); + foreach ( $colWidth as $col => $width ) + { + $colWidth[$col] += floor( $width / $widthSum * $spareWidth ); + } + } + } + + // Finally sanitize values from rounding issues, if necessary + if ( ( $colSum = array_sum( $colWidth ) ) != $globalWidth && $this->properties['options']->widthType === ezcConsoleTable::WIDTH_FIXED ) + { + $colWidth[count( $colWidth ) - 1] -= $colSum - $globalWidth; + } + return $colWidth; + } + + /** + * Returns the given $text formatted with $format. + * + * In case $useFormats is set to false in the output handler, the text is + * returned as given, without any formatting. + * + * @param string $text + * @param string $format + * @return string + */ + private function formatText( $text, $format ) + { + if ( $this->outputHandler->options->useFormats ) + { + return $this->outputHandler->formatText( $text, $format ); + } + else + { + return $text; + } + } +} +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/table/cell.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/table/cell.php new file mode 100644 index 0000000..636a6ce --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/table/cell.php @@ -0,0 +1,152 @@ +mixed) + */ + protected $properties; + + /** + * Create a new ezcConsoleProgressbarCell. + * Creates a new ezcConsoleProgressbarCell. You can either submit the cell + * data through the constructor or set them as properties. + * + * @param string $content Content of the cell. + * @param string $format Format to display the cell with. + * @param mixed $align Alignment of the content in the cell. + * @return void + */ + public function __construct( $content = '', $format = 'default', $align = ezcConsoleTable::ALIGN_DEFAULT ) + { + $this->__set( 'content', $content ); + $this->__set( 'format', $format ); + $this->__set( 'align', $align ); + } + + /** + * Property read access. + * + * @param string $key Name of the property. + * @return mixed Value of the property or null. + * + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * @ignore + */ + public function __get( $key ) + { + if ( isset( $this->properties[$key] ) ) + { + return $this->properties[$key]; + } + throw new ezcBasePropertyNotFoundException( $key ); + } + + /** + * Property write access. + * + * @param string $key Name of the property. + * @param mixed $val The value for the property. + * + * @throws ezcBaseValueException + * If a the value submitted for the align is not in the range of + * {@link ezcConsoleTable::ALIGN_LEFT}, + * {@link ezcConsoleTable::ALIGN_CENTER}, + * {@link ezcConsoleTable::ALIGN_RIGHT}, + * {@link ezcConsoleTable::ALIGN_DEFAULT} + * + * @ignore + */ + public function __set( $key, $val ) + { + + switch ( $key ) + { + case 'content': + if ( is_string( $val ) === false ) + { + throw new ezcBaseValueException( $key, $val, "string" ); + } + break; + case 'format': + if ( is_string( $val ) === false || strlen( $val ) < 1 ) + { + throw new ezcBaseValueException( $key, $val, "string, length > 0" ); + } + break; + case 'align': + if ( $val !== ezcConsoleTable::ALIGN_LEFT + && $val !== ezcConsoleTable::ALIGN_CENTER + && $val !== ezcConsoleTable::ALIGN_RIGHT + && $val !== ezcConsoleTable::ALIGN_DEFAULT + ) + { + throw new ezcBaseValueException( $key, $val, 'ezcConsoleTable::ALIGN_DEFAULT, ezcConsoleTable::ALIGN_LEFT, ezcConsoleTable::ALIGN_CENTER, ezcConsoleTable::ALIGN_RIGHT' ); + } + break; + default: + throw new ezcBasePropertyNotFoundException( $key ); + } + $this->properties[$key] = $val; + return; + } + + /** + * Property isset access. + * + * @param string $key Name of the property. + * @return bool True is the property is set, otherwise false. + * @ignore + */ + public function __isset( $key ) + { + switch ( $key ) + { + case 'content': + case 'format': + case 'align': + return true; + default: + break; + } + return false; + } + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/table/row.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/table/row.php new file mode 100644 index 0000000..3e0de90 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/table/row.php @@ -0,0 +1,372 @@ + + * // Create new table row + * $row = new ezcConsoleTableRow(); + * + * // Set default format of the row's cells + * $row->format = 'headline'; + * + * // On the fly create the cell no 0 + * $row[0]->content = 'Name'; + * // On the fly create the cell no 1 + * $row[1]->content = 'Cellphone'; + * + * // Change a setting on cell 0 + * $row[0]->align = ezcConsoleTable::ALIGN_CENTER; + * + * // Iterate through the row's cells. + * foreach ( $row as $cell ) + * { + * var_dump( $cell ); + * } + * + * // Set the default align property for all cells in the row + * $row->align = ezcConsoleTable::ALIGN_CENTER; + * + * + * + * This class stores the rows for the {@link ezcConsoleTable} class. + * + * @property string $borderFormat + * Set the format applied to the borders of this row. See + * {@link ezcConsoleOutput} + * @property string $format + * Format applied to cell contents of cells marked with + * format "default" in this row. + * @property mixed $align + * Alignment applied to cells marked with + * ezcConsoleTable::ALIGN_DEFAULT. + * + * @package ConsoleTools + * @version 1.6.1 + */ +class ezcConsoleTableRow implements Countable, Iterator, ArrayAccess +{ + /** + * Container to hold the properties + * + * @var array(string=>mixed) + */ + protected $properties; + + /** + * The cells of the row. + * + * @var array(ezcConsoleTableCell) + */ + protected $cells = array(); + + /** + * Create a new ezcConsoleProgressbarRow. + * Creates a new ezcConsoleProgressbarRow. + * + * This method takes any number of {@link ezcConsoleTableCell} objects as + * parameter, which will be added as table cells to the row in their + * specified order. + * + * @throws ezcBaseValueException + * If a parameter is not of type {@link ezcConsoleTableCell}. + */ + public function __construct() + { + $this->properties['borderFormat'] = 'default'; + $this->properties['format'] = 'default'; + $this->properties['align'] = ezcConsoleTable::ALIGN_DEFAULT; + + if ( func_num_args() > 0 ) + { + foreach ( func_get_args() as $id => $arg ) + { + if ( !( $arg instanceof ezcConsoleTableCell ) ) + { + throw new ezcBaseValueException( 'Parameter'.$id, $arg, 'ezcConsoleTableCell' ); + } + $this->cells[] = $arg; + } + } + } + + /** + * Returns if the given offset exists. + * This method is part of the ArrayAccess interface to allow access to the + * data of this object as if it was an array. + * + * @param int $offset The offset to check. + * @return bool True when the offset exists, otherwise false. + * + * @throws ezcBaseValueException + * If a non numeric cell ID is requested. + */ + public function offsetExists( $offset ) + { + if ( !is_int( $offset ) || $offset < 0 ) + { + throw new ezcBaseValueException( 'offset', $offset, 'int >= 0' ); + } + return isset( $this->cells[$offset] ); + } + + /** + * Returns the element with the given offset. + * This method is part of the ArrayAccess interface to allow access to the + * data of this object as if it was an array. In case of the + * ezcConsoleTableRow class this method always returns a valid cell object + * since it creates them on the fly, if a given item does not exist. + * + * @param int $offset The offset to check. + * @return ezcConsoleTableCell + * + * @throws ezcBaseValueException + * If a non numeric cell ID is requested. + */ + public function offsetGet( $offset ) + { + if ( !isset( $offset ) ) + { + $offset = count( $this ); + $this->cells[$offset] = new ezcConsoleTableCell(); + } + if ( !is_int( $offset ) || $offset < 0 ) + { + throw new ezcBaseValueException( 'offset', $offset, 'int >= 0' ); + } + if ( !isset( $this->cells[$offset] ) ) + { + $this->cells[$offset] = new ezcConsoleTableCell(); + } + return $this->cells[$offset]; + } + + /** + * Set the element with the given offset. + * This method is part of the ArrayAccess interface to allow access to the + * data of this object as if it was an array. + * + * @param int $offset The offset to assign an item to. + * @param ezcConsoleTableCell $value The cell to assign. + * @return void + * + * @throws ezcBaseValueException + * If a non numeric cell ID is requested. + * @throws ezcBaseValueException + * If the provided value is not of type {@ling ezcConsoleTableCell}. + */ + public function offsetSet( $offset, $value ) + { + if ( !( $value instanceof ezcConsoleTableCell ) ) + { + throw new ezcBaseValueException( 'value', $value, 'ezcConsoleTableCell' ); + } + if ( !isset( $offset ) ) + { + $offset = count( $this ); + } + if ( !is_int( $offset ) || $offset < 0 ) + { + throw new ezcBaseValueException( 'offset', $offset, 'int >= 0' ); + } + $this->cells[$offset] = $value; + } + + /** + * Unset the element with the given offset. + * This method is part of the ArrayAccess interface to allow access to the + * data of this object as if it was an array. + * + * @param int $offset The offset to unset the value for. + * @return void + * + * @throws ezcBaseValueException + * If a non numeric cell ID is requested. + */ + public function offsetUnset( $offset ) + { + if ( !is_int( $offset ) || $offset < 0 ) + { + throw new ezcBaseValueException( 'offset', $offset, 'int >= 0' ); + } + if ( isset( $this->cells[$offset] ) ) + { + unset( $this->cells[$offset] ); + } + } + + /** + * Returns the number of cells in the row. + * This method is part of the Countable interface to allow the usage of + * PHP's count() function to check how many cells this row has. + * + * @return int Number of cells in this row. + */ + public function count() + { + $keys = array_keys( $this->cells ); + return count( $keys ) > 0 ? ( end( $keys ) + 1 ) : 0; + } + + /** + * Returns the currently selected cell. + * This method is part of the Iterator interface to allow acces to the + * cells of this row by iterating over it like an array (e.g. using + * foreach). + * + * @return ezcConsoleTableCell The currently selected cell. + */ + public function current() + { + return current( $this->cells ); + } + + /** + * Returns the key of the currently selected cell. + * This method is part of the Iterator interface to allow acces to the + * cells of this row by iterating over it like an array (e.g. using + * foreach). + * + * @return int The key of the currently selected cell. + */ + public function key() + { + return key( $this->cells ); + } + + /** + * Returns the next cell and selects it or false on the last cell. + * This method is part of the Iterator interface to allow acces to the + * cells of this row by iterating over it like an array (e.g. using + * foreach). + * + * @return mixed ezcConsoleTableCell if the next cell exists, or false. + */ + public function next() + { + return next( $this->cells ); + } + + /** + * Selects the very first cell and returns it. + * This method is part of the Iterator interface to allow acces to the + * cells of this row by iterating over it like an array (e.g. using + * foreach). + * + * @return ezcConsoleTableCell The very first cell of this row. + */ + public function rewind() + { + return reset( $this->cells ); + } + + /** + * Returns if the current cell is valid. + * This method is part of the Iterator interface to allow acces to the + * cells of this row by iterating over it like an array (e.g. using + * foreach). + * + * @return ezcConsoleTableCell The very first cell of this row. + */ + public function valid() + { + return current( $this->cells ) !== false; + } + + /** + * Property read access. + * + * @param string $key Name of the property. + * @return mixed Value of the property or null. + * + * @throws ezcBasePropertyNotFoundException + * If the the desired property is not found. + * @ignore + */ + public function __get( $key ) + { + if ( isset( $this->properties[$key] ) ) + { + return $this->properties[$key]; + } + throw new ezcBasePropertyNotFoundException( $key ); + } + + /** + * Property write access. + * + * @param string $key Name of the property. + * @param mixed $val The value for the property. + * + * @throws ezcBaseValueException + * If a the value submitted for the align is not in the range of + * {@link ezcConsoleTable::ALIGN_LEFT}, + * {@link ezcConsoleTable::ALIGN_CENTER}, + * {@link ezcConsoleTable::ALIGN_RIGHT}, + * {@link ezcConsoleTable::ALIGN_DEFAULT} + * + * @ignore + */ + public function __set( $key, $val ) + { + + switch ( $key ) + { + case 'format': + case 'borderFormat': + if ( is_string( $val ) === false || strlen( $val ) < 1 ) + { + throw new ezcBaseValueException( $key, $val, "string, length > 0" ); + } + break; + case 'align': + if ( $val !== ezcConsoleTable::ALIGN_LEFT + && $val !== ezcConsoleTable::ALIGN_CENTER + && $val !== ezcConsoleTable::ALIGN_RIGHT + && $val !== ezcConsoleTable::ALIGN_DEFAULT + ) + { + throw new ezcBaseValueException( $key, $val, 'ezcConsoleTable::ALIGN_DEFAULT, ezcConsoleTable::ALIGN_LEFT, ezcConsoleTable::ALIGN_CENTER, ezcConsoleTable::ALIGN_RIGHT' ); + } + break; + default: + throw new ezcBasePropertyNotFoundException( $key ); + } + $this->properties[$key] = $val; + } + + /** + * Property isset access. + * + * @param string $key Name of the property. + * @return bool True is the property is set, otherwise false. + * @ignore + */ + public function __isset( $key ) + { + switch ( $key ) + { + case 'format': + case 'borderFormat': + case 'align': + return true; + default: + return false; + } + } + +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/tools/string.php b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/tools/string.php new file mode 100644 index 0000000..eac2fff --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/ConsoleTools/tools/string.php @@ -0,0 +1,184 @@ += $width ) + { + $newtext .= iconv_substr( $str, $laststart, $current - $laststart, 'UTF-8' ) + . $break; + $laststart = $current + 1; + } + $lastspace = $current; + } + + // Special cut case, if no space has been seen + else if ( $current - $laststart >= $width + && $cut && $laststart >= $lastspace + ) + { + $newtext .= iconv_substr( $str, $laststart, $current - $laststart, 'UTF-8' ) + . $break; + $laststart = $lastspace = $current; + } + + + // Usual case that line got longer than expected + else if ( $current - $laststart >= $width + && $laststart < $lastspace + ) + { + $newtext .= iconv_substr( $str, $laststart, $lastspace - $laststart, 'UTF-8' ) + . $break; + // $laststart = $lastspace = $lastspace + 1; + $laststart = ++$lastspace; + } + } + + // Rest of the string + if ( $laststart !== $current ) + { + $newtext .= iconv_substr( $str, $laststart, $current - $laststart, 'UTF-8' ); + } + + return $newtext; + } + + /** + * Binary safe str_pad() replacement. + * + * This method is a multi-byte encoding safe replacement for the PHP + * function str_pad(). It mimics exactly the behavior of str_pad(), but + * uses iconv_* functions with UTF-8 encoding. The parameters received by + * this method equal the parameters of {@link http://php.net/str_pad + * str_pad()}. Note: Make sure to hand only UTF-8 encoded content to this + * method. + * + * @param string $input + * @param int $padLength + * @param string $padString + * @param int $padType + * @return string + */ + public function strPad( $input, $padLength, $padString = ' ', $padType = STR_PAD_RIGHT ) + { + $input = (string) $input; + + $strLen = iconv_strlen( $input, 'UTF-8' ); + $padStrLen = iconv_strlen( $padString, 'UTF-8' ); + + if ( $strLen >= $padLength ) + { + return $input; + } + + if ( $padType === STR_PAD_BOTH ) + { + return $this->strPad( + $this->strPad( + $input, + $strLen + ceil( ( $padLength - $strLen ) / 2 ), + $padString + ), + $padLength, + $padString, + STR_PAD_LEFT + ); + } + + $fullStrRepeats = (int) ( ( $padLength - $strLen ) / $padStrLen ); + $partlyPad = iconv_substr( + $padString, + 0, + ( ( $padLength - $strLen ) % $padStrLen ) + ); + + $padding = str_repeat( $padString, $fullStrRepeats ) . $partlyPad; + + switch ( $padType ) + { + case STR_PAD_LEFT: + return $padding . $input; + case STR_PAD_RIGHT: + default: + return $input . $padding; + } + } +} + +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/autoload/base_autoload.php b/typo3conf/ext/phpunit/PEAR/ezc/autoload/base_autoload.php new file mode 100644 index 0000000..b6575e0 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/autoload/base_autoload.php @@ -0,0 +1,47 @@ + 'Base/exceptions/exception.php', + 'ezcBaseFileException' => 'Base/exceptions/file_exception.php', + 'ezcBaseAutoloadException' => 'Base/exceptions/autoload.php', + 'ezcBaseDoubleClassRepositoryPrefixException' => 'Base/exceptions/double_class_repository_prefix.php', + 'ezcBaseExtensionNotFoundException' => 'Base/exceptions/extension_not_found.php', + 'ezcBaseFileIoException' => 'Base/exceptions/file_io.php', + 'ezcBaseFileNotFoundException' => 'Base/exceptions/file_not_found.php', + 'ezcBaseFilePermissionException' => 'Base/exceptions/file_permission.php', + 'ezcBaseFunctionalityNotSupportedException' => 'Base/exceptions/functionality_not_supported.php', + 'ezcBaseInitCallbackConfiguredException' => 'Base/exceptions/init_callback_configured.php', + 'ezcBaseInitInvalidCallbackClassException' => 'Base/exceptions/invalid_callback_class.php', + 'ezcBaseInvalidParentClassException' => 'Base/exceptions/invalid_parent_class.php', + 'ezcBasePropertyNotFoundException' => 'Base/exceptions/property_not_found.php', + 'ezcBasePropertyPermissionException' => 'Base/exceptions/property_permission.php', + 'ezcBaseSettingNotFoundException' => 'Base/exceptions/setting_not_found.php', + 'ezcBaseSettingValueException' => 'Base/exceptions/setting_value.php', + 'ezcBaseValueException' => 'Base/exceptions/value.php', + 'ezcBaseWhateverException' => 'Base/exceptions/whatever.php', + 'ezcBaseOptions' => 'Base/options.php', + 'ezcBaseStruct' => 'Base/struct.php', + 'ezcBase' => 'Base/base.php', + 'ezcBaseAutoloadOptions' => 'Base/options/autoload.php', + 'ezcBaseConfigurationInitializer' => 'Base/interfaces/configuration_initializer.php', + 'ezcBaseExportable' => 'Base/interfaces/exportable.php', + 'ezcBaseFeatures' => 'Base/features.php', + 'ezcBaseFile' => 'Base/file.php', + 'ezcBaseFileFindContext' => 'Base/structs/file_find_context.php', + 'ezcBaseInit' => 'Base/init.php', + 'ezcBaseMetaData' => 'Base/metadata.php', + 'ezcBaseMetaDataPearReader' => 'Base/metadata/pear.php', + 'ezcBaseMetaDataTarballReader' => 'Base/metadata/tarball.php', + 'ezcBasePersistable' => 'Base/interfaces/persistable.php', + 'ezcBaseRepositoryDirectory' => 'Base/structs/repository_directory.php', +); +?> diff --git a/typo3conf/ext/phpunit/PEAR/ezc/autoload/console_autoload.php b/typo3conf/ext/phpunit/PEAR/ezc/autoload/console_autoload.php new file mode 100644 index 0000000..4d44e02 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/ezc/autoload/console_autoload.php @@ -0,0 +1,76 @@ + 'ConsoleTools/exceptions/exception.php', + 'ezcConsoleArgumentException' => 'ConsoleTools/exceptions/argument.php', + 'ezcConsoleOptionException' => 'ConsoleTools/exceptions/option.php', + 'ezcConsoleArgumentAlreadyRegisteredException' => 'ConsoleTools/exceptions/argument_already_registered.php', + 'ezcConsoleArgumentMandatoryViolationException' => 'ConsoleTools/exceptions/argument_mandatory_violation.php', + 'ezcConsoleArgumentTypeViolationException' => 'ConsoleTools/exceptions/argument_type_violation.php', + 'ezcConsoleDialogAbortException' => 'ConsoleTools/exceptions/dialog_abort.php', + 'ezcConsoleInvalidOptionNameException' => 'ConsoleTools/exceptions/invalid_option_name.php', + 'ezcConsoleInvalidOutputTargetException' => 'ConsoleTools/exceptions/invalid_output_target.php', + 'ezcConsoleNoPositionStoredException' => 'ConsoleTools/exceptions/no_position_stored.php', + 'ezcConsoleNoValidDialogResultException' => 'ConsoleTools/exceptions/no_valid_dialog_result.php', + 'ezcConsoleOptionAlreadyRegisteredException' => 'ConsoleTools/exceptions/option_already_registered.php', + 'ezcConsoleOptionArgumentsViolationException' => 'ConsoleTools/exceptions/option_arguments_violation.php', + 'ezcConsoleOptionDependencyViolationException' => 'ConsoleTools/exceptions/option_dependency_violation.php', + 'ezcConsoleOptionExclusionViolationException' => 'ConsoleTools/exceptions/option_exclusion_violation.php', + 'ezcConsoleOptionMandatoryViolationException' => 'ConsoleTools/exceptions/option_mandatory_violation.php', + 'ezcConsoleOptionMissingValueException' => 'ConsoleTools/exceptions/option_missing_value.php', + 'ezcConsoleOptionNoAliasException' => 'ConsoleTools/exceptions/option_no_alias.php', + 'ezcConsoleOptionNotExistsException' => 'ConsoleTools/exceptions/option_not_exists.php', + 'ezcConsoleOptionStringNotWellformedException' => 'ConsoleTools/exceptions/option_string_not_wellformed.php', + 'ezcConsoleOptionTooManyValuesException' => 'ConsoleTools/exceptions/option_too_many_values.php', + 'ezcConsoleOptionTypeViolationException' => 'ConsoleTools/exceptions/option_type_violation.php', + 'ezcConsoleTooManyArgumentsException' => 'ConsoleTools/exceptions/argument_too_many.php', + 'ezcConsoleDialogValidator' => 'ConsoleTools/interfaces/dialog_validator.php', + 'ezcConsoleQuestionDialogValidator' => 'ConsoleTools/interfaces/question_dialog_validator.php', + 'ezcConsoleDialog' => 'ConsoleTools/interfaces/dialog.php', + 'ezcConsoleDialogOptions' => 'ConsoleTools/options/dialog.php', + 'ezcConsoleInputHelpGenerator' => 'ConsoleTools/interfaces/input_help_generator.php', + 'ezcConsoleInputValidator' => 'ConsoleTools/interfaces/input_validator.php', + 'ezcConsoleMenuDialogValidator' => 'ConsoleTools/interfaces/menu_dialog_validator.php', + 'ezcConsoleQuestionDialogCollectionValidator' => 'ConsoleTools/dialog/validators/question_dialog_collection.php', + 'ezcConsoleArgument' => 'ConsoleTools/input/argument.php', + 'ezcConsoleArguments' => 'ConsoleTools/input/arguments.php', + 'ezcConsoleDialogViewer' => 'ConsoleTools/dialog_viewer.php', + 'ezcConsoleInput' => 'ConsoleTools/input.php', + 'ezcConsoleInputStandardHelpGenerator' => 'ConsoleTools/input/help_generators/standard.php', + 'ezcConsoleMenuDialog' => 'ConsoleTools/dialog/menu_dialog.php', + 'ezcConsoleMenuDialogDefaultValidator' => 'ConsoleTools/dialog/validators/menu_dialog_default.php', + 'ezcConsoleMenuDialogOptions' => 'ConsoleTools/options/menu_dialog.php', + 'ezcConsoleOption' => 'ConsoleTools/input/option.php', + 'ezcConsoleOptionRule' => 'ConsoleTools/structs/option_rule.php', + 'ezcConsoleOutput' => 'ConsoleTools/output.php', + 'ezcConsoleOutputFormat' => 'ConsoleTools/structs/output_format.php', + 'ezcConsoleOutputFormats' => 'ConsoleTools/structs/output_formats.php', + 'ezcConsoleOutputOptions' => 'ConsoleTools/options/output.php', + 'ezcConsoleProgressMonitor' => 'ConsoleTools/progressmonitor.php', + 'ezcConsoleProgressMonitorOptions' => 'ConsoleTools/options/progressmonitor.php', + 'ezcConsoleProgressbar' => 'ConsoleTools/progressbar.php', + 'ezcConsoleProgressbarOptions' => 'ConsoleTools/options/progressbar.php', + 'ezcConsoleQuestionDialog' => 'ConsoleTools/dialog/question_dialog.php', + 'ezcConsoleQuestionDialogMappingValidator' => 'ConsoleTools/dialog/validators/question_dialog_mapping.php', + 'ezcConsoleQuestionDialogOptions' => 'ConsoleTools/options/question_dialog.php', + 'ezcConsoleQuestionDialogRegexValidator' => 'ConsoleTools/dialog/validators/question_dialog_regex.php', + 'ezcConsoleQuestionDialogTypeValidator' => 'ConsoleTools/dialog/validators/question_dialog_type.php', + 'ezcConsoleStandardInputValidator' => 'ConsoleTools/input/validators/standard.php', + 'ezcConsoleStatusbar' => 'ConsoleTools/statusbar.php', + 'ezcConsoleStatusbarOptions' => 'ConsoleTools/options/statusbar.php', + 'ezcConsoleStringTool' => 'ConsoleTools/tools/string.php', + 'ezcConsoleTable' => 'ConsoleTools/table.php', + 'ezcConsoleTableCell' => 'ConsoleTools/table/cell.php', + 'ezcConsoleTableOptions' => 'ConsoleTools/options/table.php', + 'ezcConsoleTableRow' => 'ConsoleTools/table/row.php', +); +?> diff --git a/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStream.php b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStream.php new file mode 100644 index 0000000..7194fda --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStream.php @@ -0,0 +1,191 @@ +at($directory); + return $directory; + } + + /** + * returns current user + * + * If the system does not support posix_getuid() the current user will be root (0). + * + * @return int + */ + public static function getCurrentUser() + { + return function_exists('posix_getuid') ? posix_getuid() : self::OWNER_ROOT; + } + + /** + * returns current group + * + * If the system does not support posix_getgid() the current group will be root (0). + * + * @return int + */ + public static function getCurrentGroup() + { + return function_exists('posix_getgid') ? posix_getgid() : self::GROUP_ROOT; + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamAbstractContent.php b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamAbstractContent.php new file mode 100644 index 0000000..e2ec02d --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamAbstractContent.php @@ -0,0 +1,323 @@ +name = $name; + $this->lastModified = time(); + if (null === $permissions) { + $permissions = $this->getDefaultPermissions() & ~vfsStream::umask(); + } + + $this->permissions = $permissions; + $this->user = vfsStream::getCurrentUser(); + $this->group = vfsStream::getCurrentGroup(); + } + + /** + * returns default permissions for concrete implementation + * + * @return int + * @since 0.8.0 + */ + protected abstract function getDefaultPermissions(); + + /** + * returns the file name of the content + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * renames the content + * + * @param string $newName + */ + public function rename($newName) + { + $this->name = $newName; + } + + /** + * checks whether the container can be applied to given name + * + * @param string $name + * @return bool + */ + public function appliesTo($name) + { + if ($name === $this->name) { + return true; + } + + return (substr($name, 0, strlen($this->name)) === $this->name && strpos($name, '/') !== false); + } + + /** + * returns the type of the container + * + * @return int + */ + public function getType() + { + return $this->type; + } + + /** + * alias for lastModified() + * + * @param int $filemtime + * @return vfsStreamContent + * @see lastModified() + */ + public function setFilemtime($filemtime) + { + return $this->lastModified($filemtime); + } + + /** + * sets the last modification time of the stream content + * + * @param int $filemtime + * @return vfsStreamContent + */ + public function lastModified($filemtime) + { + $this->lastModified = $filemtime; + return $this; + } + + /** + * returns the last modification time of the stream content + * + * @return int + */ + public function filemtime() + { + return $this->lastModified; + } + + /** + * adds content to given container + * + * @param vfsStreamContainer $container + * @return vfsStreamContent + */ + public function at(vfsStreamContainer $container) + { + $container->addChild($this); + return $this; + } + + /** + * change file mode to given permissions + * + * @param int $permissions + * @return vfsStreamContent + */ + public function chmod($permissions) + { + $this->permissions = $permissions; + clearstatcache(); + return $this; + } + + /** + * returns permissions + * + * @return int + */ + public function getPermissions() + { + return $this->permissions; + } + + /** + * checks whether content is readable + * + * @param int $user id of user to check for + * @param int $group id of group to check for + * @return bool + */ + public function isReadable($user, $group) + { + if ($this->user === $user) { + $check = 0400; + } elseif ($this->group === $group) { + $check = 0040; + } else { + $check = 0004; + } + + return (bool) ($this->permissions & $check); + } + + /** + * checks whether content is writable + * + * @param int $user id of user to check for + * @param int $group id of group to check for + * @return bool + */ + public function isWritable($user, $group) + { + if ($this->user === $user) { + $check = 0200; + } elseif ($this->group === $group) { + $check = 0020; + } else { + $check = 0002; + } + + return (bool) ($this->permissions & $check); + } + + /** + * checks whether content is executable + * + * @param int $user id of user to check for + * @param int $group id of group to check for + * @return bool + */ + public function isExecutable($user, $group) + { + if ($this->user === $user) { + $check = 0100; + } elseif ($this->group === $group) { + $check = 0010; + } else { + $check = 0001; + } + + return (bool) ($this->permissions & $check); + } + + /** + * change owner of file to given user + * + * @param int $user + * @return vfsStreamContent + */ + public function chown($user) + { + $this->user = $user; + return $this; + } + + /** + * checks whether file is owned by given user + * + * @param int $user + * @return bool + */ + public function isOwnedByUser($user) + { + return $this->user === $user; + } + + /** + * returns owner of file + * + * @return int + */ + public function getUser() + { + return $this->user; + } + + /** + * change owner group of file to given group + * + * @param int $group + * @return vfsStreamContent + */ + public function chgrp($group) + { + $this->group = $group; + return $this; + } + + /** + * checks whether file is owned by group + * + * @param int $group + * @return bool + */ + public function isOwnedByGroup($group) + { + return $this->group === $group; + } + + /** + * returns owner group of file + * + * @return int + */ + public function getGroup() + { + return $this->group; + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamContainer.php b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamContainer.php new file mode 100644 index 0000000..3037c4e --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamContainer.php @@ -0,0 +1,53 @@ + + */ + public function getChildren(); +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamContainerIterator.php b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamContainerIterator.php new file mode 100644 index 0000000..0685799 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamContainerIterator.php @@ -0,0 +1,89 @@ + + */ + protected $children = array(); + + /** + * constructor + * + * @param array $children + */ + public function __construct(array $children) + { + $this->children = $children; + reset($this->children); + } + + /** + * resets children pointer + */ + public function rewind() + { + reset($this->children); + } + + /** + * returns the current child + * + * @return vfsStreamContent + */ + public function current() + { + $child = current($this->children); + if (false === $child) { + return null; + } + + return $child; + } + + /** + * returns the name of the current child + * + * @return string + */ + public function key() + { + $child = current($this->children); + if (false === $child) { + return null; + } + + return $child->getName(); + } + + /** + * iterates to next child + */ + public function next() + { + next($this->children); + } + + /** + * checks if the current value is valid + * + * @return bool + */ + public function valid() + { + return (false !== current($this->children)); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamContent.php b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamContent.php new file mode 100644 index 0000000..aea56a8 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamContent.php @@ -0,0 +1,194 @@ + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamDirectory.php b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamDirectory.php new file mode 100644 index 0000000..b87b882 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamDirectory.php @@ -0,0 +1,212 @@ + + */ + protected $children = array(); + + /** + * constructor + * + * @param string $name + * @param int $permissions optional + * @throws vfsStreamException + */ + public function __construct($name, $permissions = null) + { + if (strstr($name, '/') !== false) { + throw new vfsStreamException('Directory name can not contain /.'); + } + + $this->type = vfsStreamContent::TYPE_DIR; + parent::__construct($name, $permissions); + } + + /** + * returns default permissions for concrete implementation + * + * @return int + * @since 0.8.0 + */ + protected function getDefaultPermissions() + { + return 0777; + } + + /** + * returns size of directory + * + * The size of a directory is always 0 bytes. To calculate the summarized + * size of all children in the directory use sizeSummarized(). + * + * @return int + */ + public function size() + { + return 0; + } + + /** + * returns summarized size of directory and its children + * + * @return int + */ + public function sizeSummarized() + { + $size = 0; + foreach ($this->children as $child) { + if ($child->getType() === vfsStreamContent::TYPE_DIR) { + $size += $child->sizeSummarized(); + } else { + $size += $child->size(); + } + } + + return $size; + } + + /** + * renames the content + * + * @param string $newName + * @throws vfsStreamException + */ + public function rename($newName) + { + if (strstr($newName, '/') !== false) { + throw new vfsStreamException('Directory name can not contain /.'); + } + + parent::rename($newName); + } + + /** + * adds child to the directory + * + * @param vfsStreamContent $child + */ + public function addChild(vfsStreamContent $child) + { + $this->children[$child->getName()] = $child; + } + + /** + * removes child from the directory + * + * @param string $name + * @return bool + */ + public function removeChild($name) + { + foreach ($this->children as $key => $child) { + if ($child->appliesTo($name) === true) { + unset($this->children[$key]); + return true; + } + } + + return false; + } + + /** + * checks whether the container contains a child with the given name + * + * @param string $name + * @return bool + */ + public function hasChild($name) + { + return ($this->getChild($name) !== null); + } + + /** + * returns the child with the given name + * + * @param string $name + * @return vfsStreamContent + */ + public function getChild($name) + { + $childName = $this->getRealChildName($name); + foreach ($this->children as $child) { + if ($child->getName() === $childName) { + return $child; + } + + if ($child->appliesTo($childName) === true && $child->hasChild($childName) === true) { + return $child->getChild($childName); + } + } + + return null; + } + + /** + * helper method to detect the real child name + * + * @param string $name + * @return string + */ + protected function getRealChildName($name) + { + if ($this->appliesTo($name) === true) { + return self::getChildName($name, $this->name); + } + + return $name; + } + + /** + * helper method to calculate the child name + * + * @param string $name + * @param string $ownName + * @return string + */ + protected static function getChildName($name, $ownName) + { + return substr($name, strlen($ownName) + 1); + } + + /** + * returns a list of children for this directory + * + * @return array + */ + public function getChildren() + { + return array_values($this->children); + } + + /** + * returns iterator for the children + * + * @return vfsStreamContainerIterator + */ + public function getIterator() + { + return new vfsStreamContainerIterator($this->children); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamException.php b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamException.php new file mode 100644 index 0000000..126cd49 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamException.php @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamFile.php b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamFile.php new file mode 100644 index 0000000..911a682 --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamFile.php @@ -0,0 +1,203 @@ +type = vfsStreamContent::TYPE_FILE; + parent::__construct($name, $permissions); + } + + /** + * returns default permissions for concrete implementation + * + * @return int + * @since 0.8.0 + */ + protected function getDefaultPermissions() + { + return 0666; + } + + /** + * checks whether the container can be applied to given name + * + * @param string $name + * @return bool + */ + public function appliesTo($name) + { + return ($name === $this->name); + } + + /** + * alias for withContent() + * + * @param string $content + * @return vfsStreamFile + * @see withContent() + */ + public function setContent($content) + { + return $this->withContent($content); + } + + /** + * sets the contents of the file + * + * Setting content with this method does not change the time when the file + * was last modified. + * + * @param string $content + * @return vfsStreamFile + * @see setContent() + */ + public function withContent($content) + { + $this->content = $content; + return $this; + } + + /** + * returns the contents of the file + * + * @return string + */ + public function getContent() + { + return $this->content; + } + + /** + * reads the given amount of bytes from content + * + * @param int $count + * @return string + */ + public function read($count) + { + $data = substr($this->content, $this->bytes_read, $count); + $this->bytes_read += $count; + return $data; + } + + /** + * returns the content until its end from current offset + * + * @return string + */ + public function readUntilEnd() + { + return substr($this->content, $this->bytes_read); + } + + /** + * writes an amount of data + * + * Using this method changes the time when the file was last modified. + * + * @param string $data + * @return amount of written bytes + */ + public function write($data) + { + $dataLen = strlen($data); + $this->content = substr($this->content, 0, $this->bytes_read) . $data . substr($this->content, $this->bytes_read + $dataLen); + $this->bytes_read += $dataLen; + $this->filemtime = time(); + return $dataLen; + } + + /** + * checks whether pointer is at end of file + * + * @return bool + */ + public function eof() + { + return $this->bytes_read >= strlen($this->content); + } + + /** + * returns the current position within the file + * + * @return int + */ + public function getBytesRead() + { + return $this->bytes_read; + } + + /** + * seeks to the given offset + * + * @param int $offset + * @param int $whence + * @return bool + */ + public function seek($offset, $whence) + { + switch ($whence) { + case SEEK_CUR: + $this->bytes_read += $offset; + return true; + + case SEEK_END: + $this->bytes_read = strlen($this->content) + $offset; + return true; + + case SEEK_SET: + $this->bytes_read = $offset; + return true; + + default: + return false; + } + + return false; + } + + /** + * returns size of content + * + * @return int + */ + public function size() + { + return strlen($this->content); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamWrapper.php b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamWrapper.php new file mode 100644 index 0000000..92671bb --- /dev/null +++ b/typo3conf/ext/phpunit/PEAR/vfsStream/vfsStreamWrapper.php @@ -0,0 +1,681 @@ +getName() === $path) { + return self::$root; + } + + if (self::$root->hasChild($path) === true) { + return self::$root->getChild($path); + } + + return null; + } + + /** + * returns content for given path but only when it is of given type + * + * @param string $path + * @param int $type + * @return vfsStreamContent + */ + protected function getContentOfType($path, $type) + { + $content = $this->getContent($path); + if (null !== $content && $content->getType() === $type) { + return $content; + } + + return null; + } + + /** + * splits path into its dirname and the basename + * + * @param string $path + * @return array + */ + protected function splitPath($path) + { + $lastSlashPos = strrpos($path, '/'); + if (false === $lastSlashPos) { + return array('dirname' => '', 'basename' => $path); + } + + return array('dirname' => substr($path, 0, $lastSlashPos), + 'basename' => substr($path, $lastSlashPos + 1) + ); + } + + /** + * helper method to resolve a path from /foo/bar/. to /foo/bar + * + * @param string $path + * @return string + */ + protected function resolvePath($path) + { + $newPath = array(); + foreach (explode('/', $path) as $pathPart) { + if ('.' !== $pathPart) { + if ('..' !== $pathPart) { + $newPath[] = $pathPart; + } else { + array_pop($newPath); + } + } + } + + return implode('/', $newPath); + } + + /** + * open the stream + * + * @param string $path the path to open + * @param string $mode mode for opening + * @param string $options options for opening + * @param string $opened_path full path that was actually opened + * @return bool + */ + public function stream_open($path, $mode, $options, $opened_path) + { + $extended = ((strstr($mode, '+') !== false) ? (true) : (false)); + $mode = str_replace(array('b', '+'), '', $mode); + if (in_array($mode, array('r', 'w', 'a', 'x')) === false) { + if (!($options & STREAM_REPORT_ERRORS)) { + trigger_error('Illegal mode ' . $mode . ', use r, w, a or x, flavoured with b and/or +', E_USER_WARNING); + } + + return false; + } + + $this->mode = $this->calculateMode($mode, $extended); + $path = $this->resolvePath(vfsStream::path($path)); + $this->content = $this->getContentOfType($path, vfsStreamContent::TYPE_FILE); + if (null !== $this->content) { + if (self::WRITE === $mode) { + if (!($options & STREAM_REPORT_ERRORS)) { + trigger_error('File ' . $path . ' already exists, can not open with mode x', E_USER_WARNING); + } + + return false; + } + + $this->content->seek(0, SEEK_SET); + if (self::TRUNCATE === $mode && $this->content->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === true) { + $this->content->setContent(''); // truncate + } elseif (self::APPEND === $mode) { + $this->content->seek(0, SEEK_END); + } + + return true; + } + + $names = $this->splitPath($path); + if (empty($names['dirname']) === true) { + if (!($options & STREAM_REPORT_ERRORS)) { + trigger_error('File ' . $names['basename'] . ' does not exist', E_USER_WARNING); + } + + return false; + } + + $dir = $this->getContentOfType($names['dirname'], vfsStreamContent::TYPE_DIR); + if (null === $dir) { + if (!($options & STREAM_REPORT_ERRORS)) { + trigger_error('Directory ' . $names['dirname'] . ' does not exist', E_USER_WARNING); + } + + return false; + } elseif ($dir->hasChild($names['basename']) === true) { + if (!($options & STREAM_REPORT_ERRORS)) { + trigger_error('Directory ' . $names['dirname'] . ' already contains a director named ' . $names['basename'], E_USER_WARNING); + } + + return false; + } + + if (self::READ === $mode) { + if (!($options & STREAM_REPORT_ERRORS)) { + trigger_error('Can not open non-existing file ' . $path . ' for reading', E_USER_WARNING); + } + + return false; + } + + if ($dir->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + if (!($options & STREAM_REPORT_ERRORS)) { + trigger_error('Can not create new file in non-writable path ' . $names['dirname'], E_USER_WARNING); + } + + return false; + } + + $this->content = vfsStream::newFile($names['basename'])->at($dir); + return true; + } + + /** + * calculates the file mode + * + * @param string $mode opening mode: r, w, a or x + * @param bool $extended true if + was set with opening mode + * @return int + */ + protected function calculateMode($mode, $extended) + { + if (true === $extended) { + return self::ALL; + } + + if (self::READ === $mode) { + return self::READONLY; + } + + return self::WRITEONLY; + } + + /** + * closes the stream + */ + public function stream_close() + { + // nothing to do + } + + /** + * read the stream up to $count bytes + * + * @param int $count amount of bytes to read + * @return string + */ + public function stream_read($count) + { + if (self::WRITEONLY === $this->mode) { + return ''; + } + + if ($this->content->isReadable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + return ''; + } + + return $this->content->read($count); + } + + /** + * writes data into the stream + * + * @param string $data + * @return int amount of bytes written + */ + public function stream_write($data) + { + if (self::READONLY === $this->mode) { + return 0; + } + + if ($this->content->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + return 0; + } + + return $this->content->write($data); + } + + /** + * checks whether stream is at end of file + * + * @return bool + */ + public function stream_eof() + { + return $this->content->eof(); + } + + /** + * returns the current position of the stream + * + * @return int + */ + public function stream_tell() + { + return $this->content->getBytesRead(); + } + + /** + * seeks to the given offset + * + * @param int $offset + * @param int $whence + * @return bool + */ + public function stream_seek($offset, $whence) + { + return $this->content->seek($offset, $whence); + } + + /** + * flushes unstored data into storage + * + * @return bool + */ + public function stream_flush() + { + return true; + } + + /** + * returns status of stream + * + * @return array + */ + public function stream_stat() + { + $fileStat = array('dev' => 0, + 'ino' => 0, + 'mode' => $this->content->getType() | $this->content->getPermissions(), + 'nlink' => 0, + 'uid' => $this->content->getUser(), + 'gid' => $this->content->getGroup(), + 'rdev' => 0, + 'size' => $this->content->size(), + 'atime' => $this->content->filemtime(), + 'mtime' => $this->content->filemtime(), + 'ctime' => $this->content->filemtime(), + 'blksize' => -1, + 'blocks' => -1 + ); + return array_merge(array_values($fileStat), $fileStat); + } + + /** + * remove the data under the given path + * + * @param string $path + * @return bool + */ + public function unlink($path) + { + $realPath = $this->resolvePath(vfsStream::path($path)); + $content = $this->getContent($realPath); + if (null === $content || $content->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + return false; + } + + if (self::$root->getName() === $realPath) { + // delete root? very brave. :) + self::$root = null; + clearstatcache(); + return true; + } + + $names = $this->splitPath($realPath); + $content = $this->getContent($names['dirname']); + if ($content->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + return false; + } + + clearstatcache(); + return $content->removeChild($names['basename']); + } + + /** + * rename from one path to another + * + * @param string $path_from + * @param string $path_to + * @return bool + * @author Benoit Aubuchon + */ + public function rename($path_from, $path_to) + { + $srcRealPath = $this->resolvePath(vfsStream::path($path_from)); + $dstRealPath = vfsStream::path($path_to); + $srcContent = $this->getContent($srcRealPath); + if (null == $srcContent) { + trigger_error(' No such file or directory', E_USER_WARNING); + return false; + } + + $dstContent = clone $srcContent; + $dstNames = $this->splitPath($dstRealPath); + // Renaming the filename + $dstContent->rename($dstNames['basename']); + // Copying to the destination + $dstParentContent = $this->getContent($dstNames['dirname']); + if (null == $dstParentContent) { + trigger_error('No such file or directory', E_USER_WARNING); + return false; + } + + if ($dstParentContent->getType() !== vfsStreamContent::TYPE_DIR) { + trigger_error('Target is not a directory', E_USER_WARNING); + return false; + } + + $dstParentContent->addChild($dstContent); + // Removing the source + return $this->unlink($path_from); + } + + /** + * creates a new directory + * + * @param string $path + * @param int $mode + * @param int $options + * @return bool + */ + public function mkdir($path, $mode, $options) + { + $umask = vfsStream::umask(); + if (0 < $umask) { + $permissions = $mode & ~$umask; + } else { + $permissions = $mode; + } + + $path = vfsStream::path($path); + if (null === self::$root) { + self::$root = vfsStream::newDirectory($path, $permissions); + return true; + } + + $maxDepth = count(explode('/', $path)); + $names = $this->splitPath($path); + $newDirs = $names['basename']; + $dir = null; + $i = 0; + while ($dir === null && $i < $maxDepth) { + $dir = $this->getContent($names['dirname']); + $names = $this->splitPath($names['dirname']); + $newDirs = $names['basename'] . '/' . $newDirs; + $i++; + } + + if (null === $dir + || $dir->getType() !== vfsStreamContent::TYPE_DIR + || $dir->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + return false; + } + + $newDirs = str_replace($dir->getName() . '/', '', $newDirs); + $recursive = ((STREAM_MKDIR_RECURSIVE & $options) !== 0) ? (true) : (false); + if (strpos($newDirs, '/') !== false && false === $recursive) { + return false; + } + + vfsStream::newDirectory($newDirs, $permissions)->at($dir); + return true; + } + + /** + * removes a directory + * + * @param string $path + * @param int $options + * @return bool + * @todo consider $options with STREAM_MKDIR_RECURSIVE + */ + public function rmdir($path, $options) + { + $path = $this->resolvePath(vfsStream::path($path)); + $child = $this->getContentOfType($path, vfsStreamContent::TYPE_DIR); + if (null === $child) { + return false; + } + + // can only remove empty directories + if (count($child->getChildren()) > 0) { + return false; + } + + if (self::$root->getName() === $path) { + // delete root? very brave. :) + self::$root = null; + clearstatcache(); + return true; + } + + $names = $this->splitPath($path); + $dir = $this->getContentOfType($names['dirname'], vfsStreamContent::TYPE_DIR); + if ($dir->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + return false; + } + + clearstatcache(); + return $dir->removeChild($child->getName()); + } + + /** + * opens a directory + * + * @param string $path + * @param int $options + * @return bool + */ + public function dir_opendir($path, $options) + { + $path = $this->resolvePath(vfsStream::path($path)); + $this->dir = $this->getContentOfType($path, vfsStreamContent::TYPE_DIR); + if (null === $this->dir || $this->dir->isReadable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) { + return false; + } + + $this->dirIterator = $this->dir->getIterator(); + return true; + } + + /** + * reads directory contents + * + * @return string + */ + public function dir_readdir() + { + $dir = $this->dirIterator->current(); + if (null === $dir) { + return false; + } + + $this->dirIterator->next(); + return $dir->getName(); + } + + /** + * reset directory iteration + * + * @return bool + */ + public function dir_rewinddir() + { + return $this->dirIterator->rewind(); + } + + /** + * closes directory + * + * @return bool + */ + public function dir_closedir() + { + $this->dirIterator = null; + return true; + } + + /** + * returns status of url + * + * @param string $path path of url to return status for + * @param ? $flags flags set by the stream API + * @return array + */ + public function url_stat($path, $flags) + { + $path = $this->resolvePath(vfsStream::path($path)); + $content = $this->getContent($path); + if (null === $content) { + if (!($flags & STREAM_URL_STAT_QUIET)) { + trigger_error(' No such file or directory', E_USER_WARNING); + } + return false; + + } + + $fileStat = array('dev' => 0, + 'ino' => 0, + 'mode' => $content->getType() | $content->getPermissions(), + 'nlink' => 0, + 'uid' => $content->getUser(), + 'gid' => $content->getGroup(), + 'rdev' => 0, + 'size' => $content->size(), + 'atime' => $content->filemtime(), + 'mtime' => $content->filemtime(), + 'ctime' => $content->filemtime(), + 'blksize' => -1, + 'blocks' => -1 + ); + return array_merge(array_values($fileStat), $fileStat); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Resources/Private/Language/locallang_backend.xml b/typo3conf/ext/phpunit/Resources/Private/Language/locallang_backend.xml new file mode 100644 index 0000000..89c775c --- /dev/null +++ b/typo3conf/ext/phpunit/Resources/Private/Language/locallang_backend.xml @@ -0,0 +1,172 @@ + + + + Language labels for module "tools_txphpunitbeM1" + module + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Resources/Private/Language/locallang_report.xml b/typo3conf/ext/phpunit/Resources/Private/Language/locallang_report.xml new file mode 100644 index 0000000..b608a85 --- /dev/null +++ b/typo3conf/ext/phpunit/Resources/Private/Language/locallang_report.xml @@ -0,0 +1,95 @@ + + + + module + Language labels for the PHPUnit status reports + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Resources/Public/CSS/BackEnd.css b/typo3conf/ext/phpunit/Resources/Public/CSS/BackEnd.css new file mode 100644 index 0000000..ae115fb --- /dev/null +++ b/typo3conf/ext/phpunit/Resources/Public/CSS/BackEnd.css @@ -0,0 +1,214 @@ +h3 { + font-size: 100%; + margin: 0; + padding: 0; +} + +p { + margin-bottom: 8px; +} + +a { + color: blue; +} + +a:hover { + color: blue; + text-decoration: underline; +} + +p, div, body, input, select, textarea, .defstyle { + color: black; +} + +/* Safari hack, http://dustinbrewer.com/css-hackgetting-safari-to-behave/ */ +@media screen and (-webkit-min-device-pixel-ratio:0) { + form select { + text-indent: 18px; + } +} + +#opennewwindow { + text-decoration: none; +} + +#opennewwindow:hover { + background-color: white; +} + +h1, h2, h3, h4 { + background-color: transparent; + color: black; + text-align: left; +} + +.access-key { + text-decoration: underline; +} + +/* Temporary bugfix for issue http://bugs.typo3.org/view.php?id=7631 */ +body#typo3-mod-php { + overflow: auto; +} + +/* Now we have a somewhat sane setup. Let's style get to work styling. */ + +.progress-bar-wrap { + height: 2em; + margin-bottom: 1em; + border: 1px solid black; + background-color: white; + width: 100%; +} + +#progress-bar, +#transparent-bar { + border: 0; + height: 100%; +} + +#progress-bar { + float: left; +} + +#transparent-bar { + float: left; + background-color: grey; +} + +.alltests { + border-top: 1px solid #999999; + border-bottom: 1px solid #999999; +} + +.wasSuccessful { + background-color: green; +} + +.hadFailure { + background-color: yellow; +} + +.hadError { + background-color: red; +} + +.inCompleteTest { + color: grey; +} + +.message { + margin: 0.5em; + border: 1px solid #eeeeee; + padding: 0.5em; + margin-left: 0.2em; + background-color: white; +} + +.testcaseOutput, +.testcaseFailure, +.testcaseError { + padding: .2em 0 .2em .3em; + margin: 0.3em 0 0.3em 0; + background-color: #f1fff1; +} + +.testcaseOutput { + border-left: 2px solid lightgreen; +} +.testcaseOutput img.runner { + border: 1px solid transparent; + vertical-align: middle; + padding: 0 2px; + border-radius: .2em; +} +.testcaseOutput img.runner:hover { + background-image: url(/typo3conf/ext/phpunit/Resources/Public/Icons/RunnerRunning.gif); + background-repeat: no-repeat; + background-position: 2px 0; + border-color: lightgreen; +} +.testcaseOutput.testcaseError img.runner:hover { + border-color: #ff0000; +} +.testcaseOutput.testcaseFailure img.runner:hover { + border-color: yellow; +} +.testcaseOutput pre.message { + white-space: normal; +} +.testcaseFailure { + border-left: 2px solid yellow; + background-color: #fffec3; +} + +.testcaseError { + border-left: 2px solid red; + background-color: #ffc3c3; +} + +.testcaseNotImplemented { + border-left: 2px solid #CCC; + background-color: #EEE; +} + +.testcaseSkipped { + border-left: 2px solid #CCC; + background-color: #EEE; +} + +.tx_phpunit_testcase_progressbox { + background-color: aqua; + width: 100%; + height: 100%; + border: 1px solid black; + float: left; +} + +#testsHaveFinished { + display: none; +} + +/* + * Changes to general layout + */ +#doc3 { + margin: 0; + padding: 0; +} + +html { + background-color: #F8F8F8; +} + +th, td { + border: 0; +} + +.testSuiteName { + font-size: 13px; +} +.wasSuccessful { + color: #3b7826; + background-color: #cdeaca; + border-color: #58b548; +} +.hadFailure { + color: #9e7d4a; + background-color: #fbf6de; + border-color: #b1905c; +} +.hadError { + color: #aa0225; + background-color: #f6d3cf; + border-color: #d66c68; +} +h2.wasSuccessful, h2.hadFailure, h2.hadError { + padding: 2px 5px; + border-width: 1px; + border-style: solid; + border-radius: 4px; +} +#progress-bar.wasSuccessful { + width:100%; +} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Resources/Public/Icons/BackEndModule.gif b/typo3conf/ext/phpunit/Resources/Public/Icons/BackEndModule.gif new file mode 100644 index 0000000000000000000000000000000000000000..f0c4885bd79ff3ab435991af22d192ad0d8e2392 GIT binary patch literal 563 zcmZ?wbhEHb13J$>uyyPo$ZQ`r8iLYBHewjFJf7jHn{nH=LnzOEV#`{@wx6Pfut$)_f zsk5KVntN`}ykqkg?3^+8#r%bb7B1ejV9~xwbN^47_kZ5vlT+sZpRwS}lBGMRE%-le z;s2RS{?A_Wf92|}vzPv#v-IzrrT^zG{Xciv|9Q*)uUd0p-ikj9R(@Nw`v2lJ|JQ9i zv2^YK)$5-vTmOCe`u{68{NK85|EdlD*KGQ~cJu!oI}fhe`fuHq|7*AX-?8K6j-AhT z?Y*>Z=a(&e{%_s$|L~Esd-ng^ckutdL;sE*zjX4{g`=nbpFMZ|?715kFWtU!_1=|h z_pV;Md-K-g+jkz{zyIX^gXa$(zIgWR^~+c9zJC4jpE#iSlZBCip`Jm90SG{G!oWVE zp}szok;N;csk5tILeX86O+~Z2Q^+?Z)=hzfl{=tIPB1hk+`~j!oR2B3(@fsm&(mI& zol{sQy(x!Z+t$&>TuD}%IlD88%gV~y%2b1w$1WtRNx;Iz$=SulK}|%fC^@d4!5}O+ u@TGr{j($@?eZIPwu1|D)LZW2elw2cM!6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW3IP8AEC2ui01f~W000P`0RIUbNU&f*a{t%>fMQS}I)P9QglH&m zn5Q0fpfyw`q`(3Ib^eVj7z;rG000!QY3L1yER-mR8B~@8je!6y7-W!1&{>=(00?*z z1;T+EgF_Sm(DqN=rcVZMbO11lqQDFQ7AUx8?q9lr4_6Ub@dAL6hQk^xkn|76S%U2T it&m_!U=Jb&KgdWnu!$Xme+kxzWUyO7ADajU1OPk0aliTi literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/Resources/Public/Icons/RunnerRunning.gif b/typo3conf/ext/phpunit/Resources/Public/Icons/RunnerRunning.gif new file mode 100644 index 0000000000000000000000000000000000000000..9362b9ecf252d4b888cfbe86d61cffd8586dc3c8 GIT binary patch literal 839 zcmZ?wbhEHbG1`bk?>Y|NZ~}_l+9&g$wt-e*mmb_mU;|i4*<){|m8M{r>&;jT!fkANPk1_m3U-hYkv{ zS^DSF`R3C3`}_B>W%sdX_N7hx{QdW;Sofw+`Q*;S?ACLVEpRV_LM38`t|$l-1mCpFv3InfH_{ft8uU9v|b^reV{{Q~@+P3$rS^%w3 z_{fyl@Z<=vS3kdd_`7=dlqve+$^HHN_mCm^`}+5W4EL#1_mCh8u~_@{@6_<&<@M|z zw`K*eR06M4K)`(P`Sk1d@cjAp_l_I@tx*ZESf$>;r{Kc%`}p|FoA;zk#q8Jjixnrh zYWK8k_pDm?m@@Z|9{>OUF6Lk200003bW%=J|Nj8j$_+sP000?uMObuGZ)S9NVRB^v zL1b@YWgtmyVP|DhWnpA_ami&o0002bNklhV^XvZG{Bq9VG_dBC zAp2B)9(9I{Z7*zNfnknrwn8m;FGeOP*+&g#{h{NXZsTw+CJmjO>)m? zpz1hX7}R^DNVEujpC@48i%(0BmVoOAFzCDrOPYB5O*EiAE-4ng+-pFqTuB=5ZvZ|o uB1PN&FR-+^c+o)=200&&D<300||D===1223){C=this.createResponseObject(F,B);if(G&&G.success){if(!G.scope){G.success(C);}else{G.success.apply(G.scope,[C]);}}this.successEvent.fire(C);if(F.successEvent){F.successEvent.fire(C);}}else{switch(D){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:C=this.createExceptionObject(F.tId,B,(A?A:false));if(G&&G.failure){if(!G.scope){G.failure(C);}else{G.failure.apply(G.scope,[C]);}}break;default:C=this.createResponseObject(F,B);if(G&&G.failure){if(!G.scope){G.failure(C);}else{G.failure.apply(G.scope,[C]);}}}this.failureEvent.fire(C);if(F.failureEvent){F.failureEvent.fire(C);}}this.releaseObject(F);C=null;},createResponseObject:function(A,G){var D={};var I={};try{var C=A.conn.getAllResponseHeaders();var F=C.split("\n");for(var E=0;E-1){A=B.options[B.selectedIndex];F[O++]=K+encodeURIComponent((A.attributes.value&&A.attributes.value.specified)?A.value:A.text);}break;case"select-multiple":if(B.selectedIndex>-1){for(D=B.selectedIndex,N=B.options.length;D');if(typeof A=="boolean"){C.src="javascript:false";}}else{C=document.createElement("iframe");C.id=B;C.name=B;}C.style.position="absolute";C.style.top="-1000px";C.style.left="-1000px";document.body.appendChild(C);},appendPostData:function(A){var D=[],B=A.split("&"),C,E;for(C=0;C0){for(H=0;H=0;--i){if(pstack[i]===o){return"null";}}pstack[pstack.length]=o;a=[];isArray=l.isArray(o);if(d>0){if(isArray){for(i=o.length-1;i>=0;--i){a[i]=_stringify(o,i,d-1,w,pstack)||"null";}}else{j=0;if(l.isArray(w)){for(i=0,len=w.length;i=0?d:1/0;return _stringify({"":o},"",d,w,[]);}return undefined;},dateToString:function(d){function _zeroPad(v){return v<10?"0"+v:v;}return d.getUTCFullYear()+"-"+_zeroPad(d.getUTCMonth()+1)+"-"+_zeroPad(d.getUTCDate())+"T"+_zeroPad(d.getUTCHours())+":"+_zeroPad(d.getUTCMinutes())+":"+_zeroPad(d.getUTCSeconds())+"Z";},stringToDate:function(str){if(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$/.test(str)){var d=new Date();d.setUTCFullYear(RegExp.$1,(RegExp.$2|0)-1,RegExp.$3);d.setUTCHours(RegExp.$4,RegExp.$5,RegExp.$6);return d;}return str;}};})();YAHOO.register("json",YAHOO.lang.JSON,{version:"2.7.0",build:"1799"}); \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Resources/Public/YUI/reset-fonts-grids.css b/typo3conf/ext/phpunit/Resources/Public/YUI/reset-fonts-grids.css new file mode 100644 index 0000000..cdacf12 --- /dev/null +++ b/typo3conf/ext/phpunit/Resources/Public/YUI/reset-fonts-grids.css @@ -0,0 +1,7 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.7.0 +*/ +html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;}body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}select,input,button,textarea,button{font:99% arial,helvetica,clean,sans-serif;}table{font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;}body{text-align:center;}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{margin:auto;text-align:left;width:57.69em;*width:56.25em;}#doc2{width:73.076em;*width:71.25em;}#doc3{margin:auto 10px;width:auto;}#doc4{width:74.923em;*width:73.05em;}.yui-b{position:relative;}.yui-b{_position:static;}#yui-main .yui-b{position:static;}#yui-main,.yui-g .yui-u .yui-g{width:100%;}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em;}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em;}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em;}.yui-t1 #yui-main .yui-b{margin-left:13.30769em;*margin-left:13.05em;}.yui-t2 .yui-b{float:left;width:13.8461em;*width:13.50em;}.yui-t2 #yui-main .yui-b{margin-left:14.8461em;*margin-left:14.55em;}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em;}.yui-t3 #yui-main .yui-b{margin-left:24.0769em;*margin-left:23.62em;}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em;}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.55em;}.yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em;}.yui-t5 #yui-main .yui-b{margin-right:19.4615em;*margin-right:19.125em;}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em;}.yui-t6 #yui-main .yui-b{margin-right:24.0769em;*margin-right:23.62em;}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0;}#yui-main .yui-b{float:none;width:auto;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right;}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-gc div.first div.first{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:1.99%;}.yui-gb .yui-u{*margin-left:1.9%;*width:31.9%;}.yui-gc div.first,.yui-gd .yui-u{width:66%;}.yui-gd div.first{width:32%;}.yui-ge div.first,.yui-gf .yui-u{width:74.2%;}.yui-ge .yui-u,.yui-gf div.first{width:24%;}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0;}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-g .yui-g .yui-u{width:48.1%;}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-g .yui-gc div.first,.yui-gd .yui-g{width:66%;}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0;}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-g .yui-gb .yui-u{_margin-left:1.0%;}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0;}.yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0;}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;}.yui-gb .yui-gd div.first{width:32%;}.yui-g .yui-gd div.first{_width:29.9%;}.yui-ge .yui-g{width:24%;}.yui-gf .yui-g{width:74.2%;}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first{float:left;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}.yui-ge div.first .yui-gd .yui-u{width:65%;}.yui-ge div.first .yui-gd div.first{width:32%;}#hd:after,#bd:after,#ft:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#hd,#bd,#ft,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1;} \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Resources/Public/YUI/yahoo-dom-event.js b/typo3conf/ext/phpunit/Resources/Public/YUI/yahoo-dom-event.js new file mode 100644 index 0000000..8a63c10 --- /dev/null +++ b/typo3conf/ext/phpunit/Resources/Public/YUI/yahoo-dom-event.js @@ -0,0 +1,13 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.7.0 +*/ +if(typeof YAHOO=="undefined"||!YAHOO){var YAHOO={};}YAHOO.namespace=function(){var A=arguments,E=null,C,B,D;for(C=0;C0)?B.dump(G[I],L-1):O);}else{N.push(G[I]);}N.push(M);}if(N.length>1){N.pop();}N.push("]");}else{N.push("{");for(I in G){if(B.hasOwnProperty(G,I)){N.push(I+J);if(B.isObject(G[I])){N.push((L>0)?B.dump(G[I],L-1):O);}else{N.push(G[I]);}N.push(M);}}if(N.length>1){N.pop();}N.push("}");}return N.join("");},substitute:function(V,H,O){var L,K,J,R,S,U,Q=[],I,M="dump",P=" ",G="{",T="}",N;for(;;){L=V.lastIndexOf(G);if(L<0){break;}K=V.indexOf(T,L);if(L+1>=K){break;}I=V.substring(L+1,K);R=I;U=null;J=R.indexOf(P);if(J>-1){U=R.substring(J+1);R=R.substring(0,J);}S=H[R];if(O){S=O(R,S,U);}if(B.isObject(S)){if(B.isArray(S)){S=B.dump(S,parseInt(U,10));}else{U=U||"";N=U.indexOf(M);if(N>-1){U=U.substring(4);}if(S.toString===A.toString||N>-1){S=B.dump(S,parseInt(U,10));}else{S=S.toString();}}}else{if(!B.isString(S)&&!B.isNumber(S)){S="~-"+Q.length+"-~";Q[Q.length]=I;}}V=V.substring(0,L)+S+V.substring(K+1);}for(L=Q.length-1;L>=0;L=L-1){V=V.replace(new RegExp("~-"+L+"-~"),"{"+Q[L]+"}","g");}return V;},trim:function(G){try{return G.replace(/^\s+|\s+$/g,"");}catch(H){return G;}},merge:function(){var J={},H=arguments,G=H.length,I;for(I=0;I519)?true:false);while((G=G[u])){z[0]+=G[b];z[1]+=G[P];if(AC){z=E.Dom._calcBorders(G,z);}}if(E.Dom._getStyle(y,p)!==f){G=y;while((G=G[Z])&&G[C]){AA=G[i];AB=G[O];if(H&&(E.Dom._getStyle(G,"overflow")!=="visible")){z=E.Dom._calcBorders(G,z);}if(AA||AB){z[0]-=AB;z[1]-=AA;}}z[0]+=x;z[1]+=Y;}else{if(D){z[0]-=x;z[1]-=Y;}else{if(I||H){z[0]+=x;z[1]+=Y;}}}z[0]=Math.floor(z[0]);z[1]=Math.floor(z[1]);}else{}return z;};}}(),getX:function(G){var Y=function(x){return E.Dom.getXY(x)[0];};return E.Dom.batch(G,Y,E.Dom,true);},getY:function(G){var Y=function(x){return E.Dom.getXY(x)[1];};return E.Dom.batch(G,Y,E.Dom,true);},setXY:function(G,x,Y){E.Dom.batch(G,E.Dom._setXY,{pos:x,noRetry:Y});},_setXY:function(G,z){var AA=E.Dom._getStyle(G,p),y=E.Dom.setStyle,AD=z.pos,Y=z.noRetry,AB=[parseInt(E.Dom.getComputedStyle(G,j),10),parseInt(E.Dom.getComputedStyle(G,o),10)],AC,x;if(AA=="static"){AA=V;y(G,p,AA);}AC=E.Dom._getXY(G);if(!AD||AC===false){return false;}if(isNaN(AB[0])){AB[0]=(AA==V)?0:G[b];}if(isNaN(AB[1])){AB[1]=(AA==V)?0:G[P];}if(AD[0]!==null){y(G,j,AD[0]-AC[0]+AB[0]+"px");}if(AD[1]!==null){y(G,o,AD[1]-AC[1]+AB[1]+"px");}if(!Y){x=E.Dom._getXY(G);if((AD[0]!==null&&x[0]!=AD[0])||(AD[1]!==null&&x[1]!=AD[1])){E.Dom._setXY(G,{pos:AD,noRetry:true});}}},setX:function(Y,G){E.Dom.setXY(Y,[G,null]);},setY:function(G,Y){E.Dom.setXY(G,[null,Y]);},getRegion:function(G){var Y=function(x){var y=false;if(E.Dom._canPosition(x)){y=E.Region.getRegion(x);}else{}return y;};return E.Dom.batch(G,Y,E.Dom,true);},getClientWidth:function(){return E.Dom.getViewportWidth();},getClientHeight:function(){return E.Dom.getViewportHeight();},getElementsByClassName:function(AB,AF,AC,AE,x,AD){AB=L.trim(AB);AF=AF||"*";AC=(AC)?E.Dom.get(AC):null||K;if(!AC){return[];}var Y=[],G=AC.getElementsByTagName(AF),z=E.Dom.hasClass;for(var y=0,AA=G.length;y-1;}}else{}return G;},addClass:function(Y,G){return E.Dom.batch(Y,E.Dom._addClass,G);},_addClass:function(x,Y){var G=false,y;if(x&&Y){y=E.Dom.getAttribute(x,F)||J;if(!E.Dom._hasClass(x,Y)){E.Dom.setAttribute(x,F,A(y+B+Y));G=true;}}else{}return G;},removeClass:function(Y,G){return E.Dom.batch(Y,E.Dom._removeClass,G);},_removeClass:function(y,x){var Y=false,AA,z,G;if(y&&x){AA=E.Dom.getAttribute(y,F)||J;E.Dom.setAttribute(y,F,AA.replace(E.Dom._getClassRegex(x),J));z=E.Dom.getAttribute(y,F);if(AA!==z){E.Dom.setAttribute(y,F,A(z));Y=true;if(E.Dom.getAttribute(y,F)===""){G=(y.hasAttribute&&y.hasAttribute(g))?g:F;y.removeAttribute(G);}}}else{}return Y;},replaceClass:function(x,Y,G){return E.Dom.batch(x,E.Dom._replaceClass,{from:Y,to:G}); +},_replaceClass:function(y,x){var Y,AB,AA,G=false,z;if(y&&x){AB=x.from;AA=x.to;if(!AA){G=false;}else{if(!AB){G=E.Dom._addClass(y,x.to);}else{if(AB!==AA){z=E.Dom.getAttribute(y,F)||J;Y=(B+z.replace(E.Dom._getClassRegex(AB),B+AA)).split(E.Dom._getClassRegex(AA));Y.splice(1,0,B+AA);E.Dom.setAttribute(y,F,A(Y.join(J)));G=true;}}}}else{}return G;},generateId:function(G,x){x=x||"yui-gen";var Y=function(y){if(y&&y.id){return y.id;}var z=x+YAHOO.env._id_counter++;if(y){if(y[e].getElementById(z)){return E.Dom.generateId(y,z+x);}y.id=z;}return z;};return E.Dom.batch(G,Y,E.Dom,true)||Y.apply(E.Dom,arguments);},isAncestor:function(Y,x){Y=E.Dom.get(Y);x=E.Dom.get(x);var G=false;if((Y&&x)&&(Y[l]&&x[l])){if(Y.contains&&Y!==x){G=Y.contains(x);}else{if(Y.compareDocumentPosition){G=!!(Y.compareDocumentPosition(x)&16);}}}else{}return G;},inDocument:function(G,Y){return E.Dom._inDoc(E.Dom.get(G),Y);},_inDoc:function(Y,x){var G=false;if(Y&&Y[C]){x=x||Y[e];G=E.Dom.isAncestor(x[v],Y);}else{}return G;},getElementsBy:function(Y,AF,AB,AD,y,AC,AE){AF=AF||"*";AB=(AB)?E.Dom.get(AB):null||K;if(!AB){return[];}var x=[],G=AB.getElementsByTagName(AF);for(var z=0,AA=G.length;z=this.left&&A.right<=this.right&&A.top>=this.top&&A.bottom<=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(E){var C=Math.max(this.top,E.top),D=Math.min(this.right,E.right),A=Math.min(this.bottom,E.bottom),B=Math.max(this.left,E.left);if(A>=C&&D>=B){return new YAHOO.util.Region(C,D,A,B); +}else{return null;}};YAHOO.util.Region.prototype.union=function(E){var C=Math.min(this.top,E.top),D=Math.max(this.right,E.right),A=Math.max(this.bottom,E.bottom),B=Math.min(this.left,E.left);return new YAHOO.util.Region(C,D,A,B);};YAHOO.util.Region.prototype.toString=function(){return("Region {"+"top: "+this.top+", right: "+this.right+", bottom: "+this.bottom+", left: "+this.left+", height: "+this.height+", width: "+this.width+"}");};YAHOO.util.Region.getRegion=function(D){var F=YAHOO.util.Dom.getXY(D),C=F[1],E=F[0]+D.offsetWidth,A=F[1]+D.offsetHeight,B=F[0];return new YAHOO.util.Region(C,E,A,B);};YAHOO.util.Point=function(A,B){if(YAHOO.lang.isArray(A)){B=A[1];A=A[0];}YAHOO.util.Point.superclass.constructor.call(this,B,A,B,A);};YAHOO.extend(YAHOO.util.Point,YAHOO.util.Region);(function(){var B=YAHOO.util,A="clientTop",F="clientLeft",J="parentNode",K="right",W="hasLayout",I="px",U="opacity",L="auto",D="borderLeftWidth",G="borderTopWidth",P="borderRightWidth",V="borderBottomWidth",S="visible",Q="transparent",N="height",E="width",H="style",T="currentStyle",R=/^width|height$/,O=/^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,M={get:function(X,Z){var Y="",a=X[T][Z];if(Z===U){Y=B.Dom.getStyle(X,U);}else{if(!a||(a.indexOf&&a.indexOf(I)>-1)){Y=a;}else{if(B.Dom.IE_COMPUTED[Z]){Y=B.Dom.IE_COMPUTED[Z](X,Z);}else{if(O.test(a)){Y=B.Dom.IE.ComputedStyle.getPixel(X,Z);}else{Y=a;}}}}return Y;},getOffset:function(Z,e){var b=Z[T][e],X=e.charAt(0).toUpperCase()+e.substr(1),c="offset"+X,Y="pixel"+X,a="",d;if(b==L){d=Z[c];if(d===undefined){a=0;}a=d;if(R.test(e)){Z[H][e]=d;if(Z[c]>d){a=d-(Z[c]-d);}Z[H][e]=L;}}else{if(!Z[H][Y]&&!Z[H][e]){Z[H][e]=b;}a=Z[H][Y];}return a+I;},getBorderWidth:function(X,Z){var Y=null;if(!X[T][W]){X[H].zoom=1;}switch(Z){case G:Y=X[A];break;case V:Y=X.offsetHeight-X.clientHeight-X[A];break;case D:Y=X[F];break;case P:Y=X.offsetWidth-X.clientWidth-X[F];break;}return Y+I;},getPixel:function(Y,X){var a=null,b=Y[T][K],Z=Y[T][X];Y[H][K]=Z;a=Y[H].pixelRight;Y[H][K]=b;return a+I;},getMargin:function(Y,X){var Z;if(Y[T][X]==L){Z=0+I;}else{Z=B.Dom.IE.ComputedStyle.getPixel(Y,X);}return Z;},getVisibility:function(Y,X){var Z;while((Z=Y[T])&&Z[X]=="inherit"){Y=Y[J];}return(Z)?Z[X]:S;},getColor:function(Y,X){return B.Dom.Color.toRGB(Y[T][X])||Q;},getBorderColor:function(Y,X){var Z=Y[T],a=Z[X]||Z.color;return B.Dom.Color.toRGB(B.Dom.Color.toHex(a));}},C={};C.top=C.right=C.bottom=C.left=C[E]=C[N]=M.getOffset;C.color=M.getColor;C[G]=C[P]=C[V]=C[D]=M.getBorderWidth;C.marginTop=C.marginRight=C.marginBottom=C.marginLeft=M.getMargin;C.visibility=M.getVisibility;C.borderColor=C.borderTopColor=C.borderRightColor=C.borderBottomColor=C.borderLeftColor=M.getBorderColor;B.Dom.IE_COMPUTED=C;B.Dom.IE_ComputedStyle=M;})();(function(){var C="toString",A=parseInt,B=RegExp,D=YAHOO.util;D.Dom.Color={KEYWORDS:{black:"000",silver:"c0c0c0",gray:"808080",white:"fff",maroon:"800000",red:"f00",purple:"800080",fuchsia:"f0f",green:"008000",lime:"0f0",olive:"808000",yellow:"ff0",navy:"000080",blue:"00f",teal:"008080",aqua:"0ff"},re_RGB:/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,re_hex:/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,re_hex3:/([0-9A-F])/gi,toRGB:function(E){if(!D.Dom.Color.re_RGB.test(E)){E=D.Dom.Color.toHex(E);}if(D.Dom.Color.re_hex.exec(E)){E="rgb("+[A(B.$1,16),A(B.$2,16),A(B.$3,16)].join(", ")+")";}return E;},toHex:function(H){H=D.Dom.Color.KEYWORDS[H]||H;if(D.Dom.Color.re_RGB.exec(H)){var G=(B.$1.length===1)?"0"+B.$1:Number(B.$1),F=(B.$2.length===1)?"0"+B.$2:Number(B.$2),E=(B.$3.length===1)?"0"+B.$3:Number(B.$3);H=[G[C](16),F[C](16),E[C](16)].join("");}if(H.length<6){H=H.replace(D.Dom.Color.re_hex3,"$1$1");}if(H!=="transparent"&&H.indexOf("#")<0){H="#"+H;}return H.toLowerCase();}};}());YAHOO.register("dom",YAHOO.util.Dom,{version:"2.7.0",build:"1799"});YAHOO.util.CustomEvent=function(D,C,B,A){this.type=D;this.scope=C||window;this.silent=B;this.signature=A||YAHOO.util.CustomEvent.LIST;this.subscribers=[];if(!this.silent){}var E="_YUICEOnSubscribe";if(D!==E){this.subscribeEvent=new YAHOO.util.CustomEvent(E,this,true);}this.lastError=null;};YAHOO.util.CustomEvent.LIST=0;YAHOO.util.CustomEvent.FLAT=1;YAHOO.util.CustomEvent.prototype={subscribe:function(A,B,C){if(!A){throw new Error("Invalid callback for subscriber to '"+this.type+"'");}if(this.subscribeEvent){this.subscribeEvent.fire(A,B,C);}this.subscribers.push(new YAHOO.util.Subscriber(A,B,C));},unsubscribe:function(D,F){if(!D){return this.unsubscribeAll();}var E=false;for(var B=0,A=this.subscribers.length;B0){B=I[0];}try{G=M.fn.call(L,B,M.obj);}catch(F){this.lastError=F;if(A){throw F;}}}else{try{G=M.fn.call(L,this.type,I,M.obj);}catch(H){this.lastError=H;if(A){throw H;}}}if(false===G){if(!this.silent){}break;}}}return(G!==false);},unsubscribeAll:function(){var A=this.subscribers.length,B;for(B=A-1;B>-1;B--){this._delete(B);}this.subscribers=[];return A;},_delete:function(A){var B=this.subscribers[A];if(B){delete B.fn;delete B.obj;}this.subscribers.splice(A,1);},toString:function(){return"CustomEvent: "+"'"+this.type+"', "+"context: "+this.scope;}};YAHOO.util.Subscriber=function(A,B,C){this.fn=A;this.obj=YAHOO.lang.isUndefined(B)?null:B;this.overrideContext=C;};YAHOO.util.Subscriber.prototype.getScope=function(A){if(this.overrideContext){if(this.overrideContext===true){return this.obj;}else{return this.overrideContext;}}return A;};YAHOO.util.Subscriber.prototype.contains=function(A,B){if(B){return(this.fn==A&&this.obj==B);}else{return(this.fn==A);}};YAHOO.util.Subscriber.prototype.toString=function(){return"Subscriber { obj: "+this.obj+", overrideContext: "+(this.overrideContext||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var H=false;var I=[];var J=[];var G=[];var E=[];var C=0;var F=[];var B=[];var A=0;var D={63232:38,63233:40,63234:37,63235:39,63276:33,63277:34,25:9};var K=YAHOO.env.ua.ie?"focusin":"focus";var L=YAHOO.env.ua.ie?"focusout":"blur";return{POLL_RETRYS:2000,POLL_INTERVAL:20,EL:0,TYPE:1,FN:2,WFN:3,UNLOAD_OBJ:3,ADJ_SCOPE:4,OBJ:5,OVERRIDE:6,lastError:null,isSafari:YAHOO.env.ua.webkit,webkit:YAHOO.env.ua.webkit,isIE:YAHOO.env.ua.ie,_interval:null,_dri:null,DOMReady:false,throwErrors:false,startInterval:function(){if(!this._interval){var M=this;var N=function(){M._tryPreloadAttach();};this._interval=setInterval(N,this.POLL_INTERVAL);}},onAvailable:function(S,O,Q,R,P){var M=(YAHOO.lang.isString(S))?[S]:S;for(var N=0;N-1;Q--){W=(this.removeListener(N[Q],M,V)&&W);}return W;}}if(!V||!V.call){return this.purgeElement(N,false,M);}if("unload"==M){for(Q=J.length-1;Q>-1;Q--){X=J[Q];if(X&&X[0]==N&&X[1]==M&&X[2]==V){J.splice(Q,1);return true;}}return false;}var R=null;var S=arguments[3];if("undefined"===typeof S){S=this._getCacheIndex(N,M,V);}if(S>=0){R=I[S];}if(!N||!R){return false;}if(this.useLegacyEvent(N,M)){var P=this.getLegacyIndex(N,M);var O=E[P];if(O){for(Q=0,T=O.length;Q0&&F.length>0);}var R=[];var T=function(V,W){var U=V;if(W.overrideContext){if(W.overrideContext===true){U=W.obj;}else{U=W.overrideContext;}}W.fn.call(U,W.obj);};var N,M,Q,P,O=[];for(N=0,M=F.length;N-1;N--){Q=F[N];if(!Q||!Q.id){F.splice(N,1);}}this.startInterval();}else{if(this._interval){clearInterval(this._interval);this._interval=null;}}this.locked=false;},purgeElement:function(Q,R,T){var O=(YAHOO.lang.isString(Q))?this.getEl(Q):Q;var S=this.getListeners(O,T),P,M;if(S){for(P=S.length-1;P>-1;P--){var N=S[P];this.removeListener(O,N.type,N.fn);}}if(R&&O&&O.childNodes){for(P=0,M=O.childNodes.length;P-1;P--){O=I[P];if(O){N.removeListener(O[N.EL],O[N.TYPE],O[N.FN],P);}}O=null;}G=null;N._simpleRemove(window,"unload",N._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var M=document.documentElement,N=document.body;if(M&&(M.scrollTop||M.scrollLeft)){return[M.scrollTop,M.scrollLeft];}else{if(N){return[N.scrollTop,N.scrollLeft];}else{return[0,0];}}},regCE:function(){},_simpleAdd:function(){if(window.addEventListener){return function(O,P,N,M){O.addEventListener(P,N,(M));};}else{if(window.attachEvent){return function(O,P,N,M){O.attachEvent("on"+P,N);};}else{return function(){};}}}(),_simpleRemove:function(){if(window.removeEventListener){return function(O,P,N,M){O.removeEventListener(P,N,(M));};}else{if(window.detachEvent){return function(N,O,M){N.detachEvent("on"+O,M);};}else{return function(){};}}}()};}();(function(){var EU=YAHOO.util.Event;EU.on=EU.addListener;EU.onFocus=EU.addFocusListener;EU.onBlur=EU.addBlurListener; +/* DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller */ +if(EU.isIE){YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event,true);var n=document.createElement("p");EU._dri=setInterval(function(){try{n.doScroll("left");clearInterval(EU._dri);EU._dri=null;EU._ready();n=null;}catch(ex){}},EU.POLL_INTERVAL);}else{if(EU.webkit&&EU.webkit<525){EU._dri=setInterval(function(){var rs=document.readyState;if("loaded"==rs||"complete"==rs){clearInterval(EU._dri);EU._dri=null;EU._ready();}},EU.POLL_INTERVAL);}else{EU._simpleAdd(document,"DOMContentLoaded",EU._ready);}}EU._simpleAdd(window,"load",EU._load);EU._simpleAdd(window,"unload",EU._unload);EU._tryPreloadAttach();})();}YAHOO.util.EventProvider=function(){};YAHOO.util.EventProvider.prototype={__yui_events:null,__yui_subscribers:null,subscribe:function(A,C,F,E){this.__yui_events=this.__yui_events||{};var D=this.__yui_events[A];if(D){D.subscribe(C,F,E); +}else{this.__yui_subscribers=this.__yui_subscribers||{};var B=this.__yui_subscribers;if(!B[A]){B[A]=[];}B[A].push({fn:C,obj:F,overrideContext:E});}},unsubscribe:function(C,E,G){this.__yui_events=this.__yui_events||{};var A=this.__yui_events;if(C){var F=A[C];if(F){return F.unsubscribe(E,G);}}else{var B=true;for(var D in A){if(YAHOO.lang.hasOwnProperty(A,D)){B=B&&A[D].unsubscribe(E,G);}}return B;}return false;},unsubscribeAll:function(A){return this.unsubscribe(A);},createEvent:function(G,D){this.__yui_events=this.__yui_events||{};var A=D||{};var I=this.__yui_events;if(I[G]){}else{var H=A.scope||this;var E=(A.silent);var B=new YAHOO.util.CustomEvent(G,H,E,YAHOO.util.CustomEvent.FLAT);I[G]=B;if(A.onSubscribeCallback){B.subscribeEvent.subscribe(A.onSubscribeCallback);}this.__yui_subscribers=this.__yui_subscribers||{};var F=this.__yui_subscribers[G];if(F){for(var C=0;C + */ +class Tx_Phpunit_BackEnd_AjaxTest extends Tx_Phpunit_TestCase { + /** + * @var Tx_Phpunit_BackEnd_Ajax + */ + private $fixture = NULL; + + /** + * backup of $GLOBALS['BE_USER'] + * + * @var t3lib_beUserAuth + */ + private $backEndUserBackup = NULL; + + /** + * backup of $_POST + * + * @var array + */ + private $postBackup = array(); + + public function setUp() { + $this->postBackup = $_POST; + $this->backEndUserBackup = $GLOBALS['BE_USER']; + + $_POST = array(); + $GLOBALS['BE_USER'] = $this->getMock('t3lib_beUserAuth'); + + $this->fixture = new Tx_Phpunit_BackEnd_Ajax(); + } + + public function tearDown() { + $GLOBALS['BE_USER'] = $this->backEndUserBackup; + $_POST = $this->postBackup; + + unset($this->fixture, $this->backEndUserBackup, $this->postBackup); + } + + /** + * @test + */ + public function ajaxBrokerForFailureCheckboxParameterAndStateTrueSavesOnStateToUserSettings() { + $_POST['checkbox'] = 'failure'; + $_POST['state'] = 'true'; + + $GLOBALS['BE_USER']->expects($this->once())->method('writeUC'); + + $this->fixture->ajaxBroker(array(), $this->getMock('TYPO3AJAX')); + + $this->assertSame( + 'on', + $GLOBALS['BE_USER']->uc['moduleData']['tools_txphpunitM1']['failure'] + ); + } + + /** + * @test + */ + public function ajaxBrokerForFailureCheckboxParameterAndMissingStateSavesOffStateToUserSettings() { + $_POST['checkbox'] = 'failure'; + + $GLOBALS['BE_USER']->expects($this->once())->method('writeUC'); + + $this->fixture->ajaxBroker(array(), $this->getMock('TYPO3AJAX')); + + $this->assertSame( + 'off', + $GLOBALS['BE_USER']->uc['moduleData']['tools_txphpunitM1']['failure'] + ); + } + + /** + * @test + */ + public function ajaxBrokerForFailureCheckboxParameterAddsSuccessContent() { + $_POST['checkbox'] = 'failure'; + + $ajax = $this->getMock('TYPO3AJAX'); + $ajax->expects($this->once())->method('addContent')->with('success', TRUE); + $ajax->expects($this->never())->method('setError'); + + $this->fixture->ajaxBroker(array(), $ajax); + } + + /** + * @test + */ + public function ajaxBrokerForSuccessCheckboxParameterAddsSuccessContent() { + $_POST['checkbox'] = 'success'; + + $ajax = $this->getMock('TYPO3AJAX'); + $ajax->expects($this->once())->method('addContent')->with('success', TRUE); + $ajax->expects($this->never())->method('setError'); + + $this->fixture->ajaxBroker(array(), $ajax); + } + + /** + * @test + */ + public function ajaxBrokerForErrorCheckboxParameterAddsSuccessContent() { + $_POST['checkbox'] = 'error'; + + $ajax = $this->getMock('TYPO3AJAX'); + $ajax->expects($this->once())->method('addContent')->with('success', TRUE); + $ajax->expects($this->never())->method('setError'); + + $this->fixture->ajaxBroker(array(), $ajax); + } + + /** + * @test + */ + public function ajaxBrokerForSkippedCheckboxParameterAddsSuccessContent() { + $_POST['checkbox'] = 'skipped'; + + $ajax = $this->getMock('TYPO3AJAX'); + $ajax->expects($this->once())->method('addContent')->with('success', TRUE); + $ajax->expects($this->never())->method('setError'); + + $this->fixture->ajaxBroker(array(), $ajax); + } + + /** + * @test + */ + public function ajaxBrokerForNotImplementedCheckboxParameterAddsSuccessContent() { + $_POST['checkbox'] = 'notimplemented'; + + $ajax = $this->getMock('TYPO3AJAX'); + $ajax->expects($this->once())->method('addContent')->with('success', TRUE); + $ajax->expects($this->never())->method('setError'); + + $this->fixture->ajaxBroker(array(), $ajax); + } + + /** + * @test + */ + public function ajaxBrokerForTestDoxCheckboxParameterAddsSuccessContent() { + $_POST['checkbox'] = 'testdox'; + + $ajax = $this->getMock('TYPO3AJAX'); + $ajax->expects($this->once())->method('addContent')->with('success', TRUE); + $ajax->expects($this->never())->method('setError'); + + $this->fixture->ajaxBroker(array(), $ajax); + } + + /** + * @test + */ + public function ajaxBrokerForCodeCoverageCheckboxParameterAddsSuccessContent() { + $_POST['checkbox'] = 'codeCoverage'; + + $ajax = $this->getMock('TYPO3AJAX'); + $ajax->expects($this->once())->method('addContent')->with('success', TRUE); + $ajax->expects($this->never())->method('setError'); + + $this->fixture->ajaxBroker(array(), $ajax); + } + + /** + * @test + */ + public function ajaxBrokerForShowMemoryAndTimeCheckboxParameterAddsSuccessContent() { + $_POST['checkbox'] = 'showMemoryAndTime'; + + $ajax = $this->getMock('TYPO3AJAX'); + $ajax->expects($this->once())->method('addContent')->with('success', TRUE); + $ajax->expects($this->never())->method('setError'); + + $this->fixture->ajaxBroker(array(), $ajax); + } + + /** + * @test + */ + public function ajaxBrokerForRunSeleniumTestsCheckboxParameterAddsSuccessContent() { + $_POST['checkbox'] = 'runSeleniumTests'; + + $ajax = $this->getMock('TYPO3AJAX'); + $ajax->expects($this->once())->method('addContent')->with('success', TRUE); + $ajax->expects($this->never())->method('setError'); + + $this->fixture->ajaxBroker(array(), $ajax); + } + + /** + * @test + */ + public function ajaxBrokerForMissingCheckboxParameterSetsError() { + $ajax = $this->getMock('TYPO3AJAX'); + $ajax->expects($this->once())->method('setError'); + + $this->fixture->ajaxBroker(array(), $ajax); + } + + /** + * @test + */ + public function ajaxBrokerForInvalidCheckboxParameterSetsError() { + $_POST['checkbox'] = 'anything else'; + + $ajax = $this->getMock('TYPO3AJAX'); + $ajax->expects($this->once())->method('setError'); + + $this->fixture->ajaxBroker(array(), $ajax); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/AnotherDataProviderTest.php b/typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/AnotherDataProviderTest.php new file mode 100644 index 0000000..d771a17 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/AnotherDataProviderTest.php @@ -0,0 +1,81 @@ + + */ +class Tx_Phpunit_BackEnd_Fixtures_AnotherDataProviderTest extends Tx_Phpunit_TestCase { + /** + * @test + */ + public function test1() { + } + + /** + * @test + */ + public function test2() { + } + + /** + * Data provider that just returns three empty arrays. + * + * @see dataProviderTest + * + * @return array + */ + public function dataProvider() { + return array( + 'some data' => array(), + 'more data' => array(), + 'and even more data' => array() + ); + } + + /** + * @test + * + * @dataProvider dataProvider + */ + public function dataProviderTest() { + } + + /** + * @test + */ + public function test3() { + } + + /** + * @test + */ + public function test4() { + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/DataProviderTest.php b/typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/DataProviderTest.php new file mode 100644 index 0000000..c2c3dde --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/DataProviderTest.php @@ -0,0 +1,81 @@ + + */ +class Tx_Phpunit_BackEnd_Fixtures_DataProviderTest extends Tx_Phpunit_TestCase { + /** + * @test + */ + public function test1() { + } + + /** + * @test + */ + public function test2() { + } + + /** + * Data provider that just returns three empty arrays. + * + * @see dataProviderTest + * + * @return array + */ + public function dataProvider() { + return array( + 'some data' => array(), + 'more data' => array(), + 'and even more data' => array() + ); + } + + /** + * @test + * + * @dataProvider dataProvider + */ + public function dataProviderTest() { + } + + /** + * @test + */ + public function test3() { + } + + /** + * @test + */ + public function test4() { + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/LoadMe.php b/typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/LoadMe.php new file mode 100644 index 0000000..9dc726b --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/LoadMe.php @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/LoadMeToo.php b/typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/LoadMeToo.php new file mode 100644 index 0000000..0f02b55 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/BackEnd/Fixtures/LoadMeToo.php @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/BackEnd/ModuleTest.php b/typo3conf/ext/phpunit/Tests/BackEnd/ModuleTest.php new file mode 100644 index 0000000..5f3ee5e --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/BackEnd/ModuleTest.php @@ -0,0 +1,767 @@ +includeLLFile('EXT:phpunit/Resources/Private/Language/locallang_backend.xml'); + +/** + * Testcase for the Tx_Phpunit_BackEnd_Module class. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Oliver Klee + */ +class Tx_Phpunit_BackEnd_ModuleTest extends Tx_Phpunit_TestCase { + /** + * @var Tx_Phpunit_BackEnd_Module + */ + private $fixture; + + /** + * @var t3lib_beUserAuth + */ + private $backEndUserBackup = NULL; + + /** + * backup of $_POST + * + * @var array + */ + private $postBackup = array(); + + /** + * backup of $_GET + * + * @var array + */ + private $getBackup = array(); + + /** + * the output of the module + * + * @var string + */ + private $output = ''; + + public function setUp() { + $this->backEndUserBackup = $GLOBALS['BE_USER']; + $this->postBackup = $_POST; + $this->getBackup = $_GET; + $_POST = array(); + $_GET = array(); + + $this->fixture = $this->getMock( + $this->createAccessibleProxy(), array('output') + ); + $this->fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + } + + public function tearDown() { + $this->fixture->__destruct(); + + $_POST = $this->postBackup; + $_GET = $this->getBackup; + + $GLOBALS['BE_USER'] = $this->backEndUserBackup; + + unset($this->fixture, $this->backEndUserBackup); + } + + /* + * Utility functions + */ + + /** + * Creates a subclass Tx_Phpunit_BackEnd_Module with the protected functions + * made public. + * + * @return string the name of the accessible proxy class + */ + private function createAccessibleProxy() { + $className = 'Tx_Phpunit_BackEnd_ModuleAccessibleProxy'; + if (!class_exists($className, FALSE)) { + eval( + 'class ' . $className . ' extends Tx_Phpunit_BackEnd_Module {' . + ' public function getTestFinder() {' . + ' return parent::getTestFinder();' . + ' }' . + ' public function runTests_render() {' . + ' parent::runTests_render();' . + ' }' . + ' public function runTests_renderIntro() {' . + ' parent::runTests_renderIntro();' . + ' }' . + ' public function runTests_renderIntro_renderExtensionSelector(array $extensionsWithTestSuites) {' . + ' return parent::runTests_renderIntro_renderExtensionSelector($extensionsWithTestSuites);' . + ' }' . + ' public function findTestCasesInDir($directory) {' . + ' return parent::findTestCasesInDir($directory);' . + ' }' . + ' public function loadRequiredTestClasses(array $paths) {' . + ' parent::loadRequiredTestClasses($paths);' . + ' }' . + ' public function isExtensionLoaded($extensionKey) {' . + ' return parent::isExtensionLoaded($extensionKey);' . + ' }' . + ' public function createIconStyle($extensionKey) {' . + ' return parent::createIconStyle($extensionKey);' . + ' }' . + ' public function output($output) {' . + ' parent::output($output);' . + ' }' . + ' public function isAcceptedTestSuitClass($class) {' . + ' return parent::isAcceptedTestSuitClass($class);' . + ' }' . + '}' + ); + } + + return $className; + } + + /** + * Callback function for collecting the output of the module. + * + * @param string $text the output to collect, may also be empty + * + * @return void + */ + public function outputCallback($text) { + $this->output .= $text; + } + + /** + * @test + */ + public function createAccessibleProxyCreatesModuleSubclass() { + $className = $this->createAccessibleProxy(); + + $this->assertInstanceOf( + 'Tx_Phpunit_BackEnd_Module', + new $className() + ); + } + + /** + * @test + */ + public function outputCallbackCollectsOutput() { + $this->outputCallback('Hello world!'); + + $this->assertSame( + 'Hello world!', + $this->output + ); + } + + /** + * @test + */ + public function outputCallbackCollectsOutputInAddingOrder() { + $this->outputCallback('1'); + $this->outputCallback('2'); + + $this->assertSame( + '12', + $this->output + ); + } + + + /* + * Unit tests + */ + + /** + * @test + */ + public function getTestFinderReturnsTestFinderInstance() { + $this->assertInstanceOf( + 'Tx_Phpunit_Service_TestFinder', + $this->fixture->getTestFinder() + ); + } + + /** + * @test + */ + public function mainForNoAdminBackEndUserShowsAdminRightsNeeded() { + $GLOBALS['BE_USER']->user['admin'] = FALSE; + + $this->fixture->main(); + + $this->assertContains( + $GLOBALS['LANG']->getLL('admin_rights_needed'), + $this->output + ); + } + + /** + * @test + */ + public function mainForAdminBackEndUserRunsTests() { + $GLOBALS['BE_USER']->user['admin'] = TRUE; + + $fixture = $this->getMock( + $this->createAccessibleProxy(), array('output', 'runTests_render') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + $fixture->expects($this->once())->method('runTests_render'); + + $fixture->main(); + } + + /** + * @test + */ + public function runTests_renderForEmptyCommandRendersIntro() { + $fixture = $this->getMock( + $this->createAccessibleProxy(), + array('runTests_renderIntro', 'runTests_renderRunningTest', 'output') + ); + $fixture->MOD_SETTINGS = array('extSel' => 'phpunit'); + + $fixture->expects($this->once())->method('runTests_renderIntro'); + + $_GET['command'] = ''; + + $fixture->runTests_render(); + } + + /** + * @test + */ + public function runTests_renderForEmptyCommandNotRunsTests() { + $fixture = $this->getMock( + $this->createAccessibleProxy(), + array('runTests_renderIntro', 'runTests_renderRunningTest', 'output') + ); + $fixture->MOD_SETTINGS = array('extSel' => 'phpunit'); + + $fixture->expects($this->never())->method('runTests_renderRunningTest'); + + $_GET['command'] = ''; + + $fixture->runTests_render(); + } + + /** + * @test + */ + public function runTests_renderForInvalidCommandRendersIntro() { + $fixture = $this->getMock( + $this->createAccessibleProxy(), + array('runTests_renderIntro', 'runTests_renderRunningTest', 'output') + ); + $fixture->MOD_SETTINGS = array('extSel' => 'phpunit'); + + $fixture->expects($this->once())->method('runTests_renderIntro'); + + $_GET['command'] = 'invalid'; + + $fixture->runTests_render(); + } + + /** + * @test + */ + public function runTests_renderForInvalidCommandNotRunsTests() { + $fixture = $this->getMock( + $this->createAccessibleProxy(), + array('runTests_renderIntro', 'runTests_renderRunningTest', 'output') + ); + $fixture->MOD_SETTINGS = array('extSel' => 'phpunit'); + + $fixture->expects($this->never())->method('runTests_renderRunningTest'); + + $_GET['command'] = 'invalid'; + + $fixture->runTests_render(); + } + + /** + * @test + */ + public function runTests_renderForRunAllTestsCommandRendersIntroAndTests() { + $fixture = $this->getMock( + $this->createAccessibleProxy(), + array('runTests_renderIntro', 'runTests_renderRunningTest', 'output') + ); + $fixture->MOD_SETTINGS = array('extSel' => 'phpunit'); + + $fixture->expects($this->once())->method('runTests_renderIntro'); + $fixture->expects($this->once())->method('runTests_renderRunningTest'); + + $_GET['command'] = 'runalltests'; + + $fixture->runTests_render(); + } + + /** + * @test + */ + public function runTests_renderForRunTestCaseFileCommandRendersIntroAndTests() { + $fixture = $this->getMock( + $this->createAccessibleProxy(), + array('runTests_renderIntro', 'runTests_renderRunningTest', 'output') + ); + $fixture->MOD_SETTINGS = array('extSel' => 'phpunit'); + + $fixture->expects($this->once())->method('runTests_renderIntro'); + $fixture->expects($this->once())->method('runTests_renderRunningTest'); + + $_GET['command'] = 'runTestCaseFile'; + + $fixture->runTests_render(); + } + + /** + * @test + */ + public function runTests_renderForRunSingleTestCommandRendersIntroAndTests() { + $fixture = $this->getMock( + $this->createAccessibleProxy(), + array('runTests_renderIntro', 'runTests_renderRunningTest', 'output') + ); + $fixture->MOD_SETTINGS = array('extSel' => 'phpunit'); + + $fixture->expects($this->once())->method('runTests_renderIntro'); + $fixture->expects($this->once())->method('runTests_renderRunningTest'); + + $_GET['command'] = 'runsingletest'; + + $fixture->runTests_render(); + } + + /** + * @test + */ + public function runTests_renderIntroForNoExtensionsWithTestSuitesShowsErrorMessage() { + $fixture = $this->getMock( + $this->createAccessibleProxy(), + array( + 'getExtensionsWithTestSuites', 'runTests_renderIntro_renderExtensionSelector', + 'runTests_renderIntro_renderTestSelector', 'output' + ) + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + $fixture->expects($this->once())->method('getExtensionsWithTestSuites') + ->will($this->returnValue(array())); + + $fixture->MOD_SETTINGS = array('extSel' => 'phpunit'); + + $fixture->runTests_renderIntro(); + + $this->assertContains( + $GLOBALS['LANG']->getLL('could_not_find_exts_with_tests'), + $this->output + ); + } + + /** + * @test + */ + public function runTests_renderIntroForNoExtensionsWithTestSuitesNotRendersExtensionSelector() { + $fixture = $this->getMock( + $this->createAccessibleProxy(), + array( + 'getExtensionsWithTestSuites', 'runTests_renderIntro_renderExtensionSelector', + 'runTests_renderIntro_renderTestSelector', 'output' + ) + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + $fixture->expects($this->once())->method('getExtensionsWithTestSuites') + ->will($this->returnValue(array())); + $fixture->expects($this->never())->method('runTests_renderIntro_renderExtensionSelector') + ->will($this->returnValue('extension selector')); + + $fixture->MOD_SETTINGS = array('extSel' => 'phpunit'); + + $fixture->runTests_renderIntro(); + } + + /** + * @test + */ + public function runTests_renderIntroForExistingExtensionsWithTestSuitesRendersExtensionSelector() { + $fixture = $this->getMock( + $this->createAccessibleProxy(), + array( + 'getExtensionsWithTestSuites', 'runTests_renderIntro_renderExtensionSelector', + 'runTests_renderIntro_renderTestSelector', 'output' + ) + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + $fixture->expects($this->once())->method('getExtensionsWithTestSuites') + ->will($this->returnValue(array('phpunit' => 'phpunit'))); + $fixture->expects($this->once())->method('runTests_renderIntro_renderExtensionSelector') + ->will($this->returnValue('extension selector')); + + $fixture->MOD_SETTINGS = array('extSel' => 'phpunit'); + + $fixture->runTests_renderIntro(); + + $this->assertContains( + 'extension selector', + $this->output + ); + } + + /** + * @test + */ + public function runTests_renderIntroForSelectedExtensionRendersTestSelector() { + $extensionsWithTests = array('phpunit' => 'phpunit'); + $selectedExtension = 'phpunit'; + + $fixture = $this->getMock( + $this->createAccessibleProxy(), + array( + 'getExtensionsWithTestSuites', 'runTests_renderIntro_renderExtensionSelector', + 'runTests_renderIntro_renderTestSelector', 'output' + ) + ); + $fixture->MOD_SETTINGS = array('extSel' => $selectedExtension); + + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + $fixture->expects($this->once())->method('getExtensionsWithTestSuites') + ->will($this->returnValue($extensionsWithTests)); + $fixture->expects($this->once())->method('runTests_renderIntro_renderTestSelector') + ->with($extensionsWithTests, $selectedExtension)->will($this->returnValue('test selector')); + + $fixture->runTests_renderIntro(); + + $this->assertContains( + 'test selector', + $this->output + ); + } + + /** + * @test + */ + public function runTests_renderIntro_renderExtensionSelectorCreatesOptionForExtensionWithTests() { + $extensionsWithTests = array('phpunit' => 'phpunit'); + $selectedExtension = 'aaa'; + + $className = $this->createAccessibleProxy(); + $fixture = new $className(); + $fixture->MOD_SETTINGS = array('extSel' => $selectedExtension); + + $this->assertRegExp( + '/]*value="phpunit"/', + $fixture->runTests_renderIntro_renderExtensionSelector($extensionsWithTests) + ); + } + + /** + * @test + */ + public function findTestCasesInDirReturnsEmptyArrayIfDirectoryDoesNotExist() { + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot(new vfsStreamDirectory('Foo')); + $notExistingDirectory = 'vfs://Foo/bar'; + + $this->assertSame( + array(), + $this->fixture->findTestCasesInDir($notExistingDirectory) + ); + } + + /** + * @test + */ + public function findTestCasesInDirCallsFindTestCasesInDirectoryOfTestFinderObject() { + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot(new vfsStreamDirectory('Foo')); + $directory = 'vfs://Foo/'; + + $testFinderMock = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', array('findTestCasesInDirectory') + ); + $testFinderMock->expects($this->once())->method('findTestCasesInDirectory')->with($directory); + + $fixture = $this->getMock( + $this->createAccessibleProxy(), array('getTestFinder') + ); + $fixture->expects($this->once())->method('getTestFinder') + ->will($this->returnValue($testFinderMock)); + + $fixture->findTestCasesInDir($directory); + } + + /** + * @test + */ + public function findTestCasesInDirReturnsArrayWithFoundTestCaseFiles() { + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot(new vfsStreamDirectory('Foo')); + $directory = 'vfs://Foo/'; + $testFiles = array('class.test1Test.php', 'class.test2Test.php'); + + $testFinderMock = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', + array('findTestCasesInDirectory') + ); + $testFinderMock->expects($this->once())->method('findTestCasesInDirectory') + ->will($this->returnValue($testFiles)); + + $fixture = $this->getMock( + $this->createAccessibleProxy(), array('getTestFinder') + ); + $fixture->expects($this->once())->method('getTestFinder') + ->will($this->returnValue($testFinderMock)); + + $this->assertSame( + array($directory => $testFiles), + $fixture->findTestCasesInDir($directory) + ); + } + + /** + * @test + */ + public function loadRequiredTestClassesLoadsFileInFirstPath() { + $this->fixture->loadRequiredTestClasses( + array( + t3lib_extMgm::extPath('phpunit') . 'Tests/BackEnd/Fixtures/' => array( + 'LoadMe.php', + ), + ) + ); + + $this->assertTrue( + class_exists('Tx_Phpunit_BackEnd_Fixtures_LoadMe', FALSE) + ); + } + + /** + * @test + */ + public function loadRequiredTestClassesLoadsSecondFileInFirstPath() { + $this->fixture->loadRequiredTestClasses( + array( + t3lib_extMgm::extPath('phpunit') . 'Tests/BackEnd/Fixtures/' => array( + 'LoadMe.php', + 'LoadMeToo.php', + ), + ) + ); + + $this->assertTrue( + class_exists('Tx_Phpunit_BackEnd_Fixtures_LoadMeToo', FALSE) + ); + } + + /** + * @test + */ + public function loadRequiredTestClassesLoadsFileInSecondPath() { + $this->fixture->loadRequiredTestClasses( + array( + t3lib_extMgm::extPath('phpunit') . 'Tests/BackEnd/Fixtures/' => array( + 'LoadMe.php', + ), + t3lib_extMgm::extPath('phpunit') . 'Tests/Fixtures/' => array( + 'LoadMe.php', + ), + ) + ); + + $this->assertTrue( + class_exists('Tx_Phpunit_Fixtures_LoadMe', FALSE) + ); + } + + /** + * @test + */ + public function isExtensionLoadedEmptyKeyReturnsFalse() { + $this->assertFalse( + $this->fixture->isExtensionLoaded('') + ); + } + + /** + * @test + */ + public function isExtensionLoadedForLoadedExtensionReturnsTrue() { + $this->assertTrue( + $this->fixture->isExtensionLoaded('phpunit') + ); + } + + /** + * @test + */ + public function isExtensionLoadedForNotLoadedExtensionReturnsFalse() { + $this->assertFalse( + $this->fixture->isExtensionLoaded('not_loaded_extension') + ); + } + + /** + * @test + */ + public function isExtensionLoadedForCoreWithExistingTestsReturnsTrue() { + $testFinder = t3lib_div::makeInstance('Tx_Phpunit_Service_TestFinder'); + if (!$testFinder->hasCoreTests()) { + $this->markTestSkipped('This test can only be run if the TYPO3 Core unit tests are present.'); + } + + $this->assertTrue( + $this->fixture->isExtensionLoaded(Tx_Phpunit_TestableCode::CORE_KEY) + ); + } + + /** + * @test + */ + public function isExtensionLoadedForCoreWithoutExistingTestsReturnsFalse() { + $testFinder = t3lib_div::makeInstance('Tx_Phpunit_Service_TestFinder'); + if ($testFinder->hasCoreTests()) { + $this->markTestSkipped('This test can only be run if no TYPO3 Core unit tests are present.'); + } + + $this->assertFalse( + $this->fixture->isExtensionLoaded(Tx_Phpunit_TestableCode::CORE_KEY) + ); + } + + /** + * @test + */ + public function createIconStyleForLoadedExtensionReturnsExtensionIcon() { + $this->assertContains( + 'url(' . t3lib_extMgm::extRelPath('phpunit') . 'ext_icon.gif)', + $this->fixture->createIconStyle('phpunit') + ); + } + + /** + * @test + */ + public function createIconStyleForCoreReturnsTypo3Icon() { + $testFinder = t3lib_div::makeInstance('Tx_Phpunit_Service_TestFinder'); + if (!$testFinder->hasCoreTests()) { + $this->markTestSkipped('This test can only be run if the TYPO3 Core unit tests are present.'); + } + + $this->assertContains( + 'url(' . t3lib_extMgm::extRelPath('phpunit') . 'Resources/Public/Icons/Typo3.png)', + $this->fixture->createIconStyle(Tx_Phpunit_TestableCode::CORE_KEY) + ); + } + + /** + * @test + * + * @expectedException Tx_Phpunit_Exception_NoTestsDirectory + */ + public function createIconStyleForNotLoadedExtensionThrowsException() { + $this->fixture->createIconStyle('not_loaded_extension'); + } + + /** + * @test + * + * @expectedException Tx_Phpunit_Exception_NoTestsDirectory + */ + public function createIconStyleForEmptyExtensionKeyThrowsException() { + $this->fixture->createIconStyle(''); + } + + /** + * @test + */ + public function outputOutputsOutput() { + $className = $this->createAccessibleProxy(); + $fixture = new $className(); + + $output = 'Hello world!'; + + ob_start(); + $fixture->output($output); + + $this->assertSame( + $output, + ob_get_contents() + ); + + ob_end_clean(); + } + + /** + * @test + */ + public function isAcceptedTestSuitClassReturnsTrueForNonSpecialClass() { + $this->assertTrue( + $this->fixture->isAcceptedTestSuitClass('foo') + ); + } + + /** + * @test + */ + public function isAcceptedTestSuitClassReturnsTrueForTestCaseSubClass() { + $this->assertTrue( + $this->fixture->isAcceptedTestSuitClass(get_class($this)) + ); + } + + /** + * @test + */ + public function isAcceptedTestSuitClassReturnsFalseForPhpunitTestCase() { + $this->assertFalse( + $this->fixture->isAcceptedTestSuitClass('Tx_Phpunit_TestCase') + ); + } + + /** + * @test + */ + public function isAcceptedTestSuitClassReturnsFalseForPhpunitDatabaseTestCase() { + $this->assertFalse( + $this->fixture->isAcceptedTestSuitClass('Tx_Phpunit_Database_TestCase') + ); + } + + /** + * @test + */ + public function isAcceptedTestSuitClassReturnsFalseForPhpunitSeleniumTestCase() { + $this->assertFalse( + $this->fixture->isAcceptedTestSuitClass('Tx_Phpunit_Selenium_TestCase') + ); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/BackEnd/TestListenerTest.php b/typo3conf/ext/phpunit/Tests/BackEnd/TestListenerTest.php new file mode 100644 index 0000000..d98009d --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/BackEnd/TestListenerTest.php @@ -0,0 +1,930 @@ + + */ +class Tx_Phpunit_BackEnd_TestListenerTest extends Tx_Phpunit_TestCase { + /** + * @var Tx_Phpunit_BackEnd_TestListener + */ + private $fixture; + + /** + * the output of the test lister + * + * @var string + */ + private $output = ''; + + public function setUp() { + $fixtureClassName = $this->createAccessibleProxy(); + $this->fixture = new $fixtureClassName(); + } + + public function tearDown() { + $this->fixture->__destruct(); + + unset($this->fixture); + } + + + /* + * Utility functions + */ + + /** + * Creates a subclass Tx_Phpunit_BackEnd_TestListener with the protected + * functions made public. + * + * @return string the name of the accessible proxy class + */ + private function createAccessibleProxy() { + $className = 'Tx_Phpunit_BackEnd_TestListenerAccessibleProxy'; + if (!class_exists($className, FALSE)) { + eval( + 'class ' . $className . ' extends Tx_Phpunit_BackEnd_TestListener {' . + ' public function createReRunLink(PHPUnit_Framework_TestCase $test) {' . + ' return parent::createReRunLink($test);' . + ' }' . + ' public function createReRunUrl(PHPUnit_Framework_TestCase $test) {' . + ' return parent::createReRunUrl($test);' . + ' }' . + ' public function prettifyTestMethod($testClass) {' . + ' return parent::prettifyTestMethod($testClass);' . + ' }' . + ' public function prettifyTestClass($testClassName) {' . + ' return parent::prettifyTestClass($testClassName);' . + ' }' . + ' public function setNumberOfAssertions($number) {' . + ' $this->testAssertions = $number;' . + ' }' . + ' public function setTestNumber($number) {' . + ' $this->currentTestNumber = $number;' . + ' }' . + ' public function setDataProviderNumber($number) {' . + ' $this->currentDataProviderNumber = $number;' . + ' }' . + ' public function output($output) {' . + ' parent::output($output);' . + ' }' . + '}' + ); + } + + return $className; + } + + /** + * Callback function for collecting the output of the test listener. + * + * @param string $text the output to collect, may also be empty + * + * @return void + */ + public function outputCallback($text) { + $this->output .= $text; + } + + /** + * @test + */ + public function createAccessibleProxyCreatesTestListenerSubclass() { + $className = $this->createAccessibleProxy(); + + $this->assertInstanceOf( + 'Tx_Phpunit_BackEnd_TestListener', + new $className() + ); + } + + /** + * @test + */ + public function outputCallbackCollectsOutput() { + $this->outputCallback('Hello world!'); + + $this->assertSame( + 'Hello world!', + $this->output + ); + } + + /** + * @test + */ + public function outputCallbackCollectsOutputInAddingOrder() { + $this->outputCallback('1'); + $this->outputCallback('2'); + + $this->assertSame( + '12', + $this->output + ); + } + + + /* + * Unit tests + */ + + /** + * @test + */ + public function addFailureOutputsTestName() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + + $testCase = $this->getMock('PHPUnit_Framework_TestCase', array('run'), array('aTestName')); + $error = $this->getMock('PHPUnit_Framework_AssertionFailedError'); + $time = 0.0; + + $fixture->addFailure($testCase, $error, $time); + + $this->assertContains( + 'aTestName', + $this->output + ); + } + + /** + * @test + */ + public function addFailureWithComparisonFailureOutputsHtmlSpecialchardExpectedString() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + + $testCase = $this->getMock('PHPUnit_Framework_TestCase', array('run'), array('aTestName')); + $error = new PHPUnit_Framework_ExpectationFailedException( + '', new PHPUnit_Framework_ComparisonFailure_String('expected&correct', 'actual&incorrect') + ); + $time = 0.0; + + $fixture->addFailure($testCase, $error, $time); + + $this->assertContains( + 'expected&correct', + strip_tags($this->output) + ); + } + + /** + * @test + */ + public function addFailureWithComparisonFailureForTwoStringsOutputsHtmlSpecialcharedActualString() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + + $testCase = $this->getMock('PHPUnit_Framework_TestCase', array('run'), array('aTestName')); + $error = new PHPUnit_Framework_ExpectationFailedException( + '', new PHPUnit_Framework_ComparisonFailure_String('expected&correct', 'actual&incorrect') + ); + $time = 0.0; + + $fixture->addFailure($testCase, $error, $time); + + $this->assertContains( + 'actual&incorrect', + strip_tags($this->output) + ); + } + + /** + * @test + */ + public function addFailureWithComparisonFailureForTwoStringsDoesNotCrash() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + + $testCase = $this->getMock('PHPUnit_Framework_TestCase', array('run'), array('aTestName')); + $error = new PHPUnit_Framework_ExpectationFailedException( + '', new PHPUnit_Framework_ComparisonFailure_String('expected&correct', 'actual&incorrect') + ); + $time = 0.0; + + $fixture->addFailure($testCase, $error, $time); + } + + /** + * @test + */ + public function addFailureWithComparisonFailureForTwoArraysDoesNotCrash() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + + $testCase = $this->getMock('PHPUnit_Framework_TestCase', array('run'), array('aTestName')); + $error = new PHPUnit_Framework_ExpectationFailedException( + '', new PHPUnit_Framework_ComparisonFailure_Array(array('foo'), array('bar')) + ); + $time = 0.0; + + $fixture->addFailure($testCase, $error, $time); + } + + /** + * @test + */ + public function addFailureWithComparisonFailureForTwoObjectsDoesNotCrash() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + + $testCase = $this->getMock('PHPUnit_Framework_TestCase', array('run'), array('aTestName')); + $error = new PHPUnit_Framework_ExpectationFailedException( + '', new PHPUnit_Framework_ComparisonFailure_Object(new stdClass(), new stdClass()) + ); + $time = 0.0; + + $fixture->addFailure($testCase, $error, $time); + } + + /** + * @test + */ + public function addFailureWithComparisonFailureForTwoIntegersDoesNotCrash() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + + $testCase = $this->getMock('PHPUnit_Framework_TestCase', array('run'), array('aTestName')); + $error = new PHPUnit_Framework_ExpectationFailedException( + '', new PHPUnit_Framework_ComparisonFailure_Scalar(8, 9) + ); + $time = 0.0; + + $fixture->addFailure($testCase, $error, $time); + } + + /** + * @test + */ + public function addFailureWithComparisonFailureForTwoFloatsDoesNotCrash() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + + $testCase = $this->getMock('PHPUnit_Framework_TestCase', array('run'), array('aTestName')); + $error = new PHPUnit_Framework_ExpectationFailedException( + '', new PHPUnit_Framework_ComparisonFailure_Scalar(1.2, 2.3) + ); + $time = 0.0; + + $fixture->addFailure($testCase, $error, $time); + } + + /** + * @test + */ + public function addFailureWithComparisonFailureForTwoTypesDoesNotCrash() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + + $testCase = $this->getMock('PHPUnit_Framework_TestCase', array('run'), array('aTestName')); + $error = new PHPUnit_Framework_ExpectationFailedException( + '', new PHPUnit_Framework_ComparisonFailure_Type(new stdClass(), 'anotherClass') + ); + $time = 0.0; + + $fixture->addFailure($testCase, $error, $time); + } + + + /** + * @test + */ + public function addIncompleteTestOutputsTestName() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + + $testCase = $this->getMock('PHPUnit_Framework_TestCase', array('run'), array('aTestName')); + $exception = new Exception(); + $time = 0.0; + + $fixture->addIncompleteTest($testCase, $exception, $time); + + $this->assertContains( + 'aTestName', + $this->output + ); + } + + /** + * @test + */ + public function addSkippedTestOutputsTestName() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + + $testCase = $this->getMock('PHPUnit_Framework_TestCase', array('run'), array('aTestName')); + $exception = new Exception(); + $time = 0.0; + + $fixture->addSkippedTest($testCase, $exception, $time); + + $this->assertContains( + 'aTestName', + $this->output + ); + } + + /** + * @test + */ + public function startTestSuiteOutputsPrettifiedTestClassName() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output', 'prettifyTestClass') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + + $testSuite = $this->getMock('PHPUnit_Framework_TestSuite', array('run'), array('aTestSuiteName')); + $fixture->expects($this->once())->method('prettifyTestClass') + ->with('aTestSuiteName')->will($this->returnValue('a test suite name')); + + $fixture->startTestSuite($testSuite); + + $this->assertContains( + 'a test suite name', + $this->output + ); + } + + /** + * @test + */ + public function endTestSuiteCanBeCalled() { + $testSuite = $this->getMock('PHPUnit_Framework_TestSuite'); + + $this->fixture->endTestSuite($testSuite); + } + + /** + * @test + */ + public function startTestSetsTimeLimitOf30Seconds() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('setTimeLimit', 'output') + ); + + $fixture->expects($this->once())->method('setTimeLimit')->with(30); + + $fixture->startTest($this->getMock('PHPUnit_Framework_TestCase')); + } + + /** + * @test + */ + public function startTestOutputsCurrentTestNumberAndDataProviderNumberAsHtmlId() { + $fixture = $this->getMock( + $this->createAccessibleProxy(), array('setTimeLimit', 'output') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + + $fixture->setTestNumber(42); + $fixture->setDataProviderNumber(91); + + $testCase = $this->getMock('PHPUnit_Framework_TestCase'); + $fixture->startTest($testCase); + + $this->assertContains( + 'id="testcaseNum-42_91"', + $this->output + ); + } + + /** + * @test + */ + public function startTestOutputsReRunLink() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('setTimeLimit', 'output', 'createReRunLink') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + + $testCase = $this->getMock('PHPUnit_Framework_TestCase'); + $fixture->expects($this->once())->method('createReRunLink') + ->with($testCase)->will($this->returnValue('the re-run URL')); + + $fixture->startTest($testCase); + + $this->assertContains( + 'the re-run URL', + $this->output + ); + } + + /** + * @test + */ + public function startTestOutputsPrettifiedTestName() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('setTimeLimit', 'output', 'prettifyTestMethod') + ); + $fixture->expects($this->any())->method('output') + ->will($this->returnCallback(array($this, 'outputCallback'))); + + $testCase = $this->getMock('PHPUnit_Framework_TestCase', array('run'), array('aTestName')); + $fixture->expects($this->once())->method('prettifyTestMethod') + ->with('aTestName')->will($this->returnValue('a test name')); + + $fixture->startTest($testCase); + + $this->assertContains( + 'a test name', + $this->output + ); + } + + /** + * @test + */ + public function endTestAddsTestAssertionsToTotalAssertionCount() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output', 'flushOutputBuffer') + ); + + $testCase1 = $this->getMock('PHPUnit_Framework_TestCase', array('getNumAssertions')); + $testCase1->expects($this->once())->method('getNumAssertions')->will($this->returnValue(1)); + + $fixture->endTest($testCase1, 0.0); + $this->assertEquals( + 1, + $fixture->assertionCount(), + 'The assertions of the first test case have not been counted.' + ); + + $testCase2 = $this->getMock('PHPUnit_Framework_TestCase', array('getNumAssertions')); + $testCase2->expects($this->once())->method('getNumAssertions')->will($this->returnValue(4)); + + $fixture->endTest($testCase2, 0.0); + $this->assertEquals( + 5, + $fixture->assertionCount(), + 'The assertions of the second test case have not been counted.' + ); + } + + /** + * @test + */ + public function endTestForTestCaseInstanceLeavesAssertionCountUnchanged() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output', 'flushOutputBuffer') + ); + + $test = $this->getMock('PHPUnit_Framework_TestCase'); + + $fixture->endTest($test, 0.0); + $this->assertEquals( + 0, + $fixture->assertionCount() + ); + } + + /** + * @test + */ + public function endTestForPlainTestInstanceLeavesAssertionCountUnchanged() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output', 'flushOutputBuffer') + ); + + $test = $this->getMock('PHPUnit_Framework_Test'); + + $fixture->endTest($test, 0.0); + $this->assertEquals( + 0, + $fixture->assertionCount() + ); + } + + /** + * @test + */ + public function endTestIncreasesTotalNumberOfDataProvidedTestsWhenRunWithDataProvidedTests() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output', 'flushOutputBuffer') + ); + + $test = $this->getMock('PHPUnit_Framework_TestCase', array('dummy'), array('Test 1')); + $test2 = $this->getMock('PHPUnit_Framework_TestCase', array('dummy'), array('Test 2')); + + $fixture->endTest($test, 0.0); + $fixture->endTest($test2, 0.0); + + $this->assertSame( + 1, + $fixture->getTotalNumberOfDetectedDataProviderTests() + ); + } + + /** + * @test + */ + public function endTestDoesNotIncreaseTotalNumberOfDataProvidedTestsWhenRunWithNormalTests() { + $fixture = $this->getMock( + 'Tx_Phpunit_BackEnd_TestListener', array('output', 'flushOutputBuffer') + ); + + $test = $this->getMock('PHPUnit_Framework_TestCase', array('dummy'), array('FirstTest')); + $test2 = $this->getMock('PHPUnit_Framework_TestCase', array('dummy'), array('SecondTest')); + + $fixture->endTest($test, 0.0); + $fixture->endTest($test2, 0.0); + + $this->assertSame( + 0, + $fixture->getTotalNumberOfDetectedDataProviderTests() + ); + } + + /** + * @test + */ + public function createReRunLinkContainsLinkToReRunUrl() { + $reRunUrl = 'index.php?reRun=1&foo=bar'; + + $test = $this->getMock( + 'PHPUnit_Framework_TestCase', array(), array('myTest') + ); + + $fixture = $this->getMock($this->createAccessibleProxy(), array('createReRunUrl')); + $fixture->expects($this->once())->method('createReRunUrl') + ->will($this->returnValue($reRunUrl)); + + $this->assertContains( + 'createReRunLink($test) + ); + } + + /** + * @test + */ + public function createReRunLinkAddsSpaceAfterLink() { + $reRunUrl = 'index.php?reRun=1&foo=bar'; + + $test = $this->getMock( + 'PHPUnit_Framework_TestCase', array(), array('myTest') + ); + + $fixture = $this->getMock($this->createAccessibleProxy(), array('createReRunUrl')); + $fixture->expects($this->once())->method('createReRunUrl') + ->will($this->returnValue($reRunUrl)); + + $this->assertContains( + ' ', + $fixture->createReRunLink($test) + ); + } + + /** + * @test + */ + public function createReRunLinkUsesEmptyAltAttribute() { + $reRunUrl = 'index.php?reRun=1&foo=bar'; + + $test = $this->getMock( + 'PHPUnit_Framework_TestCase', array(), array('myTest') + ); + + $fixture = $this->getMock($this->createAccessibleProxy(), array('createReRunUrl')); + $fixture->expects($this->once())->method('createReRunUrl') + ->will($this->returnValue($reRunUrl)); + + $this->assertContains( + 'alt=""', + $fixture->createReRunLink($test) + ); + } + + /** + * @test + */ + public function createReRunUrlContainsModuleParameter() { + $test = $this->getMock( + 'PHPUnit_Framework_TestCase', array(), array('myTest') + ); + + $this->assertContains( + 'mod.php?M=tools_txphpunitbeM1', + $this->fixture->createReRunUrl($test) + ); + } + + /** + * @test + */ + public function createReRunUrlContainsRunSingleCommand() { + $test = $this->getMock( + 'PHPUnit_Framework_TestCase', array(), array('myTest') + ); + + $this->assertContains( + 'command=runsingletest', + $this->fixture->createReRunUrl($test) + ); + } + + /** + * @test + */ + public function createReRunUrlContainsTestCaseFileName() { + $test = $this->getMock( + 'PHPUnit_Framework_TestCase', array(), array('myTest') + ); + + $this->fixture->setTestSuiteName('myTestCase'); + + $this->assertContains( + 'testCaseFile=myTestCase', + $this->fixture->createReRunUrl($test) + ); + } + + /** + * @test + */ + public function createReRunUrlContainsTestCaseName() { + $test = $this->getMock( + 'PHPUnit_Framework_TestCase', array(), array('myTest') + ); + + $this->fixture->setTestSuiteName('myTestCase'); + + $this->assertContains( + 'testname=myTest', + $this->fixture->createReRunUrl($test) + ); + } + + /** + * @test + */ + public function createReRunUrlEscapesAmpersands() { + $test = $this->getMock( + 'PHPUnit_Framework_TestCase', array(), array('myTest') + ); + + $this->fixture->setTestSuiteName('myTestCase'); + + $this->assertContains( + '&', + $this->fixture->createReRunUrl($test) + ); + } + + /** + * @test + */ + public function prettifyTestMethodForTestPrefixByDefaultReturnsNameUnchanged() { + $camelCaseName = 'testFreshEspressoTastesNice'; + + $this->assertSame( + $camelCaseName, + $this->fixture->prettifyTestMethod($camelCaseName) + ); + } + + /** + * @test + */ + public function prettifyTestMethodForTestPrefixAfterUseHumanReadableTextFormatConvertCamelCaseToWordsAndDropsTestPrefix() { + $this->fixture->useHumanReadableTextFormat(); + + $this->assertSame( + 'Fresh espresso tastes nice', + $this->fixture->prettifyTestMethod('testFreshEspressoTastesNice') + ); + } + + /** + * @test + */ + public function prettifyTestMethodForTestPrefixWithUnderscoreByDefaultReturnsNameUnchanged() { + $camelCaseName = 'test_freshEspressoTastesNice'; + + $this->assertSame( + $camelCaseName, + $this->fixture->prettifyTestMethod($camelCaseName) + ); + } + + /** + * @test + */ + public function prettifyTestMethodForTestPrefixWithUnderscoreAfterUseHumanReadableTextFormatConvertCamelCaseToWordsAndDropsTestPrefix() { + $this->fixture->useHumanReadableTextFormat(); + + $this->assertSame( + 'Fresh espresso tastes nice', + $this->fixture->prettifyTestMethod('test_freshEspressoTastesNice') + ); + } + + /** + * @test + */ + public function prettifyTestMethodByDefaultReturnsNameUnchanged() { + $camelCaseName = 'freshEspressoTastesNice'; + + $this->assertSame( + $camelCaseName, + $this->fixture->prettifyTestMethod($camelCaseName) + ); + } + + /** + * @test + */ + public function prettifyTestMethodAfterUseHumanReadableTextFormatConvertCamelCaseToWords() { + $this->fixture->useHumanReadableTextFormat(); + + $this->assertSame( + 'Fresh espresso tastes nice', + $this->fixture->prettifyTestMethod('freshEspressoTastesNice') + ); + } + + /** + * @test + */ + public function prettifyTestClassByDefaultReturnsNameUnchanged() { + $camelCaseName = 'tx_phpunit_BackEnd_TestListenerTest'; + + $this->assertSame( + $camelCaseName, + $this->fixture->prettifyTestClass($camelCaseName) + ); + } + + /** + * @test + */ + public function prettifyTestClassForTestSuffixAfterUseHumanReadableTextFormatConvertCamelCaseToWordsAndDropsTxPrefix() { + $this->fixture->useHumanReadableTextFormat(); + + $this->assertSame( + 'phpunit BackEnd TestListener', + $this->fixture->prettifyTestClass('tx_phpunit_BackEnd_TestListenerTest') + ); + } + + /** + * @test + */ + public function prettifyTestClassForTestcaseSuffixAfterUseHumanReadableTextFormatConvertCamelCaseToWordsAndDropsTxPrefix() { + $this->fixture->useHumanReadableTextFormat(); + + $this->assertSame( + 'phpunit BackEnd TestListener', + $this->fixture->prettifyTestClass('tx_phpunit_BackEnd_TestListener_testcase') + ); + } + + /** + * @test + */ + public function prettifyTestClassForExtbaseClassNameByDefaultReturnsNameUnchanged() { + $camelCaseName = 'Tx_Phpunit_BackEnd_TestListenerTest'; + + $this->assertSame( + $camelCaseName, + $this->fixture->prettifyTestClass($camelCaseName) + ); + } + + /** + * @test + */ + public function prettifyTestClassForExtbaseClassNameAfterUseHumanReadableTextFormatConvertCamelCaseToWordsAndDropsTestSuffix() { + $this->fixture->useHumanReadableTextFormat(); + + $this->assertSame( + 'Phpunit BackEnd TestListener', + $this->fixture->prettifyTestClass('Tx_Phpunit_BackEnd_TestListenerTest') + ); + } + + /** + * @test + */ + public function prettifyTestClassForCoreTestByDefaultReturnsNameUnchanged() { + $camelCaseName = 't3lib_formprotection_InstallToolFormProtectionTest'; + + $this->assertSame( + $camelCaseName, + $this->fixture->prettifyTestClass($camelCaseName) + ); + } + + /** + * @test + */ + public function prettifyTestClassForCoreTestAndForTestSuffixAfterUseHumanReadableTextFormatConvertCamelCaseToWords() { + $this->fixture->useHumanReadableTextFormat(); + + $this->assertSame( + 't3lib formprotection InstallToolFormProtection', + $this->fixture->prettifyTestClass('t3lib_formprotection_InstallToolFormProtectionTest') + ); + } + + /** + * @test + */ + public function assertionCountInitiallyReturnsZero() { + $this->assertSame( + 0, + $this->fixture->assertionCount() + ); + } + + /** + * @test + */ + public function assertionCountReturnsNumberOfAssertions() { + $this->fixture->setNumberOfAssertions(42); + + $this->assertSame( + 42, + $this->fixture->assertionCount() + ); + } + + /** + * @test + */ + public function outputOutputsOutput() { + $output = 'Hello world!'; + + ob_start(); + $this->fixture->output($output); + + $this->assertSame( + $output, + ob_get_contents() + ); + + ob_end_clean(); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Database/Fixtures/DataSet.xml b/typo3conf/ext/phpunit/Tests/Database/Fixtures/DataSet.xml new file mode 100644 index 0000000..812d8b9 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Database/Fixtures/DataSet.xml @@ -0,0 +1,22 @@ + + + 0 + + </tx_ccc_data> + + <tx_ccc_test id="1"> + <hidden>0</hidden> + </tx_ccc_test> + <tx_ccc_test id="2"> + <hidden>0</hidden> + </tx_ccc_test> + + <tx_ccc_data_test_mm> + <uid_local ref="tx_ccc_data#1" /> + <uid_foreign ref="tx_ccc_test#1" /> + </tx_ccc_data_test_mm> + <tx_ccc_data_test_mm> + <uid_local ref="tx_ccc_data#1" /> + <uid_foreign ref="tx_ccc_test#2" /> + </tx_ccc_data_test_mm> +</dataset> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Database/TestCaseTest.php b/typo3conf/ext/phpunit/Tests/Database/TestCaseTest.php new file mode 100644 index 0000000..c6027c7 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Database/TestCaseTest.php @@ -0,0 +1,269 @@ +<?php +/*************************************************************** + * Copyright notice + * + * (c) 2008-2011 Kasper Ligaard (kasperligaard@gmail.com) + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/** + * Testcase for the database functions of the "phpunit" extension. + * + * These testcases require that the following extensions are installed: + * 1. aaa + * 2. bbb (depends on aaa and alters aaa' tables) + * 3. ccc (depends on bbb) + * 4. ddd (depends on bbb) + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Kasper Ligaard <kasperligaard@gmail.com> + * @author Oliver Klee <typo3-coding@oliverklee.de> + */ +class Tx_Phpunit_Database_TestCaseTest extends Tx_Phpunit_Database_TestCase { + public function tearDown() { + $this->dropDatabase(); + $this->switchToTypo3Database(); + } + + /** + * @test + */ + public function nullToEmptyString() { + $this->assertEquals('', mysql_real_escape_string(NULL)); + } + + /** + * @test + */ + public function creatingTestDatabase() { + if (!$this->dropDatabase() || !$this->createDatabase()) { + $this->markTestSkipped( + 'This test can only be run if the current DB user has the ' . + 'permissions to CREATE and DROP databases.' + ); + } + + $db = $GLOBALS['TYPO3_DB']; + + $databaseNames = $db->admin_get_dbs(); + + $this->assertContains($this->testDatabase, $databaseNames); + } + + /** + * @test + */ + public function droppingTestDatabase() { + $db = $GLOBALS['TYPO3_DB']; + $databaseNames = $db->admin_get_dbs(); + + if (!in_array($this->testDatabase, $databaseNames)) { + if (!$this->createDatabase()) { + $this->markTestSkipped( + 'This test can only be run if the current DB user has the ' . + 'permissions to CREATE and DROP databases.' + ); + } + $databaseNames = $db->admin_get_dbs(); + $this->assertContains($this->testDatabase, $databaseNames); + } + + if (!$this->dropDatabase()) { + $this->markTestSkipped( + 'This test can only be run if the current DB user has the ' . + 'permissions to CREATE and DROP databases.' + ); + } + $databaseNames = $db->admin_get_dbs(); + $this->assertNotContains($this->testDatabase, $databaseNames); + } + + /** + * @test + */ + public function cleaningDatabase() { + if (!$this->createDatabase()) { + $this->markTestSkipped( + 'This test can only be run if the current DB user has the ' . + 'permissions to CREATE and DROP databases.' + ); + } + $this->importExtensions(array('tsconfig_help')); + + $db = $this->useTestDatabase(); + $res = $db->sql_query('show tables'); + $rows = mysql_num_rows($res); + $this->assertNotEquals(0, $rows); + + $this->cleanDatabase(); + $res = $db->sql_query('show tables'); + $rows = mysql_num_rows($res); + $this->assertEquals(0, $rows); + } + + /** + * @test + */ + public function importingExtension() { + if (!$this->createDatabase()) { + $this->markTestSkipped( + 'This test can only be run if the current DB user has the ' . + 'permissions to CREATE and DROP databases.' + ); + } + $db = $this->useTestDatabase(); + $this->importExtensions(array('tsconfig_help')); + + $res = $db->sql_query('show tables'); + $rows = mysql_num_rows($res); + + $this->assertNotEquals(0, $rows); + } + + /** + * @test + */ + public function extensionAlteringTable() { + if (!t3lib_extMgm::isLoaded('aaa') || !t3lib_extMgm::isLoaded('bbb')) { + $this->markTestSkipped( + 'This test can only be run if the extensions aaa and bbb ' . + 'from tests/res are installed.' + ); + } + + if (!$this->createDatabase()) { + $this->markTestSkipped( + 'This test can only be run if the current DB user has the ' . + 'permissions to CREATE and DROP databases.' + ); + } + $db = $this->useTestDatabase(); + $this->importExtensions(array('bbb'), TRUE); + + $tableNames = $this->getDatabaseTables(); + $this->assertContains('tx_bbb_test', $tableNames, 'Check that extension bbb is installed. The extension can be found in Tests/Fixtures/Extensions/.'); + $this->assertContains('tx_aaa_test', $tableNames, 'Check that extension aaa is installed. The extension can be found in Tests/Fixtures/Extensions/.'); + + // extension BBB extends an AAA table + $columns = $db->admin_get_fields('tx_aaa_test'); + $this->assertContains('tx_bbb_test', array_keys($columns)); + } + + /** + * @test + */ + public function recursiveImportingExtensions() { + if (!t3lib_extMgm::isLoaded('aaa') || !t3lib_extMgm::isLoaded('bbb') + || !t3lib_extMgm::isLoaded('ccc') + ) { + $this->markTestSkipped( + 'This test can only be run if the extensions aaa, bbb and ccc ' . + 'from tests/res are installed.' + ); + } + + if (!$this->createDatabase()) { + $this->markTestSkipped( + 'This test can only be run if the current DB user has the ' . + 'permissions to CREATE and DROP databases.' + ); + } + $this->useTestDatabase(); + $this->importExtensions(array('ccc', 'aaa'), TRUE); + + $tableNames = $this->getDatabaseTables(); + + $this->assertContains('tx_ccc_test', $tableNames, 'Check that extension ccc is installed. The extension can be found in Tests/Fixtures/Extensions/.'); + $this->assertContains('tx_bbb_test', $tableNames, 'Check that extension bbb is installed. The extension can be found in Tests/Fixtures/Extensions/.'); + $this->assertContains('tx_aaa_test', $tableNames, 'Check that extension aaa is installed. The extension can be found in Tests/Fixtures/Extensions/.'); + } + + /** + * @test + */ + public function skippingDependencyExtensions() { + if (!t3lib_extMgm::isLoaded('aaa') || !t3lib_extMgm::isLoaded('bbb') + || !t3lib_extMgm::isLoaded('ccc') || !t3lib_extMgm::isLoaded('ddd') + ) { + $this->markTestSkipped( + 'This test can only be run if the extensions aaa, bbb, ccc ' . + 'and ddd from tests/res are installed.' + ); + } + + if (!$this->createDatabase()) { + $this->markTestSkipped( + 'This test can only be run if the current DB user has the ' . + 'permissions to CREATE and DROP databases.' + ); + } + $this->useTestDatabase(); + + $toSkip = array('bbb'); + $this->importExtensions(array('ccc', 'ddd'), TRUE, $toSkip); + + $tableNames = $this->getDatabaseTables(); + + $this->assertContains('tx_ccc_test', $tableNames, 'Check that extension ccc is installed. The extension can be found in Tests/Fixtures/Extensions/.'); + $this->assertContains('tx_ddd_test', $tableNames, 'Check that extension ddd is installed. The extension can be found in Tests/Fixtures/Extensions/.'); + $this->assertNotContains('tx_bbb_test', $tableNames); + $this->assertNotContains('tx_aaa_test', $tableNames); + } + + /** + * @test + */ + public function importingDataSet() { + if (!t3lib_extMgm::isLoaded('ccc')) { + $this->markTestSkipped( + 'This test can only be run if the extension ccc from ' . + 'tests/res is installed.' + ); + } + + if (!$this->createDatabase()) { + $this->markTestSkipped( + 'This test can only be run if the current DB user has the ' . + 'permissions to CREATE and DROP databases.' + ); + } + $db = $this->useTestDatabase(); + $this->importExtensions(array('ccc')); + $this->importDataSet(t3lib_extMgm::extPath('phpunit') . 'Tests/Database/Fixtures/DataSet.xml'); + + $result = $db->exec_SELECTgetRows('*', 'tx_ccc_test', NULL); + $this->assertEquals(2, count($result)); + $this->assertEquals(1, $result[0]['uid']); + $this->assertEquals(2, $result[1]['uid']); + + $result = $db->exec_SELECTgetRows('*', 'tx_ccc_data', NULL); + $this->assertEquals(1, count($result)); + $this->assertEquals(1, $result[0]['uid']); + + $result = $db->exec_SELECTgetRows('*', 'tx_ccc_data_test_mm', NULL); + $this->assertEquals(2, count($result)); + $this->assertEquals(1, $result[0]['uid_local']); + $this->assertEquals(1, $result[0]['uid_foreign']); + $this->assertEquals(1, $result[1]['uid_local']); + $this->assertEquals(2, $result[1]['uid_foreign']); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Exception/DatabaseTest.php b/typo3conf/ext/phpunit/Tests/Exception/DatabaseTest.php new file mode 100644 index 0000000..b97ae0c --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Exception/DatabaseTest.php @@ -0,0 +1,43 @@ +<?php +/*************************************************************** +* Copyright notice +* +* (c) 2011 Oliver Klee (typo3-coding@oliverklee.de) +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +/** + * Testcase for the Tx_Phpunit_Exception_Database class. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Oliver Klee <typo3-coding@oliverklee.de> + */ +class Tx_Phpunit_Exception_DatabaseTest extends Tx_Phpunit_TestCase { + /** + * @test + * + * @expectedException Tx_Phpunit_Exception_Database + */ + public function exceptionCanBeThrown() { + throw new Tx_Phpunit_Exception_Database(); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Exception/EmptyQueryResultTest.php b/typo3conf/ext/phpunit/Tests/Exception/EmptyQueryResultTest.php new file mode 100644 index 0000000..4c5b565 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Exception/EmptyQueryResultTest.php @@ -0,0 +1,83 @@ +<?php +/*************************************************************** +* Copyright notice +* +* (c) 2009-2011 Oliver Klee (typo3-coding@oliverklee.de) +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +/** + * Testcase for the Tx_Phpunit_Exception_EmptyQueryResultTest class. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Oliver Klee <typo3-coding@oliverklee.de> + */ +class Tx_Phpunit_Exception_EmptyQueryResultTest extends Tx_Phpunit_TestCase { + /** + * the saved content of $GLOBALS['TYPO3_DB']->debugOutput + * + * @var boolean + */ + private $savedDebugOutput; + + /** + * the saved content of $GLOBALS['TYPO3_DB']->store_lastBuiltQuery + * + * @var boolean + */ + private $savedStoreLastBuildQuery; + + public function setUp() { + $this->savedDebugOutput = $GLOBALS['TYPO3_DB']->debugOutput; + $this->savedStoreLastBuildQuery = $GLOBALS['TYPO3_DB']->store_lastBuiltQuery; + + $GLOBALS['TYPO3_DB']->debugOutput = FALSE; + $GLOBALS['TYPO3_DB']->store_lastBuiltQuery = TRUE; + } + + public function tearDown() { + $GLOBALS['TYPO3_DB']->debugOutput = $this->savedDebugOutput; + $GLOBALS['TYPO3_DB']->store_lastBuiltQuery = $this->savedStoreLastBuildQuery; + } + + /** + * @test + * + * @expectedException Tx_Phpunit_Exception_EmptyQueryResult + */ + public function exceptionCanBeThrown() { + throw new Tx_Phpunit_Exception_EmptyQueryResult(); + } + + /** + * @test + */ + public function messageAfterQueryWithLastQueryEnabledContainsLastQuery() { + $GLOBALS['TYPO3_DB']->exec_SELECTquery('title', 'tx_phpunit_test', ''); + $fixture = new Tx_Phpunit_Exception_EmptyQueryResult(); + + $this->assertContains( + 'SELECT', + $fixture->getMessage() + ); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Exception/NoTestsDirectoryTest.php b/typo3conf/ext/phpunit/Tests/Exception/NoTestsDirectoryTest.php new file mode 100644 index 0000000..c30155f --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Exception/NoTestsDirectoryTest.php @@ -0,0 +1,43 @@ +<?php +/*************************************************************** +* Copyright notice +* +* (c) 2011 Oliver Klee (typo3-coding@oliverklee.de) +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +/** + * Testcase for the Tx_Phpunit_Exception_NoTestsDirectory class. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Oliver Klee <typo3-coding@oliverklee.de> + */ +class Tx_Phpunit_Exception_NoTestsDirectoryTest extends Tx_Phpunit_TestCase { + /** + * @test + * + * @expectedException Tx_Phpunit_Exception_NoTestsDirectory + */ + public function exceptionCanBeThrown() { + throw new Tx_Phpunit_Exception_NoTestsDirectory(); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/ext_emconf.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/ext_emconf.php new file mode 100644 index 0000000..2e8ba82 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/ext_emconf.php @@ -0,0 +1,44 @@ +<?php + +######################################################################## +# Extension Manager/Repository config file for ext: "aaa" +# +# Auto generated 13-02-2008 11:01 +# +# Manual updates: +# Only the data in the array - anything else is removed by next write. +# "version" and "dependencies" must not be touched! +######################################################################## + +$EM_CONF[$_EXTKEY] = array( + 'title' => 'AAA', + 'description' => '', + 'category' => 'example', + 'author' => '', + 'author_email' => '', + 'shy' => '', + 'dependencies' => '', + 'conflicts' => '', + 'priority' => '', + 'module' => '', + 'state' => 'alpha', + 'internal' => '', + 'uploadfolder' => 0, + 'createDirs' => '', + 'modify_tables' => '', + 'clearCacheOnLoad' => 0, + 'lockType' => '', + 'author_company' => '', + 'version' => '0.0.0', + 'constraints' => array( + 'depends' => array( + ), + 'conflicts' => array( + ), + 'suggests' => array( + ), + ), + '_md5_values_when_last_written' => 'a:10:{s:9:"ChangeLog";s:4:"661e";s:10:"README.txt";s:4:"ee2d";s:12:"ext_icon.gif";s:4:"1bdc";s:14:"ext_tables.php";s:4:"6a79";s:14:"ext_tables.sql";s:4:"1764";s:20:"icon_tx_aaa_test.gif";s:4:"475a";s:16:"locallang_db.xml";s:4:"9d47";s:7:"tca.php";s:4:"ddf9";s:19:"doc/wizard_form.dat";s:4:"1855";s:20:"doc/wizard_form.html";s:4:"a38d";}', +); + +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/ext_icon.gif b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/ext_icon.gif new file mode 100644 index 0000000000000000000000000000000000000000..ef451bc8a5acc0b3a09b9c9966cac4279f72eceb GIT binary patch literal 630 zcmV-+0*U=cNk%w1VG;lk0LFg+?(g@RqW_MOr-q2OiI)Ds#{X}8<y&K=@$&Yyy#IQ8 zgQ>6nmZAUp`um)w|H8z~>FVvVvbuhOnTC@3R9u+c-Q&&8|NZ^{tg`>??ek}G%(J`y zq^<v=s{j7}|6*l@xV-=T{r!}l|B{{ma&?a5<L9fh|Fg8anxy}iqW^t~@u8~!m7xFh z^!8<O(U+O1mzk!=%>P$ilU`=4@$vJxxxayi$e5X*hm`+ub(H)2{Lj(a#>exBij|g^ z!)I)sl9Zvcxc`ip|72^TVQat8(Eo9Cq>h;GoSmwCh1s#Q!u0j{thN7gcAK`l|Gd5S zVP%PKaf@ngjE<0?^Yr(mrnRZ6w1biViHx7o(%6KO|FO6Ko1fi$fTetXmdMG?xWNC4 zkk_lU|GdBdU0-OMrvL2i?}v$;kdd5KTaL-j|AL9wV`z`Kxx{R5kdTw6mY1V#ah$uq z|DmY=!o<<X$k1J8vRr4sn56%(vglr8f?s5ekevUMp8uk$|NsC0A^8LW004ggEC2ui z01^NY000NmfPaF2dQes+gNcfNQw9VY6eKl^iZXaHU}Y*qX;@#Bb$1(T1sfa;I0klm zaEcNt8(;}yD=b0;T30S_i4-X&OeP!-BNGQrKX(FyZ5j?M9V-qDd@~U@5ik{lITH*4 zC@2gg1YIWzWQipQDSa&OA|otA=T>Mtf>lWl0sa0cN7ziE^QS_OKOYu!@WZg-91b1U zd>Dj;gpCDGwqV%EF-RCCimF60!bMJjF(6VFhy#IAmKRb6<grl1!V?LU5<NKM#s`l9 Q4{|Dk5Wx$OMS%bSJIf?g*Z=?k literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/ext_tables.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/ext_tables.php new file mode 100644 index 0000000..70f647c --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/ext_tables.php @@ -0,0 +1,22 @@ +<?php +if (!defined ('TYPO3_MODE')) die ('Access denied.'); +$TCA["tx_aaa_test"] = array ( + "ctrl" => array ( + 'title' => 'LLL:EXT:aaa/locallang_db.xml:tx_aaa_test', + 'label' => 'uid', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'cruser_id' => 'cruser_id', + 'default_sortby' => "ORDER BY crdate", + 'delete' => 'deleted', + 'enablecolumns' => array ( + 'disabled' => 'hidden', + ), + 'dynamicConfigFile' => t3lib_extMgm::extPath($_EXTKEY).'tca.php', + 'iconfile' => t3lib_extMgm::extRelPath($_EXTKEY).'icon_tx_aaa_test.gif', + ), + "feInterface" => array ( + "fe_admin_fieldList" => "hidden", + ) +); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/ext_tables.sql b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/ext_tables.sql new file mode 100644 index 0000000..fa394be --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/ext_tables.sql @@ -0,0 +1,15 @@ +# +# Table structure for table 'tx_aaa_test' +# +CREATE TABLE tx_aaa_test ( + uid int(11) NOT NULL auto_increment, + pid int(11) DEFAULT '0' NOT NULL, + tstamp int(11) DEFAULT '0' NOT NULL, + crdate int(11) DEFAULT '0' NOT NULL, + cruser_id int(11) DEFAULT '0' NOT NULL, + deleted tinyint(4) DEFAULT '0' NOT NULL, + hidden tinyint(4) DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid), + KEY parent (pid) +); \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/icon_tx_aaa_test.gif b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/icon_tx_aaa_test.gif new file mode 100644 index 0000000000000000000000000000000000000000..eb01f27c21a11808859d61916a9a6489a117587a GIT binary patch literal 135 zcmZ?wbhEHb6k-rySoELa|NsBT4j*f2YGGgiv4JE6DE{Ymbn$m`wek!y)H7hZ_m)BN zCkrD30}F!=NC8MU1GAOKraNCga5`x7DjmwqW|(=b^gsfiQYLGL$*P=Hac|8of0Eg4 ezTx)v`AgJ81hNk+1PNwX%|AN1q|1ka!5RSJcrLgA literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/locallang_db.xml b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/locallang_db.xml new file mode 100644 index 0000000..c9db1c0 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/locallang_db.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<T3locallang> + <meta type="array"> + <type>database</type> + <description>Language labels for database tables/fields belonging to extension 'aaa'</description> + </meta> + <data type="array"> + <languageKey index="default" type="array"> + <label index="tx_aaa_test">test</label> + </languageKey> + </data> +</T3locallang> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/tca.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/tca.php new file mode 100644 index 0000000..dff5272 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/aaa/tca.php @@ -0,0 +1,27 @@ +<?php +if (!defined ('TYPO3_MODE')) die ('Access denied.'); + +$TCA["tx_aaa_test"] = array ( + "ctrl" => $TCA["tx_aaa_test"]["ctrl"], + "interface" => array ( + "showRecordFieldList" => "hidden" + ), + "feInterface" => $TCA["tx_aaa_test"]["feInterface"], + "columns" => array ( + 'hidden' => array ( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden', + 'config' => array ( + 'type' => 'check', + 'default' => '0' + ) + ), + ), + "types" => array ( + "0" => array("showitem" => "hidden;;1;;1-1-1") + ), + "palettes" => array ( + "1" => array("showitem" => "") + ) +); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/ext_emconf.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/ext_emconf.php new file mode 100644 index 0000000..e36acd9 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/ext_emconf.php @@ -0,0 +1,45 @@ +<?php + +######################################################################## +# Extension Manager/Repository config file for ext: "bbb" +# +# Auto generated 20-02-2008 09:04 +# +# Manual updates: +# Only the data in the array - anything else is removed by next write. +# "version" and "dependencies" must not be touched! +######################################################################## + +$EM_CONF[$_EXTKEY] = array( + 'title' => 'BBB', + 'description' => 'bbb', + 'category' => 'example', + 'author' => '', + 'author_email' => '', + 'shy' => '', + 'dependencies' => 'aaa', + 'conflicts' => '', + 'priority' => '', + 'module' => '', + 'state' => 'alpha', + 'internal' => '', + 'uploadfolder' => 0, + 'createDirs' => '', + 'modify_tables' => '', + 'clearCacheOnLoad' => 0, + 'lockType' => '', + 'author_company' => '', + 'version' => '0.0.0', + 'constraints' => array( + 'depends' => array( + 'aaa' => '', + ), + 'conflicts' => array( + ), + 'suggests' => array( + ), + ), + '_md5_values_when_last_written' => 'a:10:{s:9:"ChangeLog";s:4:"1da2";s:10:"README.txt";s:4:"ee2d";s:12:"ext_icon.gif";s:4:"1bdc";s:14:"ext_tables.php";s:4:"84d0";s:14:"ext_tables.sql";s:4:"717c";s:20:"icon_tx_bbb_test.gif";s:4:"475a";s:16:"locallang_db.xml";s:4:"7f20";s:7:"tca.php";s:4:"f9d2";s:19:"doc/wizard_form.dat";s:4:"12fb";s:20:"doc/wizard_form.html";s:4:"37bf";}', +); + +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/ext_icon.gif b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/ext_icon.gif new file mode 100644 index 0000000000000000000000000000000000000000..ef451bc8a5acc0b3a09b9c9966cac4279f72eceb GIT binary patch literal 630 zcmV-+0*U=cNk%w1VG;lk0LFg+?(g@RqW_MOr-q2OiI)Ds#{X}8<y&K=@$&Yyy#IQ8 zgQ>6nmZAUp`um)w|H8z~>FVvVvbuhOnTC@3R9u+c-Q&&8|NZ^{tg`>??ek}G%(J`y zq^<v=s{j7}|6*l@xV-=T{r!}l|B{{ma&?a5<L9fh|Fg8anxy}iqW^t~@u8~!m7xFh z^!8<O(U+O1mzk!=%>P$ilU`=4@$vJxxxayi$e5X*hm`+ub(H)2{Lj(a#>exBij|g^ z!)I)sl9Zvcxc`ip|72^TVQat8(Eo9Cq>h;GoSmwCh1s#Q!u0j{thN7gcAK`l|Gd5S zVP%PKaf@ngjE<0?^Yr(mrnRZ6w1biViHx7o(%6KO|FO6Ko1fi$fTetXmdMG?xWNC4 zkk_lU|GdBdU0-OMrvL2i?}v$;kdd5KTaL-j|AL9wV`z`Kxx{R5kdTw6mY1V#ah$uq z|DmY=!o<<X$k1J8vRr4sn56%(vglr8f?s5ekevUMp8uk$|NsC0A^8LW004ggEC2ui z01^NY000NmfPaF2dQes+gNcfNQw9VY6eKl^iZXaHU}Y*qX;@#Bb$1(T1sfa;I0klm zaEcNt8(;}yD=b0;T30S_i4-X&OeP!-BNGQrKX(FyZ5j?M9V-qDd@~U@5ik{lITH*4 zC@2gg1YIWzWQipQDSa&OA|otA=T>Mtf>lWl0sa0cN7ziE^QS_OKOYu!@WZg-91b1U zd>Dj;gpCDGwqV%EF-RCCimF60!bMJjF(6VFhy#IAmKRb6<grl1!V?LU5<NKM#s`l9 Q4{|Dk5Wx$OMS%bSJIf?g*Z=?k literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/ext_tables.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/ext_tables.php new file mode 100644 index 0000000..ffeea3b --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/ext_tables.php @@ -0,0 +1,39 @@ +<?php +if (!defined ('TYPO3_MODE')) die ('Access denied.'); +$TCA["tx_bbb_test"] = array ( + "ctrl" => array ( + 'title' => 'LLL:EXT:bbb/locallang_db.xml:tx_bbb_test', + 'label' => 'uid', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'cruser_id' => 'cruser_id', + 'default_sortby' => "ORDER BY crdate", + 'delete' => 'deleted', + 'enablecolumns' => array ( + 'disabled' => 'hidden', + ), + 'dynamicConfigFile' => t3lib_extMgm::extPath($_EXTKEY).'tca.php', + 'iconfile' => t3lib_extMgm::extRelPath($_EXTKEY).'icon_tx_bbb_test.gif', + ), + "feInterface" => array ( + "fe_admin_fieldList" => "hidden", + ) +); + +$tempColumns = Array ( + "tx_bbb_test" => Array ( + "exclude" => 1, + "label" => "LLL:EXT:bbb/locallang_db.xml:tx_aaa_test.tx_bbb_test", + "config" => Array ( + "type" => "input", + "size" => "30", + "eval" => "trim", + ) + ), +); + + +t3lib_div::loadTCA("tx_aaa_test"); +t3lib_extMgm::addTCAcolumns("tx_aaa_test",$tempColumns,1); +t3lib_extMgm::addToAllTCAtypes("tx_aaa_test","tx_bbb_test;;;;1-1-1"); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/ext_tables.sql b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/ext_tables.sql new file mode 100644 index 0000000..1d5c808 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/ext_tables.sql @@ -0,0 +1,24 @@ +# +# Table structure for table 'tx_bbb_test' +# +CREATE TABLE tx_bbb_test ( + uid int(11) NOT NULL auto_increment, + pid int(11) DEFAULT '0' NOT NULL, + tstamp int(11) DEFAULT '0' NOT NULL, + crdate int(11) DEFAULT '0' NOT NULL, + cruser_id int(11) DEFAULT '0' NOT NULL, + deleted tinyint(4) DEFAULT '0' NOT NULL, + hidden tinyint(4) DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid), + KEY parent (pid) +); + + + +# +# Table structure for table 'tx_aaa_test' +# +CREATE TABLE tx_aaa_test ( + tx_bbb_test varchar(255) DEFAULT '' NOT NULL +); \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/icon_tx_bbb_test.gif b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/icon_tx_bbb_test.gif new file mode 100644 index 0000000000000000000000000000000000000000..eb01f27c21a11808859d61916a9a6489a117587a GIT binary patch literal 135 zcmZ?wbhEHb6k-rySoELa|NsBT4j*f2YGGgiv4JE6DE{Ymbn$m`wek!y)H7hZ_m)BN zCkrD30}F!=NC8MU1GAOKraNCga5`x7DjmwqW|(=b^gsfiQYLGL$*P=Hac|8of0Eg4 ezTx)v`AgJ81hNk+1PNwX%|AN1q|1ka!5RSJcrLgA literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/locallang_db.xml b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/locallang_db.xml new file mode 100644 index 0000000..cfdc8e1 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/locallang_db.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<T3locallang> + <meta type="array"> + <type>database</type> + <description>Language labels for database tables/fields belonging to extension 'bbb'</description> + </meta> + <data type="array"> + <languageKey index="default" type="array"> + <label index="tx_bbb_test">test</label> + <label index="tx_aaa_test.tx_bbb_test">test</label> + </languageKey> + </data> +</T3locallang> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/tca.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/tca.php new file mode 100644 index 0000000..ca8239d --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/bbb/tca.php @@ -0,0 +1,27 @@ +<?php +if (!defined ('TYPO3_MODE')) die ('Access denied.'); + +$TCA["tx_bbb_test"] = array ( + "ctrl" => $TCA["tx_bbb_test"]["ctrl"], + "interface" => array ( + "showRecordFieldList" => "hidden" + ), + "feInterface" => $TCA["tx_bbb_test"]["feInterface"], + "columns" => array ( + 'hidden' => array ( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden', + 'config' => array ( + 'type' => 'check', + 'default' => '0' + ) + ), + ), + "types" => array ( + "0" => array("showitem" => "hidden;;1;;1-1-1") + ), + "palettes" => array ( + "1" => array("showitem" => "") + ) +); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/ext_emconf.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/ext_emconf.php new file mode 100644 index 0000000..cc797db --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/ext_emconf.php @@ -0,0 +1,45 @@ +<?php + +######################################################################## +# Extension Manager/Repository config file for ext: "ccc" +# +# Auto generated 28-02-2008 15:51 +# +# Manual updates: +# Only the data in the array - anything else is removed by next write. +# "version" and "dependencies" must not be touched! +######################################################################## + +$EM_CONF[$_EXTKEY] = array( + 'title' => 'CCC', + 'description' => 'ccc', + 'category' => 'example', + 'author' => '', + 'author_email' => '', + 'shy' => '', + 'dependencies' => 'bbb', + 'conflicts' => '', + 'priority' => '', + 'module' => '', + 'state' => 'alpha', + 'internal' => '', + 'uploadfolder' => 0, + 'createDirs' => '', + 'modify_tables' => '', + 'clearCacheOnLoad' => 0, + 'lockType' => '', + 'author_company' => '', + 'version' => '0.0.0', + 'constraints' => array( + 'depends' => array( + 'bbb' => '', + ), + 'conflicts' => array( + ), + 'suggests' => array( + ), + ), + '_md5_values_when_last_written' => 'a:11:{s:9:"ChangeLog";s:4:"6901";s:10:"README.txt";s:4:"ee2d";s:12:"ext_icon.gif";s:4:"1bdc";s:14:"ext_tables.php";s:4:"7b15";s:14:"ext_tables.sql";s:4:"ed29";s:20:"icon_tx_ccc_data.gif";s:4:"475a";s:20:"icon_tx_ccc_test.gif";s:4:"475a";s:16:"locallang_db.xml";s:4:"4f69";s:7:"tca.php";s:4:"eb30";s:19:"doc/wizard_form.dat";s:4:"5b6a";s:20:"doc/wizard_form.html";s:4:"79f5";}', +); + +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/ext_icon.gif b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/ext_icon.gif new file mode 100644 index 0000000000000000000000000000000000000000..ef451bc8a5acc0b3a09b9c9966cac4279f72eceb GIT binary patch literal 630 zcmV-+0*U=cNk%w1VG;lk0LFg+?(g@RqW_MOr-q2OiI)Ds#{X}8<y&K=@$&Yyy#IQ8 zgQ>6nmZAUp`um)w|H8z~>FVvVvbuhOnTC@3R9u+c-Q&&8|NZ^{tg`>??ek}G%(J`y zq^<v=s{j7}|6*l@xV-=T{r!}l|B{{ma&?a5<L9fh|Fg8anxy}iqW^t~@u8~!m7xFh z^!8<O(U+O1mzk!=%>P$ilU`=4@$vJxxxayi$e5X*hm`+ub(H)2{Lj(a#>exBij|g^ z!)I)sl9Zvcxc`ip|72^TVQat8(Eo9Cq>h;GoSmwCh1s#Q!u0j{thN7gcAK`l|Gd5S zVP%PKaf@ngjE<0?^Yr(mrnRZ6w1biViHx7o(%6KO|FO6Ko1fi$fTetXmdMG?xWNC4 zkk_lU|GdBdU0-OMrvL2i?}v$;kdd5KTaL-j|AL9wV`z`Kxx{R5kdTw6mY1V#ah$uq z|DmY=!o<<X$k1J8vRr4sn56%(vglr8f?s5ekevUMp8uk$|NsC0A^8LW004ggEC2ui z01^NY000NmfPaF2dQes+gNcfNQw9VY6eKl^iZXaHU}Y*qX;@#Bb$1(T1sfa;I0klm zaEcNt8(;}yD=b0;T30S_i4-X&OeP!-BNGQrKX(FyZ5j?M9V-qDd@~U@5ik{lITH*4 zC@2gg1YIWzWQipQDSa&OA|otA=T>Mtf>lWl0sa0cN7ziE^QS_OKOYu!@WZg-91b1U zd>Dj;gpCDGwqV%EF-RCCimF60!bMJjF(6VFhy#IAmKRb6<grl1!V?LU5<NKM#s`l9 Q4{|Dk5Wx$OMS%bSJIf?g*Z=?k literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/ext_tables.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/ext_tables.php new file mode 100644 index 0000000..9be69f3 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/ext_tables.php @@ -0,0 +1,42 @@ +<?php +if (!defined ('TYPO3_MODE')) die ('Access denied.'); +$TCA["tx_ccc_test"] = array ( + "ctrl" => array ( + 'title' => 'LLL:EXT:ccc/locallang_db.xml:tx_ccc_test', + 'label' => 'uid', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'cruser_id' => 'cruser_id', + 'default_sortby' => "ORDER BY crdate", + 'delete' => 'deleted', + 'enablecolumns' => array ( + 'disabled' => 'hidden', + ), + 'dynamicConfigFile' => t3lib_extMgm::extPath($_EXTKEY).'tca.php', + 'iconfile' => t3lib_extMgm::extRelPath($_EXTKEY).'icon_tx_ccc_test.gif', + ), + "feInterface" => array ( + "fe_admin_fieldList" => "hidden", + ) +); + +$TCA["tx_ccc_data"] = array ( + "ctrl" => array ( + 'title' => 'LLL:EXT:ccc/locallang_db.xml:tx_ccc_data', + 'label' => 'uid', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'cruser_id' => 'cruser_id', + 'default_sortby' => "ORDER BY crdate", + 'delete' => 'deleted', + 'enablecolumns' => array ( + 'disabled' => 'hidden', + ), + 'dynamicConfigFile' => t3lib_extMgm::extPath($_EXTKEY).'tca.php', + 'iconfile' => t3lib_extMgm::extRelPath($_EXTKEY).'icon_tx_ccc_data.gif', + ), + "feInterface" => array ( + "fe_admin_fieldList" => "hidden, title, test", + ) +); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/ext_tables.sql b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/ext_tables.sql new file mode 100644 index 0000000..5b15b5d --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/ext_tables.sql @@ -0,0 +1,51 @@ +# +# Table structure for table 'tx_ccc_test' +# +CREATE TABLE tx_ccc_test ( + uid int(11) NOT NULL auto_increment, + pid int(11) DEFAULT '0' NOT NULL, + tstamp int(11) DEFAULT '0' NOT NULL, + crdate int(11) DEFAULT '0' NOT NULL, + cruser_id int(11) DEFAULT '0' NOT NULL, + deleted tinyint(4) DEFAULT '0' NOT NULL, + hidden tinyint(4) DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid), + KEY parent (pid) +); + + + + +# +# Table structure for table 'tx_ccc_data_test_mm' +# +# +CREATE TABLE tx_ccc_data_test_mm ( + uid_local int(11) DEFAULT '0' NOT NULL, + uid_foreign int(11) DEFAULT '0' NOT NULL, + tablenames varchar(30) DEFAULT '' NOT NULL, + sorting int(11) DEFAULT '0' NOT NULL, + KEY uid_local (uid_local), + KEY uid_foreign (uid_foreign) +); + + + +# +# Table structure for table 'tx_ccc_data' +# +CREATE TABLE tx_ccc_data ( + uid int(11) NOT NULL auto_increment, + pid int(11) DEFAULT '0' NOT NULL, + tstamp int(11) DEFAULT '0' NOT NULL, + crdate int(11) DEFAULT '0' NOT NULL, + cruser_id int(11) DEFAULT '0' NOT NULL, + deleted tinyint(4) DEFAULT '0' NOT NULL, + hidden tinyint(4) DEFAULT '0' NOT NULL, + title varchar(255) DEFAULT '' NOT NULL, + test int(11) DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid), + KEY parent (pid) +); \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/icon_tx_ccc_data.gif b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/icon_tx_ccc_data.gif new file mode 100644 index 0000000000000000000000000000000000000000..eb01f27c21a11808859d61916a9a6489a117587a GIT binary patch literal 135 zcmZ?wbhEHb6k-rySoELa|NsBT4j*f2YGGgiv4JE6DE{Ymbn$m`wek!y)H7hZ_m)BN zCkrD30}F!=NC8MU1GAOKraNCga5`x7DjmwqW|(=b^gsfiQYLGL$*P=Hac|8of0Eg4 ezTx)v`AgJ81hNk+1PNwX%|AN1q|1ka!5RSJcrLgA literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/icon_tx_ccc_test.gif b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/icon_tx_ccc_test.gif new file mode 100644 index 0000000000000000000000000000000000000000..eb01f27c21a11808859d61916a9a6489a117587a GIT binary patch literal 135 zcmZ?wbhEHb6k-rySoELa|NsBT4j*f2YGGgiv4JE6DE{Ymbn$m`wek!y)H7hZ_m)BN zCkrD30}F!=NC8MU1GAOKraNCga5`x7DjmwqW|(=b^gsfiQYLGL$*P=Hac|8of0Eg4 ezTx)v`AgJ81hNk+1PNwX%|AN1q|1ka!5RSJcrLgA literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/locallang_db.xml b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/locallang_db.xml new file mode 100644 index 0000000..05c3e20 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/locallang_db.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<T3locallang> + <meta type="array"> + <type>database</type> + <description>Language labels for database tables/fields belonging to extension 'ccc'</description> + </meta> + <data type="array"> + <languageKey index="default" type="array"> + <label index="tx_ccc_test">test</label> + <label index="tx_ccc_data">data</label> + </languageKey> + </data> +</T3locallang> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/tca.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/tca.php new file mode 100644 index 0000000..c1ded11 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ccc/tca.php @@ -0,0 +1,75 @@ +<?php +if (!defined ('TYPO3_MODE')) die ('Access denied.'); + +$TCA["tx_ccc_test"] = array ( + "ctrl" => $TCA["tx_ccc_test"]["ctrl"], + "interface" => array ( + "showRecordFieldList" => "hidden" + ), + "feInterface" => $TCA["tx_ccc_test"]["feInterface"], + "columns" => array ( + 'hidden' => array ( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden', + 'config' => array ( + 'type' => 'check', + 'default' => '0' + ) + ), + ), + "types" => array ( + "0" => array("showitem" => "hidden;;1;;1-1-1") + ), + "palettes" => array ( + "1" => array("showitem" => "") + ) +); + + + +$TCA["tx_ccc_data"] = array ( + "ctrl" => $TCA["tx_ccc_data"]["ctrl"], + "interface" => array ( + "showRecordFieldList" => "hidden,title,test" + ), + "feInterface" => $TCA["tx_ccc_data"]["feInterface"], + "columns" => array ( + 'hidden' => array ( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden', + 'config' => array ( + 'type' => 'check', + 'default' => '0' + ) + ), + "title" => Array ( + "exclude" => 1, + "label" => "LLL:EXT:ccc/locallang_db.xml:tx_ccc_data.title", + "config" => Array ( + "type" => "input", + "size" => "30", + "eval" => "trim", + ) + ), + "test" => Array ( + "exclude" => 1, + "label" => "LLL:EXT:ccc/locallang_db.xml:tx_ccc_data.test", + "config" => Array ( + "type" => "group", + "internal_type" => "db", + "allowed" => "tx_ccc_test", + "size" => 1, + "minitems" => 0, + "maxitems" => 1, + "MM" => "tx_ccc_data_test_mm", + ) + ), + ), + "types" => array ( + "0" => array("showitem" => "hidden;;1;;1-1-1, title;;;;2-2-2, test;;;;3-3-3") + ), + "palettes" => array ( + "1" => array("showitem" => "") + ) +); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/ext_emconf.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/ext_emconf.php new file mode 100644 index 0000000..08ca3de --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/ext_emconf.php @@ -0,0 +1,45 @@ +<?php + +######################################################################## +# Extension Manager/Repository config file for ext: "ddd" +# +# Auto generated 13-02-2008 13:19 +# +# Manual updates: +# Only the data in the array - anything else is removed by next write. +# "version" and "dependencies" must not be touched! +######################################################################## + +$EM_CONF[$_EXTKEY] = array( + 'title' => 'DDD', + 'description' => 'ddd', + 'category' => 'example', + 'author' => '', + 'author_email' => '', + 'shy' => '', + 'dependencies' => 'bbb', + 'conflicts' => '', + 'priority' => '', + 'module' => '', + 'state' => 'alpha', + 'internal' => '', + 'uploadfolder' => 0, + 'createDirs' => '', + 'modify_tables' => '', + 'clearCacheOnLoad' => 0, + 'lockType' => '', + 'author_company' => '', + 'version' => '0.0.0', + 'constraints' => array( + 'depends' => array( + 'bbb' => '', + ), + 'conflicts' => array( + ), + 'suggests' => array( + ), + ), + '_md5_values_when_last_written' => 'a:10:{s:9:"ChangeLog";s:4:"661e";s:10:"README.txt";s:4:"ee2d";s:12:"ext_icon.gif";s:4:"1bdc";s:14:"ext_tables.php";s:4:"eed5";s:14:"ext_tables.sql";s:4:"df94";s:20:"icon_tx_ddd_test.gif";s:4:"475a";s:16:"locallang_db.xml";s:4:"0b54";s:7:"tca.php";s:4:"7e17";s:19:"doc/wizard_form.dat";s:4:"4baa";s:20:"doc/wizard_form.html";s:4:"7033";}', +); + +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/ext_icon.gif b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/ext_icon.gif new file mode 100644 index 0000000000000000000000000000000000000000..ef451bc8a5acc0b3a09b9c9966cac4279f72eceb GIT binary patch literal 630 zcmV-+0*U=cNk%w1VG;lk0LFg+?(g@RqW_MOr-q2OiI)Ds#{X}8<y&K=@$&Yyy#IQ8 zgQ>6nmZAUp`um)w|H8z~>FVvVvbuhOnTC@3R9u+c-Q&&8|NZ^{tg`>??ek}G%(J`y zq^<v=s{j7}|6*l@xV-=T{r!}l|B{{ma&?a5<L9fh|Fg8anxy}iqW^t~@u8~!m7xFh z^!8<O(U+O1mzk!=%>P$ilU`=4@$vJxxxayi$e5X*hm`+ub(H)2{Lj(a#>exBij|g^ z!)I)sl9Zvcxc`ip|72^TVQat8(Eo9Cq>h;GoSmwCh1s#Q!u0j{thN7gcAK`l|Gd5S zVP%PKaf@ngjE<0?^Yr(mrnRZ6w1biViHx7o(%6KO|FO6Ko1fi$fTetXmdMG?xWNC4 zkk_lU|GdBdU0-OMrvL2i?}v$;kdd5KTaL-j|AL9wV`z`Kxx{R5kdTw6mY1V#ah$uq z|DmY=!o<<X$k1J8vRr4sn56%(vglr8f?s5ekevUMp8uk$|NsC0A^8LW004ggEC2ui z01^NY000NmfPaF2dQes+gNcfNQw9VY6eKl^iZXaHU}Y*qX;@#Bb$1(T1sfa;I0klm zaEcNt8(;}yD=b0;T30S_i4-X&OeP!-BNGQrKX(FyZ5j?M9V-qDd@~U@5ik{lITH*4 zC@2gg1YIWzWQipQDSa&OA|otA=T>Mtf>lWl0sa0cN7ziE^QS_OKOYu!@WZg-91b1U zd>Dj;gpCDGwqV%EF-RCCimF60!bMJjF(6VFhy#IAmKRb6<grl1!V?LU5<NKM#s`l9 Q4{|Dk5Wx$OMS%bSJIf?g*Z=?k literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/ext_tables.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/ext_tables.php new file mode 100644 index 0000000..020d3de --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/ext_tables.php @@ -0,0 +1,22 @@ +<?php +if (!defined ('TYPO3_MODE')) die ('Access denied.'); +$TCA["tx_ddd_test"] = array ( + "ctrl" => array ( + 'title' => 'LLL:EXT:ddd/locallang_db.xml:tx_ddd_test', + 'label' => 'uid', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'cruser_id' => 'cruser_id', + 'default_sortby' => "ORDER BY crdate", + 'delete' => 'deleted', + 'enablecolumns' => array ( + 'disabled' => 'hidden', + ), + 'dynamicConfigFile' => t3lib_extMgm::extPath($_EXTKEY).'tca.php', + 'iconfile' => t3lib_extMgm::extRelPath($_EXTKEY).'icon_tx_ddd_test.gif', + ), + "feInterface" => array ( + "fe_admin_fieldList" => "hidden", + ) +); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/ext_tables.sql b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/ext_tables.sql new file mode 100644 index 0000000..0857352 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/ext_tables.sql @@ -0,0 +1,15 @@ +# +# Table structure for table 'tx_ddd_test' +# +CREATE TABLE tx_ddd_test ( + uid int(11) NOT NULL auto_increment, + pid int(11) DEFAULT '0' NOT NULL, + tstamp int(11) DEFAULT '0' NOT NULL, + crdate int(11) DEFAULT '0' NOT NULL, + cruser_id int(11) DEFAULT '0' NOT NULL, + deleted tinyint(4) DEFAULT '0' NOT NULL, + hidden tinyint(4) DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid), + KEY parent (pid) +); \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/icon_tx_ddd_test.gif b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/icon_tx_ddd_test.gif new file mode 100644 index 0000000000000000000000000000000000000000..eb01f27c21a11808859d61916a9a6489a117587a GIT binary patch literal 135 zcmZ?wbhEHb6k-rySoELa|NsBT4j*f2YGGgiv4JE6DE{Ymbn$m`wek!y)H7hZ_m)BN zCkrD30}F!=NC8MU1GAOKraNCga5`x7DjmwqW|(=b^gsfiQYLGL$*P=Hac|8of0Eg4 ezTx)v`AgJ81hNk+1PNwX%|AN1q|1ka!5RSJcrLgA literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/locallang_db.xml b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/locallang_db.xml new file mode 100644 index 0000000..e241cff --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/locallang_db.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<T3locallang> + <meta type="array"> + <type>database</type> + <description>Language labels for database tables/fields belonging to extension 'ddd'</description> + </meta> + <data type="array"> + <languageKey index="default" type="array"> + <label index="tx_ddd_test">test</label> + </languageKey> + </data> +</T3locallang> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/tca.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/tca.php new file mode 100644 index 0000000..5ef46fa --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/ddd/tca.php @@ -0,0 +1,27 @@ +<?php +if (!defined ('TYPO3_MODE')) die ('Access denied.'); + +$TCA["tx_ddd_test"] = array ( + "ctrl" => $TCA["tx_ddd_test"]["ctrl"], + "interface" => array ( + "showRecordFieldList" => "hidden" + ), + "feInterface" => $TCA["tx_ddd_test"]["feInterface"], + "columns" => array ( + 'hidden' => array ( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden', + 'config' => array ( + 'type' => 'check', + 'default' => '0' + ) + ), + ), + "types" => array ( + "0" => array("showitem" => "hidden;;1;;1-1-1") + ), + "palettes" => array ( + "1" => array("showitem" => "") + ) +); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/ext_emconf.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/ext_emconf.php new file mode 100644 index 0000000..4ba59f3 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/ext_emconf.php @@ -0,0 +1,46 @@ +<?php + +######################################################################## +# Extension Manager/Repository config file for ext "user_phpunittest". +# +# Auto generated 22-05-2010 09:54 +# +# Manual updates: +# Only the data in the array - everything else is removed by next +# writing. "version" and "dependencies" must not be touched! +######################################################################## + +$EM_CONF[$_EXTKEY] = array( + 'title' => 'Test extension for tx_phpunit', + 'description' => 'Test extension for tx_phpunit', + 'category' => 'example', + 'author' => 'Niels Pardon', + 'author_email' => 'mail@niels-pardon.de', + 'shy' => '', + 'dependencies' => '', + 'conflicts' => '', + 'priority' => '', + 'module' => '', + 'state' => 'alpha', + 'internal' => '', + 'uploadfolder' => 0, + 'createDirs' => '', + 'modify_tables' => '', + 'clearCacheOnLoad' => 0, + 'lockType' => '', + 'author_company' => '', + 'version' => '0.0.0', + 'constraints' => array( + 'depends' => array( + ), + 'conflicts' => array( + ), + 'suggests' => array( + ), + ), + '_md5_values_when_last_written' => 'a:6:{s:12:"ext_icon.gif";s:4:"1bdc";s:14:"ext_tables.php";s:4:"03b8";s:14:"ext_tables.sql";s:4:"a0a5";s:28:"icon_user_phpunittest_test.gif";s:4:"475a";s:16:"locallang_db.xml";s:4:"32f9";s:7:"tca.php";s:4:"7e91";}', + 'suggests' => array( + ), +); + +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/ext_icon.gif b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/ext_icon.gif new file mode 100644 index 0000000000000000000000000000000000000000..ef451bc8a5acc0b3a09b9c9966cac4279f72eceb GIT binary patch literal 630 zcmV-+0*U=cNk%w1VG;lk0LFg+?(g@RqW_MOr-q2OiI)Ds#{X}8<y&K=@$&Yyy#IQ8 zgQ>6nmZAUp`um)w|H8z~>FVvVvbuhOnTC@3R9u+c-Q&&8|NZ^{tg`>??ek}G%(J`y zq^<v=s{j7}|6*l@xV-=T{r!}l|B{{ma&?a5<L9fh|Fg8anxy}iqW^t~@u8~!m7xFh z^!8<O(U+O1mzk!=%>P$ilU`=4@$vJxxxayi$e5X*hm`+ub(H)2{Lj(a#>exBij|g^ z!)I)sl9Zvcxc`ip|72^TVQat8(Eo9Cq>h;GoSmwCh1s#Q!u0j{thN7gcAK`l|Gd5S zVP%PKaf@ngjE<0?^Yr(mrnRZ6w1biViHx7o(%6KO|FO6Ko1fi$fTetXmdMG?xWNC4 zkk_lU|GdBdU0-OMrvL2i?}v$;kdd5KTaL-j|AL9wV`z`Kxx{R5kdTw6mY1V#ah$uq z|DmY=!o<<X$k1J8vRr4sn56%(vglr8f?s5ekevUMp8uk$|NsC0A^8LW004ggEC2ui z01^NY000NmfPaF2dQes+gNcfNQw9VY6eKl^iZXaHU}Y*qX;@#Bb$1(T1sfa;I0klm zaEcNt8(;}yD=b0;T30S_i4-X&OeP!-BNGQrKX(FyZ5j?M9V-qDd@~U@5ik{lITH*4 zC@2gg1YIWzWQipQDSa&OA|otA=T>Mtf>lWl0sa0cN7ziE^QS_OKOYu!@WZg-91b1U zd>Dj;gpCDGwqV%EF-RCCimF60!bMJjF(6VFhy#IAmKRb6<grl1!V?LU5<NKM#s`l9 Q4{|Dk5Wx$OMS%bSJIf?g*Z=?k literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/ext_tables.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/ext_tables.php new file mode 100644 index 0000000..b6ae821 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/ext_tables.php @@ -0,0 +1,24 @@ +<?php +if (!defined ('TYPO3_MODE')) die ('Access denied.'); +$TCA["user_phpunittest_test"] = array ( + "ctrl" => array ( + 'title' => 'LLL:EXT:user_phpunittest/locallang_db.xml:user_phpunittest_test', + 'label' => 'title', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'cruser_id' => 'cruser_id', + 'default_sortby' => "ORDER BY crdate", + 'delete' => 'deleted', + 'enablecolumns' => array ( + 'disabled' => 'hidden', + 'starttime' => 'starttime', + 'endtime' => 'endtime', + ), + 'dynamicConfigFile' => t3lib_extMgm::extPath($_EXTKEY).'tca.php', + 'iconfile' => t3lib_extMgm::extRelPath($_EXTKEY).'icon_user_phpunittest_test.gif', + ), + "feInterface" => array ( + "fe_admin_fieldList" => "hidden, starttime, endtime, title", + ) +); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/ext_tables.sql b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/ext_tables.sql new file mode 100644 index 0000000..53c1c54 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/ext_tables.sql @@ -0,0 +1,37 @@ +# +# Table structure for table 'user_phpunittest_test' +# +CREATE TABLE user_phpunittest_test ( + uid int(11) NOT NULL auto_increment, + pid int(11) DEFAULT '0' NOT NULL, + tstamp int(11) DEFAULT '0' NOT NULL, + crdate int(11) DEFAULT '0' NOT NULL, + cruser_id int(11) DEFAULT '0' NOT NULL, + deleted tinyint(4) DEFAULT '0' NOT NULL, + hidden tinyint(4) DEFAULT '0' NOT NULL, + starttime int(11) DEFAULT '0' NOT NULL, + endtime int(11) DEFAULT '0' NOT NULL, + title tinytext NOT NULL, + + tx_phpunit_is_dummy_record tinyint(1) unsigned DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid), + KEY parent (pid), + KEY dummy (tx_phpunit_is_dummy_record) +); + + +# +# Table structure for table 'user_phpunittest_test_article_mm' +# +CREATE TABLE user_phpunittest_test_article_mm ( + uid_local int(11) unsigned DEFAULT '0' NOT NULL, + uid_foreign int(11) unsigned DEFAULT '0' NOT NULL, + sorting int(11) unsigned DEFAULT '0' NOT NULL, + + tx_phpunit_is_dummy_record tinyint(1) unsigned DEFAULT '0' NOT NULL, + + KEY uid_local (uid_local), + KEY uid_foreign (uid_foreign), + KEY dummy (tx_phpunit_is_dummy_record) +); \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/icon_user_oelibtest_test.gif b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/icon_user_oelibtest_test.gif new file mode 100644 index 0000000000000000000000000000000000000000..eb01f27c21a11808859d61916a9a6489a117587a GIT binary patch literal 135 zcmZ?wbhEHb6k-rySoELa|NsBT4j*f2YGGgiv4JE6DE{Ymbn$m`wek!y)H7hZ_m)BN zCkrD30}F!=NC8MU1GAOKraNCga5`x7DjmwqW|(=b^gsfiQYLGL$*P=Hac|8of0Eg4 ezTx)v`AgJ81hNk+1PNwX%|AN1q|1ka!5RSJcrLgA literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/locallang_db.xml b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/locallang_db.xml new file mode 100644 index 0000000..dde68fa --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/locallang_db.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<T3locallang> + <meta type="array"> + <type>database</type> + <description>Language labels for database tables/fields belonging to extension 'user_phpunittest'</description> + </meta> + <data type="array"> + <languageKey index="default" type="array"> + <label index="user_phpunittest_test">Test</label> + <label index="user_phpunittest_test.title">Title</label> + </languageKey> + </data> +</T3locallang> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/tca.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/tca.php new file mode 100644 index 0000000..f15d922 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest/tca.php @@ -0,0 +1,64 @@ +<?php +if (!defined ('TYPO3_MODE')) die ('Access denied.'); + +$TCA["user_phpunittest_test"] = array ( + "ctrl" => $TCA["user_phpunittest_test"]["ctrl"], + "interface" => array ( + "showRecordFieldList" => "hidden,starttime,endtime,title" + ), + "feInterface" => $TCA["user_phpunittest_test"]["feInterface"], + "columns" => array ( + 'hidden' => array ( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden', + 'config' => array ( + 'type' => 'check', + 'default' => '0' + ) + ), + 'starttime' => array ( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.starttime', + 'config' => array ( + 'type' => 'input', + 'size' => '8', + 'max' => '20', + 'eval' => 'date', + 'default' => '0', + 'checkbox' => '0' + ) + ), + 'endtime' => array ( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.endtime', + 'config' => array ( + 'type' => 'input', + 'size' => '8', + 'max' => '20', + 'eval' => 'date', + 'checkbox' => '0', + 'default' => '0', + 'range' => array ( + 'upper' => mktime(0, 0, 0, 12, 31, 2020), + 'lower' => mktime(0, 0, 0, date('m')-1, date('d'), date('Y')) + ) + ) + ), + "title" => Array ( + "exclude" => 0, + "label" => "LLL:EXT:user_phpunittest/locallang_db.xml:user_phpunittest_test.title", + "config" => Array ( + "type" => "input", + "size" => "30", + "eval" => "required", + ) + ), + ), + "types" => array ( + "0" => array("showitem" => "hidden;;1;;1-1-1, title;;;;2-2-2") + ), + "palettes" => array ( + "1" => array("showitem" => "starttime, endtime") + ) +); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/ext_emconf.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/ext_emconf.php new file mode 100644 index 0000000..a64ef79 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/ext_emconf.php @@ -0,0 +1,46 @@ +<?php + +######################################################################## +# Extension Manager/Repository config file for ext "user_phpunittest2". +# +# Auto generated 22-05-2010 09:54 +# +# Manual updates: +# Only the data in the array - everything else is removed by next +# writing. "version" and "dependencies" must not be touched! +######################################################################## + +$EM_CONF[$_EXTKEY] = array( + 'title' => 'Second test extension for tx_phpunit', + 'description' => 'Second test extension for tx_phpunit', + 'category' => 'example', + 'author' => 'Niels Pardon', + 'author_email' => 'mail@niels-pardon.de', + 'shy' => '', + 'dependencies' => '', + 'conflicts' => '', + 'priority' => '', + 'module' => '', + 'state' => 'alpha', + 'internal' => '', + 'uploadfolder' => 0, + 'createDirs' => '', + 'modify_tables' => '', + 'clearCacheOnLoad' => 0, + 'lockType' => '', + 'author_company' => '', + 'version' => '0.0.0', + 'constraints' => array( + 'depends' => array( + ), + 'conflicts' => array( + ), + 'suggests' => array( + ), + ), + '_md5_values_when_last_written' => 'a:6:{s:12:"ext_icon.gif";s:4:"bd58";s:14:"ext_tables.php";s:4:"1bbe";s:14:"ext_tables.sql";s:4:"e709";s:29:"icon_user_phpunittest2_test.gif";s:4:"bd58";s:16:"locallang_db.xml";s:4:"717d";s:7:"tca.php";s:4:"c191";}', + 'suggests' => array( + ), +); + +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/ext_icon.gif b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/ext_icon.gif new file mode 100644 index 0000000000000000000000000000000000000000..ef451bc8a5acc0b3a09b9c9966cac4279f72eceb GIT binary patch literal 630 zcmV-+0*U=cNk%w1VG;lk0LFg+?(g@RqW_MOr-q2OiI)Ds#{X}8<y&K=@$&Yyy#IQ8 zgQ>6nmZAUp`um)w|H8z~>FVvVvbuhOnTC@3R9u+c-Q&&8|NZ^{tg`>??ek}G%(J`y zq^<v=s{j7}|6*l@xV-=T{r!}l|B{{ma&?a5<L9fh|Fg8anxy}iqW^t~@u8~!m7xFh z^!8<O(U+O1mzk!=%>P$ilU`=4@$vJxxxayi$e5X*hm`+ub(H)2{Lj(a#>exBij|g^ z!)I)sl9Zvcxc`ip|72^TVQat8(Eo9Cq>h;GoSmwCh1s#Q!u0j{thN7gcAK`l|Gd5S zVP%PKaf@ngjE<0?^Yr(mrnRZ6w1biViHx7o(%6KO|FO6Ko1fi$fTetXmdMG?xWNC4 zkk_lU|GdBdU0-OMrvL2i?}v$;kdd5KTaL-j|AL9wV`z`Kxx{R5kdTw6mY1V#ah$uq z|DmY=!o<<X$k1J8vRr4sn56%(vglr8f?s5ekevUMp8uk$|NsC0A^8LW004ggEC2ui z01^NY000NmfPaF2dQes+gNcfNQw9VY6eKl^iZXaHU}Y*qX;@#Bb$1(T1sfa;I0klm zaEcNt8(;}yD=b0;T30S_i4-X&OeP!-BNGQrKX(FyZ5j?M9V-qDd@~U@5ik{lITH*4 zC@2gg1YIWzWQipQDSa&OA|otA=T>Mtf>lWl0sa0cN7ziE^QS_OKOYu!@WZg-91b1U zd>Dj;gpCDGwqV%EF-RCCimF60!bMJjF(6VFhy#IAmKRb6<grl1!V?LU5<NKM#s`l9 Q4{|Dk5Wx$OMS%bSJIf?g*Z=?k literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/ext_tables.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/ext_tables.php new file mode 100644 index 0000000..6603787 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/ext_tables.php @@ -0,0 +1,24 @@ +<?php +if (!defined ('TYPO3_MODE')) die ('Access denied.'); +$TCA["user_phpunittest2_test"] = array ( + "ctrl" => array ( + 'title' => 'LLL:EXT:user_phpunittest2/locallang_db.xml:user_phpunittest2_test', + 'label' => 'title', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'cruser_id' => 'cruser_id', + 'default_sortby' => "ORDER BY crdate", + 'delete' => 'deleted', + 'enablecolumns' => array ( + 'disabled' => 'hidden', + 'starttime' => 'starttime', + 'endtime' => 'endtime', + ), + 'dynamicConfigFile' => t3lib_extMgm::extPath($_EXTKEY).'tca.php', + 'iconfile' => t3lib_extMgm::extRelPath($_EXTKEY).'icon_user_phpunittest2_test.gif', + ), + "feInterface" => array ( + "fe_admin_fieldList" => "hidden, starttime, endtime, title", + ) +); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/ext_tables.sql b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/ext_tables.sql new file mode 100644 index 0000000..b207f4b --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/ext_tables.sql @@ -0,0 +1,31 @@ +# +# Table structure for table 'user_phpunittest2_test' +# +CREATE TABLE user_phpunittest2_test ( + uid int(11) NOT NULL auto_increment, + pid int(11) DEFAULT '0' NOT NULL, + tstamp int(11) DEFAULT '0' NOT NULL, + crdate int(11) DEFAULT '0' NOT NULL, + cruser_id int(11) DEFAULT '0' NOT NULL, + deleted tinyint(4) DEFAULT '0' NOT NULL, + hidden tinyint(4) DEFAULT '0' NOT NULL, + starttime int(11) DEFAULT '0' NOT NULL, + endtime int(11) DEFAULT '0' NOT NULL, + title tinytext NOT NULL, + + PRIMARY KEY (uid), + KEY parent (pid) +); + + +# +# Table structure for table 'user_phpunittest2_test_article_mm' +# +CREATE TABLE user_phpunittest2_test_article_mm ( + uid_local int(11) unsigned DEFAULT '0' NOT NULL, + uid_foreign int(11) unsigned DEFAULT '0' NOT NULL, + sorting int(11) unsigned DEFAULT '0' NOT NULL, + + KEY uid_local (uid_local), + KEY uid_foreign (uid_foreign) +); \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/icon_user_oelibtest2_test.gif b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/icon_user_oelibtest2_test.gif new file mode 100644 index 0000000000000000000000000000000000000000..2b01e35451de1739b23e5306c56916a6e9c97775 GIT binary patch literal 652 zcmV;70(1RGNk%w1VG;lk0OkMy@$KsE>E-;{Q-y_uxV5vjg*CyNLjQpP|DBil-MYY* zLF1|(;@{i$mIeIDm%Wue(9O!ZkvYANJ-LlJm6MVG$pinz0AXQZ|CIp$jR5@9asP(^ zYinwdkB|R;0fT~qeSCaqXJ>hNdH=xx|G5DFy#W7;0CskDTw7ZIkpT4Y?Ei!Sad2++ z@$LVkjIM|}|H%jW>9YNuL;05p;;0+Bi8+>)l>f;9US3^hW@U<rhy2rXiHV8)(r^EU z2K}f?{g^b9fM5IKgr$&g`@Dmdgk$I9;Q8gXk&uu1=eqgmy8OqL<lx+{tf~LO1pm4O zeSCVw!obbS$8c|Mn3t8kl0A8NcYuF>_w(-e^6jOhqSVsQ{H|pCv~Rk&wf~a@yt=sm zj0F0~ny{^_{jo^h+19{?DEIH^v4Js?kdXb&NZ74Ga&d6Ai8X(Ie*M!(jg5?|fj9cd zl*qP^|9=Lep`ZEOy!^|V{j5mX)zaG6)WnD@$BQn3fPiIWWB2p#A^8LW004ggEC2ui z01^NY000N+fPa5ma5i2lf`Tp%iGnSE3_Jq^V2Lpr2uoOrbqs%c10NlTN-zRD2zOb6 zeQ;3(A6IFANlq3O0+@_{9U#8GZgWp1Bew!Q2!dK7%*;gw3nauAH$q2(Mo1^yK?(}c z(j#w;e*h3tLlP2I4-YgXYUGItGki4@6A=+>0RZv|UobS-Q=mYb7aXiy@zTgnm<%Zd znn4pMghh*E1fB7*!30Es1^kE{$wp9@11ma0BvU5Gg$q!0T$mz=iwBe)@%#zE0f(PF mf0|GcB!<q-6+aSDK!Jh<lX8iO$N(azQ2+{lP(WxD2mm{i1w<|Y literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/locallang_db.xml b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/locallang_db.xml new file mode 100644 index 0000000..9adca8b --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/locallang_db.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<T3locallang> + <meta type="array"> + <type>database</type> + <description>Language labels for database tables/fields belonging to extension 'user_phpunittest2'</description> + </meta> + <data type="array"> + <languageKey index="default" type="array"> + <label index="user_phpunittest2_test">Test</label> + <label index="user_phpunittest2_test.title">Title</label> + </languageKey> + </data> +</T3locallang> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/tca.php b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/tca.php new file mode 100644 index 0000000..71f925c --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/Extensions/user_phpunittest2/tca.php @@ -0,0 +1,64 @@ +<?php +if (!defined ('TYPO3_MODE')) die ('Access denied.'); + +$TCA["user_phpunittest2_test"] = array ( + "ctrl" => $TCA["user_phpunittest2_test"]["ctrl"], + "interface" => array ( + "showRecordFieldList" => "hidden,starttime,endtime,title" + ), + "feInterface" => $TCA["user_phpunittest2_test"]["feInterface"], + "columns" => array ( + 'hidden' => array ( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden', + 'config' => array ( + 'type' => 'check', + 'default' => '0' + ) + ), + 'starttime' => array ( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.starttime', + 'config' => array ( + 'type' => 'input', + 'size' => '8', + 'max' => '20', + 'eval' => 'date', + 'default' => '0', + 'checkbox' => '0' + ) + ), + 'endtime' => array ( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.endtime', + 'config' => array ( + 'type' => 'input', + 'size' => '8', + 'max' => '20', + 'eval' => 'date', + 'checkbox' => '0', + 'default' => '0', + 'range' => array ( + 'upper' => mktime(0, 0, 0, 12, 31, 2020), + 'lower' => mktime(0, 0, 0, date('m')-1, date('d'), date('Y')) + ) + ) + ), + "title" => Array ( + "exclude" => 0, + "label" => "LLL:EXT:user_phpunittest2/locallang_db.xml:user_phpunittest2_test.title", + "config" => Array ( + "type" => "input", + "size" => "30", + "eval" => "required", + ) + ), + ), + "types" => array ( + "0" => array("showitem" => "hidden;;1;;1-1-1, title;;;;2-2-2") + ), + "palettes" => array ( + "1" => array("showitem" => "starttime, endtime") + ) +); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/LoadMe.php b/typo3conf/ext/phpunit/Tests/Fixtures/LoadMe.php new file mode 100644 index 0000000..ef6f441 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Fixtures/LoadMe.php @@ -0,0 +1,3 @@ +<?php +class Tx_Phpunit_Fixtures_LoadMe {} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Fixtures/test.png b/typo3conf/ext/phpunit/Tests/Fixtures/test.png new file mode 100644 index 0000000000000000000000000000000000000000..3428c78e6138a35eeea2a483ba7025b6cb8cecee GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^DIm<q3?#jD*u{YqV{wqX6T`Z5GB1G~<^Z1%*Z=?j zFFzuE0wkB@?e4<R!7A$k<Zu>vL>4nJa0`PlBg3pY5<o%r5>H=O_8T0+{1O^}rhhmC u6cX`taSX9Iotz-Sx;R0krzz0EpMin3f`L)9aOWSOJcFmJpUXO@geCxklO>-3 literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/Tests/FrameworkTest.php b/typo3conf/ext/phpunit/Tests/FrameworkTest.php new file mode 100644 index 0000000..5b50e5f --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/FrameworkTest.php @@ -0,0 +1,4772 @@ +<?php +/*************************************************************** +* Copyright notice +* +* (c) 2007-2011 Mario Rimann (typo3-coding@rimann.org) +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +/** + * Testcase for the Tx_Phpunit_Framework class. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Mario Rimann <typo3-coding@rimann.org> + * @author Oliver Klee <typo3-coding@oliverklee.de> + * @author Saskia Metzler <saskia@merlin.owl.de> + * @author Niels Pardon <mail@niels-pardon.de> + */ +class Tx_Phpunit_FrameworkTest extends tx_phpunit_testcase { + /** + * @var Tx_Phpunit_Framework + */ + private $fixture; + + /** + * absolute path to a "foreign" file which was created for test purposes and + * which should be deleted in tearDown(); this is needed for + * deleteDummyFileWithForeignFileThrowsException + * + * @var string + */ + private $foreignFileToDelete = ''; + + /** + * absolute path to a "foreign" folder which was created for test purposes + * and which should be deleted in tearDown(); this is needed for + * deleteDummyFolderWithForeignFolderThrowsException + * + * @var string + */ + private $foreignFolderToDelete = ''; + + /** + * backed-up extension configuration of the TYPO3 configuration variables + * + * @var array + */ + private $extConfBackup = array(); + + /** + * backed-up T3_VAR configuration + * + * @var array + */ + private $t3VarBackup = array(); + + public function setUp() { + $this->extConfBackup = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']; + $this->t3VarBackup = $GLOBALS['T3_VAR']['getUserObj']; + + $this->fixture = new Tx_Phpunit_Framework('tx_phpunit', array('user_phpunittest')); + } + + public function tearDown() { + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'] = $this->extConfBackup; + $GLOBALS['T3_VAR']['getUserObj'] = $this->t3VarBackup; + + $this->fixture->setResetAutoIncrementThreshold(1); + $this->fixture->purgeHooks(); + $this->fixture->cleanUp(); + $this->deleteForeignFile(); + $this->deleteForeignFolder(); + + unset($this->fixture); + } + + + // --------------------------------------------------------------------- + // Utility functions. + // --------------------------------------------------------------------- + + /** + * Returns the sorting value of the relation between the local UID given by + * the first parameter $uidLocal and the foreign UID given by the second + * parameter $uidForeign. + * + * @param integer $uidLocal + * the UID of the local record, must be > 0 + * @param integer $uidForeign + * the UID of the foreign record, must be > 0 + * + * @return integer the sorting value of the relation + */ + private function getSortingOfRelation($uidLocal, $uidForeign) { + $row = Tx_Phpunit_Service_Database::selectSingle( + 'sorting', + 'tx_phpunit_test_article_mm', + 'uid_local = ' . $uidLocal.' AND uid_foreign = ' . $uidForeign + ); + + return $row['sorting']; + } + + /** + * Checks whether the extension user_phpunittest is currently loaded and lets + * a test fail if the extension is not loaded. + */ + private function checkIfExtensionUserPhpUnittestIsLoaded() { + if (!t3lib_extMgm::isLoaded('user_phpunittest')) { + $this->fail( + 'Extension user_phpunittest is not installed but needs to be ' . + 'installed! Please install it from EXT:phpunit/Tests/' . + 'Fixtures/Extensions/user_phpunittest/.' + ); + } + } + + /** + * Checks whether the extension user_phpunittest2 is currently loaded and lets + * a test fail if the extension is not loaded. + */ + private function checkIfExtensionUserPhpUnittest2IsLoaded() { + if (!t3lib_extMgm::isLoaded('user_phpunittest')) { + $this->fail( + 'Extension user_phpunittest2 is not installed but needs to be ' . + 'installed! Please install it from EXT:phpunit/Tests/' . + 'Fixtures/Extensions/user_phpunittest2/.' + ); + } + } + + /** + * Deletes a "foreign" file which was created for test purposes. + */ + private function deleteForeignFile() { + if ($this->foreignFileToDelete == '') { + return; + } + + @unlink($this->foreignFileToDelete); + $this->foreignFileToDelete = ''; + } + + /** + * Deletes a "foreign" folder which was created for test purposes. + */ + private function deleteForeignFolder() { + if ($this->foreignFolderToDelete == '') { + return; + } + + t3lib_div::rmdir($this->foreignFolderToDelete); + $this->foreignFolderToDelete = ''; + } + + /** + * Marks a test as skipped if the ZIPArchive class is not available in the + * PHP installation. + */ + private function markAsSkippedForNoZipArchive() { + try { + $this->fixture->checkForZipArchive(); + } catch (Exception $exception) { + $this->markTestSkipped($exception->getMessage()); + } + } + + + // --------------------------------------------------------------------- + // Tests regarding markTableAsDirty() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function markTableAsDirty() { + $this->assertEquals( + array(), + $this->fixture->getListOfDirtyTables() + ); + + $this->fixture->createRecord('tx_phpunit_test', array()); + $this->assertEquals( + array( + 'tx_phpunit_test' => 'tx_phpunit_test' + ), + $this->fixture->getListOfDirtyTables() + ); + } + + /** + * @test + */ + public function markTableAsDirtyWillCleanUpANonSystemTable() { + $uid = Tx_Phpunit_Service_Database::insert( + 'tx_phpunit_test', array('is_dummy_record' => 1) + ); + + $this->fixture->markTableAsDirty('tx_phpunit_test'); + $this->fixture->cleanUp(); + $this->assertEquals( + 0, + $this->fixture->countRecords('tx_phpunit_test', 'uid=' . $uid) + ); + } + + /** + * @test + */ + public function markTableAsDirtyWillCleanUpASystemTable() { + $uid = Tx_Phpunit_Service_Database::insert ( + 'pages', array('tx_phpunit_is_dummy_record' => 1) + ); + + $this->fixture->markTableAsDirty('pages'); + $this->fixture->cleanUp(); + $this->assertEquals( + 0, + $this->fixture->countRecords('pages', 'uid=' . $uid) + ); + } + + /** + * @test + */ + public function markTableAsDirtyWillCleanUpAdditionalAllowedTable() { + $this->checkIfExtensionUserPhpUnittestIsLoaded(); + + $uid = Tx_Phpunit_Service_Database::insert( + 'user_phpunittest_test', array('tx_phpunit_is_dummy_record' => 1) + ); + + $this->fixture->markTableAsDirty('user_phpunittest_test'); + $this->fixture->cleanUp(); + $this->assertEquals( + 0, + $this->fixture->countRecords('user_phpunittest_test', 'uid=' . $uid) + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function markTableAsDirtyFailsOnInexistentTable() { + $this->fixture->markTableAsDirty('tx_phpunit_DOESNOTEXIST'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function markTableAsDirtyFailsOnNotAllowedSystemTable() { + $this->fixture->markTableAsDirty('sys_domain'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function markTableAsDirtyFailsOnForeignTable() { + $this->fixture->markTableAsDirty('tx_seminars_seminars'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function markTableAsDirtyFailsWithEmptyTableName() { + $this->fixture->markTableAsDirty(''); + } + + /** + * @test + */ + public function markTableAsDirtyAcceptsCommaSeparatedListOfTableNames() { + $this->fixture->markTableAsDirty('tx_phpunit_test'.','.'tx_phpunit_test_article_mm'); + $this->assertEquals( + array( + 'tx_phpunit_test' => 'tx_phpunit_test', + 'tx_phpunit_test_article_mm' => 'tx_phpunit_test_article_mm' + ), + $this->fixture->getListOfDirtyTables() + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding createRecord() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function createRecordOnValidTableWithNoData() { + $this->assertNotEquals( + 0, + $this->fixture->createRecord('tx_phpunit_test', array()) + ); + } + + /** + * @test + */ + public function createRecordWithValidData() { + $title = 'TEST record'; + $uid = $this->fixture->createRecord( + 'tx_phpunit_test', + array( + 'title' => $title + ) + ); + $this->assertNotEquals( + 0, + $uid + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'title', + 'tx_phpunit_test', + 'uid = ' . $uid + ); + + $this->assertEquals( + $title, + $row['title'] + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function createRecordOnInvalidTable() { + $this->fixture->createRecord('tx_phpunit_DOESNOTEXIST', array()); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function createRecordWithEmptyTableName() { + $this->fixture->createRecord('', array()); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function createRecordWithUidFails() { + $this->fixture->createRecord( + 'tx_phpunit_test', array('uid' => 99999) + ); + } + + /** + * @test + */ + public function createRecordOnValidAdditionalAllowedTableWithValidDataSucceeds() { + $this->checkIfExtensionUserPhpUnittestIsLoaded(); + + $title = 'TEST record'; + $this->fixture->createRecord( + 'user_phpunittest_test', + array( + 'title' => $title + ) + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding changeRecord() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function changeRecordWithExistingRecord() { + $uid = $this->fixture->createRecord( + 'tx_phpunit_test', + array('title' => 'foo') + ); + + $this->fixture->changeRecord( + 'tx_phpunit_test', + $uid, + array('title' => 'bar') + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'title', + 'tx_phpunit_test', + 'uid = ' . $uid + ); + + $this->assertEquals( + 'bar', + $row['title'] + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function changeRecordFailsOnForeignTable() { + $this->fixture->changeRecord( + 'tx_seminars_seminars', + 99999, + array('title' => 'foo') + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function changeRecordFailsOnInexistentTable() { + $this->fixture->changeRecord( + 'tx_phpunit_DOESNOTEXIST', + 99999, + array('title' => 'foo') + ); + } + + /** + * @test + */ + public function changeRecordOnAllowedSystemTableForPages() { + $pid = $this->fixture->createFrontEndPage(0, array('title' => 'foo')); + + $this->fixture->changeRecord( + 'pages', + $pid, + array('title' => 'bar') + ); + + $this->assertEquals( + 1, + $this->fixture->countRecords('pages', 'uid='.$pid.' AND title="bar"') + ); + } + + /** + * @test + */ + public function changeRecordOnAllowedSystemTableForContent() { + $pid = $this->fixture->createFrontEndPage(0, array('title' => 'foo')); + $uid = $this->fixture->createContentElement( + $pid, + array('titleText' => 'foo') + ); + + $this->fixture->changeRecord( + 'tt_content', + $uid, + array('titleText' => 'bar') + ); + + $this->assertEquals( + 1, + $this->fixture->countRecords('tt_content', 'uid=' . $uid.' AND titleText="bar"') + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function changeRecordFailsOnOtherSystemTable() { + $this->fixture->changeRecord( + 'sys_domain', + 1, + array('title' => 'bar') + ); + } + + /** + * @test + */ + public function changeRecordOnAdditionalAllowedTableSucceeds() { + $this->checkIfExtensionUserPhpUnittestIsLoaded(); + + $uid = $this->fixture->createRecord( + 'user_phpunittest_test', + array('title' => 'foo') + ); + + $this->fixture->changeRecord( + 'user_phpunittest_test', + $uid, + array('title' => 'bar') + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function changeRecordFailsWithUidZero() { + $this->fixture->changeRecord('tx_phpunit_test', 0, array('title' => 'foo')); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function changeRecordFailsWithEmptyData() { + $uid = $this->fixture->createRecord('tx_phpunit_test', array()); + + $this->fixture->changeRecord( + 'tx_phpunit_test', $uid, array() + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function changeRecordFailsWithUidFieldInRecordData() { + $uid = $this->fixture->createRecord('tx_phpunit_test', array()); + + $this->fixture->changeRecord( + 'tx_phpunit_test', $uid, array('uid' => '55742') + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function changeRecordFailsWithDummyRecordFieldInRecordData() { + $uid = $this->fixture->createRecord('tx_phpunit_test', array()); + + $this->fixture->changeRecord( + 'tx_phpunit_test', $uid, array('is_dummy_record' => 0) + ); + } + + /** + * @test + * + * @expectedException Tx_Phpunit_Exception_Database + */ + public function changeRecordFailsOnInexistentRecord() { + $uid = $this->fixture->createRecord('tx_phpunit_test', array()); + + $this->fixture->changeRecord( + 'tx_phpunit_test', $uid + 1, array('title' => 'foo') + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding deleteRecord() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function deleteRecordOnValidDummyRecord() { + // Creates and directly destroys a dummy record. + $uid = $this->fixture->createRecord('tx_phpunit_test', array()); + $this->fixture->deleteRecord('tx_phpunit_test', $uid); + + // Checks whether the record really was removed from the database. + $this->assertEquals( + 0, + $this->fixture->countRecords('tx_phpunit_test', 'uid=' . $uid) + ); + } + + /** + * @test + */ + public function deleteRecordOnValidDummyRecordOnAdditionalAllowedTableSucceeds() { + $this->checkIfExtensionUserPhpUnittestIsLoaded(); + + // Creates and directly destroys a dummy record. + $uid = $this->fixture->createRecord('user_phpunittest_test', array()); + $this->fixture->deleteRecord('user_phpunittest_test', $uid); + } + + /** + * @test + */ + public function deleteRecordOnInexistentRecord() { + $uid = 99999; + + // Checks that the record is inexistent before testing on it. + $this->assertEquals( + 0, + $this->fixture->countRecords('tx_phpunit_test', 'uid=' . $uid) + ); + + // Runs our delete function - it should run through even when it can't + // delete a record. + $this->fixture->deleteRecord('tx_phpunit_test', $uid); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function deleteRecordOnForeignTable() { + $table = 'tx_seminars_seminars'; + $uid = 99999; + + $this->fixture->deleteRecord($table, $uid); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function deleteRecordOnInexistentTable() { + $table = 'tx_phpunit_DOESNOTEXIST'; + $uid = 99999; + + $this->fixture->deleteRecord($table, $uid); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function deleteRecordWithEmptyTableName() { + $table = ''; + $uid = 99999; + + $this->fixture->deleteRecord($table, $uid); + } + + /** + * @test + */ + public function deleteRecordOnNonTestRecordNotDeletesRecord() { + // Create a new record that looks like a real record, i.e. the + // is_dummy_record flag is set to 0. + $uid = Tx_Phpunit_Service_Database::insert( + 'tx_phpunit_test', + array( + 'title' => 'TEST', + 'is_dummy_record' => 0 + ) + ); + + // Runs our delete method which should NOT affect the record created + // above. + $this->fixture->deleteRecord('tx_phpunit_test', $uid); + + // Remembers whether the record still exists. + $counter = Tx_Phpunit_Service_Database::count('tx_phpunit_test', 'uid = ' . $uid); + + // Deletes the record as it will not be caught by the clean up function. + Tx_Phpunit_Service_Database::delete( + 'tx_phpunit_test', + 'uid = ' . $uid . ' AND is_dummy_record = 0' + ); + + // Checks whether the record still had existed. + $this->assertEquals( + 1, + $counter + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding createRelation() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function createRelationWithValidData() { + $uidLocal = $this->fixture->createRecord('tx_phpunit_test'); + $uidForeign = $this->fixture->createRecord('tx_phpunit_test'); + + $this->fixture->createRelation( + 'tx_phpunit_test_article_mm', $uidLocal, $uidForeign + ); + + // Checks whether the record really exists. + $this->assertEquals( + 1, + $this->fixture->countRecords( + 'tx_phpunit_test_article_mm', + 'uid_local=' . $uidLocal.' AND uid_foreign=' . $uidForeign + ) + ); + } + + /** + * @test + */ + public function createRelationWithValidDataOnAdditionalAllowedTableSucceeds() { + $this->checkIfExtensionUserPhpUnittestIsLoaded(); + + $uidLocal = $this->fixture->createRecord('user_phpunittest_test'); + $uidForeign = $this->fixture->createRecord('user_phpunittest_test'); + + $this->fixture->createRelation( + 'user_phpunittest_test_article_mm', $uidLocal, $uidForeign + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function createRelationWithInvalidTable() { + $table = 'tx_phpunit_test_DOESNOTEXIST_mm'; + $uidLocal = 99999; + $uidForeign = 199999; + + $this->fixture->createRelation($table, $uidLocal, $uidForeign); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function createRelationWithEmptyTableName() { + $this->fixture->createRelation('', 99999, 199999); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function createRelationWithZeroFirstUid() { + $uid = $this->fixture->createRecord('tx_phpunit_test'); + $this->fixture->createRelation('tx_phpunit_test_article_mm', 0, $uid); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function createRelationWithZeroSecondUid() { + $uid = $this->fixture->createRecord('tx_phpunit_test'); + $this->fixture->createRelation('tx_phpunit_test_article_mm', $uid, 0); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function createRelationWithNegativeFirstUid() { + $uid = $this->fixture->createRecord('tx_phpunit_test'); + $this->fixture->createRelation('tx_phpunit_test_article_mm', -1, $uid); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function createRelationWithNegativeSecondUid() { + $uid = $this->fixture->createRecord('tx_phpunit_test'); + $this->fixture->createRelation('tx_phpunit_test_article_mm', $uid, -1); + } + + + /** + * @test + */ + public function createRelationWithAutomaticSorting() { + $uidLocal = $this->fixture->createRecord('tx_phpunit_test'); + $uidForeign = $this->fixture->createRecord('tx_phpunit_test'); + $this->fixture->createRelation( + 'tx_phpunit_test_article_mm', $uidLocal, $uidForeign + ); + $previousSorting = $this->getSortingOfRelation($uidLocal, $uidForeign); + $this->assertGreaterThan( + 0, + $previousSorting + ); + + + $uidForeign = $this->fixture->createRecord('tx_phpunit_test'); + $this->fixture->createRelation( + 'tx_phpunit_test_article_mm', $uidLocal, $uidForeign + ); + $nextSorting = $this->getSortingOfRelation($uidLocal, $uidForeign); + $this->assertEquals( + ($previousSorting + 1), + $nextSorting + ); + } + + /** + * @test + */ + public function createRelationWithManualSorting() { + $uidLocal = $this->fixture->createRecord('tx_phpunit_test'); + $uidForeign = $this->fixture->createRecord('tx_phpunit_test'); + $sorting = 99999; + + $this->fixture->createRelation( + 'tx_phpunit_test_article_mm', $uidLocal, $uidForeign, $sorting + ); + + $this->assertEquals( + $sorting, + $this->getSortingOfRelation($uidLocal, $uidForeign) + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding createRelationFromTca() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function createRelationAndUpdateCounterIncreasesZeroValueCounterByOne() { + $firstRecordUid = $this->fixture->createRecord('tx_phpunit_test'); + $secondRecordUid = $this->fixture->createRecord('tx_phpunit_test'); + + $this->fixture->createRelationAndUpdateCounter( + 'tx_phpunit_test', + $firstRecordUid, + $secondRecordUid, + 'related_records' + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'related_records', + 'tx_phpunit_test', + 'uid = ' . $firstRecordUid + ); + + $this->assertEquals( + 1, + $row['related_records'] + ); + } + + /** + * @test + */ + public function createRelationAndUpdateCounterIncreasesNonZeroValueCounterToOne() { + $firstRecordUid = $this->fixture->createRecord( + 'tx_phpunit_test', + array('related_records' => 1) + ); + $secondRecordUid = $this->fixture->createRecord('tx_phpunit_test'); + + $this->fixture->createRelationAndUpdateCounter( + 'tx_phpunit_test', + $firstRecordUid, + $secondRecordUid, + 'related_records' + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'related_records', + 'tx_phpunit_test', + 'uid = ' . $firstRecordUid + ); + + $this->assertEquals( + 2, + $row['related_records'] + ); + } + + /** + * @test + */ + public function createRelationAndUpdateCounterCreatesRecordInRelationTable() { + $firstRecordUid = $this->fixture->createRecord('tx_phpunit_test'); + $secondRecordUid = $this->fixture->createRecord('tx_phpunit_test'); + + $this->fixture->createRelationAndUpdateCounter( + 'tx_phpunit_test', + $firstRecordUid, + $secondRecordUid, + 'related_records' + ); + + $count = $this->fixture->countRecords( + 'tx_phpunit_test_article_mm', + 'uid_local=' . $firstRecordUid + ); + $this->assertEquals( + 1, + $count + ); + } + + + /** + * @test + */ + public function createRelationAndUpdateCounterWithBidirectionalRelationIncreasesCounter() { + $firstRecordUid = $this->fixture->createRecord('tx_phpunit_test'); + $secondRecordUid = $this->fixture->createRecord('tx_phpunit_test'); + + $this->fixture->createRelationAndUpdateCounter( + 'tx_phpunit_test', + $firstRecordUid, + $secondRecordUid, + 'bidirectional' + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'bidirectional', + 'tx_phpunit_test', + 'uid = ' . $firstRecordUid + ); + + $this->assertEquals( + 1, + $row['bidirectional'] + ); + } + + /** + * @test + */ + public function createRelationAndUpdateCounterWithBidirectionalRelationIncreasesOppositeFieldCounterInForeignTable() { + $firstRecordUid = $this->fixture->createRecord('tx_phpunit_test'); + $secondRecordUid = $this->fixture->createRecord('tx_phpunit_test'); + + $this->fixture->createRelationAndUpdateCounter( + 'tx_phpunit_test', + $firstRecordUid, + $secondRecordUid, + 'bidirectional' + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'related_records', + 'tx_phpunit_test', + 'uid = ' . $secondRecordUid + ); + + $this->assertEquals( + 1, + $row['related_records'] + ); + } + + /** + * @test + */ + public function createRelationAndUpdateCounterWithBidirectionalRelationCreatesRecordInRelationTable() { + $firstRecordUid = $this->fixture->createRecord('tx_phpunit_test'); + $secondRecordUid = $this->fixture->createRecord('tx_phpunit_test'); + + $this->fixture->createRelationAndUpdateCounter( + 'tx_phpunit_test', + $firstRecordUid, + $secondRecordUid, + 'bidirectional' + ); + + $count = $this->fixture->countRecords( + 'tx_phpunit_test_article_mm', + 'uid_local=' . $secondRecordUid . ' AND uid_foreign=' . + $firstRecordUid + ); + $this->assertEquals( + 1, + $count + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding removeRelation() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function removeRelationOnValidDummyRecord() { + $uidLocal = $this->fixture->createRecord('tx_phpunit_test'); + $uidForeign = $this->fixture->createRecord('tx_phpunit_test'); + + // Creates and directly destroys a dummy record. + $this->fixture->createRelation( + 'tx_phpunit_test_article_mm', $uidLocal, $uidForeign + ); + $this->fixture->removeRelation( + 'tx_phpunit_test_article_mm', $uidLocal, $uidForeign + ); + + // Checks whether the record really was removed from the database. + $this->assertEquals( + 0, + $this->fixture->countRecords( + 'tx_phpunit_test_article_mm', + 'uid_local=' . $uidLocal.' AND uid_foreign=' . $uidForeign + ) + ); + } + + /** + * @test + */ + public function removeRelationOnValidDummyRecordOnAdditionalAllowedTableSucceeds() { + $this->checkIfExtensionUserPhpUnittestIsLoaded(); + + $uidLocal = $this->fixture->createRecord('user_phpunittest_test'); + $uidForeign = $this->fixture->createRecord('user_phpunittest_test'); + + // Creates and directly destroys a dummy record. + $this->fixture->createRelation( + 'user_phpunittest_test_article_mm', $uidLocal, $uidForeign + ); + $this->fixture->removeRelation( + 'user_phpunittest_test_article_mm', $uidLocal, $uidForeign + ); + } + + /** + * @test + */ + public function removeRelationOnInexistentRecord() { + $uid = $this->fixture->createRecord('tx_phpunit_test'); + $uidLocal = $uid + 1; + $uidForeign = $uid + 2; + + // Checks that the record is inexistent before testing on it. + $this->assertEquals( + 0, + $this->fixture->countRecords( + 'tx_phpunit_test_article_mm', + 'uid_local=' . $uidLocal.' AND uid_foreign=' . $uidForeign + ) + ); + + // Runs our delete function - it should run through even when it can't + // delete a record. + $this->fixture->removeRelation( + 'tx_phpunit_test_article_mm', $uidLocal, $uidForeign + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function removeRelationOnForeignTable() { + $table = 'tx_seminars_seminars_places_mm'; + $uidLocal = 99999; + $uidForeign = 199999; + + $this->fixture->removeRelation($table, $uidLocal, $uidForeign); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function removeRelationOnInexistentTable() { + $table = 'tx_phpunit_DOESNOTEXIST'; + $uidLocal = 99999; + $uidForeign = 199999; + + $this->fixture->removeRelation($table, $uidLocal, $uidForeign); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function removeRelationWithEmptyTableName() { + $table = ''; + $uidLocal = 99999; + $uidForeign = 199999; + + $this->fixture->removeRelation($table, $uidLocal, $uidForeign); + } + + /** + * @test + */ + public function removeRelationOnRealRecordNotRemovesRelation() { + $uidLocal = $this->fixture->createRecord('tx_phpunit_test'); + $uidForeign = $this->fixture->createRecord('tx_phpunit_test');; + + // Create a new record that looks like a real record, i.e. the + // is_dummy_record flag is set to 0. + Tx_Phpunit_Service_Database::insert( + 'tx_phpunit_test_article_mm', + array( + 'uid_local' => $uidLocal, + 'uid_foreign' => $uidForeign, + 'is_dummy_record' => 0 + ) + ); + + // Runs our delete method which should NOT affect the record created + // above. + $this->fixture->removeRelation( + 'tx_phpunit_test_article_mm', $uidLocal, $uidForeign + ); + + // Caches the value that will be tested for later. We need to use the + // following order to make sure the test record gets deleted even if + // this test fails: + // 1. reads the value to test + // 2. deletes the test record + // 3. tests the previously read value (and possibly fails) + $numberOfCreatedRelations = Tx_Phpunit_Service_Database::count( + 'tx_phpunit_test_article_mm', + 'uid_local = ' . $uidLocal . ' AND uid_foreign = ' . $uidForeign + ); + + // Deletes the record as it will not be caught by the clean up function. + Tx_Phpunit_Service_Database::delete( + 'tx_phpunit_test_article_mm', + 'uid_local = ' . $uidLocal . ' AND uid_foreign = ' . $uidForeign + .' AND is_dummy_record = 0' + ); + + // Checks whether the relation had been created further up. + $this->assertEquals( + 1, + $numberOfCreatedRelations + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding cleanUp() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function cleanUpWithRegularCleanUp() { + // Creates a dummy record (and marks that table as dirty). + $this->fixture->createRecord('tx_phpunit_test'); + + // Creates a dummy record directly in the database, without putting this + // table name to the list of dirty tables. + Tx_Phpunit_Service_Database::insert( + 'tx_phpunit_test_article_mm', array('is_dummy_record' => 1) + ); + + // Runs a regular clean up. This should now delete only the first record + // which was created through the testing framework and thus that table + // is on the list of dirty tables. The second record was directly put + // into the database and it's table is not on this list and will not be + // removed by a regular clean up run. + $this->fixture->cleanUp(); + + // Checks whether the first dummy record is deleted. + $this->assertEquals( + 0, + $this->fixture->countRecords('tx_phpunit_test'), + 'Some test records were not deleted from table "tx_phpunit_test"' + ); + + // Checks whether the second dummy record still exists. + $this->assertEquals( + 1, + $this->fixture->countRecords('tx_phpunit_test_article_mm') + ); + + // Runs a deep clean up to delete all dummy records. + $this->fixture->cleanUp(TRUE); + } + + /** + * @test + */ + public function cleanUpWithDeepCleanup() { + // Creates a dummy record (and marks that table as dirty). + $this->fixture->createRecord('tx_phpunit_test'); + + // Creates a dummy record directly in the database without putting this + // table name to the list of dirty tables. + Tx_Phpunit_Service_Database::insert( + 'tx_phpunit_test_article_mm', array('is_dummy_record' => 1) + ); + + // Deletes all dummy records. + $this->fixture->cleanUp(TRUE); + + // Checks whether ALL dummy records were deleted (independent of the + // list of dirty tables). + $allowedTables = $this->fixture->getListOfDirtyTables(); + foreach ($allowedTables as $currentTable) { + $this->assertEquals( + 0, + $this->fixture->countRecords($currentTable), + 'Some test records were not deleted from table "'.$currentTable.'"' + ); + } + } + + /** + * @test + */ + public function cleanUpDeletesCreatedDummyFile() { + $fileName = $this->fixture->createDummyFile(); + + $this->fixture->cleanUp(); + + $this->assertFalse(file_exists($fileName)); + } + + /** + * @test + */ + public function cleanUpDeletesCreatedDummyFolder() { + $folderName = $this->fixture->createDummyFolder('test_folder'); + + $this->fixture->cleanUp(); + + $this->assertFalse(file_exists($folderName)); + } + + /** + * @test + */ + public function cleanUpDeletesCreatedNestedDummyFolders() { + $outerDummyFolder = $this->fixture->createDummyFolder('test_folder'); + $innerDummyFolder = $this->fixture->createDummyFolder( + $this->fixture->getPathRelativeToUploadDirectory($outerDummyFolder) . + '/test_folder' + ); + + $this->fixture->cleanUp(); + + $this->assertFalse( + file_exists($outerDummyFolder) && file_exists($innerDummyFolder) + ); + } + + /** + * @test + */ + public function cleanUpDeletesCreatedDummyUploadFolder() { + $this->fixture->setUploadFolderPath(PATH_site . 'typo3temp/tx_phpunit_test/'); + $this->fixture->createDummyFile(); + + $this->assertTrue(is_dir($this->fixture->getUploadFolderPath())); + + $this->fixture->cleanUp(); + + $this->assertFalse(is_dir($this->fixture->getUploadFolderPath())); + } + + /** + * @test + */ + public function cleanUpExecutesCleanUpHook() { + $this->fixture->purgeHooks(); + + $cleanUpHookMock = $this->getMock('Tx_Phpunit_Interface_FrameworkCleanupHook', array('cleanUp')); + $cleanUpHookMock->expects($this->atLeastOnce())->method('cleanUp'); + + $hookClassName = get_class($cleanUpHookMock); + + $GLOBALS['T3_VAR']['getUserObj'][$hookClassName] = $cleanUpHookMock; + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['FrameworkCleanUp']['phpunit_tests'] = $hookClassName; + + $this->fixture->cleanUp(); + } + + /** + * @test + * + * @expectedException t3lib_exception + */ + public function cleanUpForHookWithoutHookInterfaceThrowsException() { + $this->fixture->purgeHooks(); + + $hookClassName = uniqid('cleanUpHook'); + $cleanUpHookMock = $this->getMock($hookClassName, array('cleanUp')); + + $GLOBALS['T3_VAR']['getUserObj'][$hookClassName] = $cleanUpHookMock; + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['FrameworkCleanUp']['phpunit_tests'] = $hookClassName; + + $this->fixture->cleanUp(); + } + + + // --------------------------------------------------------------------- + // Tests regarding createListOfAllowedTables() + // + // The method is called in the constructor of the fixture. + // --------------------------------------------------------------------- + + /** + * @test + */ + public function createListOfAllowedTablesContainsOurTestTable() { + $allowedTables = $this->fixture->getListOfOwnAllowedTableNames(); + $this->assertContains( + 'tx_phpunit_test', + $allowedTables + ); + } + + /** + * @test + */ + public function createListOfAllowedTablesDoesNotContainForeignTables() { + $allowedTables = $this->fixture->getListOfOwnAllowedTableNames(); + $this->assertNotContains( + 'be_users', + $allowedTables + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding createListOfAdditionalAllowedTables() + // + // (That method is called in the constructor of the fixture.) + // --------------------------------------------------------------------- + + /** + * @test + */ + public function createListOfAdditionalAllowedTablesContainsOurTestTable() { + $this->checkIfExtensionUserPhpUnittestIsLoaded(); + + $allowedTables = $this->fixture->getListOfAdditionalAllowedTableNames(); + $this->assertContains( + 'user_phpunittest_test', + $allowedTables + ); + } + + /** + * @test + */ + public function createListOfAdditionalAllowedTablesDoesNotContainForeignTables() { + $allowedTables = $this->fixture->getListOfAdditionalAllowedTableNames(); + $this->assertNotContains( + 'be_users', + $allowedTables + ); + } + + /** + * @test + */ + public function createListOfAdditionalAllowedTablesContainsOurTestTables() { + $this->checkIfExtensionUserPhpUnittestIsLoaded(); + $this->checkIfExtensionUserPhpUnittest2IsLoaded(); + + $fixture = new Tx_Phpunit_Framework( + 'tx_phpunit', array('user_phpunittest', 'user_phpunittest2') + ); + + $allowedTables = $fixture->getListOfAdditionalAllowedTableNames(); + $this->assertContains( + 'user_phpunittest_test', + $allowedTables + ); + $this->assertContains( + 'user_phpunittest2_test', + $allowedTables + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding getAutoIncrement() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function getAutoIncrementReturnsOneForTruncatedTable() { + Tx_Phpunit_Service_Database::enableQueryLogging(); + $dbResult = $GLOBALS['TYPO3_DB']->sql_query( + 'TRUNCATE TABLE tx_phpunit_test;' + ); + if (!$dbResult) { + throw new Tx_Phpunit_Exception_Database(); + } + + $this->assertEquals( + 1, + $this->fixture->getAutoIncrement('tx_phpunit_test') + ); + } + + /** + * @test + */ + public function getAutoIncrementGetsCurrentAutoIncrement() { + $uid = $this->fixture->createRecord('tx_phpunit_test'); + + // $uid will equals be the previous auto increment value, so $uid + 1 + // should be equal to the current auto increment value. + $this->assertEquals( + $uid + 1, + $this->fixture->getAutoIncrement('tx_phpunit_test') + ); + } + + /** + * @test + */ + public function getAutoIncrementForFeUsersTableIsAllowed() { + $this->fixture->getAutoIncrement('fe_users'); + } + + /** + * @test + */ + public function getAutoIncrementForPagesTableIsAllowed() { + $this->fixture->getAutoIncrement('pages'); + } + + /** + * @test + */ + public function getAutoIncrementForTtContentTableIsAllowed() { + $this->fixture->getAutoIncrement('tt_content'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function getAutoIncrementWithOtherSystemTableFails() { + $this->fixture->getAutoIncrement('sys_domains'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function getAutoIncrementWithEmptyTableNameFails() { + $this->fixture->getAutoIncrement(''); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function getAutoIncrementWithForeignTableFails() { + $this->fixture->getAutoIncrement('tx_seminars_seminars'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function getAutoIncrementWithInexistentTableFails() { + $this->fixture->getAutoIncrement('tx_phpunit_DOESNOTEXIST'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function getAutoIncrementWithTableWithoutUidFails() { + $this->fixture->getAutoIncrement('tx_phpunit_test_article_mm'); + } + + + // --------------------------------------------------------------------- + // Tests regarding countRecords() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function countRecordsWithEmptyWhereClauseIsAllowed() { + $this->fixture->countRecords('tx_phpunit_test', ''); + } + + /** + * @test + */ + public function countRecordsWithMissingWhereClauseIsAllowed() { + $this->fixture->countRecords('tx_phpunit_test'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function countRecordsWithEmptyTableNameThrowsException() { + $this->fixture->countRecords(''); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function countRecordsWithInvalidTableNameThrowsException() { + $table = 'foo_bar'; + $this->fixture->countRecords($table); + } + + /** + * @test + */ + public function countRecordsWithFeGroupsTableIsAllowed() { + $table = 'fe_groups'; + $this->fixture->countRecords($table); + } + + /** + * @test + */ + public function countRecordsWithFeUsersTableIsAllowed() { + $table = 'fe_users'; + $this->fixture->countRecords($table); + } + + /** + * @test + */ + public function countRecordsWithPagesTableIsAllowed() { + $table = 'pages'; + $this->fixture->countRecords($table); + } + + /** + * @test + */ + public function countRecordsWithTtContentTableIsAllowed() { + $table = 'tt_content'; + $this->fixture->countRecords($table); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function countRecordsWithOtherTableThrowsException() { + $this->fixture->countRecords('sys_domain'); + } + + /** + * @test + */ + public function countRecordsReturnsZeroForNoMatches() { + $this->assertEquals( + 0, + $this->fixture->countRecords('tx_phpunit_test', 'title = "foo"') + ); + } + + /** + * @test + */ + public function countRecordsReturnsOneForOneDummyRecordMatch() { + $this->fixture->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + + $this->assertEquals( + 1, + $this->fixture->countRecords('tx_phpunit_test', 'title = "foo"') + ); + } + + /** + * @test + */ + public function countRecordsWithMissingWhereClauseReturnsOneForOneDummyRecordMatch() { + $this->fixture->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + + $this->assertEquals( + 1, + $this->fixture->countRecords('tx_phpunit_test') + ); + } + + /** + * @test + */ + public function countRecordsReturnsTwoForTwoMatches() { + $this->fixture->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + $this->fixture->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + + $this->assertEquals( + 2, + $this->fixture->countRecords('tx_phpunit_test', 'title = "foo"') + ); + } + + /** + * @test + */ + public function countRecordsForPagesTableIsAllowed() { + $this->fixture->countRecords('pages'); + } + + /** + * @test + */ + public function countRecordsIgnoresNonDummyRecords() { + Tx_Phpunit_Service_Database::insert( + 'tx_phpunit_test', array('title' => 'foo') + ); + + $testResult = $this->fixture->countRecords( + 'tx_phpunit_test', 'title = "foo"' + ); + + Tx_Phpunit_Service_Database::delete( + 'tx_phpunit_test', + 'title = "foo"' + ); + // We need to do this manually to not confuse the auto_increment counter + // of the testing framework. + $this->fixture->resetAutoIncrement('tx_phpunit_test'); + + $this->assertEquals( + 0, + $testResult + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding existsRecord() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function existsRecordWithEmptyWhereClauseIsAllowed() { + $this->fixture->existsRecord('tx_phpunit_test', ''); + } + + /** + * @test + */ + public function existsRecordWithMissingWhereClauseIsAllowed() { + $this->fixture->existsRecord('tx_phpunit_test'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function existsRecordWithEmptyTableNameThrowsException() { + $this->fixture->existsRecord(''); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function existsRecordWithInvalidTableNameThrowsException() { + $table = 'foo_bar'; + $this->fixture->existsRecord($table); + } + + /** + * @test + */ + public function existsRecordForNoMatchesReturnsFalse() { + $this->assertFalse( + $this->fixture->existsRecord('tx_phpunit_test', 'title = "foo"') + ); + } + + /** + * @test + */ + public function existsRecordForOneMatchReturnsTrue() { + $this->fixture->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + + $this->assertTrue( + $this->fixture->existsRecord('tx_phpunit_test', 'title = "foo"') + ); + } + + /** + * @test + */ + public function existsRecordForTwoMatchesReturnsTrue() { + $this->fixture->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + $this->fixture->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + + $this->assertTrue( + $this->fixture->existsRecord('tx_phpunit_test', 'title = "foo"') + ); + } + + /** + * @test + */ + public function existsRecordIgnoresNonDummyRecords() { + Tx_Phpunit_Service_Database::insert( + 'tx_phpunit_test', array('title' => 'foo') + ); + + $testResult = $this->fixture->existsRecord( + 'tx_phpunit_test', 'title = "foo"' + ); + + Tx_Phpunit_Service_Database::delete( + 'tx_phpunit_test', + 'title = "foo"' + ); + // We need to do this manually to not confuse the auto_increment counter + // of the testing framework. + $this->fixture->resetAutoIncrement('tx_phpunit_test'); + + $this->assertFalse( + $testResult + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding existsRecordWithUid() + // --------------------------------------------------------------------- + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function existsRecordWithUidWithZeroUidThrowsException() { + $this->fixture->existsRecordWithUid('tx_phpunit_test', 0); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function existsRecordWithUidWithNegativeUidThrowsException() { + $this->fixture->existsRecordWithUid('tx_phpunit_test', -1); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function existsRecordWithUidWithEmptyTableNameThrowsException() { + $this->fixture->existsRecordWithUid('', 1); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function existsRecordWithUidWithInvalidTableNameThrowsException() { + $table = 'foo_bar'; + $this->fixture->existsRecordWithUid($table, 1); + } + + /** + * @test + */ + public function existsRecordWithUidForNoMatcheReturnsFalse() { + $uid = $this->fixture->createRecord('tx_phpunit_test'); + $this->fixture->deleteRecord('tx_phpunit_test', $uid); + + $this->assertFalse( + $this->fixture->existsRecordWithUid( + 'tx_phpunit_test', $uid + ) + ); + } + + /** + * @test + */ + public function existsRecordWithUidForAMatchReturnsTrue() { + $uid = $this->fixture->createRecord('tx_phpunit_test'); + + $this->assertTrue( + $this->fixture->existsRecordWithUid('tx_phpunit_test', $uid) + ); + } + + /** + * @test + */ + public function existsRecordWithUidIgnoresNonDummyRecords() { + $uid = Tx_Phpunit_Service_Database::insert( + 'tx_phpunit_test', array('title' => 'foo') + ); + + $testResult = $this->fixture->existsRecordWithUid( + 'tx_phpunit_test', $uid + ); + + Tx_Phpunit_Service_Database::delete( + 'tx_phpunit_test', 'uid = ' . $uid + ); + // We need to do this manually to not confuse the auto_increment counter + // of the testing framework. + $this->fixture->resetAutoIncrement('tx_phpunit_test'); + + $this->assertFalse( + $testResult + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding existsExactlyOneRecord() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function existsExactlyOneRecordWithEmptyWhereClauseIsAllowed() { + $this->fixture->existsExactlyOneRecord('tx_phpunit_test', ''); + } + + /** + * @test + */ + public function existsExactlyOneRecordWithMissingWhereClauseIsAllowed() { + $this->fixture->existsExactlyOneRecord('tx_phpunit_test'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function existsExactlyOneRecordWithEmptyTableNameThrowsException() { + $this->fixture->existsExactlyOneRecord(''); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function existsExactlyOneRecordWithInvalidTableNameThrowsException() { + $table = 'foo_bar'; + $this->fixture->existsExactlyOneRecord($table); + } + + /** + * @test + */ + public function existsExactlyOneRecordForNoMatchesReturnsFalse() { + $this->assertFalse( + $this->fixture->existsExactlyOneRecord( + 'tx_phpunit_test', 'title = "foo"' + ) + ); + } + + /** + * @test + */ + public function existsExactlyOneRecordForOneMatchReturnsTrue() { + $this->fixture->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + + $this->assertTrue( + $this->fixture->existsExactlyOneRecord( + 'tx_phpunit_test', 'title = "foo"' + ) + ); + } + + /** + * @test + */ + public function existsExactlyOneRecordForTwoMatchesReturnsFalse() { + $this->fixture->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + $this->fixture->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + + $this->assertFalse( + $this->fixture->existsExactlyOneRecord('tx_phpunit_test', 'title = "foo"') + ); + } + + /** + * @test + */ + public function existsExactlyOneRecordIgnoresNonDummyRecords() { + Tx_Phpunit_Service_Database::insert( + 'tx_phpunit_test', array('title' => 'foo') + ); + + $testResult = $this->fixture->existsExactlyOneRecord( + 'tx_phpunit_test', 'title = "foo"' + ); + + Tx_Phpunit_Service_Database::delete( + 'tx_phpunit_test', + 'title = "foo"' + ); + // We need to do this manually to not confuse the auto_increment counter + // of the testing framework. + $this->fixture->resetAutoIncrement('tx_phpunit_test'); + + $this->assertFalse( + $testResult + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding resetAutoIncrement() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function resetAutoIncrementForTestTableSucceeds() { + $latestUid = $this->fixture->createRecord('tx_phpunit_test'); + $this->fixture->deleteRecord('tx_phpunit_test', $latestUid); + $this->fixture->resetAutoIncrement('tx_phpunit_test'); + + $this->assertEquals( + $latestUid, + $this->fixture->getAutoIncrement('tx_phpunit_test') + ); + } + + /** + * @test + */ + public function resetAutoIncrementForUnchangedTestTableCanBeRun() { + $this->fixture->resetAutoIncrement('tx_phpunit_test'); + } + + /** + * @test + */ + public function resetAutoIncrementForAdditionalAllowedTableSucceeds() { + $this->checkIfExtensionUserPhpUnittestIsLoaded(); + + // Creates and deletes a record and then resets the auto increment. + $latestUid = $this->fixture->createRecord('user_phpunittest_test'); + $this->fixture->deleteRecord('user_phpunittest_test', $latestUid); + $this->fixture->resetAutoIncrement('user_phpunittest_test'); + } + + /** + * @test + */ + public function resetAutoIncrementForTableWithoutUidIsAllowed() { + $this->fixture->resetAutoIncrement('tx_phpunit_test_article_mm'); + } + + /** + * @test + */ + public function resetAutoIncrementForFeUsersTableIsAllowed() { + $this->fixture->resetAutoIncrement('fe_users'); + } + + /** + * @test + */ + public function resetAutoIncrementForPagesTableIsAllowed() { + $this->fixture->resetAutoIncrement('pages'); + } + + /** + * @test + */ + public function resetAutoIncrementForTtContentTableIsAllowed() { + $this->fixture->resetAutoIncrement('tt_content'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function resetAutoIncrementWithOtherSystemTableFails() { + $this->fixture->resetAutoIncrement('sys_domains'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function resetAutoIncrementWithEmptyTableNameFails() { + $this->fixture->resetAutoIncrement(''); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function resetAutoIncrementWithForeignTableFails() { + $this->fixture->resetAutoIncrement('tx_seminars_seminars'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function resetAutoIncrementWithInexistentTableFails() { + $this->fixture->resetAutoIncrement('tx_phpunit_DOESNOTEXIST'); + } + + + // --------------------------------------------------------------------- + // Tests regarding resetAutoIncrementLazily() and + // setResetAutoIncrementThreshold + // --------------------------------------------------------------------- + + /** + * @test + */ + public function resetAutoIncrementLazilyForTestTableIsAllowed() { + $this->fixture->resetAutoIncrementLazily('tx_phpunit_test'); + } + + /** + * @test + */ + public function resetAutoIncrementLazilyForTableWithoutUidIsAllowed() { + $this->fixture->resetAutoIncrementLazily('tx_phpunit_test_article_mm'); + } + + /** + * @test + */ + public function resetAutoIncrementLazilyForFeUsersTableIsAllowed() { + $this->fixture->resetAutoIncrementLazily('fe_users'); + } + + /** + * @test + */ + public function resetAutoIncrementLazilyForPagesTableIsAllowed() { + $this->fixture->resetAutoIncrementLazily('pages'); + } + + /** + * @test + */ + public function resetAutoIncrementLazilyForTtContentTableIsAllowed() { + $this->fixture->resetAutoIncrementLazily('tt_content'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function resetAutoIncrementLazilyWithOtherSystemTableFails() { + $this->fixture->resetAutoIncrementLazily('sys_domains'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function resetAutoIncrementLazilyWithEmptyTableNameFails() { + $this->fixture->resetAutoIncrementLazily(''); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function resetAutoIncrementLazilyWithForeignTableFails() { + $this->fixture->resetAutoIncrementLazily('tx_seminars_seminars'); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function resetAutoIncrementLazilyWithInexistentTableFails() { + $this->fixture->resetAutoIncrementLazily('tx_phpunit_DOESNOTEXIST'); + } + + /** + * @test + */ + public function resetAutoIncrementLazilyDoesNothingAfterOneNewRecordByDefault() { + $oldAutoIncrement = $this->fixture->getAutoIncrement('tx_phpunit_test'); + + $latestUid = $this->fixture->createRecord('tx_phpunit_test'); + $this->fixture->deleteRecord('tx_phpunit_test', $latestUid); + $this->fixture->resetAutoIncrementLazily('tx_phpunit_test'); + + $this->assertNotEquals( + $oldAutoIncrement, + $this->fixture->getAutoIncrement('tx_phpunit_test') + ); + } + + /** + * @test + */ + public function resetAutoIncrementLazilyCleansUpsAfterOneNewRecordWithThreshholdOfOne() { + $oldAutoIncrement = $this->fixture->getAutoIncrement('tx_phpunit_test'); + $this->fixture->setResetAutoIncrementThreshold(1); + + $latestUid = $this->fixture->createRecord('tx_phpunit_test'); + $this->fixture->deleteRecord('tx_phpunit_test', $latestUid); + $this->fixture->resetAutoIncrementLazily('tx_phpunit_test'); + + $this->assertEquals( + $oldAutoIncrement, + $this->fixture->getAutoIncrement('tx_phpunit_test') + ); + } + + /** + * @test + */ + public function resetAutoIncrementLazilyCleansUpsAfter100NewRecordsByDefault() { + $oldAutoIncrement = $this->fixture->getAutoIncrement('tx_phpunit_test'); + + for ($i = 0; $i < 100; $i++) { + $latestUid = $this->fixture->createRecord('tx_phpunit_test'); + $this->fixture->deleteRecord('tx_phpunit_test', $latestUid); + } + + $this->fixture->resetAutoIncrementLazily('tx_phpunit_test'); + + $this->assertEquals( + $oldAutoIncrement, + $this->fixture->getAutoIncrement('tx_phpunit_test') + ); + } + + /** + * @test + */ + public function setResetAutoIncrementThresholdForOneIsAllowed() { + $this->fixture->setResetAutoIncrementThreshold(1); + } + + /** + * @test + */ + public function setResetAutoIncrementThresholdFor100IsAllowed() { + $this->fixture->setResetAutoIncrementThreshold(100); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function setResetAutoIncrementThresholdForZeroFails() { + $this->fixture->setResetAutoIncrementThreshold(0); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function setResetAutoIncrementThresholdForMinus1Fails() { + $this->fixture->setResetAutoIncrementThreshold(-1); + } + + + // --------------------------------------------------------------------- + // Tests regarding createFrontEndPage() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function frontEndPageCanBeCreated() { + $uid = $this->fixture->createFrontEndPage(); + + $this->assertNotEquals( + 0, + $uid + ); + + $this->assertEquals( + 1, + $this->fixture->countRecords( + 'pages', 'uid=' . $uid + ) + ); + } + + /** + * @test + */ + public function createFrontEndPageSetsCorrectDocumentType() { + $uid = $this->fixture->createFrontEndPage(); + + $this->assertNotEquals( + 0, + $uid + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'doktype', + 'pages', + 'uid = ' . $uid + ); + + $this->assertEquals( + 1, + $row['doktype'] + ); + } + + /** + * @test + */ + public function frontEndPageWillBeCreatedOnRootPage() { + $uid = $this->fixture->createFrontEndPage(); + + $this->assertNotEquals( + 0, + $uid + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'pid', + 'pages', + 'uid = ' . $uid + ); + + $this->assertEquals( + 0, + $row['pid'] + ); + } + + /** + * @test + */ + public function frontEndPageCanBeCreatedOnOtherPage() { + $parent = $this->fixture->createFrontEndPage(); + $uid = $this->fixture->createFrontEndPage($parent); + + $this->assertNotEquals( + 0, + $uid + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'pid', + 'pages', + 'uid = ' . $uid + ); + + $this->assertEquals( + $parent, + $row['pid'] + ); + } + + /** + * @test + */ + public function frontEndPageCanBeDirty() { + $this->assertEquals( + 0, + count($this->fixture->getListOfDirtySystemTables()) + ); + $uid = $this->fixture->createFrontEndPage(); + $this->assertNotEquals( + 0, + $uid + ); + + $this->assertNotEquals( + 0, + count($this->fixture->getListOfDirtySystemTables()) + ); + } + + /** + * @test + */ + public function frontEndPageWillBeCleanedUp() { + $uid = $this->fixture->createFrontEndPage(); + $this->assertNotEquals( + 0, + $uid + ); + + $this->fixture->cleanUp(); + $this->assertEquals( + 0, + $this->fixture->countRecords( + 'pages', 'uid=' . $uid + ) + ); + } + + /** + * @test + */ + public function frontEndPageHasNoTitleByDefault() { + $uid = $this->fixture->createFrontEndPage(); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'title', + 'pages', + 'uid = ' . $uid + ); + + $this->assertEquals( + '', + $row['title'] + ); + } + + /** + * @test + */ + public function frontEndPageCanHaveTitle() { + $uid = $this->fixture->createFrontEndPage( + 0, + array('title' => 'Test title') + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'title', + 'pages', + 'uid = ' . $uid + ); + + $this->assertEquals( + 'Test title', + $row['title'] + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function frontEndPageMustHaveNoZeroPid() { + $this->fixture->createFrontEndPage(0, array('pid' => 0)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function frontEndPageMustHaveNoNonZeroPid() { + $this->fixture->createFrontEndPage(0, array('pid' => 99999)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function frontEndPageMustHaveNoZeroUid() { + $this->fixture->createFrontEndPage(0, array('uid' => 0)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function frontEndPageMustHaveNoNonZeroUid() { + $this->fixture->createFrontEndPage(0, array('uid' => 99999)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function frontEndPageMustHaveNoZeroDoktype() { + $this->fixture->createFrontEndPage(0, array('doktype' => 0)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function frontEndPageMustHaveNoNonZeroDoktype() { + $this->fixture->createFrontEndPage(0, array('doktype' => 99999)); + } + + + // --------------------------------------------------------------------- + // Tests regarding createSystemFolder() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function systemFolderCanBeCreated() { + $uid = $this->fixture->createSystemFolder(); + + $this->assertNotEquals( + 0, + $uid + ); + + $this->assertEquals( + 1, + $this->fixture->countRecords( + 'pages', 'uid=' . $uid + ) + ); + } + + /** + * @test + */ + public function createSystemFolderSetsCorrectDocumentType() { + $uid = $this->fixture->createSystemFolder(); + + $this->assertNotEquals( + 0, + $uid + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'doktype', + 'pages', + 'uid = ' . $uid + ); + + $this->assertEquals( + 254, + $row['doktype'] + ); + } + + /** + * @test + */ + public function systemFolderWillBeCreatedOnRootPage() { + $uid = $this->fixture->createSystemFolder(); + + $this->assertNotEquals( + 0, + $uid + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'pid', + 'pages', + 'uid = ' . $uid + ); + + $this->assertEquals( + 0, + $row['pid'] + ); + } + + /** + * @test + */ + public function systemFolderCanBeCreatedOnOtherPage() { + $parent = $this->fixture->createSystemFolder(); + $uid = $this->fixture->createSystemFolder($parent); + + $this->assertNotEquals( + 0, + $uid + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'pid', + 'pages', + 'uid = ' . $uid + ); + + $this->assertEquals( + $parent, + $row['pid'] + ); + } + + /** + * @test + */ + public function systemFolderCanBeDirty() { + $this->assertEquals( + 0, + count($this->fixture->getListOfDirtySystemTables()) + ); + $uid = $this->fixture->createSystemFolder(); + $this->assertNotEquals( + 0, + $uid + ); + + $this->assertNotEquals( + 0, + count($this->fixture->getListOfDirtySystemTables()) + ); + } + + /** + * @test + */ + public function systemFolderWillBeCleanedUp() { + $uid = $this->fixture->createSystemFolder(); + $this->assertNotEquals( + 0, + $uid + ); + + $this->fixture->cleanUp(); + $this->assertEquals( + 0, + $this->fixture->countRecords( + 'pages', 'uid=' . $uid + ) + ); + } + + /** + * @test + */ + public function systemFolderHasNoTitleByDefault() { + $uid = $this->fixture->createSystemFolder(); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'title', + 'pages', + 'uid = ' . $uid + ); + + $this->assertEquals( + '', + $row['title'] + ); + } + + /** + * @test + */ + public function systemFolderCanHaveTitle() { + $uid = $this->fixture->createSystemFolder( + 0, + array('title' => 'Test title') + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'title', + 'pages', + 'uid = ' . $uid + ); + + $this->assertEquals( + 'Test title', + $row['title'] + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function systemFolderMustHaveNoZeroPid() { + $this->fixture->createSystemFolder(0, array('pid' => 0)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function systemFolderMustHaveNoNonZeroPid() { + $this->fixture->createSystemFolder(0, array('pid' => 99999)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function systemFolderMustHaveNoZeroUid() { + $this->fixture->createSystemFolder(0, array('uid' => 0)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function systemFolderMustHaveNoNonZeroUid() { + $this->fixture->createSystemFolder(0, array('uid' => 99999)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function systemFolderMustHaveNoZeroDoktype() { + $this->fixture->createSystemFolder(0, array('doktype' => 0)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function systemFolderMustHaveNoNonZeroDoktype() { + $this->fixture->createSystemFolder(0, array('doktype' => 99999)); + } + + + // --------------------------------------------------------------------- + // Tests regarding createContentElement() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function contentElementCanBeCreated() { + $uid = $this->fixture->createContentElement(); + + $this->assertNotEquals( + 0, + $uid + ); + + $this->assertEquals( + 1, + $this->fixture->countRecords( + 'tt_content', 'uid=' . $uid + ) + ); + } + + /** + * @test + */ + public function contentElementWillBeCreatedOnRootPage() { + $uid = $this->fixture->createContentElement(); + + $this->assertNotEquals( + 0, + $uid + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'pid', + 'tt_content', + 'uid = ' . $uid + ); + + $this->assertEquals( + 0, + $row['pid'] + ); + } + + /** + * @test + */ + public function contentElementCanBeCreatedOnNonRootPage() { + $parent = $this->fixture->createSystemFolder(); + $uid = $this->fixture->createContentElement($parent); + + $this->assertNotEquals( + 0, + $uid + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'pid', + 'tt_content', + 'uid = ' . $uid + ); + + $this->assertEquals( + $parent, + $row['pid'] + ); + } + + /** + * @test + */ + public function contentElementCanBeDirty() { + $this->assertEquals( + 0, + count($this->fixture->getListOfDirtySystemTables()) + ); + $uid = $this->fixture->createContentElement(); + $this->assertNotEquals( + 0, + $uid + ); + + $this->assertNotEquals( + 0, + count($this->fixture->getListOfDirtySystemTables()) + ); + } + + /** + * @test + */ + public function contentElementWillBeCleanedUp() { + $uid = $this->fixture->createContentElement(); + $this->assertNotEquals( + 0, + $uid + ); + + $this->fixture->cleanUp(); + $this->assertEquals( + 0, + $this->fixture->countRecords( + 'tt_content', 'uid=' . $uid + ) + ); + } + + /** + * @test + */ + public function contentElementHasNoHeaderByDefault() { + $uid = $this->fixture->createContentElement(); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'header', + 'tt_content', + 'uid = ' . $uid + ); + + $this->assertEquals( + '', + $row['header'] + ); + } + + /** + * @test + */ + public function contentElementCanHaveHeader() { + $uid = $this->fixture->createContentElement( + 0, + array('header' => 'Test header') + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'header', + 'tt_content', + 'uid = ' . $uid + ); + + $this->assertEquals( + 'Test header', + $row['header'] + ); + } + + /** + * @test + */ + public function contentElementIsTextElementByDefault() { + $uid = $this->fixture->createContentElement(); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'CType', + 'tt_content', + 'uid = ' . $uid + ); + + $this->assertEquals( + 'text', + $row['CType'] + ); + } + + /** + * @test + */ + public function contentElementCanHaveOtherType() { + $uid = $this->fixture->createContentElement( + 0, + array('CType' => 'list') + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'CType', + 'tt_content', + 'uid = ' . $uid + ); + + $this->assertEquals( + 'list', + $row['CType'] + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function contentElementMustHaveNoZeroPid() { + $this->fixture->createContentElement(0, array('pid' => 0)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function contentElementMustHaveNoNonZeroPid() { + $this->fixture->createContentElement(0, array('pid' => 99999)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function contentElementMustHaveNoZeroUid() { + $this->fixture->createContentElement(0, array('uid' => 0)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function contentElementMustHaveNoNonZeroUid() { + $this->fixture->createContentElement(0, array('uid' => 99999)); + } + + + // --------------------------------------------------------------------- + // Tests regarding createTemplate() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function templateCanBeCreatedOnNonRootPage() { + $pageId = $this->fixture->createFrontEndPage(); + $uid = $this->fixture->createTemplate($pageId); + + $this->assertNotEquals( + 0, + $uid + ); + + $this->assertEquals( + 1, + $this->fixture->countRecords( + 'sys_template', 'uid=' . $uid + ) + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function templateCannotBeCreatedOnRootPage() { + $this->fixture->createTemplate(0); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function templateCannotBeCreatedWithNegativePageNumber() { + $this->fixture->createTemplate(-1); + } + + /** + * @test + */ + public function templateCanBeDirty() { + $this->assertEquals( + 0, + count($this->fixture->getListOfDirtySystemTables()) + ); + + $pageId = $this->fixture->createFrontEndPage(); + $uid = $this->fixture->createTemplate($pageId); + $this->assertNotEquals( + 0, + $uid + ); + + $this->assertNotEquals( + 0, + count($this->fixture->getListOfDirtySystemTables()) + ); + } + + /** + * @test + */ + public function templateWillBeCleanedUp() { + $pageId = $this->fixture->createFrontEndPage(); + $uid = $this->fixture->createTemplate($pageId); + $this->assertNotEquals( + 0, + $uid + ); + + $this->fixture->cleanUp(); + $this->assertEquals( + 0, + $this->fixture->countRecords( + 'sys_template', 'uid=' . $uid + ) + ); + } + + /** + * @test + */ + public function templateInitiallyHasNoConfig() { + $pageId = $this->fixture->createFrontEndPage(); + $uid = $this->fixture->createTemplate($pageId); + $row = Tx_Phpunit_Service_Database::selectSingle( + 'config', + 'sys_template', + 'uid = ' . $uid + ); + + $this->assertEquals( + '', + $row['config'] + ); + } + + /** + * @test + */ + public function templateCanHaveConfig() { + $pageId = $this->fixture->createFrontEndPage(); + $uid = $this->fixture->createTemplate( + $pageId, + array('config' => 'plugin.tx_phpunit.test = 1') + ); + $row = Tx_Phpunit_Service_Database::selectSingle( + 'config', + 'sys_template', + 'uid = ' . $uid + ); + + $this->assertEquals( + 'plugin.tx_phpunit.test = 1', + $row['config'] + ); + } + + /** + * @test + */ + public function templateInitiallyHasNoConstants() { + $pageId = $this->fixture->createFrontEndPage(); + $uid = $this->fixture->createTemplate($pageId); + $row = Tx_Phpunit_Service_Database::selectSingle( + 'constants', + 'sys_template', + 'uid = ' . $uid + ); + + $this->assertEquals( + '', + $row['constants'] + ); + } + + /** + * @test + */ + public function templateCanHaveConstants() { + $pageId = $this->fixture->createFrontEndPage(); + $uid = $this->fixture->createTemplate( + $pageId, + array('constants' => 'plugin.tx_phpunit.test = 1') + ); + $row = Tx_Phpunit_Service_Database::selectSingle( + 'constants', + 'sys_template', + 'uid = ' . $uid + ); + + $this->assertEquals( + 'plugin.tx_phpunit.test = 1', + $row['constants'] + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function templateMustNotHaveAZeroPid() { + $this->fixture->createTemplate(42, array('pid' => 0)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function templateMustNotHaveANonZeroPid() { + $this->fixture->createTemplate(42, array('pid' => 99999)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function templateMustHaveNoZeroUid() { + $this->fixture->createTemplate(42, array('uid' => 0)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function templateMustNotHaveANonZeroUid() { + $this->fixture->createTemplate(42, array('uid' => 99999)); + } + + + // --------------------------------------------------------------------- + // Tests regarding createDummyFile() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function createDummyFileCreatesFile() { + $dummyFile = $this->fixture->createDummyFile(); + + $this->assertTrue(file_exists($dummyFile)); + } + + /** + * @test + */ + public function createDummyFileCreatesFileInSubfolder() { + $dummyFolder = $this->fixture->createDummyFolder('test_folder'); + $dummyFile = $this->fixture->createDummyFile( + $this->fixture->getPathRelativeToUploadDirectory($dummyFolder) . + '/test.txt' + ); + + $this->assertTrue(file_exists($dummyFile)); + } + + /** + * @test + */ + public function createDummyFileCreatesFileWithTheProvidedContent() { + $dummyFile = $this->fixture->createDummyFile('test.txt', 'Hello world!'); + + $this->assertEquals('Hello world!', file_get_contents($dummyFile)); + } + + /** + * @test + */ + public function createDummyFileForNonExistentUploadFolderSetCreatesUploadFolder() { + $this->fixture->setUploadFolderPath(PATH_site . 'typo3temp/tx_phpunit_test/'); + $this->fixture->createDummyFile(); + + $this->assertTrue(is_dir($this->fixture->getUploadFolderPath())); + } + + /** + * @test + */ + public function createDummyFileForNonExistentUploadFolderSetCreatesFileInCreatedUploadFolder() { + $this->fixture->setUploadFolderPath(PATH_site . 'typo3temp/tx_phpunit_test/'); + $dummyFile = $this->fixture->createDummyFile(); + + $this->assertTrue(file_exists($dummyFile)); + } + + + // --------------------------------------------------------------------- + // Tests regarding createDummyZipArchive() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function createDummyZipArchiveForNoContentProvidedCreatesZipArchive() { + $this->markAsSkippedForNoZipArchive(); + + $dummyFile = $this->fixture->createDummyZipArchive(); + + $this->assertTrue(file_exists($dummyFile)); + } + + /** + * @test + */ + public function createDummyZipArchiveForFileNameInSubFolderProvidedCreatesZipArchiveInSubFolder() { + $this->markAsSkippedForNoZipArchive(); + + $this->fixture->setUploadFolderPath(PATH_site . 'typo3temp/tx_phpunit_test/'); + $dummyFolder = $this->fixture->getPathRelativeToUploadDirectory( + $this->fixture->createDummyFolder('sub-folder') + ); + $this->fixture->createDummyZipArchive($dummyFolder . 'foo.zip'); + + $this->assertTrue( + file_exists($this->fixture->getUploadFolderPath() . $dummyFolder . 'foo.zip') + ); + } + + /** + * @test + */ + public function createDummyZipArchiveForNoContentProvidedCreatesZipArchiveWithDummyFile() { + $this->markAsSkippedForNoZipArchive(); + + $this->fixture->setUploadFolderPath(PATH_site . 'typo3temp/tx_phpunit_test/'); + $dummyFile = $this->fixture->createDummyZipArchive(); + $zip = new ZipArchive(); + $zip->open($dummyFile); + $zip->extractTo($this->fixture->getUploadFolderPath()); + $zip->close(); + + $this->assertTrue( + file_exists($this->fixture->getUploadFolderPath() . 'test.txt') + ); + } + + /** + * @test + */ + public function createDummyZipArchiveForFileProvidedCreatesZipArchiveWithThatFile() { + $this->markAsSkippedForNoZipArchive(); + + $this->fixture->setUploadFolderPath(PATH_site . 'typo3temp/tx_phpunit_test/'); + $dummyFile = $this->fixture->createDummyZipArchive( + 'foo.zip', array($this->fixture->createDummyFile('bar.txt')) + ); + $zip = new ZipArchive(); + $zip->open($dummyFile); + $zip->extractTo($this->fixture->getUploadFolderPath()); + $zip->close(); + + $this->assertTrue( + file_exists($this->fixture->getUploadFolderPath() . 'bar.txt') + ); + } + + /** + * @test + */ + public function createDummyZipArchiveForFileProvidedWithContentCreatesZipArchiveWithThatFileAndContentInIt() { + $this->markAsSkippedForNoZipArchive(); + + $this->fixture->setUploadFolderPath(PATH_site . 'typo3temp/tx_phpunit_test/'); + $dummyFile = $this->fixture->createDummyZipArchive( + 'foo.zip', array($this->fixture->createDummyFile('bar.txt', 'foo bar')) + ); + $zip = new ZipArchive(); + $zip->open($dummyFile); + $zip->extractTo($this->fixture->getUploadFolderPath()); + $zip->close(); + + $this->assertEquals( + 'foo bar', + file_get_contents($this->fixture->getUploadFolderPath() . 'bar.txt') + ); + } + + /** + * @test + */ + public function createDummyZipArchiveForTwoFilesProvidedCreatesZipArchiveWithTheseFiles() { + $this->markAsSkippedForNoZipArchive(); + + $this->fixture->setUploadFolderPath(PATH_site . 'typo3temp/tx_phpunit_test/'); + $dummyFile = $this->fixture->createDummyZipArchive( + 'foo.zip', array( + $this->fixture->createDummyFile('foo.txt'), + $this->fixture->createDummyFile('bar.txt'), + ) + ); + $zip = new ZipArchive(); + $zip->open($dummyFile); + $zip->extractTo($this->fixture->getUploadFolderPath()); + $zip->close(); + + $this->assertTrue( + file_exists($this->fixture->getUploadFolderPath() . 'foo.txt') + ); + $this->assertTrue( + file_exists($this->fixture->getUploadFolderPath() . 'bar.txt') + ); + } + + /** + * @test + */ + public function createDummyZipArchiveForFileInSubFolderOfUploadFolderProvidedCreatesZipArchiveWithFileInSubFolder() { + $this->markAsSkippedForNoZipArchive(); + + $this->fixture->setUploadFolderPath(PATH_site . 'typo3temp/tx_phpunit_test/'); + $this->fixture->createDummyFolder('sub-folder'); + $dummyFile = $this->fixture->createDummyZipArchive( + 'foo.zip', array($this->fixture->createDummyFile('sub-folder/foo.txt')) + ); + $zip = new ZipArchive(); + $zip->open($dummyFile); + $zip->extractTo($this->fixture->getUploadFolderPath()); + $zip->close(); + + $this->assertTrue( + file_exists($this->fixture->getUploadFolderPath() . 'sub-folder/foo.txt') + ); + } + + /** + * @test + */ + public function createDummyZipArchiveForNonExistentUploadFolderSetCreatesUploadFolder() { + $this->markAsSkippedForNoZipArchive(); + + $this->fixture->setUploadFolderPath(PATH_site . 'typo3temp/tx_phpunit_test/'); + $this->fixture->createDummyZipArchive(); + + $this->assertTrue(is_dir($this->fixture->getUploadFolderPath())); + } + + /** + * @test + */ + public function createDummyZipArchiveForNonExistentUploadFolderSetCreatesFileInCreatedUploadFolder() { + $this->markAsSkippedForNoZipArchive(); + + $this->fixture->setUploadFolderPath(PATH_site . 'typo3temp/tx_phpunit_test/'); + $dummyFile = $this->fixture->createDummyZipArchive(); + + $this->assertTrue(file_exists($dummyFile)); + } + + + // --------------------------------------------------------------------- + // Tests regarding deleteDummyFile() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function deleteDummyFileDeletesCreatedDummyFile() { + $dummyFile = $this->fixture->createDummyFile(); + $this->fixture->deleteDummyFile(basename($dummyFile)); + + $this->assertFalse(file_exists($dummyFile)); + } + + /** + * @test + */ + public function deleteDummyFileWithAlreadyDeletedFileThrowsNoException() { + $dummyFile = $this->fixture->createDummyFile(); + unlink($dummyFile); + + $this->fixture->deleteDummyFile(basename($dummyFile)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function deleteDummyFileWithInexistentFileThrowsException() { + $uniqueFileName = $this->fixture->getUniqueFileOrFolderPath('test.txt'); + + $this->fixture->deleteDummyFile(basename($uniqueFileName)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function deleteDummyFileWithForeignFileThrowsException() { + $uniqueFileName = $this->fixture->getUniqueFileOrFolderPath('test.txt'); + t3lib_div::writeFile($uniqueFileName, ''); + $this->foreignFileToDelete = $uniqueFileName; + + $this->fixture->deleteDummyFile(basename($uniqueFileName)); + } + + + // --------------------------------------------------------------------- + // Tests regarding createDummyFolder() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function createDummyFolderCreatesFolder() { + $dummyFolder = $this->fixture->createDummyFolder('test_folder'); + + $this->assertTrue(is_dir($dummyFolder)); + } + + /** + * @test + */ + public function createDummyFolderCanCreateFolderInDummyFolder() { + $outerDummyFolder = $this->fixture->createDummyFolder('test_folder'); + $innerDummyFolder = $this->fixture->createDummyFolder( + $this->fixture->getPathRelativeToUploadDirectory($outerDummyFolder) . + '/test_folder' + ); + + $this->assertTrue(is_dir($innerDummyFolder)); + } + + /** + * @test + */ + public function createDummyFolderForNonExistentUploadFolderSetCreatesUploadFolder() { + $this->fixture->setUploadFolderPath(PATH_site . 'typo3temp/tx_phpunit_test/'); + $this->fixture->createDummyFolder('test_folder'); + + $this->assertTrue(is_dir($this->fixture->getUploadFolderPath())); + } + + /** + * @test + */ + public function createDummyFolderForNonExistentUploadFolderSetCreatesFileInCreatedUploadFolder() { + $this->fixture->setUploadFolderPath(PATH_site . 'typo3temp/tx_phpunit_test/'); + $dummyFolder = $this->fixture->createDummyFolder('test_folder'); + + $this->assertTrue(is_dir($dummyFolder)); + } + + + // --------------------------------------------------------------------- + // Tests regarding deleteDummyFolder() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function deleteDummyFolderDeletesCreatedDummyFolder() { + $dummyFolder = $this->fixture->createDummyFolder('test_folder'); + $this->fixture->deleteDummyFolder( + $this->fixture->getPathRelativeToUploadDirectory($dummyFolder) + ); + + $this->assertFalse(is_dir($dummyFolder)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function deleteDummyFolderWithInexistentFolderThrowsException() { + $uniqueFolderName = $this->fixture->getUniqueFileOrFolderPath('test_folder'); + + $this->fixture->deleteDummyFolder( + $this->fixture->getPathRelativeToUploadDirectory($uniqueFolderName) + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function deleteDummyFolderWithForeignFolderThrowsException() { + $uniqueFolderName = $this->fixture->getUniqueFileOrFolderPath('test_folder'); + t3lib_div::mkdir($uniqueFolderName); + $this->foreignFolderToDelete = $uniqueFolderName; + + $this->fixture->deleteDummyFolder(basename($uniqueFolderName)); + } + + /** + * @test + */ + public function deleteDummyFolderCanDeleteCreatedDummyFolderInDummyFolder() { + $outerDummyFolder = $this->fixture->createDummyFolder('test_folder'); + $innerDummyFolder = $this->fixture->createDummyFolder( + $this->fixture->getPathRelativeToUploadDirectory($outerDummyFolder) . + '/test_folder' + ); + + $this->fixture->deleteDummyFolder( + $this->fixture->getPathRelativeToUploadDirectory($innerDummyFolder) + ); + + $this->assertFalse(file_exists($innerDummyFolder)); + $this->assertTrue(file_exists($outerDummyFolder)); + } + + /** + * @test + * + * @expectedException t3lib_exception + */ + public function deleteDummyFolderWithNonEmptyDummyFolderThrowsException() { + $dummyFolder = $this->fixture->createDummyFolder('test_folder'); + $this->fixture->createDummyFile( + $this->fixture->getPathRelativeToUploadDirectory($dummyFolder) . + '/test.txt' + ); + + $this->fixture->deleteDummyFolder( + $this->fixture->getPathRelativeToUploadDirectory($dummyFolder) + ); + } + + /** + * @test + */ + public function deleteDummyFolderWithFolderNameConsistingOnlyOfNumbersDoesNotThrowAnException() { + $dummyFolder = $this->fixture->createDummyFolder('123'); + + $this->fixture->deleteDummyFolder( + $this->fixture->getPathRelativeToUploadDirectory($dummyFolder) + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding set- and getUploadFolderPath() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function getUploadFolderPathReturnsUploadFolderPathIncludingTablePrefix() { + $this->assertRegExp( + '/\/uploads\/tx_phpunit\/$/', + $this->fixture->getUploadFolderPath() + ); + } + + /** + * @test + */ + public function getUploadFolderPathAfterSetReturnsSetUploadFolderPath() { + $this->fixture->setUploadFolderPath('/foo/bar/'); + + $this->assertEquals( + '/foo/bar/', + $this->fixture->getUploadFolderPath() + ); + } + + /** + * @test + * + * @expectedException t3lib_exception + */ + public function setUploadFolderPathAfterCreatingADummyFileThrowsException() { + $this->fixture->createDummyFile(); + $this->fixture->setUploadFolderPath('/foo/bar/'); + } + + + // --------------------------------------------------------------------- + // Tests regarding getPathRelativeToUploadDirectory() + // --------------------------------------------------------------------- + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function getPathRelativeToUploadDirectoryWithPathOutsideUploadDirectoryThrowsException() { + $this->fixture->getPathRelativeToUploadDirectory(PATH_site); + } + + + // --------------------------------------------------------------------- + // Tests regarding getUniqueFileOrFolderPath() + // --------------------------------------------------------------------- + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function getUniqueFileOrFolderPathWithEmptyPathThrowsException() { + $this->fixture->getUniqueFileOrFolderPath(''); + } + + + // --------------------------------------------------------------------- + // Tests regarding createFrontEndUserGroup() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function frontEndUserGroupCanBeCreated() { + $uid = $this->fixture->createFrontEndUserGroup(); + + $this->assertNotEquals( + 0, + $uid + ); + + $this->assertEquals( + 1, + $this->fixture->countRecords( + 'fe_groups', 'uid=' . $uid + ) + ); + } + + /** + * @test + */ + public function frontEndUserGroupTableCanBeDirty() { + $this->assertEquals( + 0, + count($this->fixture->getListOfDirtySystemTables()) + ); + $uid = $this->fixture->createFrontEndUserGroup(); + $this->assertNotEquals( + 0, + $uid + ); + + $this->assertNotEquals( + 0, + count($this->fixture->getListOfDirtySystemTables()) + ); + } + + /** + * @test + */ + public function frontEndUserGroupTableWillBeCleanedUp() { + $uid = $this->fixture->createFrontEndUserGroup(); + $this->assertNotEquals( + 0, + $uid + ); + + $this->fixture->cleanUp(); + $this->assertEquals( + 0, + $this->fixture->countRecords( + 'fe_groups', 'uid=' . $uid + ) + ); + } + + /** + * @test + */ + public function frontEndUserGroupHasNoTitleByDefault() { + $uid = $this->fixture->createFrontEndUserGroup(); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'title', + 'fe_groups', + 'uid = ' . $uid + ); + + $this->assertEquals( + '', + $row['title'] + ); + } + + /** + * @test + */ + public function frontEndUserGroupCanHaveATitle() { + $uid = $this->fixture->createFrontEndUserGroup( + array('title' => 'Test title') + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'title', + 'fe_groups', + 'uid = ' . $uid + ); + + $this->assertEquals( + 'Test title', + $row['title'] + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function frontEndUserGroupMustHaveNoZeroUid() { + $this->fixture->createFrontEndUserGroup(array('uid' => 0)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function frontEndUserGroupMustHaveNoNonZeroUid() { + $this->fixture->createFrontEndUserGroup(array('uid' => 99999)); + } + + + // --------------------------------------------------------------------- + // Tests regarding createFrontEndUser() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function frontEndUserCanBeCreated() { + $uid = $this->fixture->createFrontEndUser(); + + $this->assertNotEquals( + 0, + $uid + ); + + $this->assertEquals( + 1, + $this->fixture->countRecords( + 'fe_users', 'uid=' . $uid + ) + ); + } + + /** + * @test + */ + public function frontEndUserTableCanBeDirty() { + $this->assertEquals( + 0, + count($this->fixture->getListOfDirtySystemTables()) + ); + $uid = $this->fixture->createFrontEndUser(); + $this->assertNotEquals( + 0, + $uid + ); + + $this->greaterThan( + 1, + count($this->fixture->getListOfDirtySystemTables()) + ); + } + + /** + * @test + */ + public function frontEndUserTableWillBeCleanedUp() { + $uid = $this->fixture->createFrontEndUser(); + $this->assertNotEquals( + 0, + $uid + ); + + $this->fixture->cleanUp(); + $this->assertEquals( + 0, + $this->fixture->countRecords( + 'fe_users', 'uid=' . $uid + ) + ); + } + + /** + * @test + */ + public function frontEndUserHasNoUserNameByDefault() { + $uid = $this->fixture->createFrontEndUser(); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'username', + 'fe_users', + 'uid = ' . $uid + ); + + $this->assertEquals( + '', + $row['username'] + ); + } + + /** + * @test + */ + public function frontEndUserCanHaveAUserName() { + $uid = $this->fixture->createFrontEndUser( + '', + array('username' => 'Test name') + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'username', + 'fe_users', + 'uid = ' . $uid + ); + + $this->assertEquals( + 'Test name', + $row['username'] + ); + } + + /** + * @test + */ + public function frontEndUserCanHaveSeveralUserGroups() { + $feUserGroupUidOne = $this->fixture->createFrontEndUserGroup(); + $feUserGroupUidTwo = $this->fixture->createFrontEndUserGroup(); + $feUserGroupUidThree = $this->fixture->createFrontEndUserGroup(); + $uid = $this->fixture->createFrontEndUser( + $feUserGroupUidOne.', '.$feUserGroupUidTwo.', '.$feUserGroupUidThree + ); + + $this->assertNotEquals( + 0, + $uid + ); + + $this->assertEquals( + 1, + $this->fixture->countRecords( + 'fe_users', 'uid=' . $uid + ) + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function frontEndUserMustHaveNoZeroUid() { + $this->fixture->createFrontEndUser('', array('uid' => 0)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function frontEndUserMustHaveNoNonZeroUid() { + $this->fixture->createFrontEndUser('', array('uid' => 99999)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function frontEndUserMustHaveNoZeroUserGroupInTheDataArray() { + $this->fixture->createFrontEndUser('', array('usergroup' => 0)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function frontEndUserMustHaveNoNonZeroUserGroupInTheDataArray() { + $this->fixture->createFrontEndUser('', array('usergroup' => 99999)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function frontEndUserMustHaveNoUserGroupListInTheDataArray() { + $this->fixture->createFrontEndUser( + '', array('usergroup' => '1,2,4,5') + ); + } + + /** + * @test + */ + public function createFrontEndUserWithEmptyGroupCreatesGroup() { + $this->fixture->createFrontEndUser(''); + + $this->assertTrue( + $this->fixture->existsExactlyOneRecord('fe_groups') + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function frontEndUserMustHaveNoZeroUserGroupEvenIfSeveralGroupsAreProvided() { + $feUserGroupUidOne = $this->fixture->createFrontEndUserGroup(); + $feUserGroupUidTwo = $this->fixture->createFrontEndUserGroup(); + $feUserGroupUidThree = $this->fixture->createFrontEndUserGroup(); + + $this->fixture->createFrontEndUser( + $feUserGroupUidOne.', '.$feUserGroupUidTwo.', 0, '.$feUserGroupUidThree + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function frontEndUserMustHaveNoAlphabeticalCharactersInTheUserGroupList() { + $feUserGroupUid = $this->fixture->createFrontEndUserGroup(); + + $this->fixture->createFrontEndUser( + $feUserGroupUid.', abc' + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding createBackEndUser() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function createBackEndUserReturnsUidGreaterZero() { + $this->assertNotEquals( + 0, + $this->fixture->createBackEndUser() + ); + } + + /** + * @test + */ + public function createBackEndUserCreatesBackEndUserRecordInTheDatabase() { + $this->assertEquals( + 1, + $this->fixture->countRecords( + 'be_users', 'uid=' . $this->fixture->createBackEndUser() + ) + ); + } + + /** + * @test + */ + public function createBackEndUserMarksBackEndUserTableAsDirty() { + $this->assertEquals( + 0, + count($this->fixture->getListOfDirtySystemTables()) + ); + $this->fixture->createBackEndUser(); + + $this->greaterThan( + 1, + count($this->fixture->getListOfDirtySystemTables()) + ); + } + + /** + * @test + */ + public function cleanUpCleansUpDirtyBackEndUserTable() { + $uid = $this->fixture->createBackEndUser(); + + $this->fixture->cleanUp(); + $this->assertEquals( + 0, + $this->fixture->countRecords('be_users', 'uid=' . $uid) + ); + } + + /** + * @test + */ + public function createBackEndUserCreatesRecordWithoutUserNameByDefault() { + $uid = $this->fixture->createBackEndUser(); + + $row = Tx_Phpunit_Service_Database::selectSingle('username', 'be_users', 'uid = ' . $uid); + + $this->assertEquals( + '', + $row['username'] + ); + } + + /** + * @test + */ + public function createBackEndUserForUserNameProvidedCreatesRecordWithUserName() { + $uid = $this->fixture->createBackEndUser(array('username' => 'Test name')); + + $row = Tx_Phpunit_Service_Database::selectSingle('username', 'be_users', 'uid = ' . $uid); + + $this->assertEquals( + 'Test name', + $row['username'] + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function createBackEndUserWithZeroUidProvidedInRecordDataThrowsExeption() { + $this->fixture->createBackEndUser(array('uid' => 0)); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function createBackEndUserWithNonZeroUidProvidedInRecordDataThrowsExeption() { + $this->fixture->createBackEndUser(array('uid' => 999999)); + } + + + // --------------------------------------------------------------------- + // Tests concerning fakeFrontend + // --------------------------------------------------------------------- + + /** + * @test + */ + public function createFakeFrontEndCreatesGlobalFrontEnd() { + $GLOBALS['TSFE'] = NULL; + $this->fixture->createFakeFrontEnd(); + + $this->assertTrue( + $GLOBALS['TSFE'] instanceof tslib_fe + ); + } + + /** + * @test + */ + public function createFakeFrontEndReturnsPositivePageUidIfCalledWithoutParameters() { + $this->assertGreaterThan( + 0, + $this->fixture->createFakeFrontEnd() + ); + } + + /** + * @test + */ + public function createFakeFrontEndReturnsCurrentFrontEndPageUid() { + $GLOBALS['TSFE'] = NULL; + $result = $this->fixture->createFakeFrontEnd(); + + $this->assertEquals( + $GLOBALS['TSFE']->id, + $result + ); + } + + /** + * @test + */ + public function createFakeFrontEndCreatesNullTimeTrackInstance() { + $GLOBALS['TT'] = NULL; + $this->fixture->createFakeFrontEnd(); + + $this->assertTrue( + $GLOBALS['TT'] instanceof t3lib_timeTrackNull + ); + } + + /** + * @test + */ + public function createFakeFrontEndCreatesSysPage() { + $GLOBALS['TSFE'] = NULL; + $this->fixture->createFakeFrontEnd(); + + $this->assertTrue( + $GLOBALS['TSFE']->sys_page instanceof t3lib_pageSelect + ); + } + + /** + * @test + */ + public function createFakeFrontEndCreatesFrontEndUser() { + $GLOBALS['TSFE'] = NULL; + $this->fixture->createFakeFrontEnd(); + + $this->assertTrue( + $GLOBALS['TSFE']->fe_user instanceof tslib_feUserAuth + ); + } + + /** + * @test + */ + public function createFakeFrontEndCreatesContentObject() { + $GLOBALS['TSFE'] = NULL; + $this->fixture->createFakeFrontEnd(); + + $this->assertTrue( + $GLOBALS['TSFE']->cObj instanceof tslib_cObj + ); + } + + /** + * @test + */ + public function createFakeFrontEndCreatesTemplate() { + $GLOBALS['TSFE'] = NULL; + $this->fixture->createFakeFrontEnd(); + + $this->assertTrue( + $GLOBALS['TSFE']->tmpl instanceof t3lib_TStemplate + ); + } + + /** + * @test + */ + public function createFakeFrontEndReadsTypoScriptSetupFromPage() { + $pageUid = $this->fixture->createFrontEndPage(); + $this->fixture->createTemplate( + $pageUid, + array('config' => 'foo = 42') + ); + + $this->fixture->createFakeFrontEnd($pageUid); + + $this->assertEquals( + 42, + $GLOBALS['TSFE']->tmpl->setup['foo'] + ); + } + + /** + * @test + */ + public function createFakeFrontEndWithTemplateRecordMarksTemplateAsLoaded() { + $pageUid = $this->fixture->createFrontEndPage(); + $this->fixture->createTemplate( + $pageUid, + array('config' => 'foo = 42') + ); + + $this->fixture->createFakeFrontEnd($pageUid); + + $this->assertEquals( + 1, + $GLOBALS['TSFE']->tmpl->loaded + ); + } + + /** + * @test + */ + public function createFakeFrontEndCreatesConfiguration() { + $GLOBALS['TSFE'] = NULL; + $this->fixture->createFakeFrontEnd(); + + $this->assertTrue( + is_array($GLOBALS['TSFE']->config) + ); + } + + /** + * @test + */ + public function loginUserIsZeroAfterCreateFakeFrontEnd() { + $this->fixture->createFakeFrontEnd(); + + $this->assertEquals( + 0, + $GLOBALS['TSFE']->loginUser + ); + } + + /** + * @test + */ + public function createFakeFrontEndSetsDefaultGroupList() { + $this->fixture->createFakeFrontEnd(); + + $this->assertEquals( + '0,-1', + $GLOBALS['TSFE']->gr_list + ); + } + + /** + * @test + */ + public function discardFakeFrontEndNullsOutGlobalFrontEnd() { + $this->fixture->createFakeFrontEnd(); + $this->fixture->discardFakeFrontEnd(); + + $this->assertNull( + $GLOBALS['TSFE'] + ); + } + + /** + * @test + */ + public function discardFakeFrontEndNullsOutGlobalTimeTrack() { + $this->fixture->createFakeFrontEnd(); + $this->fixture->discardFakeFrontEnd(); + + $this->assertNull( + $GLOBALS['TT'] + ); + } + + /** + * @test + */ + public function discardFakeFrontEndCanBeCalledTwoTimesInARow() { + $this->fixture->discardFakeFrontEnd(); + $this->fixture->discardFakeFrontEnd(); + } + + /** + * @test + */ + public function hasFakeFrontEndInitiallyIsFalse() { + $this->assertFalse( + $this->fixture->hasFakeFrontEnd() + ); + } + + /** + * @test + */ + public function hasFakeFrontEndIsTrueAfterCreateFakeFrontEnd() { + $this->fixture->createFakeFrontEnd(); + + $this->assertTrue( + $this->fixture->hasFakeFrontEnd() + ); + } + + /** + * @test + */ + public function hasFakeFrontEndIsFalseAfterCreateAndDiscardFakeFrontEnd() { + $this->fixture->createFakeFrontEnd(); + $this->fixture->discardFakeFrontEnd(); + + $this->assertFalse( + $this->fixture->hasFakeFrontEnd() + ); + } + + /** + * @test + */ + public function cleanUpDiscardsFakeFrontEnd() { + $this->fixture->createFakeFrontEnd(); + $this->fixture->cleanUp(); + + $this->assertFalse( + $this->fixture->hasFakeFrontEnd() + ); + } + + /** + * @test + */ + public function createFakeFrontEndReturnsProvidedPageUid() { + $pageUid = $this->fixture->createFrontEndPage(); + + $this->assertEquals( + $pageUid, + $this->fixture->createFakeFrontEnd($pageUid) + ); + } + + /** + * @test + */ + public function createFakeFrontEndUsesProvidedPageUidAsFrontEndId() { + $pageUid = $this->fixture->createFrontEndPage(); + $this->fixture->createFakeFrontEnd($pageUid); + + $this->assertEquals( + $pageUid, + $GLOBALS['TSFE']->id + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function createFakeFrontThrowsExceptionForNegativePageUid() { + $this->fixture->createFakeFrontEnd(-1); + } + + // Note: In the unit tests, the src attribute of the generated image tag + // will be empty because the IMAGE handles does not accept absolute paths + // and handles relative paths and EXT: paths inconsistently: + // + // It correctly resolves paths which are relative to the TYPO3 document + // root, but then calls t3lib_stdGraphic::getImageDimensions (which is + // inherited by tslib_gifBuilder) which again uses the relative path. So + // IMAGE will use the path to the TYPO3 root (which is the same as relative + // to the FE index.php), but getImageDimensions use the path relative to the + // executed script which is the FE index.php or the PHPUnit BE module + // index.php. This results getImageDimensions not returning anything useful. + /** + * @test + */ + public function fakeFrontEndCObjImageCreatesImageTagForExistingImageFile() { + $this->fixture->createFakeFrontEnd(); + + $this->assertContains( + '<img ', + $GLOBALS['TSFE']->cObj->IMAGE( + array('file' => 'typo3conf/ext/phpunit/Tests/Fixtures/test.png') + ) + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding user login and logout + // --------------------------------------------------------------------- + + /** + * @test + */ + public function isLoggedInInitiallyIsFalse() { + $this->fixture->createFakeFrontEnd(); + + $this->assertFalse( + $this->fixture->isLoggedIn() + ); + } + + /** + * @test + * + * @expectedException t3lib_exception + */ + public function isLoggedThrowsExceptionWithoutFrontEnd() { + $this->fixture->isLoggedIn(); + } + + /** + * @test + */ + public function loginFrontEndUserSwitchesToLoggedIn() { + $this->fixture->createFakeFrontEnd(); + + $feUserId = $this->fixture->createFrontEndUser(); + $this->fixture->loginFrontEndUser($feUserId); + + $this->assertTrue( + $this->fixture->isLoggedIn() + ); + } + + /** + * @test + */ + public function loginFrontEndUserSwitchesLoginManagerToLoggedIn() { + $this->fixture->createFakeFrontEnd(); + + $feUserId = $this->fixture->createFrontEndUser(); + $this->fixture->loginFrontEndUser($feUserId); + + $this->assertTrue( + $this->fixture->isLoggedIn() + ); + } + + /** + * @test + */ + public function loginFrontEndUserSetsLoginUserToOne() { + $this->fixture->createFakeFrontEnd(); + + $feUserId = $this->fixture->createFrontEndUser(); + $this->fixture->loginFrontEndUser($feUserId); + + $this->assertEquals( + 1, + $GLOBALS['TSFE']->loginUser + ); + } + + /** + * @test + */ + public function loginFrontEndUserRetrievesNameOfUser() { + $this->fixture->createFakeFrontEnd(); + + $feUserId = $this->fixture->createFrontEndUser( + '', array('name' => 'John Doe') + ); + $this->fixture->loginFrontEndUser($feUserId); + + $this->assertEquals( + 'John Doe', + $GLOBALS['TSFE']->fe_user->user['name'] + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function loginFrontEndUserWithZeroUidThrowsException() { + $this->fixture->createFakeFrontEnd(); + + $this->fixture->loginFrontEndUser(0); + } + + /** + * @test + * + * @expectedException t3lib_exception + */ + public function loginFrontEndUserWithoutFrontEndThrowsException() { + $feUserId = $this->fixture->createFrontEndUser(); + $this->fixture->loginFrontEndUser($feUserId); + } + + /** + * @test + */ + public function loginFrontEndUserSetsGroupDataOfUser() { + $this->fixture->createFakeFrontEnd(); + + $feUserGroupUid = $this->fixture->createFrontEndUserGroup( + array('title' => 'foo') + ); + $feUserId = $this->fixture->createFrontEndUser($feUserGroupUid); + $this->fixture->loginFrontEndUser($feUserId); + + $this->assertEquals( + array($feUserGroupUid => 'foo'), + $GLOBALS['TSFE']->fe_user->groupData['title'] + ); + } + + /** + * @test + */ + public function logoutFrontEndUserAfterLoginSwitchesToNotLoggedIn() { + $this->fixture->createFakeFrontEnd(); + + $feUserId = $this->fixture->createFrontEndUser(); + $this->fixture->loginFrontEndUser($feUserId); + $this->fixture->logoutFrontEndUser(); + + $this->assertFalse( + $this->fixture->isLoggedIn() + ); + } + + /** + * @test + */ + public function logoutFrontEndUserAfterLoginSwitchesLoginManagerToNotLoggedIn() { + $this->fixture->createFakeFrontEnd(); + + $feUserId = $this->fixture->createFrontEndUser(); + $this->fixture->loginFrontEndUser($feUserId); + $this->fixture->logoutFrontEndUser(); + + $this->assertFalse( + $this->fixture->isLoggedIn() + ); + } + + /** + * @test + */ + public function logoutFrontEndUserSetsLoginUserToZero() { + $this->fixture->createFakeFrontEnd(); + + $this->fixture->logoutFrontEndUser(); + + $this->assertEquals( + 0, + $GLOBALS['TSFE']->loginUser + ); + } + + /** + * @test + * + * @expectedException t3lib_exception + */ + public function logoutFrontEndUserWithoutFrontEndThrowsException() { + $this->fixture->logoutFrontEndUser(); + } + + /** + * @test + */ + public function logoutFrontEndUserCanBeCalledTwoTimesInARow() { + $this->fixture->createFakeFrontEnd(); + + $this->fixture->logoutFrontEndUser(); + $this->fixture->logoutFrontEndUser(); + } + + /** + * @test + */ + public function createAndLogInFrontEndUserCreatesFrontEndUser() { + $this->fixture->createFakeFrontEnd(); + $this->fixture->createAndLogInFrontEndUser(); + + $this->assertEquals( + 1, + $this->fixture->countRecords('fe_users') + ); + } + + /** + * @test + */ + public function createAndLogInFrontEndUserWithRecordDataCreatesFrontEndUserWithThatData() { + $this->fixture->createFakeFrontEnd(); + $this->fixture->createAndLogInFrontEndUser( + '', array('name' => 'John Doe') + ); + + $this->assertEquals( + 1, + $this->fixture->countRecords('fe_users', 'name = "John Doe"') + ); + } + + /** + * @test + */ + public function createAndLogInFrontEndUserLogsInFrontEndUser() { + $this->fixture->createFakeFrontEnd(); + $this->fixture->createAndLogInFrontEndUser(); + + $this->assertTrue( + $this->fixture->isLoggedIn() + ); + } + + /** + * @test + */ + public function createAndLogInFrontEndUserWithFrontEndUserGroupCreatesFrontEndUser() { + $this->fixture->createFakeFrontEnd(); + $frontEndUserGroupUid = $this->fixture->createFrontEndUserGroup(); + $this->fixture->createAndLogInFrontEndUser($frontEndUserGroupUid); + + $this->assertEquals( + 1, + $this->fixture->countRecords('fe_users') + ); + } + + /** + * @test + */ + public function createAndLogInFrontEndUserWithFrontEndUserGroupCreatesFrontEndUserWithGivenGroup() { + $this->fixture->createFakeFrontEnd(); + $frontEndUserGroupUid = $this->fixture->createFrontEndUserGroup(); + $frontEndUserUid = $this->fixture->createAndLogInFrontEndUser( + $frontEndUserGroupUid + ); + + $dbResultRow = Tx_Phpunit_Service_Database::selectSingle( + 'usergroup', + 'fe_users', + 'uid = ' . $frontEndUserUid + ); + + $this->assertEquals( + $frontEndUserGroupUid, + $dbResultRow['usergroup'] + ); + } + + /** + * @test + */ + public function createAndLogInFrontEndUserWithFrontEndUserGroupDoesNotCreateAFrontEndUserGroup() { + $this->fixture->createFakeFrontEnd(); + $frontEndUserGroupUid = $this->fixture->createFrontEndUserGroup(); + $this->fixture->createAndLogInFrontEndUser( + $frontEndUserGroupUid + ); + + $this->assertEquals( + 1, + $this->fixture->countRecords('fe_groups') + ); + } + + /** + * @test + */ + public function createAndLogInFrontEndUserWithFrontEndUserGroupLogsInFrontEndUser() { + $this->fixture->createFakeFrontEnd(); + $frontEndUserGroupUid = $this->fixture->createFrontEndUserGroup(); + $this->fixture->createAndLogInFrontEndUser($frontEndUserGroupUid); + + $this->assertTrue( + $this->fixture->isLoggedIn() + ); + } + + + // --------------------------------------------------------------------- + // Tests regarding increaseRelationCounter() + // --------------------------------------------------------------------- + + /** + * @test + */ + public function increaseRelationCounterIncreasesNonZeroFieldValueByOne() { + $uid = $this->fixture->createRecord( + 'tx_phpunit_test', + array('related_records' => 41) + ); + + $this->fixture->increaseRelationCounter( + 'tx_phpunit_test', + $uid, + 'related_records' + ); + + $row = Tx_Phpunit_Service_Database::selectSingle( + 'related_records', + 'tx_phpunit_test', + 'uid = ' . $uid + ); + + $this->assertEquals( + 42, + $row['related_records'] + ); + } + + /** + * @test + * + * @expectedException Tx_Phpunit_Exception_Database + */ + public function increaseRelationCounterThrowsExceptionOnInvalidUid() { + $uid = $this->fixture->createRecord('tx_phpunit_test'); + $invalidUid = $uid + 1; + + $this->fixture->increaseRelationCounter( + 'tx_phpunit_test', + $invalidUid, + 'related_records' + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function increaseRelationCounterThrowsExceptionOnInvalidTableName() { + $uid = $this->fixture->createRecord('tx_phpunit_test'); + + $this->fixture->increaseRelationCounter( + 'tx_phpunit_inexistent', + $uid, + 'related_records' + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function increaseRelationCounterThrowsExceptionOnInexistentFieldName() { + $uid = $this->fixture->createRecord('tx_phpunit_test'); + $this->fixture->increaseRelationCounter( + 'tx_phpunit_test', + $uid, + 'inexistent_column' + ); + } + + /** + * @test + */ + public function getDummyColumnNameForExtensionTableReturnsDummyColumnName() { + $this->assertEquals( + 'is_dummy_record', + $this->fixture->getDummyColumnName('tx_phpunit_test') + ); + } + + /** + * @test + */ + public function getDummyColumnNameForSystemTableReturnsPhpUnitPrefixedColumnName() { + $this->assertEquals( + 'tx_phpunit_is_dummy_record', + $this->fixture->getDummyColumnName('fe_users') + ); + } + + /** + * @test + */ + public function getDummyColumnNameForThirdPartyExtensionTableReturnsPrefixedColumnName() { + $testingFramework = new Tx_Phpunit_Framework( + 'user_phpunittest', array('user_phpunittest2') + ); + $this->assertEquals( + 'user_phpunittest_is_dummy_record', + $testingFramework->getDummyColumnName('user_phpunittest2_test') + ); + } + + + //////////////////////////////////////////// + // Tests concerning createBackEndUserGroup + //////////////////////////////////////////// + + /** + * @test + */ + public function createBackEndUserGroupForNoDataGivenCreatesBackEndGroup() { + $this->fixture->createBackEndUserGroup(array()); + + $this->assertTrue( + $this->fixture->existsRecord('be_groups') + ); + } + + /** + * @test + */ + public function createBackEndUserGroupForNoDataGivenReturnsUidOfCreatedBackEndGroup() { + $backendGroupUid = $this->fixture->createBackEndUserGroup(array()); + + $this->assertTrue( + $this->fixture->existsRecord( + 'be_groups', 'uid = ' . $backendGroupUid + ) + ); + } + + /** + * @test + */ + public function createBackEndUserGroupForTitleGivenStoresTitleInGroupRecord() { + $this->fixture->createBackEndUserGroup( + array('title' => 'foo group') + ); + + $this->assertTrue( + $this->fixture->existsRecord( + 'be_groups', 'title = "foo group"' + ) + ); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Selenium/TestCaseTest.php b/typo3conf/ext/phpunit/Tests/Selenium/TestCaseTest.php new file mode 100644 index 0000000..37b93f9 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Selenium/TestCaseTest.php @@ -0,0 +1,265 @@ +<?php +/*************************************************************** + * Copyright notice + * + * (c) 2011 Carsten Koenig (ck@carsten-koenig.de) + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/** + * Test case for the Tx_Phpunit_Selenium_TestCase class. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Carsten Koenig <ck@carsten-koenig.de> + * @author Oliver Klee <typo3-coding@oliverklee.de> + */ +class Tx_Phpunit_Selenium_TestCaseTest extends Tx_Phpunit_TestCase { + /** + * Temporary backup for the global phpunit extension configuration during tests + * + * @var array + */ + protected $backupGlobalPhpunitConfiguration = array(); + + /** + * @var Tx_Phpunit_Selenium_TestCase + */ + private $fixture = NULL; + + protected function setUp() { + $this->backupGlobalPhpunitConfiguration = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']; + + $this->fixture = $this->getMock( + $this->createAccessibleProxyClass(), array('isSeleniumServerRunning') + ); + $this->fixture->expects($this->any())->method('isSeleniumServerRunning')->will($this->returnValue(TRUE)); + } + + protected function tearDown() { + unset($this->fixture); + + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit'] = $this->backupGlobalPhpunitConfiguration; + } + + /* + * Utitlity functions + */ + + /** + * This function creates a subclass of Tx_Phpunit_Selenium_TestCase with + * some attributes and methods made public. + * + * @return string class name, will not be empty + */ + private function createAccessibleProxyClass() { + $className = uniqid('Tx_Phpunit_Selenium_AccessibleTestCase'); + + if (!class_exists($className, FALSE)) { + eval( + 'class ' . $className . ' extends Tx_Phpunit_Selenium_TestCase {' . + ' ' . + ' public function getSeleniumBrowser() {' . + ' return parent::getSeleniumBrowser();' . + ' }' . + ' public function getSeleniumBrowserUrl() {' . + ' return parent::getSeleniumBrowserUrl();' . + ' }' . + ' public function getSeleniumHost() {' . + ' return parent::getSeleniumHost();' . + ' }' . + ' public function getSeleniumPort() {' . + ' return parent::getSeleniumPort();' . + ' }' . + ' public function isSeleniumServerRunning() {' . + ' return parent::isSeleniumServerRunning();' . + ' }' . + ' public function runTest() {' . + ' parent::runTest();' . + ' }' . + '}' + ); + } + + return $className; + } + + + /* + * Tests for the utitility functions + */ + + /** + * @test + */ + public function createAccessibleProxyClassReturnsFixtureSubclassName() { + $className = $this->createAccessibleProxyClass(); + + $this->assertInstanceOf( + 'Tx_Phpunit_Selenium_TestCase', + new $className() + ); + } + + /* + * Unit tests + */ + + /** + * @test + */ + public function getSeleniumBrowserUrlForConfiguredBrowserUrlReturnsConfiguredUrl() { + $url = 'http://example.com/'; + + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_browserurl'] = $url; + + $this->assertSame( + $url, + $this->fixture->getSeleniumBrowserUrl() + ); + } + + /** + * @test + */ + public function getSeleniumBrowserUrlForNoConfiguredBrowserUrlReturnsDefaultUrl() { + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_browserurl'] = ''; + + $expected = rtrim( + t3lib_div::getIndpEnv('TYPO3_SITE_URL'), + Tx_Phpunit_Selenium_TestCase::DEFAULT_SELENIUM_BROWSER_URL + ); + + $this->assertSame( + $expected, + $this->fixture->getSeleniumBrowserUrl() + ); + } + + /** + * @test + */ + public function getSeleniumBrowserForConfiguredBrowserReturnsConfiguredBrowser() { + $browser = '*firefox'; + + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_browser'] = $browser; + + $this->assertSame( + $browser, + $this->fixture->getSeleniumBrowser() + ); + } + + /** + * @test + */ + public function getSeleniumBrowserForNoConfiguredBrowserReturnsDefaultBrowser() { + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_browser'] = ''; + + $this->assertSame( + Tx_Phpunit_Selenium_TestCase::DEFAULT_SELENIUM_BROWSER, + $this->fixture->getSeleniumBrowser() + ); + } + + /** + * @test + */ + public function getSeleniumPortForConfiguredPortReturnsConfiguredPort() { + $port = 1234; + + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_port'] = $port; + + $this->assertSame( + $port, + $this->fixture->getSeleniumPort() + ); + } + + /** + * @test + */ + public function getSeleniumPortForNoConfiguredPortReturnsDefaultPort() { + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_port'] = 0; + + $this->assertSame( + Tx_Phpunit_Selenium_TestCase::DEFAULT_SELENIUM_PORT, + $this->fixture->getSeleniumPort() + ); + } + + /** + * @test + */ + public function getSeleniumHostForConfiguredHostReturnsConfiguredHost() { + $host = 'http://example.com/'; + + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_host'] = $host; + + $this->assertSame( + $host, + $this->fixture->getSeleniumHost() + ); + } + + /** + * @test + */ + public function getSeleniumHostForNotConfiguredHostReturnsTheDefaultHost() { + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_host'] = ''; + + $this->assertSame( + Tx_Phpunit_Selenium_TestCase::DEFAULT_SELENIUM_HOST, + $this->fixture->getSeleniumHost() + ); + } + + /** + * @test + */ + public function isSeleniumServerRunningWhenHostIsInvalidReturnsFalse() { + // We will use 'example.invalid' as an invalid host + // (according to RFC 2606 the TLD '.invalid' should be used to test for invalid hosts). + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_host'] = 'http://example.invalid'; + + $className = $this->createAccessibleProxyClass(); + $fixture = new $className(); + + $this->assertFalse( + $fixture->isSeleniumServerRunning() + ); + } + + /** + * @test + */ + public function runTestWhenServerIsNotRunningMarksTestAsSkipped() { + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['selenium_host'] = 'http://example.invalid'; + + $fixture = new Tx_Phpunit_Selenium_TestCase(); + + try { + $fixture->runTest(); + } catch (PHPUnit_Framework_SkippedTestError $e) { + $this->assertTrue(TRUE); + } + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Service/DatabaseTest.php b/typo3conf/ext/phpunit/Tests/Service/DatabaseTest.php new file mode 100644 index 0000000..2217efd --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Service/DatabaseTest.php @@ -0,0 +1,1519 @@ +<?php +/*************************************************************** + * Copyright notice + * + * (c) 2008-2011 Oliver Klee (typo3-coding@oliverklee.de) + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/** + * Testcase for the Tx_Phpunit_Service_Database class in the "phpunit" extension. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Oliver Klee <typo3-coding@oliverklee.de> + */ +class Tx_Phpunit_Service_DatabaseTest extends tx_phpunit_testcase { + /** + * @var Tx_Phpunit_Framework + */ + private $testingFramework; + + public function setUp() { + $this->testingFramework = new Tx_Phpunit_Framework('tx_phpunit'); + } + + public function tearDown() { + $this->testingFramework->cleanUp(); + + unset($this->testingFramework); + } + + + ////////////////////// + // Utility functions + ////////////////////// + + /** + * Explodes a comma-separated list of integer values and sorts them + * numerically. + * + * @param string comma-separated list of values, may be empty + * + * @return array the separate values, sorted numerically, may be empty + */ + private function sortExplode($valueList) { + if ($valueList == '') { + return array(); + } + + $numbers = t3lib_div::intExplode(',', $valueList); + sort($numbers, SORT_NUMERIC); + + return ($numbers); + } + + + //////////////////////////////////// + // Tests for the utility functions + //////////////////////////////////// + + /** + * @test + */ + public function sortExplodeWithEmptyStringReturnsEmptyArray() { + $this->assertEquals( + array(), + $this->sortExplode('') + ); + } + + /** + * @test + */ + public function sortExplodeWithOneNumberReturnsArrayWithNumber() { + $this->assertEquals( + array(42), + $this->sortExplode('42') + ); + } + + /** + * @test + */ + public function sortExplodeWithTwoAscendingNumbersReturnsArrayWithBothNumbers() { + $this->assertEquals( + array(1, 2), + $this->sortExplode('1,2') + ); + } + + /** + * @test + */ + public function sortExplodeWithTwoDescendingNumbersReturnsSortedArrayWithBothNumbers() { + $this->assertEquals( + array(1, 2), + $this->sortExplode('2,1') + ); + } + + + ////////////////////////////////// + // Tests for enableFields + ////////////////////////////////// + + /** + * @test + */ + public function enableFieldsThrowsExceptionForTooSmallShowHidden() { + $this->setExpectedException('Exception', '$showHidden may only be -1, 0 or 1, but actually is -2'); + Tx_Phpunit_Service_Database::enableFields('tx_phpunit_test', -2); + } + + /** + * @test + */ + public function enableFieldsThrowsExceptionForTooBigShowHidden() { + $this->setExpectedException('Exception', '$showHidden may only be -1, 0 or 1, but actually is 2'); + Tx_Phpunit_Service_Database::enableFields('tx_phpunit_test', 2); + } + + /** + * @test + */ + public function enableFieldsIsDifferentForDifferentTables() { + $this->assertNotEquals( + Tx_Phpunit_Service_Database::enableFields('tx_phpunit_test'), + Tx_Phpunit_Service_Database::enableFields('pages') + ); + } + + /** + * @test + */ + public function enableFieldsCanBeDifferentForShowHiddenZeroAndOne() { + $this->assertNotEquals( + Tx_Phpunit_Service_Database::enableFields('tx_phpunit_test', 0), + Tx_Phpunit_Service_Database::enableFields('tx_phpunit_test', 1) + ); + } + + /** + * @test + */ + public function enableFieldsAreTheSameForShowHiddenZeroAndMinusOne() { + $this->assertEquals( + Tx_Phpunit_Service_Database::enableFields('tx_phpunit_test', 0), + Tx_Phpunit_Service_Database::enableFields('tx_phpunit_test', -1) + ); + } + + /** + * @test + */ + public function enableFieldsCanBeDifferentForShowHiddenOneAndMinusOne() { + $this->assertNotEquals( + Tx_Phpunit_Service_Database::enableFields('tx_phpunit_test', 1), + Tx_Phpunit_Service_Database::enableFields('tx_phpunit_test', -1) + ); + } + + /** + * @test + */ + public function enableFieldsCanBeDifferentForDifferentIgnores() { + $this->assertNotEquals( + Tx_Phpunit_Service_Database::enableFields('tx_phpunit_test', 0, array()), + Tx_Phpunit_Service_Database::enableFields( + 'tx_phpunit_test', 0, array('endtime' => TRUE) + ) + ); + } + + /** + * TODO: This test does not work until the full versioning feature is + * implemented in the testing framework. + * + * @see https://bugs.oliverklee.com/show_bug.cgi?id=2180 + */ + /** + * @test + */ + public function enableFieldsCanBeDifferentForDifferentVersionParameters() { + $this->markTestSkipped( + 'This test does not work until the full versioning feature is ' . + 'implemented in the testing framework.' + ); + Tx_Phpunit_Service_Database::enableVersioningPreviewForCachedPage(); + + $this->assertNotEquals( + Tx_Phpunit_Service_Database::enableFields( + 'tx_phpunit_test', 0, array(), FALSE + ), + Tx_Phpunit_Service_Database::enableFields( + 'tx_phpunit_test', 0, array(), TRUE + ) + ); + } + + + ///////////////////////////////////////////// + // Tests concerning createRecursivePageList + ///////////////////////////////////////////// + + /** + * @test + */ + public function createRecursivePageListReturnsAnEmptyStringForNoPagesWithDefaultRecursion() { + $this->assertEquals( + '', + Tx_Phpunit_Service_Database::createRecursivePageList('') + ); + } + + /** + * @test + */ + public function createRecursivePageListReturnsAnEmptyStringForNoPagesWithZeroRecursion() { + $this->assertEquals( + '', + Tx_Phpunit_Service_Database::createRecursivePageList('', 0) + ); + } + + /** + * @test + */ + public function createRecursivePageListReturnsAnEmptyStringForNoPagesWithNonZeroRecursion() { + $this->assertEquals( + '', + Tx_Phpunit_Service_Database::createRecursivePageList('', 1) + ); + } + + /** + * @test + */ + public function createRecursivePageListThrowsWithNegativeRecursion() { + $this->setExpectedException('Exception', '$recursionDepth must be >= 0.'); + + Tx_Phpunit_Service_Database::createRecursivePageList('', -1); + } + + /** + * @test + */ + public function createRecursivePageListDoesNotContainSubpagesForOnePageWithZeroRecursion() { + $uid = $this->testingFramework->createSystemFolder(); + $this->testingFramework->createSystemFolder($uid); + + $this->assertEquals( + (string) $uid, + Tx_Phpunit_Service_Database::createRecursivePageList((string) $uid, 0) + ); + } + + /** + * @test + */ + public function createRecursivePageListDoesNotContainSubpagesForTwoPagesWithZeroRecursion() { + $uid1 = $this->testingFramework->createSystemFolder(); + $this->testingFramework->createSystemFolder($uid1); + $uid2 = $this->testingFramework->createSystemFolder(); + + $this->assertEquals( + $this->sortExplode($uid1 . ',' . $uid2), + $this->sortExplode( + Tx_Phpunit_Service_Database::createRecursivePageList($uid1.','.$uid2, 0) + ) + ); + } + + /** + * @test + */ + public function createRecursivePageListDoesNotContainSubsubpagesForRecursionOfOne() { + $uid = $this->testingFramework->createSystemFolder(); + $subFolderUid = $this->testingFramework->createSystemFolder($uid); + $this->testingFramework->createSystemFolder($subFolderUid); + + $this->assertEquals( + $this->sortExplode($uid.','.$subFolderUid), + $this->sortExplode(Tx_Phpunit_Service_Database::createRecursivePageList($uid, 1)) + ); + } + + /** + * @test + */ + public function createRecursivePageListDoesNotContainUnrelatedPages() { + $uid = $this->testingFramework->createSystemFolder(); + $this->testingFramework->createSystemFolder(); + + $this->assertEquals( + (string) $uid, + Tx_Phpunit_Service_Database::createRecursivePageList($uid, 0) + ); + } + + /** + * @test + */ + public function createRecursivePageListCanContainTwoSubpagesOfOnePage() { + $uid = $this->testingFramework->createSystemFolder(); + $subFolderUid1 = $this->testingFramework->createSystemFolder($uid); + $subFolderUid2 = $this->testingFramework->createSystemFolder($uid); + + $this->assertEquals( + $this->sortExplode($uid.','.$subFolderUid1.','.$subFolderUid2), + $this->sortExplode(Tx_Phpunit_Service_Database::createRecursivePageList($uid, 1)) + ); + } + + /** + * @test + */ + public function createRecursivePageListCanContainSubpagesOfTwoPages() { + $uid1 = $this->testingFramework->createSystemFolder(); + $uid2 = $this->testingFramework->createSystemFolder(); + $subFolderUid1 = $this->testingFramework->createSystemFolder($uid1); + $subFolderUid2 = $this->testingFramework->createSystemFolder($uid2); + + $this->assertEquals( + $this->sortExplode( + $uid1.','.$uid2.','.$subFolderUid1.','.$subFolderUid2 + ), + $this->sortExplode( + Tx_Phpunit_Service_Database::createRecursivePageList($uid1.','.$uid2, 1) + ) + ); + } + + /** + * @test + */ + public function createRecursivePageListHeedsIncreasingRecursionDepthOnSubsequentCalls() { + $uid = $this->testingFramework->createSystemFolder(); + $subFolderUid = $this->testingFramework->createSystemFolder($uid); + + $this->assertEquals( + (string) $uid, + Tx_Phpunit_Service_Database::createRecursivePageList($uid, 0) + ); + $this->assertEquals( + $this->sortExplode($uid.','.$subFolderUid), + $this->sortExplode(Tx_Phpunit_Service_Database::createRecursivePageList($uid, 1)) + ); + } + + /** + * @test + */ + public function createRecursivePageListHeedsDecreasingRecursionDepthOnSubsequentCalls() { + $uid = $this->testingFramework->createSystemFolder(); + $subFolderUid = $this->testingFramework->createSystemFolder($uid); + + $this->assertEquals( + $this->sortExplode($uid.','.$subFolderUid), + $this->sortExplode(Tx_Phpunit_Service_Database::createRecursivePageList($uid, 1)) + ); + $this->assertEquals( + (string) $uid, + Tx_Phpunit_Service_Database::createRecursivePageList($uid, 0) + ); + } + + + /////////////////////////////////////// + // Tests concerning getColumnsInTable + /////////////////////////////////////// + + /** + * @test + */ + public function getColumnsInTableForEmptyTableNameThrowsException() { + $this->setExpectedException( + 'Exception', 'The table name must not be empty.' + ); + + Tx_Phpunit_Service_Database::getColumnsInTable(''); + } + + /** + * @test + */ + public function getColumnsInTableForInexistentTableNameThrowsException() { + $this->setExpectedException( + 'Exception', 'The table "tx_phpunit_doesnotexist" does not exist.' + ); + + Tx_Phpunit_Service_Database::getColumnsInTable('tx_phpunit_doesnotexist'); + } + + /** + * @test + */ + public function getColumnsInTableReturnsArrayThatContainsExistingColumn() { + $columns = Tx_Phpunit_Service_Database::getColumnsInTable('tx_phpunit_test'); + + $this->assertTrue( + isset($columns['title']) + ); + } + + /** + * @test + */ + public function getColumnsInTableReturnsArrayThatNotContainsInexistentColumn() { + $columns = Tx_Phpunit_Service_Database::getColumnsInTable('tx_phpunit_test'); + + $this->assertFalse( + isset($columns['does_not_exist']) + ); + } + + + ////////////////////////////////////////// + // Tests concerning getColumnDefinition + ////////////////////////////////////////// + + /** + * @test + */ + public function getColumnDefinitionForEmptyTableNameThrowsException() { + $this->setExpectedException( + 'Exception', 'The table name must not be empty.' + ); + + Tx_Phpunit_Service_Database::getColumnDefinition('', 'uid'); + } + + /** + * @test + */ + public function getColumnDefinitionReturnsArrayThatContainsFieldName() { + $definition = Tx_Phpunit_Service_Database::getColumnDefinition('tx_phpunit_test', 'title'); + + $this->assertTrue( + $definition['Field'] == 'title' + ); + } + + + //////////////////////////////////////// + // Tests regarding tableHasColumnUid() + //////////////////////////////////////// + + /** + * @test + */ + public function tableHasColumnUidForEmptyTableNameThrowsException() { + $this->setExpectedException( + 'Exception', 'The table name must not be empty.' + ); + + Tx_Phpunit_Service_Database::tableHasColumnUid(''); + } + + /** + * @test + */ + public function tableHasColumnUidIsTrueOnTableWithColumnUid() { + $this->assertTrue( + Tx_Phpunit_Service_Database::tableHasColumnUid('tx_phpunit_test') + ); + } + + /** + * @test + */ + public function tableHasColumnUidIsFalseOnTableWithoutColumnUid() { + $this->assertFalse( + Tx_Phpunit_Service_Database::tableHasColumnUid('tx_phpunit_test_article_mm') + ); + } + + /** + * @test + */ + public function tableHasColumnUidCanReturnDifferentResultsForDifferentTables() { + $this->assertNotEquals( + Tx_Phpunit_Service_Database::tableHasColumnUid('tx_phpunit_test'), + Tx_Phpunit_Service_Database::tableHasColumnUid('tx_phpunit_test_article_mm') + ); + } + + + ///////////////////////////////////// + // Tests regarding tableHasColumn() + ///////////////////////////////////// + + /** + * @test + */ + public function tableHasColumnReturnsTrueOnTableWithColumn() { + $this->assertTrue( + Tx_Phpunit_Service_Database::tableHasColumn( + 'tx_phpunit_test', 'title' + ) + ); + } + + /** + * @test + */ + public function tableHasColumnReturnsFalseOnTableWithoutColumn() { + $this->assertFalse( + Tx_Phpunit_Service_Database::tableHasColumn( + 'tx_phpunit_test', 'inexistent_column' + ) + ); + } + + /** + * @test + */ + public function tableHasColumnThrowsExceptionOnEmptyTableName() { + $this->setExpectedException( + 'Exception', 'The table name must not be empty.' + ); + + Tx_Phpunit_Service_Database::tableHasColumn( + '', 'title' + ); + } + + /** + * @test + */ + public function tableHasColumnReturnsFalseOnEmptyColumnName() { + $this->assertFalse( + Tx_Phpunit_Service_Database::tableHasColumn( + 'tx_phpunit_test', '' + ) + ); + } + + + ///////////////////// + // Tests for delete + ///////////////////// + + /** + * @test + */ + public function deleteForEmptyTableNameThrowsException() { + $this->setExpectedException( + 'Exception', 'The table name must not be empty.' + ); + + Tx_Phpunit_Service_Database::delete( + '', 'uid = 0' + ); + } + + /** + * @test + */ + public function deleteDeletesRecord() { + $uid = $this->testingFramework->createRecord('tx_phpunit_test'); + + Tx_Phpunit_Service_Database::delete( + 'tx_phpunit_test', 'uid = ' . $uid + ); + + $this->assertFalse( + $this->testingFramework->existsRecordWithUid( + 'tx_phpunit_test', $uid + ) + ); + } + + /** + * @test + */ + public function deleteForNoDeletedRecordReturnsZero() { + $this->assertEquals( + 0, + Tx_Phpunit_Service_Database::delete( + 'tx_phpunit_test', 'uid = 0' + ) + ); + } + + /** + * @test + */ + public function deleteForOneDeletedRecordReturnsOne() { + $uid = $this->testingFramework->createRecord('tx_phpunit_test'); + + $this->assertEquals( + 1, + Tx_Phpunit_Service_Database::delete( + 'tx_phpunit_test', 'uid = ' . $uid + ) + ); + } + + /** + * @test + */ + public function deleteForTwoDeletedRecordsReturnsTwo() { + $uid1 = $this->testingFramework->createRecord('tx_phpunit_test'); + $uid2 = $this->testingFramework->createRecord('tx_phpunit_test'); + + $this->assertEquals( + 2, + Tx_Phpunit_Service_Database::delete( + 'tx_phpunit_test', + 'uid IN(' . $uid1 . ',' . $uid2 . ')' + ) + ); + } + + + ///////////////////// + // Tests for update + ///////////////////// + + /** + * @test + */ + public function updateForEmptyTableNameThrowsException() { + $this->setExpectedException( + 'Exception', 'The table name must not be empty.' + ); + + Tx_Phpunit_Service_Database::update( + '', 'uid = 0', array() + ); + } + + /** + * @test + */ + public function updateChangesRecord() { + $uid = $this->testingFramework->createRecord('tx_phpunit_test'); + + Tx_Phpunit_Service_Database::update( + 'tx_phpunit_test', 'uid = ' . $uid, array('title' => 'foo') + ); + + $this->assertTrue( + $this->testingFramework->existsRecord( + 'tx_phpunit_test', 'title = "foo"' + ) + ); + } + + /** + * @test + */ + public function updateForNoChangedRecordReturnsZero() { + $this->assertEquals( + 0, + Tx_Phpunit_Service_Database::update( + 'tx_phpunit_test', 'uid = 0', array('title' => 'foo') + ) + ); + } + + /** + * @test + */ + public function updateForOneChangedRecordReturnsOne() { + $uid = $this->testingFramework->createRecord('tx_phpunit_test'); + + $this->assertEquals( + 1, + Tx_Phpunit_Service_Database::update( + 'tx_phpunit_test', 'uid = ' . $uid, array('title' => 'foo') + ) + ); + } + + /** + * @test + */ + public function updateForTwoChangedRecordsReturnsTwo() { + $uid1 = $this->testingFramework->createRecord('tx_phpunit_test'); + $uid2 = $this->testingFramework->createRecord('tx_phpunit_test'); + + $this->assertEquals( + 2, + Tx_Phpunit_Service_Database::update( + 'tx_phpunit_test', + 'uid IN(' . $uid1 . ',' . $uid2 . ')', + array('title' => 'foo') + ) + ); + } + + + ///////////////////// + // Tests for insert + ///////////////////// + + /** + * @test + */ + public function insertForEmptyTableNameThrowsException() { + $this->setExpectedException( + 'Exception', 'The table name must not be empty.' + ); + + Tx_Phpunit_Service_Database::insert( + '', array('is_dummy_record' => 1) + ); + } + + /** + * @test + */ + public function insertForEmptyRecordDataThrowsException() { + $this->setExpectedException( + 'Exception', '$recordData must not be empty.' + ); + + Tx_Phpunit_Service_Database::insert( + 'tx_phpunit_test', array() + ); + } + + /** + * @test + */ + public function insertInsertsRecord() { + Tx_Phpunit_Service_Database::insert( + 'tx_phpunit_test', array('title' => 'foo', 'is_dummy_record' => 1) + ); + $this->testingFramework->markTableAsDirty('tx_phpunit_test'); + + $this->assertTrue( + $this->testingFramework->existsRecord( + 'tx_phpunit_test', 'title = "foo"' + ) + ); + } + + /** + * @test + */ + public function insertForTableWithUidReturnsUidOfCreatedRecord() { + $uid = Tx_Phpunit_Service_Database::insert( + 'tx_phpunit_test', array('is_dummy_record' => 1) + ); + $this->testingFramework->markTableAsDirty('tx_phpunit_test'); + + $this->assertTrue( + $this->testingFramework->existsRecordWithUid( + 'tx_phpunit_test', $uid + ) + ); + } + + /** + * @test + */ + public function insertForTableWithoutUidReturnsZero() { + $this->testingFramework->markTableAsDirty('tx_phpunit_test_article_mm'); + + $this->assertEquals( + 0, + Tx_Phpunit_Service_Database::insert( + 'tx_phpunit_test_article_mm', array('is_dummy_record' => 1) + ) + ); + } + + + ////////////////////////////////////////////////////////// + // Tests concerning select, selectSingle, selectMultiple + ////////////////////////////////////////////////////////// + + /** + * @test + */ + public function selectForEmptyTableNameThrowsException() { + $this->setExpectedException( + 'Exception', 'The table names must not be empty.' + ); + + Tx_Phpunit_Service_Database::select('*', ''); + } + + /** + * @test + */ + public function selectForEmptyFieldListThrowsException() { + $this->setExpectedException( + 'Exception', '$fields must not be empty.' + ); + + Tx_Phpunit_Service_Database::select('', 'tx_phpunit_test'); + } + + /** + * @test + */ + public function selectReturnsRessource() { + $this->assertTrue( + is_resource(Tx_Phpunit_Service_Database::select('title', 'tx_phpunit_test')) + ); + } + + /** + * @test + */ + public function selectSingleForEmptyTableNameThrowsException() { + $this->setExpectedException( + 'Exception', 'The table names must not be empty.' + ); + + Tx_Phpunit_Service_Database::selectSingle('*', ''); + } + + /** + * @test + */ + public function selectSingleForEmptyFieldListThrowsException() { + $this->setExpectedException( + 'Exception', '$fields must not be empty.' + ); + + Tx_Phpunit_Service_Database::selectSingle('', 'tx_phpunit_test'); + } + + /** + * @test + */ + public function selectSingleCanFindOneRow() { + $uid = $this->testingFramework->createRecord( + 'tx_phpunit_test' + ); + + $this->assertEquals( + array('uid' => $uid), + Tx_Phpunit_Service_Database::selectSingle('uid', 'tx_phpunit_test', 'uid = ' . $uid) + ); + } + + /** + * @test + */ + public function selectSingleForNoResultsThrowsEmptyQueryResultException() { + $this->setExpectedException( + 'Tx_Phpunit_Exception_EmptyQueryResult' + ); + + Tx_Phpunit_Service_Database::selectSingle('uid', 'tx_phpunit_test', 'title = "nothing"'); + } + + /** + * @test + */ + public function selectSingleCanOrderTheResults() { + $this->testingFramework->createRecord( + 'tx_phpunit_test', array('title' => 'Title A') + ); + $uid = $this->testingFramework->createRecord( + 'tx_phpunit_test', array('title' => 'Title B') + ); + + $this->assertEquals( + array('uid' => $uid), + Tx_Phpunit_Service_Database::selectSingle('uid', 'tx_phpunit_test', '', '', 'title DESC') + ); + } + + /** + * @test + */ + public function selectSingleCanUseOffset() { + $this->testingFramework->createRecord( + 'tx_phpunit_test', array('title' => 'Title A') + ); + $uid = $this->testingFramework->createRecord( + 'tx_phpunit_test', array('title' => 'Title B') + ); + + $this->assertEquals( + array('uid' => $uid), + Tx_Phpunit_Service_Database::selectSingle('uid', 'tx_phpunit_test', '', '', 'title', 1) + ); + } + + + /** + * @test + */ + public function selectMultipleForEmptyTableNameThrowsException() { + $this->setExpectedException( + 'Exception', 'The table names must not be empty.' + ); + + Tx_Phpunit_Service_Database::selectMultiple('*', ''); + } + + /** + * @test + */ + public function selectMultipleForEmptyFieldListThrowsException() { + $this->setExpectedException( + 'Exception', '$fields must not be empty.' + ); + + Tx_Phpunit_Service_Database::selectMultiple('', 'tx_phpunit_test'); + } + + /** + * @test + */ + public function selectMultipleForNoResultsReturnsEmptyArray() { + $this->assertEquals( + array(), + Tx_Phpunit_Service_Database::selectMultiple( + 'uid', 'tx_phpunit_test', 'title = "nothing"' + ) + ); + } + + /** + * @test + */ + public function selectMultipleCanFindOneRow() { + $uid = $this->testingFramework->createRecord( + 'tx_phpunit_test' + ); + + $this->assertEquals( + array(array('uid' => $uid)), + Tx_Phpunit_Service_Database::selectMultiple('uid', 'tx_phpunit_test', 'uid = ' . $uid) + ); + } + + /** + * @test + */ + public function selectMultipleCanFindTwoRows() { + $this->testingFramework->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + $this->testingFramework->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + + $this->assertEquals( + array( + array('title' => 'foo'), + array('title' => 'foo'), + ), + Tx_Phpunit_Service_Database::selectMultiple( + 'title', 'tx_phpunit_test', 'title = "foo"' + ) + ); + } + + /** + * @test + */ + public function selectColumnForMultipleForNoMatchesReturnsEmptyArray() { + $this->assertEquals( + array(), + Tx_Phpunit_Service_Database::selectColumnForMultiple( + 'title', 'tx_phpunit_test', 'title = "nothing"' + ) + ); + } + + /** + * @test + */ + public function selectColumnForMultipleForOneMatchReturnsArrayWithColumnContent() { + $uid = $this->testingFramework->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + + $this->assertEquals( + array('foo'), + Tx_Phpunit_Service_Database::selectColumnForMultiple( + 'title', 'tx_phpunit_test', 'uid = ' . $uid + ) + ); + } + + /** + * @test + */ + public function selectColumnForMultipleForTwoMatchReturnsArrayWithColumnContents() { + $uid1 = $this->testingFramework->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + $uid2 = $this->testingFramework->createRecord( + 'tx_phpunit_test', array('title' => 'bar') + ); + + $result = Tx_Phpunit_Service_Database::selectColumnForMultiple( + 'title', 'tx_phpunit_test', 'uid = ' . $uid1 . ' OR uid = ' . $uid2 + ); + sort($result); + $this->assertEquals( + array('bar', 'foo'), + $result + ); + } + + + ////////////////////////////////////// + // Tests concerning getAllTableNames + ////////////////////////////////////// + + /** + * @test + */ + public function getAllTableNamesContainsExistingTable() { + $this->assertTrue( + in_array('tx_phpunit_test', Tx_Phpunit_Service_Database::getAllTableNames()) + ); + } + + /** + * @test + */ + public function getAllTableNamesNotContainsInexistentTable() { + $this->assertFalse( + in_array('tx_phpunit_doesnotexist', Tx_Phpunit_Service_Database::getAllTableNames()) + ); + } + + + ///////////////////////////////// + // Tests concerning existsTable + ///////////////////////////////// + + /** + * @test + */ + public function existsTableWithEmptyTableNameThrowsException() { + $this->setExpectedException( + 'Exception', 'The table name must not be empty.' + ); + + Tx_Phpunit_Service_Database::existsTable(''); + } + + /** + * @test + */ + public function existsTableForExistingTableReturnsTrue() { + $this->assertTrue( + Tx_Phpunit_Service_Database::existsTable('tx_phpunit_test') + ); + } + + /** + * @test + */ + public function existsTableForInexistentTableReturnsFalse() { + $this->assertFalse( + Tx_Phpunit_Service_Database::existsTable('tx_phpunit_doesnotexist') + ); + } + + + //////////////////////////////////// + // Tests concerning getTcaForTable + //////////////////////////////////// + + /** + * @test + */ + public function getTcaForTableReturnsValidTcaArray() { + $tca = Tx_Phpunit_Service_Database::getTcaForTable('tx_phpunit_test'); + + $this->assertTrue(is_array($tca['ctrl'])); + $this->assertTrue(is_array($tca['interface'])); + $this->assertTrue(is_array($tca['columns'])); + $this->assertTrue(is_array($tca['types'])); + $this->assertTrue(is_array($tca['palettes'])); + } + + /** + * @test + */ + public function getTcaForTableWithEmptyTableNameThrowsExceptionTca() { + $this->setExpectedException( + 'Exception', 'The table name must not be empty.' + ); + + Tx_Phpunit_Service_Database::getTcaForTable(''); + } + + /** + * @test + */ + public function getTcaForTableWithInexistentTableNameThrowsExceptionTca() { + $this->setExpectedException( + 'Exception', 'The table "tx_phpunit_doesnotexist" does not exist.' + ); + + Tx_Phpunit_Service_Database::getTcaForTable('tx_phpunit_doesnotexist'); + } + + /** + * @test + */ + public function getTcaForTableThrowsExceptionOnTableWithoutTca() { + $this->setExpectedException( + 'Exception', 'The table "' . 'tx_phpunit_test_article_mm' . '" has no TCA.' + ); + + Tx_Phpunit_Service_Database::getTcaForTable('tx_phpunit_test_article_mm'); + } + + /** + * @test + */ + public function getTcaForTableCanLoadFieldsAddedByExtensions() { + if (!t3lib_extMgm::isLoaded('sr_feuser_register')) { + $this->markTestSkipped( + 'This test is only applicable if sr_feuser_register is loaded.' + ); + } + $tca = Tx_Phpunit_Service_Database::getTcaForTable('fe_users'); + + $this->assertTrue(isset($tca['columns']['gender'])); + } + + + /////////////////////////// + // Tests concerning count + /////////////////////////// + + /** + * @test + */ + public function countCanBeCalledWithEmptyWhereClause() { + Tx_Phpunit_Service_Database::count('tx_phpunit_test', ''); + } + + /** + * @test + */ + public function countCanBeCalledWithMissingWhereClause() { + Tx_Phpunit_Service_Database::count('tx_phpunit_test'); + } + + /** + * @test + */ + public function countForNoMatchesReturnsZero() { + $this->assertSame( + 0, + Tx_Phpunit_Service_Database::count( + 'tx_phpunit_test', + 'uid = 42' + ) + ); + } + + /** + * @test + */ + public function countForOneMatchReturnsOne() { + $this->assertSame( + 1, + Tx_Phpunit_Service_Database::count( + 'tx_phpunit_test', + 'uid = ' . $this->testingFramework->createRecord('tx_phpunit_test') + ) + ); + } + + /** + * @test + */ + public function countForTwoMatchesReturnsTwo() { + $uid1 = $this->testingFramework->createRecord('tx_phpunit_test'); + $uid2 = $this->testingFramework->createRecord('tx_phpunit_test'); + + $this->assertSame( + 2, + Tx_Phpunit_Service_Database::count( + 'tx_phpunit_test', + 'uid IN(' . $uid1 . ',' . $uid2 . ')' + ) + ); + } + + /** + * @test + */ + public function countCanBeCalledForTableWithoutUid() { + Tx_Phpunit_Service_Database::count('tx_phpunit_test_article_mm'); + } + + /** + * @test + */ + public function countCanBeCalledWithMultipleTables() { + Tx_Phpunit_Service_Database::count('tx_phpunit_test, tx_phpunit_testchild'); + } + + /** + * @test + */ + public function countWithInvalidTableNameThrowsException() { + $this->setExpectedException( + 'Exception', 'The table "tx_phpunit_doesnotexist" does not exist.' + ); + + Tx_Phpunit_Service_Database::count('tx_phpunit_doesnotexist', 'uid = 42'); + } + + /** + * @test + */ + public function countCanBeCalledWithJoinedTables() { + Tx_Phpunit_Service_Database::count('tx_phpunit_test JOIN tx_phpunit_testchild'); + } + + /** + * @test + */ + public function countDoesNotAllowJoinWithoutTables() { + $this->setExpectedException( + 'Exception', 'The table "JOIN" does not exist.' + ); + + Tx_Phpunit_Service_Database::count('JOIN'); + } + + /** + * @test + */ + public function countDoesNotAllowJoinWithOnlyOneTableOnTheLeft() { + $this->setExpectedException( + 'Exception', 'The table "tx_phpunit_test JOIN " does not exist.' + ); + + Tx_Phpunit_Service_Database::count('tx_phpunit_test JOIN '); + } + + /** + * @test + */ + public function countDoesNotAllowJoinWithOnlyOneTableOnTheRight() { + $this->setExpectedException( + 'Exception', 'The table "JOIN tx_phpunit_test" does not exist.' + ); + + Tx_Phpunit_Service_Database::count('JOIN tx_phpunit_test'); + } + + + ///////////////////////////////// + // Tests regarding existsRecord + ///////////////////////////////// + + /** + * @test + */ + public function existsRecordWithEmptyWhereClauseIsAllowed() { + Tx_Phpunit_Service_Database::existsRecord('tx_phpunit_test', ''); + } + + /** + * @test + */ + public function existsRecordWithMissingWhereClauseIsAllowed() { + Tx_Phpunit_Service_Database::existsRecord('tx_phpunit_test'); + } + + /** + * @test + */ + public function existsRecordWithEmptyTableNameThrowsException() { + $this->setExpectedException( + 'Exception', + 'The table name must not be empty.' + ); + + Tx_Phpunit_Service_Database::existsRecord(''); + } + + /** + * @test + */ + public function existsRecordWithInvalidTableNameThrowsException() { + $this->setExpectedException( + 'Exception', 'The table "tx_phpunit_doesnotexist" does not exist.' + ); + + Tx_Phpunit_Service_Database::existsRecord('tx_phpunit_doesnotexist'); + } + + /** + * @test + */ + public function existsRecordForNoMatchesReturnsFalse() { + $this->assertFalse( + Tx_Phpunit_Service_Database::existsRecord('tx_phpunit_test', 'uid = 42') + ); + } + + /** + * @test + */ + public function existsRecordForOneMatchReturnsTrue() { + $uid = $this->testingFramework->createRecord( + 'tx_phpunit_test' + ); + + $this->assertTrue( + Tx_Phpunit_Service_Database::existsRecord('tx_phpunit_test', 'uid = ' . $uid) + ); + } + + /** + * @test + */ + public function existsRecordForTwoMatchesReturnsTrue() { + $this->testingFramework->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + $this->testingFramework->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + + $this->assertTrue( + Tx_Phpunit_Service_Database::existsRecord('tx_phpunit_test', 'title = "foo"') + ); + } + + + /////////////////////////////////////////// + // Tests regarding existsExactlyOneRecord + /////////////////////////////////////////// + + /** + * @test + */ + public function existsExactlyOneRecordWithEmptyWhereClauseIsAllowed() { + Tx_Phpunit_Service_Database::existsExactlyOneRecord('tx_phpunit_test', ''); + } + + /** + * @test + */ + public function existsExactlyOneRecordWithMissingWhereClauseIsAllowed() { + Tx_Phpunit_Service_Database::existsExactlyOneRecord('tx_phpunit_test'); + } + + /** + * @test + */ + public function existsExactlyOneRecordWithEmptyTableNameThrowsException() { + $this->setExpectedException( + 'Exception', + 'The table name must not be empty.' + ); + + Tx_Phpunit_Service_Database::existsExactlyOneRecord(''); + } + + /** + * @test + */ + public function existsExactlyOneRecordWithInvalidTableNameThrowsException() { + $this->setExpectedException( + 'Exception', 'The table "tx_phpunit_doesnotexist" does not exist.' + ); + + Tx_Phpunit_Service_Database::existsExactlyOneRecord('tx_phpunit_doesnotexist'); + } + + /** + * @test + */ + public function existsExactlyOneRecordForNoMatchesReturnsFalse() { + $this->assertFalse( + Tx_Phpunit_Service_Database::existsExactlyOneRecord('tx_phpunit_test', 'uid = 42') + ); + } + + /** + * @test + */ + public function existsExactlyOneRecordForOneMatchReturnsTrue() { + $uid = $this->testingFramework->createRecord( + 'tx_phpunit_test' + ); + + $this->assertTrue( + Tx_Phpunit_Service_Database::existsExactlyOneRecord('tx_phpunit_test', 'uid = ' . $uid) + ); + } + + /** + * @test + */ + public function existsExactlyOneRecordForTwoMatchesReturnsFalse() { + $this->testingFramework->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + $this->testingFramework->createRecord( + 'tx_phpunit_test', array('title' => 'foo') + ); + + $this->assertFalse( + Tx_Phpunit_Service_Database::existsExactlyOneRecord('tx_phpunit_test', 'title = "foo"') + ); + } + + + //////////////////////////////////////// + // Tests regarding existsRecordWithUid + //////////////////////////////////////// + + /** + * @test + */ + public function existsRecordWithUidWithZeroUidThrowsException() { + $this->setExpectedException( + 'Exception', '$uid must be > 0.' + ); + + Tx_Phpunit_Service_Database::existsRecordWithUid('tx_phpunit_test', 0); + } + + /** + * @test + */ + public function existsRecordWithUidWithNegativeUidThrowsException() { + $this->setExpectedException( + 'Exception', '$uid must be > 0.' + ); + + Tx_Phpunit_Service_Database::existsRecordWithUid('tx_phpunit_test', -1); + } + + /** + * @test + */ + public function existsRecordWithUidWithEmptyTableNameThrowsException() { + $this->setExpectedException( + 'Exception', + 'The table name must not be empty.' + ); + + Tx_Phpunit_Service_Database::existsRecordWithUid('', 42); + } + + /** + * @test + */ + public function existsRecordWithUidWithInvalidTableNameThrowsException() { + $this->setExpectedException( + 'Exception', 'The table "tx_phpunit_doesnotexist" does not exist.' + ); + + Tx_Phpunit_Service_Database::existsRecordWithUid('tx_phpunit_doesnotexist', 42); + } + + /** + * @test + */ + public function existsRecordWithUidForNoMatchReturnsFalse() { + $this->assertFalse( + Tx_Phpunit_Service_Database::existsRecordWithUid('tx_phpunit_test', 42) + ); + } + + /** + * @test + */ + public function existsRecordWithUidForMatchReturnsTrue() { + $uid = $this->testingFramework->createRecord( + 'tx_phpunit_test' + ); + + $this->assertTrue( + Tx_Phpunit_Service_Database::existsRecordWithUid('tx_phpunit_test', $uid) + ); + } + + /** + * @test + */ + public function existsRecordWithUidUsesAdditionalNonEmptyWhereClause() { + $uid = $this->testingFramework->createRecord( + 'tx_phpunit_test', array('deleted' => 1) + ); + + $this->assertFalse( + Tx_Phpunit_Service_Database::existsRecordWithUid( + 'tx_phpunit_test', $uid, ' AND deleted = 0' + ) + ); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Service/Fixtures/NonPhpFiles/test.txt b/typo3conf/ext/phpunit/Tests/Service/Fixtures/NonPhpFiles/test.txt new file mode 100644 index 0000000..c1c8c13 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Service/Fixtures/NonPhpFiles/test.txt @@ -0,0 +1 @@ +nothing of interest here \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Service/Fixtures/NonTestFiles/Nothing.php b/typo3conf/ext/phpunit/Tests/Service/Fixtures/NonTestFiles/Nothing.php new file mode 100644 index 0000000..67c94a5 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Service/Fixtures/NonTestFiles/Nothing.php @@ -0,0 +1,2 @@ +<?php +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Service/Fixtures/OneTest.php b/typo3conf/ext/phpunit/Tests/Service/Fixtures/OneTest.php new file mode 100644 index 0000000..67c94a5 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Service/Fixtures/OneTest.php @@ -0,0 +1,2 @@ +<?php +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Service/Fixtures/Subfolder/AnotherTest.php b/typo3conf/ext/phpunit/Tests/Service/Fixtures/Subfolder/AnotherTest.php new file mode 100644 index 0000000..67c94a5 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Service/Fixtures/Subfolder/AnotherTest.php @@ -0,0 +1,2 @@ +<?php +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Service/Fixtures/XTest.php b/typo3conf/ext/phpunit/Tests/Service/Fixtures/XTest.php new file mode 100644 index 0000000..67c94a5 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Service/Fixtures/XTest.php @@ -0,0 +1,2 @@ +<?php +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/Service/TestFinderTest.php b/typo3conf/ext/phpunit/Tests/Service/TestFinderTest.php new file mode 100644 index 0000000..d697f8d --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/Service/TestFinderTest.php @@ -0,0 +1,1041 @@ +<?php +/*************************************************************** +* Copyright notice +* +* (c) 2010-2011 Oliver Klee (typo3-coding@oliverklee.de) +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +/** + * Testcase for the Tx_Phpunit_Service_TestFinder class. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Oliver Klee <typo3-coding@oliverklee.de> + */ +class Tx_Phpunit_Service_TestFinderTest extends Tx_Phpunit_TestCase { + /** + * @var Tx_Phpunit_Service_TestFinder + */ + private $fixture = NULL; + + /** + * the absolute path to the fixtures directory for this testcase + * + * @var string + */ + private $fixturesPath = ''; + + /** + * backup of $GLOBALS['TYPO3_CONF_VARS'] + * + * @var array + */ + private $typo3ConfigurationVariablesBackup = array(); + + public function setUp() { + $this->typo3ConfigurationVariablesBackup = $GLOBALS['TYPO3_CONF_VARS']; + + $this->fixture = $this->createAccessibleProxy(); + + $this->fixturesPath = t3lib_extMgm::extPath('phpunit') . 'Tests/Service/Fixtures/'; + } + + public function tearDown() { + $this->fixture->__destruct(); + unset($this->fixture); + + $GLOBALS['TYPO3_CONF_VARS'] = $this->typo3ConfigurationVariablesBackup; + } + + + /* + * Utility functions + */ + + /** + * Creates a subclass Tx_Phpunit_Service_TestFinder with the protected + * functions made public. + * + * @return Tx_Phpunit_Service_TestFinder an accessible proxy + */ + private function createAccessibleProxy() { + $className = 'Tx_Phpunit_Service_TestFinderAccessibleProxy'; + if (!class_exists($className, FALSE)) { + eval( + 'class ' . $className . ' extends Tx_Phpunit_Service_TestFinder {' . + ' public function isTestCaseFileName($path) {' . + ' return parent::isTestCaseFileName($path);' . + ' }' . + ' public function getLoadedExtensionKeys() {' . + ' return parent::getLoadedExtensionKeys();' . + ' }' . + ' public function getExcludedExtensionKeys() {' . + ' return parent::getExcludedExtensionKeys();' . + ' }' . + ' public function getDummyExtensionKeys() {' . + ' return parent::getDummyExtensionKeys();' . + ' }' . + ' public function findTestsPathForExtension($extensionKey) {' . + ' return parent::findTestsPathForExtension($extensionKey);' . + ' }' . + ' public function retrieveExtensionTitle($extensionKey) {' . + ' return parent::retrieveExtensionTitle($extensionKey);' . + ' }' . + '}' + ); + } + + return new $className(); + } + + /** + * @test + */ + public function createAccessibleProxyCreatesTestFinderSubclass() { + $this->assertTrue( + $this->createAccessibleProxy() instanceof Tx_Phpunit_Service_TestFinder + ); + } + + + /* + * Unit tests + */ + + /** + * @test + */ + public function classIsSingleton() { + $this->assertTrue( + $this->fixture instanceof t3lib_Singleton + ); + } + + /** + * @test + */ + public function getRelativeCoreTestsPathCanFindTestsInCoreSourceInSitePath() { + if (!file_exists(PATH_site . 'typo3_src/tests/')) { + $this->markTestSkipped('This test can only be run if the Core tests are located in typo3_src/tests/.'); + } + + $this->assertSame( + 'typo3_src/tests/', + $this->fixture->getRelativeCoreTestsPath() + ); + } + + /** + * @test + */ + public function getRelativeCoreTestsPathCanFindTestsDirectlyInSitePath() { + if (!file_exists(PATH_site . 'tests/')) { + $this->markTestSkipped('This test can only be run if the Core tests are located in tests/.'); + } + + $this->assertSame( + 'typo3_src/tests/', + $this->fixture->getRelativeCoreTestsPath() + ); + } + + /** + * @test + */ + public function getRelativeCoreTestsPathForNoCoreTestsReturnsEmptyString() { + if (file_exists(PATH_site . 'tests/') || file_exists(PATH_site . 'typo3_src/tests/')) { + $this->markTestSkipped('This test can only be run if there are no Core tests.'); + } + + $this->assertSame( + '', + $this->fixture->getRelativeCoreTestsPath() + ); + } + + /** + * @test + */ + public function getAbsoluteCoreTestsPathCanFindTestsInCoreSourceInSitePath() { + if (!file_exists(PATH_site . 'typo3_src/tests/')) { + $this->markTestSkipped('This test can only be run if the Core tests are located in typo3_src/tests/.'); + } + + $this->assertSame( + PATH_site . 'typo3_src/tests/', + $this->fixture->getAbsoluteCoreTestsPath() + ); + } + + /** + * @test + */ + public function getAbsoluteCoreTestsPathCanFindTestsDirectlyInSitePath() { + if (!file_exists(PATH_site . 'tests/')) { + $this->markTestSkipped('This test can only be run if the Core tests are located in tests/.'); + } + + $this->assertSame( + PATH_site . 'typo3_src/tests/', + $this->fixture->getAbsoluteCoreTestsPath() + ); + } + + /** + * @test + */ + public function getAbsoluteCoreTestsPathForNoCoreTestsReturnsEmptyString() { + if (file_exists(PATH_site . 'tests/') || file_exists(PATH_site . 'typo3_src/tests/')) { + $this->markTestSkipped('This test can only be run if there are no Core tests.'); + } + + $this->assertSame( + '', + $this->fixture->getAbsoluteCoreTestsPath() + ); + } + + /** + * @test + */ + public function hasCoreTestsForCoreTestsInCoreSourceInSitePathReturnsTrue() { + if (!file_exists(PATH_site . 'typo3_src/tests/')) { + $this->markTestSkipped('This test can only be run if the Core tests are located in typo3_src/tests/.'); + } + + $this->assertTrue( + $this->fixture->hasCoreTests() + ); + } + + /** + * @test + */ + public function hasCoreTestsForCoreTestsDirectlyInSitePathReturnsTrue() { + if (!file_exists(PATH_site . 'tests/')) { + $this->markTestSkipped('This test can only be run if the Core tests are located in typo3_src/tests/.'); + } + + $this->assertTrue( + $this->fixture->hasCoreTests() + ); + } + + /** + * @test + */ + public function hasCoreTestsForNoCoreTestsReturnsFalse() { + if (file_exists(PATH_site . 'tests/') || file_exists(PATH_site . 'typo3_src/tests/')) { + $this->markTestSkipped('This test can only be run if there are no Core tests.'); + } + + $this->assertFalse( + $this->fixture->hasCoreTests() + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function findTestCasesInDirectoryForEmptyPathThrowsException() { + $this->fixture->findTestCasesInDirectory(''); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function findTestCasesInDirectoryForInexistentPathThrowsException() { + $this->fixture->findTestCasesInDirectory( + $this->fixturesPath . 'DoesNotExist/' + ); + } + + /** + * @test + */ + public function findTestCasesInDirectoryForEmptyDirectoryReturnsEmptyArray() { + $this->assertSame( + array(), + $this->fixture->findTestCasesInDirectory($this->fixturesPath . 'Empty/') + ); + } + + /** + * @test + */ + public function findTestCasesInDirectoryFindsFileWithProperTestcaseFileName() { + $path = 'OneTest.php'; + + $fixture = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', array('isTestCaseFileName') + ); + $fixture->expects($this->at(0))->method('isTestCaseFileName') + ->with($this->fixturesPath . $path)->will($this->returnValue(TRUE)); + + $this->assertContains( + $path, + $fixture->findTestCasesInDirectory($this->fixturesPath) + ); + } + + /** + * @test + */ + public function findTestCasesInDirectoryNotFindsFileWithNonProperTestcaseFileName() { + $path = 'OneTest.php'; + + $fixture = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', array('isTestCaseFileName') + ); + $fixture->expects($this->at(0))->method('isTestCaseFileName') + ->with($this->fixturesPath . $path)->will($this->returnValue(FALSE)); + + $this->assertNotContains( + $path, + $fixture->findTestCasesInDirectory($this->fixturesPath) + ); + } + + /** + * @test + */ + public function findTestCasesInDirectoryFindsTestcaseInSubfolder() { + $path = 'Subfolder/AnotherTest.php'; + + $this->assertContains( + $path, + $this->fixture->findTestCasesInDirectory($this->fixturesPath) + ); + } + + /** + * @test + */ + public function findTestCasesInDirectoryAcceptsPathWithTrailingSlash() { + $result = $this->fixture->findTestCasesInDirectory($this->fixturesPath); + + $this->assertFalse( + empty($result) + ); + } + + /** + * @test + */ + public function findTestCasesInDirectoryAcceptsPathWithoutTrailingSlash() { + $result = $this->fixture->findTestCasesInDirectory( + t3lib_extMgm::extPath('phpunit') . 'Tests/Service/Fixtures' + ); + + $this->assertFalse( + empty($result) + ); + } + + /** + * @test + */ + public function findTestCasesInDirectorySortsFileNamesInAscendingOrder() { + $result = $this->fixture->findTestCasesInDirectory($this->fixturesPath); + + $fileName1 = 'OneTest.php'; + $fileName2 = 'XTest.php'; + + $this->assertTrue( + array_search($fileName1, $result) < array_search($fileName2, $result) + ); + } + + + /** + * @test + */ + public function isTestCaseFileNameForTestSuffixReturnsTrue() { + $this->assertTrue( + $this->fixture->isTestCaseFileName( + $this->fixturesPath . 'OneTest.php' + ) + ); + } + + /** + * @test + */ + public function isTestCaseFileNameForTestcaseSuffixReturnsTrue() { + $this->assertTrue( + $this->fixture->isTestCaseFileName( + $this->fixturesPath . 'Another_testcase.php' + ) + ); + } + + /** + * @test + */ + public function isTestCaseFileNameForOtherPhpFileReturnsFalse() { + $this->assertFalse( + $this->fixture->isTestCaseFileName( + $this->fixturesPath . 'SomethingDifferent.php' + ) + ); + } + + /** + * @test + * + * @see http://forge.typo3.org/issues/9094 + */ + public function isTestCaseFileNameForHiddenMacFileReturnsFalse() { + $this->assertFalse( + $this->fixture->isTestCaseFileName( + $this->fixturesPath . '._tx_tendbook_testTest.php' + ) + ); + } + + /** + * @test + */ + public function existsTestableCodeForKeyForEmptyKeyReturnsFalse() { + $fixture = $this->getMock('Tx_Phpunit_Service_TestFinder', array('getTestableCodeForEverything')); + $fixture->expects($this->any())->method('getTestableCodeForEverything') + ->will($this->returnValue(array('foo' => new Tx_Phpunit_TestableCode()))); + + $this->assertFalse( + $fixture->existsTestableCodeForKey('') + ); + } + + /** + * @test + */ + public function existsTestableCodeForKeyForExistingKeyReturnsTrue() { + $fixture = $this->getMock('Tx_Phpunit_Service_TestFinder', array('getTestableCodeForEverything')); + $fixture->expects($this->any())->method('getTestableCodeForEverything') + ->will($this->returnValue(array('foo' => new Tx_Phpunit_TestableCode()))); + + $this->assertTrue( + $fixture->existsTestableCodeForKey('foo') + ); + } + + /** + * @test + */ + public function existsTestableCodeForKeyForInexistentKeyReturnsFalse() { + $fixture = $this->getMock('Tx_Phpunit_Service_TestFinder', array('getTestableCodeForEverything')); + $fixture->expects($this->any())->method('getTestableCodeForEverything') + ->will($this->returnValue(array('foo' => new Tx_Phpunit_TestableCode()))); + + $this->assertFalse( + $fixture->existsTestableCodeForKey('bar') + ); + } + + /** + * @test + */ + public function getTestableCodeForEverythingForNoCoreTestsAndNoExtensionTestsReturnsEmptyArray() { + $testFinder = $this->getMock('Tx_Phpunit_Service_TestFinder', array('getTestableCodeForCore', 'getTestableCodeForExtensions')); + $testFinder->expects($this->once())->method('getTestableCodeForCore')->will($this->returnValue(array())); + $testFinder->expects($this->once())->method('getTestableCodeForExtensions')->will($this->returnValue(array())); + + $this->assertSame( + array(), + $testFinder->getTestableCodeForEverything() + ); + } + + /** + * @test + */ + public function getTestableCodeForEverythingForCoreTestsAndNoExtensionTestsReturnsCoreTests() { + $coreTests = new Tx_Phpunit_TestableCode(); + + $testFinder = $this->getMock('Tx_Phpunit_Service_TestFinder', array('getTestableCodeForCore', 'getTestableCodeForExtensions')); + $testFinder->expects($this->once())->method('getTestableCodeForCore') + ->will($this->returnValue(array(Tx_Phpunit_TestableCode::CORE_KEY => $coreTests))); + $testFinder->expects($this->once())->method('getTestableCodeForExtensions')->will($this->returnValue(array())); + + $this->assertSame( + array(Tx_Phpunit_TestableCode::CORE_KEY => $coreTests), + $testFinder->getTestableCodeForEverything() + ); + } + + /** + * @test + */ + public function getTestableCodeForEverythingForCoreTestsAndNoExtensionTestsReturnsExtensionTests() { + $extensionTests = new Tx_Phpunit_TestableCode(); + + $testFinder = $this->getMock('Tx_Phpunit_Service_TestFinder', array('getTestableCodeForCore', 'getTestableCodeForExtensions')); + $testFinder->expects($this->once())->method('getTestableCodeForCore') + ->will($this->returnValue(array())); + $testFinder->expects($this->once())->method('getTestableCodeForExtensions') + ->will($this->returnValue(array('foo' => $extensionTests))); + + $this->assertSame( + array('foo' => $extensionTests), + $testFinder->getTestableCodeForEverything() + ); + } + + /** + * @test + */ + public function getTestableCodeForEverythingForCoreTestsAndExtensionTestsReturnsCoreAndExtensionTests() { + $coreTests = new Tx_Phpunit_TestableCode(); + $extensionTests = new Tx_Phpunit_TestableCode(); + + $testFinder = $this->getMock('Tx_Phpunit_Service_TestFinder', array('getTestableCodeForCore', 'getTestableCodeForExtensions')); + $testFinder->expects($this->once())->method('getTestableCodeForCore') + ->will($this->returnValue(array(Tx_Phpunit_TestableCode::CORE_KEY => $coreTests))); + $testFinder->expects($this->once())->method('getTestableCodeForExtensions') + ->will($this->returnValue(array('foo' => $extensionTests))); + + $this->assertSame( + array( + Tx_Phpunit_TestableCode::CORE_KEY => $coreTests, + 'foo' => $extensionTests, + ), + $testFinder->getTestableCodeForEverything() + ); + } + + /** + * @test + */ + public function getTestableCodeForEverythingForCoreTestsAndExtensionCalledTwoTimesReturnsSameData() { + $coreTests = new Tx_Phpunit_TestableCode(); + $extensionTests = new Tx_Phpunit_TestableCode(); + + $testFinder = $this->getMock('Tx_Phpunit_Service_TestFinder', array('getTestableCodeForCore', 'getTestableCodeForExtensions')); + $testFinder->expects($this->any())->method('getTestableCodeForCore') + ->will($this->returnValue(array(Tx_Phpunit_TestableCode::CORE_KEY => $coreTests))); + $testFinder->expects($this->any())->method('getTestableCodeForExtensions') + ->will($this->returnValue(array('foo' => $extensionTests))); + + $this->assertSame( + $testFinder->getTestableCodeForEverything(), + $testFinder->getTestableCodeForEverything() + ); + } + + /** + * @test + */ + public function getTestableCodeForCoreForNoCoreTestsReturnsEmptyArray() { + $testFinder = $this->getMock('Tx_Phpunit_Service_TestFinder', array('hasCoreTests')); + $testFinder->expects($this->once())->method('hasCoreTests')->will($this->returnValue(FALSE)); + + $this->assertSame( + array(), + $testFinder->getTestableCodeForCore() + ); + } + + /** + * @test + */ + public function getTestableCodeForCoreExistingCoreTestsReturnsExactlyOneTestableCodeInstanceUsingCoreArrayKey() { + $testFinder = $this->getMock('Tx_Phpunit_Service_TestFinder', array('hasCoreTests', 'getAbsoluteCoreTestsPath')); + $testFinder->expects($this->once())->method('hasCoreTests')->will($this->returnValue(TRUE)); + $testFinder->expects($this->once())->method('getAbsoluteCoreTestsPath')->will($this->returnValue('/core/tests/')); + + $result = $testFinder->getTestableCodeForCore(); + + $this->assertSame( + 1, + count($result), + 'The return array does not have exactly one element.' + ); + $this->assertInstanceOf( + 'Tx_Phpunit_TestableCode', + $result[Tx_Phpunit_TestableCode::CORE_KEY] + ); + } + + /** + * @test + */ + public function getTestableCodeForCoreExistingCoreTestsReturnsTestableCodeWithCoreType() { + $testFinder = $this->getMock('Tx_Phpunit_Service_TestFinder', array('hasCoreTests', 'getAbsoluteCoreTestsPath')); + $testFinder->expects($this->once())->method('hasCoreTests')->will($this->returnValue(TRUE)); + $testFinder->expects($this->once())->method('getAbsoluteCoreTestsPath')->will($this->returnValue('/core/tests/')); + + $this->assertSame( + Tx_Phpunit_TestableCode::TYPE_CORE, + array_pop($testFinder->getTestableCodeForCore())->getType() + ); + } + + /** + * @test + */ + public function getTestableCodeForCoreExistingCoreTestsReturnsTestableCodeWithTypo3Key() { + $testFinder = $this->getMock('Tx_Phpunit_Service_TestFinder', array('hasCoreTests', 'getAbsoluteCoreTestsPath')); + $testFinder->expects($this->once())->method('hasCoreTests')->will($this->returnValue(TRUE)); + $testFinder->expects($this->once())->method('getAbsoluteCoreTestsPath')->will($this->returnValue('/core/tests/')); + + $this->assertSame( + Tx_Phpunit_TestableCode::CORE_KEY, + array_pop($testFinder->getTestableCodeForCore())->getKey() + ); + } + + /** + * @test + */ + public function getTestableCodeForCoreExistingCoreTestsReturnsTestableCodeWithTypo3CoreTitle() { + $testFinder = $this->getMock('Tx_Phpunit_Service_TestFinder', array('hasCoreTests', 'getAbsoluteCoreTestsPath')); + $testFinder->expects($this->once())->method('hasCoreTests')->will($this->returnValue(TRUE)); + $testFinder->expects($this->once())->method('getAbsoluteCoreTestsPath')->will($this->returnValue('/core/tests/')); + + $this->assertSame( + 'TYPO3 Core', + array_pop($testFinder->getTestableCodeForCore())->getTitle() + ); + } + + /** + * @test + */ + public function getTestableCodeForCoreExistingCoreTestsReturnsTestableCodeWithSitePath() { + $testFinder = $this->getMock('Tx_Phpunit_Service_TestFinder', array('hasCoreTests', 'getAbsoluteCoreTestsPath')); + $testFinder->expects($this->once())->method('hasCoreTests')->will($this->returnValue(TRUE)); + $testFinder->expects($this->once())->method('getAbsoluteCoreTestsPath')->will($this->returnValue('/core/tests/')); + + $this->assertSame( + PATH_site, + array_pop($testFinder->getTestableCodeForCore())->getCodePath() + ); + } + + /** + * @test + */ + public function getTestableCodeForCoreExistingCoreTestsReturnsTestableCodeWithCoreTestsPath() { + $coreTestsPath = '/core/tests/'; + + $testFinder = $this->getMock('Tx_Phpunit_Service_TestFinder', array('hasCoreTests', 'getAbsoluteCoreTestsPath')); + $testFinder->expects($this->once())->method('hasCoreTests')->will($this->returnValue(TRUE)); + $testFinder->expects($this->once())->method('getAbsoluteCoreTestsPath')->will($this->returnValue($coreTestsPath)); + + $this->assertSame( + $coreTestsPath, + array_pop($testFinder->getTestableCodeForCore())->getTestsPath() + ); + } + + /** + * @test + */ + public function getTestableCodeForCoreExistingCoreTestsReturnsTestableCodeWithTypo3IconPath() { + $testFinder = $this->getMock('Tx_Phpunit_Service_TestFinder', array('hasCoreTests', 'getAbsoluteCoreTestsPath')); + $testFinder->expects($this->once())->method('hasCoreTests')->will($this->returnValue(TRUE)); + $testFinder->expects($this->once())->method('getAbsoluteCoreTestsPath')->will($this->returnValue('/core/tests/')); + + $this->assertSame( + t3lib_extMgm::extRelPath('phpunit') . 'Resources/Public/Icons/Typo3.png', + array_pop($testFinder->getTestableCodeForCore())->getIconPath() + ); + } + + /** + * @test + */ + public function getLoadedExtensionKeysReturnsKeysOfLoadedExtensions() { + $GLOBALS['TYPO3_CONF_VARS']['EXT']['extList'] = 'foo,bar'; + + $this->assertSame( + array('foo', 'bar'), + $this->fixture->getLoadedExtensionKeys() + ); + } + + /** + * @test + */ + public function getExcludedExtensionKeysReturnsKeysOfExcludedExtensions() { + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['excludeextensions'] = 'foo,bar'; + + $this->assertSame( + array('foo', 'bar'), + $this->fixture->getExcludedExtensionKeys() + ); + } + + /** + * @test + */ + public function getExcludedExtensionKeysForNoExcludedExtensionsReturnsEmptyArray() { + $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['excludeextensions'] = ''; + + $this->assertSame( + array(), + $this->fixture->getExcludedExtensionKeys() + ); + } + + /** + * @test + */ + public function getExcludedExtensionKeysForNoPhpUnitConfigurationReturnsEmptyArray() { + unset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['phpunit']['excludeextensions']); + + $this->assertSame( + array(), + $this->fixture->getExcludedExtensionKeys() + ); + } + + /** + * @test + */ + public function getDummyExtensionKeysReturnsKeysOfPhpUnitDummyExtensions() { + $this->assertSame( + array('aaa', 'bbb', 'ccc', 'ddd'), + $this->fixture->getDummyExtensionKeys() + ); + } + + /** + * @test + */ + public function getTestableCodeForExtensionsCreatesTestableCodeForSingleExtensionForInstalledExtensionsWithoutExcludedExtensions() { + $testFinder = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', + array('getLoadedExtensionKeys', 'getExcludedExtensionKeys', 'findTestsPathForExtension', 'createTestableCodeForSingleExtension') + ); + $testFinder->expects($this->once())->method('getLoadedExtensionKeys')->will($this->returnValue(array('foo', 'bar', 'foobar'))); + $testFinder->expects($this->once())->method('getExcludedExtensionKeys')->will($this->returnValue(array('foo', 'baz'))); + + $testFinder->expects($this->at(2))->method('createTestableCodeForSingleExtension')->with('bar'); + $testFinder->expects($this->at(3))->method('createTestableCodeForSingleExtension')->with('foobar'); + + $testFinder->getTestableCodeForExtensions(); + } + + /** + * @test + */ + public function getTestableCodeForExtensionsCreatesTestableCodeForSingleExtensionForInstalledExtensionsWithoutDummyExtensions() { + $testFinder = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', + array('getLoadedExtensionKeys', 'getExcludedExtensionKeys', 'getDummyExtensionKeys', + 'findTestsPathForExtension', 'createTestableCodeForSingleExtension', + ) + ); + $testFinder->expects($this->once())->method('getLoadedExtensionKeys')->will($this->returnValue(array('foo', 'bar', 'foobar'))); + $testFinder->expects($this->once())->method('getExcludedExtensionKeys')->will($this->returnValue(array())); + $testFinder->expects($this->once())->method('getDummyExtensionKeys')->will($this->returnValue(array('foo', 'baz'))); + + $testFinder->expects($this->at(3))->method('createTestableCodeForSingleExtension')->with('bar'); + $testFinder->expects($this->at(4))->method('createTestableCodeForSingleExtension')->with('foobar'); + + $testFinder->getTestableCodeForExtensions(); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function findTestsPathForExtensionForExtensionWithEmptyExtensionKeyThrowsException() { + $this->fixture->findTestsPathForExtension(''); + } + + /** + * @test + * + * @expectedException Tx_Phpunit_Exception_NoTestsDirectory + */ + public function findTestsPathForExtensionForExtensionWithoutTestsPathThrowsException() { + if (!t3lib_extMgm::isLoaded('aaa')) { + $this->markTestSkipped( + 'This test can only be run if the extension "aaa" from Tests/res is installed.' + ); + } + + $this->fixture->findTestsPathForExtension('aaa'); + } + + /** + * @test + * + * Note: This tests uses a lowercase compare because some systems use a + * case-insensitive file system. + */ + public function findTestsPathForExtensionForExtensionWithUpperFirstTestsDirectoryReturnsThatDirectory() { + $this->assertSame( + strtolower(t3lib_extMgm::extPath('phpunit') . 'Tests/'), + strtolower($this->fixture->findTestsPathForExtension('phpunit')) + ); + } + + /** + * @test + * + * Note: This tests uses a lowercase compare because some systems use a + * case-insensitive file system. + */ + public function findTestsPathForExtensionForExtensionWithLowerCaseTestsDirectoryReturnsThatDirectory() { + if (!t3lib_extMgm::isLoaded('bbb')) { + $this->markTestSkipped( + 'This test can only be run if the extension "bbb" from Tests/res is installed.' + ); + } + + $this->assertSame( + strtolower(t3lib_extMgm::extPath('bbb') . 'tests/'), + strtolower($this->fixture->findTestsPathForExtension('bbb')) + ); + } + + /** + * @test + */ + public function getTestableCodeForExtensionsForNoInstalledExtensionsReturnsEmptyArray() { + $testFinder = $this->getMock('Tx_Phpunit_Service_TestFinder', array('getLoadedExtensionKeys')); + $testFinder->expects($this->once())->method('getLoadedExtensionKeys')->will($this->returnValue(array())); + + $this->assertSame( + array(), + $testFinder->getTestableCodeForExtensions() + ); + } + + /** + * @test + */ + public function getTestableCodeForExtensionsForOneInstalledExtensionsWithTestsReturnsOneTestableCodeInstance() { + $testableCodeInstance = new Tx_Phpunit_TestableCode(); + + $testFinder = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', + array('getLoadedExtensionKeys', 'getExcludedExtensionKeys', 'findTestsPathForExtension', 'createTestableCodeForSingleExtension') + ); + $testFinder->expects($this->once())->method('getLoadedExtensionKeys')->will($this->returnValue(array('foo'))); + $testFinder->expects($this->once())->method('getExcludedExtensionKeys')->will($this->returnValue(array())); + $testFinder->expects($this->once())->method('createTestableCodeForSingleExtension') + ->with('foo')->will($this->returnValue($testableCodeInstance)); + + $this->assertSame( + array('foo' => $testableCodeInstance), + $testFinder->getTestableCodeForExtensions() + ); + } + + /** + * @test + */ + public function getTestableCodeForExtensionsForTwoInstalledExtensionsWithTestsReturnsTwoResults() { + $testFinder = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', + array('getLoadedExtensionKeys', 'getExcludedExtensionKeys', 'findTestsPathForExtension', 'createTestableCodeForSingleExtension') + ); + $testFinder->expects($this->once())->method('getLoadedExtensionKeys')->will($this->returnValue(array('foo', 'bar'))); + $testFinder->expects($this->once())->method('getExcludedExtensionKeys')->will($this->returnValue(array())); + $testFinder->expects($this->at(2))->method('createTestableCodeForSingleExtension') + ->with('foo')->will($this->returnValue(new Tx_Phpunit_TestableCode())); + $testFinder->expects($this->at(3))->method('createTestableCodeForSingleExtension') + ->with('bar')->will($this->returnValue(new Tx_Phpunit_TestableCode())); + + $this->assertSame( + 2, + count($testFinder->getTestableCodeForExtensions()) + ); + } + + /** + * @test + */ + public function getTestableCodeForExtensionsForOneInstalledExtensionsWithoutTestsReturnsEmptyArray() { + $testFinder = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', + array('getLoadedExtensionKeys', 'getExcludedExtensionKeys', 'findTestsPathForExtension') + ); + $testFinder->expects($this->once())->method('getLoadedExtensionKeys')->will($this->returnValue(array('foo'))); + $testFinder->expects($this->once())->method('getExcludedExtensionKeys')->will($this->returnValue(array())); + $testFinder->expects($this->once())->method('findTestsPathForExtension') + ->with('foo')->will($this->throwException(new Tx_Phpunit_Exception_NoTestsDirectory())); + + $this->assertSame( + array(), + $testFinder->getTestableCodeForExtensions() + ); + } + + /** + * @test + */ + public function getTestableCodeForExtensionsForOneExtensionsWithoutTestsAndOneWithTestsReturnsFirstExtension() { + $testableCodeInstance = new Tx_Phpunit_TestableCode(); + + $testFinder = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', + array('getLoadedExtensionKeys', 'getExcludedExtensionKeys', 'findTestsPathForExtension', 'createTestableCodeForSingleExtension') + ); + $testFinder->expects($this->once())->method('getLoadedExtensionKeys')->will($this->returnValue(array('foo', 'bar'))); + $testFinder->expects($this->once())->method('getExcludedExtensionKeys')->will($this->returnValue(array())); + $testFinder->expects($this->at(2))->method('createTestableCodeForSingleExtension') + ->with('foo')->will($this->throwException(new Tx_Phpunit_Exception_NoTestsDirectory())); + $testFinder->expects($this->at(3))->method('createTestableCodeForSingleExtension') + ->with('bar')->will($this->returnValue($testableCodeInstance)); + + $this->assertSame( + array('bar' => $testableCodeInstance), + $testFinder->getTestableCodeForExtensions() + ); + } + + /** + * @test + */ + public function getTestableCodeForExtensionsProvidesTestableCodeInstanceWithExtensionType() { + $testFinder = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', + array('getLoadedExtensionKeys', 'getExcludedExtensionKeys', 'findTestsPathForExtension', 'retrieveExtensionTitle') + ); + $testFinder->expects($this->once())->method('getLoadedExtensionKeys')->will($this->returnValue(array('phpunit'))); + $testFinder->expects($this->once())->method('getExcludedExtensionKeys')->will($this->returnValue(array())); + $testFinder->expects($this->once())->method('findTestsPathForExtension') + ->with('phpunit')->will($this->returnValue(t3lib_extMgm::extPath('phpunit') . 'Tests/')); + + $this->assertSame( + Tx_Phpunit_TestableCode::TYPE_EXTENSION, + array_pop($testFinder->getTestableCodeForExtensions())->getType() + ); + } + + /** + * @test + */ + public function getTestableCodeForExtensionsProvidesTestableCodeInstanceWithExtensionKey() { + $testFinder = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', + array('getLoadedExtensionKeys', 'getExcludedExtensionKeys', 'findTestsPathForExtension', 'retrieveExtensionTitle') + ); + $testFinder->expects($this->once())->method('getLoadedExtensionKeys')->will($this->returnValue(array('phpunit'))); + $testFinder->expects($this->once())->method('getExcludedExtensionKeys')->will($this->returnValue(array())); + $testFinder->expects($this->once())->method('findTestsPathForExtension') + ->with('phpunit')->will($this->returnValue(t3lib_extMgm::extPath('phpunit') . 'Tests/')); + + $this->assertSame( + 'phpunit', + array_pop($testFinder->getTestableCodeForExtensions())->getKey() + ); + } + + /** + * @test + */ + public function getTestableCodeForExtensionsProvidesTestableCodeInstanceWithExtensionTitle() { + $testFinder = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', + array('getLoadedExtensionKeys', 'getExcludedExtensionKeys', 'findTestsPathForExtension', 'retrieveExtensionTitle') + ); + $testFinder->expects($this->once())->method('getLoadedExtensionKeys')->will($this->returnValue(array('phpunit'))); + $testFinder->expects($this->once())->method('getExcludedExtensionKeys')->will($this->returnValue(array())); + $testFinder->expects($this->once())->method('findTestsPathForExtension') + ->with('phpunit')->will($this->returnValue(t3lib_extMgm::extPath('phpunit') . 'Tests/')); + $testFinder->expects($this->once())->method('retrieveExtensionTitle') + ->with('phpunit')->will($this->returnValue('PHPUnit')); + + $this->assertSame( + 'PHPUnit', + array_pop($testFinder->getTestableCodeForExtensions())->getTitle() + ); + } + + /** + * @test + */ + public function getTestableCodeForExtensionsProvidesTestableCodeInstanceWithCodePath() { + $testFinder = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', + array('getLoadedExtensionKeys', 'getExcludedExtensionKeys', 'findTestsPathForExtension', 'retrieveExtensionTitle') + ); + $testFinder->expects($this->once())->method('getLoadedExtensionKeys')->will($this->returnValue(array('phpunit'))); + $testFinder->expects($this->once())->method('getExcludedExtensionKeys')->will($this->returnValue(array())); + $testFinder->expects($this->once())->method('findTestsPathForExtension') + ->with('phpunit')->will($this->returnValue(t3lib_extMgm::extPath('phpunit') . 'Tests/')); + + $this->assertSame( + t3lib_extMgm::extPath('phpunit'), + array_pop($testFinder->getTestableCodeForExtensions())->getCodePath() + ); + } + + /** + * @test + */ + public function getTestableCodeForExtensionsProvidesTestableCodeInstanceWithTestsPath() { + $testFinder = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', + array('getLoadedExtensionKeys', 'getExcludedExtensionKeys', 'findTestsPathForExtension', 'retrieveExtensionTitle') + ); + $testFinder->expects($this->once())->method('getLoadedExtensionKeys')->will($this->returnValue(array('phpunit'))); + $testFinder->expects($this->once())->method('getExcludedExtensionKeys')->will($this->returnValue(array())); + $testFinder->expects($this->once())->method('findTestsPathForExtension') + ->with('phpunit')->will($this->returnValue(t3lib_extMgm::extPath('phpunit') . 'Tests/')); + + $this->assertSame( + t3lib_extMgm::extPath('phpunit') . 'Tests/', + array_pop($testFinder->getTestableCodeForExtensions())->getTestsPath() + ); + } + + /** + * @test + */ + public function getTestableCodeForExtensionsProvidesTestableCodeInstanceWithIconPath() { + $testFinder = $this->getMock( + 'Tx_Phpunit_Service_TestFinder', + array('getLoadedExtensionKeys', 'getExcludedExtensionKeys', 'findTestsPathForExtension', 'retrieveExtensionTitle') + ); + $testFinder->expects($this->once())->method('getLoadedExtensionKeys')->will($this->returnValue(array('phpunit'))); + $testFinder->expects($this->once())->method('getExcludedExtensionKeys')->will($this->returnValue(array())); + $testFinder->expects($this->once())->method('findTestsPathForExtension') + ->with('phpunit')->will($this->returnValue(t3lib_extMgm::extPath('phpunit') . 'Tests/')); + + $this->assertSame( + t3lib_extMgm::extRelPath('phpunit') . 'ext_icon.gif', + array_pop($testFinder->getTestableCodeForExtensions())->getIconPath() + ); + } + + /** + * @test + */ + public function retrieveExtensionTitleReturnsTitleOfInstalledExtension() { + $this->assertSame( + 'PHPUnit', + $this->fixture->retrieveExtensionTitle('phpunit') + ); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/TestCaseTest.php b/typo3conf/ext/phpunit/Tests/TestCaseTest.php new file mode 100644 index 0000000..85829e6 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/TestCaseTest.php @@ -0,0 +1,54 @@ +<?php +/*************************************************************** + * Copyright notice + * + * (c) 2007-2011 Kasper Ligaard (kasperligaard@gmail.com) + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/** + * Test case for the Tx_Phpunit_TestCase class. + * + * @author Kasper Ligaard <kasperligaard@gmail.com> + */ +class Tx_Phpunit_TestCaseTest extends Tx_Phpunit_TestCase { + /** + * @test + */ + public function newArrayIsEmpty() { + $fixture = array(); + + $this->assertEquals(0, sizeof($fixture)); + } + + /** + * @test + */ + public function thisCaseIsMarkedAsSkipped() { + $this->markTestSkipped('This test is skipped while testing.'); + } + + /** + * @test + */ + public function thisCaseIsMarkedAsNotImplemented() { + $this->markTestIncomplete('This test as incomplete while not implemented for testing.'); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/TestableCodeTest.php b/typo3conf/ext/phpunit/Tests/TestableCodeTest.php new file mode 100644 index 0000000..efad0f1 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/TestableCodeTest.php @@ -0,0 +1,329 @@ +<?php +/*************************************************************** +* Copyright notice +* +* (c) 2011 Oliver Klee (typo3-coding@oliverklee.de) +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +/** + * Testcase for the Tx_Phpunit_TestableCode class. + * + * @package TYPO3 + * @subpackage tx_ + * + * @author Oliver Klee <typo3-coding@oliverklee.de> + */ +class Tx_Phpunit_TestableCodeTest extends Tx_Phpunit_TestCase { + /** + * @var Tx_Phpunit_TestableCode + */ + private $fixture; + + public function setUp() { + $this->fixture = new Tx_Phpunit_TestableCode(); + } + + public function tearDown() { + unset($this->fixture); + } + + /** + * @test + */ + public function getKeyInitiallyReturnsEmptyString() { + $this->assertSame( + '', + $this->fixture->getKey() + ); + } + + /** + * @test + */ + public function setKeySetsKey() { + $this->fixture->setKey('foo'); + + $this->assertSame( + 'foo', + $this->fixture->getKey() + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function setKeyWithEmptyStringThrowsException() { + $this->fixture->setKey(''); + } + + /** + * @test + */ + public function getTitleInitiallyReturnsEmptyString() { + $this->assertSame( + '', + $this->fixture->getTitle() + ); + } + + /** + * @test + */ + public function setTitleSetsTitle() { + $this->fixture->setTitle('White Russian'); + + $this->assertSame( + 'White Russian', + $this->fixture->getTitle() + ); + } + + /** + * @test + */ + public function setTitleCanSetTitleToEmptyString() { + $this->fixture->setTitle(''); + + $this->assertSame( + '', + $this->fixture->getTitle() + ); + } + + /** + * @test + */ + public function getTypeInitiallyReturnsUndefined() { + $this->assertSame( + Tx_Phpunit_TestableCode::TYPE_UNDEFINED, + $this->fixture->getType() + ); + } + + /** + * @test + */ + public function setTypeCanSetTypeToExtension() { + $this->fixture->setType(Tx_Phpunit_TestableCode::TYPE_EXTENSION); + + $this->assertSame( + Tx_Phpunit_TestableCode::TYPE_EXTENSION, + $this->fixture->getType() + ); + } + + /** + * @test + */ + public function setTypeCanSetTypeToCore() { + $this->fixture->setType(Tx_Phpunit_TestableCode::TYPE_CORE); + + $this->assertSame( + Tx_Phpunit_TestableCode::TYPE_CORE, + $this->fixture->getType() + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function setTypeForUndefinedTypeThrowsException() { + $this->fixture->setType(Tx_Phpunit_TestableCode::TYPE_UNDEFINED); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function setTypeForInvalidTypeThrowsException() { + $this->fixture->setType(-1); + } + + /** + * @test + */ + public function getCodePathInitiallyReturnsEmptyString() { + $this->assertSame( + '', + $this->fixture->getCodePath() + ); + } + + /** + * @test + */ + public function setCodePathSetsCodePath() { + $path = t3lib_extMgm::extPath('phpunit'); + $this->fixture->setCodePath($path); + + $this->assertSame( + $path, + $this->fixture->getCodePath() + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function setCodePathWithEmptyStringThrowsException() { + $this->fixture->setCodePath(''); + } + + /** + * @test + */ + public function getTestsPathInitiallyReturnsEmptyString() { + $this->assertSame( + '', + $this->fixture->getTestsPath() + ); + } + + /** + * @test + */ + public function setTestsPathSetsTestsPath() { + $path = t3lib_extMgm::extPath('phpunit'); + $this->fixture->setTestsPath($path); + + $this->assertSame( + $path, + $this->fixture->getTestsPath() + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function setTestsPathWithEmptyStringThrowsException() { + $this->fixture->setTestsPath(''); + } + + /** + * @test + */ + public function getBlacklistInitiallyReturnsEmptyArray() { + $this->assertSame( + array(), + $this->fixture->getBlacklist() + ); + } + + /** + * @test + */ + public function setBlacklistSetsBlacklist() { + $fileNames = array('one file', 'another file'); + $this->fixture->setBlacklist($fileNames); + + $this->assertSame( + $fileNames, + $this->fixture->getBlacklist() + ); + } + + /** + * @test + */ + public function setBlacklistCanSetEmptyBlacklist() { + $this->fixture->setBlacklist(array()); + + $this->assertSame( + array(), + $this->fixture->getBlacklist() + ); + } + + /** + * @test + */ + public function getWhitelistInitiallyReturnsEmptyArray() { + $this->assertSame( + array(), + $this->fixture->getWhitelist() + ); + } + + /** + * @test + */ + public function setWhitelistSetsWhitelist() { + $fileNames = array('one file', 'another file'); + $this->fixture->setWhitelist($fileNames); + + $this->assertSame( + $fileNames, + $this->fixture->getWhitelist() + ); + } + + /** + * @test + */ + public function setWhitelistCanSetEmptyWhitelist() { + $this->fixture->setWhitelist(array()); + + $this->assertSame( + array(), + $this->fixture->getWhitelist() + ); + } + + /** + * @test + */ + public function getIconPathInitiallyReturnsEmptyString() { + $this->assertSame( + '', + $this->fixture->getIconPath() + ); + } + + /** + * @test + */ + public function setIconPathSetsIconPath() { + $this->fixture->setIconPath('someIcon.gif'); + + $this->assertSame( + 'someIcon.gif', + $this->fixture->getIconPath() + ); + } + + /** + * @test + * + * @expectedException InvalidArgumentException + */ + public function setIconPathWithEmptyStringThrowsException() { + $this->fixture->setIconPath(''); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/VfsStreamTest.php b/typo3conf/ext/phpunit/Tests/VfsStreamTest.php new file mode 100644 index 0000000..70941f5 --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/VfsStreamTest.php @@ -0,0 +1,78 @@ +<?php +/*************************************************************** +* Copyright notice +* +* (c) 2011 Oliver Klee (typo3-coding@oliverklee.de) +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +/** + * Testcase for the vfsStream classes. + * + * @package TYPO3 + * @subpackage tx_phpunit + * + * @author Oliver Klee <typo3-coding@oliverklee.de> + */ +class Tx_PhpUnit_VfsStreamTest extends Tx_Phpunit_TestCase { + /** + * @test + */ + public function vfsStreamCanBeInstantiated() { + new vfsStream(); + } + + /** + * @test + */ + public function vfsStreamContainerIteratorCanBeInstantiated() { + new vfsStreamContainerIterator(array()); + } + + /** + * @test + */ + public function vfsStreamDirectoryCanBeInstantiated() { + new vfsStreamDirectory(''); + } + + /** + * @test + * + * @expectedException vfsStreamException + */ + public function vfsStreamExceptionCanBeThrown() { + throw new vfsStreamException(); + } + + /** + * @test + */ + public function vfsStreamFileCanBeInstantiated() { + new vfsStreamFile(''); + } + + /** + * @test + */ + public function vfsStreamWrapperCanBeInstantiated() { + new vfsStreamWrapper(); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/Tests/tx_phpunit_testsuite.php b/typo3conf/ext/phpunit/Tests/tx_phpunit_testsuite.php new file mode 100644 index 0000000..b4f7abb --- /dev/null +++ b/typo3conf/ext/phpunit/Tests/tx_phpunit_testsuite.php @@ -0,0 +1,41 @@ +<?php +/*************************************************************** + * Copyright notice + * + * (c) 2007-2011 Kasper Ligaard <kasperligaard@gmail.com> + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/** + * Test case for checking the PHPUnit 3.1.9 + * + * WARNING: Never ever run a unit test like this on a live site! + * + * @author Kasper Ligaard <kasperligaard@gmail.com> + */ +class tx_phpunit_test_testsuite extends PHPUnit_Framework_TestSuite { + /** + * The constructor. + */ + public function __construct() { + $this->addTestFile(dirname(__FILE__) . '/tx_phpunit_test_testcase.php'); + $this->addTestFile(dirname(__FILE__) . '/database_testcase.php'); + } +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/class.tx_phpunit_database_testcase.php b/typo3conf/ext/phpunit/class.tx_phpunit_database_testcase.php new file mode 100644 index 0000000..d30dedf --- /dev/null +++ b/typo3conf/ext/phpunit/class.tx_phpunit_database_testcase.php @@ -0,0 +1,6 @@ +<?php +/** + * This is a dummy placeholder. The test base classes should not get explictly + * included/required anymore. Instead, the autoloader will load them. + */ +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/class.tx_phpunit_selenium_testcase.php b/typo3conf/ext/phpunit/class.tx_phpunit_selenium_testcase.php new file mode 100644 index 0000000..d30dedf --- /dev/null +++ b/typo3conf/ext/phpunit/class.tx_phpunit_selenium_testcase.php @@ -0,0 +1,6 @@ +<?php +/** + * This is a dummy placeholder. The test base classes should not get explictly + * included/required anymore. Instead, the autoloader will load them. + */ +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/class.tx_phpunit_testcase.php b/typo3conf/ext/phpunit/class.tx_phpunit_testcase.php new file mode 100644 index 0000000..d30dedf --- /dev/null +++ b/typo3conf/ext/phpunit/class.tx_phpunit_testcase.php @@ -0,0 +1,6 @@ +<?php +/** + * This is a dummy placeholder. The test base classes should not get explictly + * included/required anymore. Instead, the autoloader will load them. + */ +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/doc/Framework/annotated.html b/typo3conf/ext/phpunit/doc/Framework/annotated.html new file mode 100644 index 0000000..4fdd877 --- /dev/null +++ b/typo3conf/ext/phpunit/doc/Framework/annotated.html @@ -0,0 +1,43 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/> +<title>PHPUnit: Data Structures + + + + + + +
    +
    +

    Data Structures

    +
    +
    +Here are the data structures with brief descriptions: + + + +
    Tx_Phpunit_Framework
    Tx_Phpunit_TestableCode
    Tx_Phpunit_TestCase
    +
    + + + diff --git a/typo3conf/ext/phpunit/doc/Framework/bc_s.png b/typo3conf/ext/phpunit/doc/Framework/bc_s.png new file mode 100644 index 0000000000000000000000000000000000000000..e4018628b5b45cb4301037485a29d7d74ac22138 GIT binary patch literal 677 zcmV;W0$TlvP)X?0Pv5h+5!wElpi=&YL!gfY!djl#UDdPKy97F|A-deTa@qo3BWh1YQIvzmHR^g zFjV4I6pLB7_*vEZk^%p7c7Bh>0`4r^X#gpJE_Vz9fSHKqclcZaV^k3gX%h+1`u||O zZ+BY?7(R=ayr^kXE=E0Dw=$Ud3VJ?9^Cz@hP?388Cw5>9TloOJ>^KczCgj zns2=|0!a|)Yq3{hjL{xyy7|Tk0N}Pe+g9PUTL!4{#;eUhrNd@!_T<>Vu+35c)h>sq ztgb?(6W3oFLz#%?OMEV@{j#4LuDvjVGZ~6hpQT8li5b0yjvK8c4efl+vSz5)P6 zle78)00_Iv5)&E~hnOdcd}L}i+MU>k+Q8#@KjqJJN`gRj(~)RmNrck9ht@LelPtVO zwp(J;k!T=gC#%o(13-^E+g@aqc()pf{+j|0w)AH*Mq$54UjLv#jV$RYpz3Vjg$$=u z>yjfBQOhL=^@+#4#$l|{~}HZ-?1Yy{lI*$N}*YDC`<{+;>_#gMXZdz4NI00000 LNkvXXu0mjfx86dR literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/doc/Framework/class_tx___phpunit___framework.html b/typo3conf/ext/phpunit/doc/Framework/class_tx___phpunit___framework.html new file mode 100644 index 0000000..aeff900 --- /dev/null +++ b/typo3conf/ext/phpunit/doc/Framework/class_tx___phpunit___framework.html @@ -0,0 +1,2139 @@ + + + + +PHPUnit: Tx_Phpunit_Framework Class Reference + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    +Public Member Functions

     __construct ($tablePrefix, array $additionalTablePrefixes=array())
     createRecord ($tableName, array $recordData=array())
     createFrontEndPage ($parentId=0, array $recordData=array())
     createSystemFolder ($parentId=0, array $recordData=array())
     createContentElement ($pageId=0, array $recordData=array())
     createTemplate ($pageId, array $recordData=array())
     createFrontEndUserGroup (array $recordData=array())
     createFrontEndUser ($frontEndUserGroups= '', array $recordData=array())
     createAndLoginFrontEndUser ($frontEndUserGroups= '', array $recordData=array())
     createBackEndUser (array $recordData=array())
     createBackEndUserGroup (array $recordData=array())
     changeRecord ($tableName, $uid, array $recordData)
     deleteRecord ($tableName, $uid)
     createRelation ($tableName, $uidLocal, $uidForeign, $sorting=0)
     createRelationAndUpdateCounter ($tableName, $uidLocal, $uidForeign, $columnName)
     removeRelation ($tableName, $uidLocal, $uidForeign)
     cleanUp ($performDeepCleanUp=FALSE)
     createDummyFile ($fileName= 'test.txt', $content= '')
     createDummyZipArchive ($fileName= 'test.zip', array $filesToAddToArchive=array())
     deleteDummyFile ($fileName)
     createDummyFolder ($folderName)
     deleteDummyFolder ($folderName)
     setUploadFolderPath ($absolutePath)
     getUploadFolderPath ()
     getPathRelativeToUploadDirectory ($absolutePath)
     getUniqueFileOrFolderPath ($path)
     createFakeFrontEnd ($pageUid=0)
     discardFakeFrontEnd ()
     hasFakeFrontEnd ()
     loginFrontEndUser ($userId)
     logoutFrontEndUser ()
     isLoggedIn ()
     getDummyColumnName ($tableName)
     countRecords ($tableName, $whereClause= '')
     existsRecord ($tableName, $whereClause= '')
     existsRecordWithUid ($tableName, $uid)
     existsExactlyOneRecord ($tableName, $whereClause= '')
     resetAutoIncrement ($tableName)
     resetAutoIncrementLazily ($tableName)
     setResetAutoIncrementThreshold ($threshold)
     getAutoIncrement ($tableName)
     getListOfOwnAllowedTableNames ()
     getListOfAdditionalAllowedTableNames ()
     markTableAsDirty ($tableNames)
     getListOfDirtyTables ()
     getListOfDirtySystemTables ()
     getRelationSorting ($tableName, $uidLocal)
     increaseRelationCounter ($tableName, $uid, $fieldName)
     checkForZipArchive ()
     purgeHooks ()

    +Protected Member Functions

     createRecordWithoutTableNameChecks ($tableName, array $recordData)
     createGeneralPageRecord ($documentType, $parentId, array $recordData)
     cleanUpTableSet ($useSystemTables, $performDeepCleanUp)
     deleteAllDummyFoldersAndFiles ()
     addToDummyFileList ($uniqueFileName)
     createDummyUploadFolder ()
     suppressFrontEndCookies ()
     createListOfOwnAllowedTables ()
     createListOfAdditionalAllowedTables ()
     isOwnTableNameAllowed ($tableName)
     isAdditionalTableNameAllowed ($tableName)
     isSystemTableNameAllowed ($tableName)
     isNoneSystemTableNameAllowed ($tableName)
     isTableNameAllowed ($tableName)
     getMaximumUidFromTable ($tableName)
     getHooks ()

    +Protected Attributes

    $tablePrefix = ''
    $additionalTablePrefixes = array()
    $ownAllowedTables = array()
    $additionalAllowedTables = array()
     $allowedSystemTables
    $dirtyTables = array()
    $dirtySystemTables = array()
    $relationSorting = array()
    $resetAutoIncrementThreshold = 100
    $dummyFiles = array()
    $dummyFolders = array()
    $uploadFolderPath = ''
    $hasFakeFrontEnd = FALSE

    +Static Protected Attributes

    +static $fileNameProcessor = NULL
    +static $hooks = array()
    +static $hooksHaveBeenRetrieved = FALSE
    +

    Constructor & Destructor Documentation

    + +
    +
    + + + + + + + + + + + + + + + + + + +
    __construct ( tablePrefix,
    array $  additionalTablePrefixes = array() 
    )
    +
    +
    +

    The constructor for this class.

    +

    This testing framework can be instantiated for one extension at a time. Example: In your testcase, you'll have something similar to this line of code: $this->fixture = new Tx_Phpunit_Framework('tx_seminars'); The parameter you provide is the prefix of the table names of that particular extension. Like this, we ensure that the testing framework creates and deletes records only on table with this prefix.

    +

    If you need dummy records on tables of multiple extensions, you'll have to instantiate the testing frame work multiple times (once per extension).

    +
    Parameters:
    + + + +
    string $tablePrefix the table name prefix of the extension for which this instance of the testing framework should be used
    array $additionalTablePrefixes the additional table name prefixes of the extensions for which this instance of the testing framework should be used, may be empty
    +
    +
    + +
    +
    +

    Member Function Documentation

    + +
    +
    + + + + + + + + + +
    addToDummyFileList ( uniqueFileName )  [protected]
    +
    +
    +

    Adds a file name to $this->dummyFiles.

    +
    Parameters:
    + + +
    string $uniqueFileName file name to add, must be the unique name of a dummy file, must not be empty
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    changeRecord ( tableName,
    uid,
    array $  recordData 
    )
    +
    +
    +

    Changes an existing dummy record and stores the new data for this record. Only fields that get new values in $recordData will be changed, everything else will stay untouched.

    +

    The array with the new recordData must contain at least one entry, but must not contain a new UID for the record. If you need to change the UID, you have to create a new record!

    +
    Parameters:
    + + + + +
    string $tableName the name of the table, must not be empty
    integer $uid the UID of the record to change, must not be empty
    array $recordData associative array containing key => value pairs for those fields of the record that need to be changed, must not be empty
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + +
    checkForZipArchive ( ) 
    +
    +
    +

    Checks whether the ZIPArchive class is provided by the PHP installation.

    +

    Note: This function can be used to mark tests as skipped if this class is not available but required for a test to pass succesfully.

    +
    Exceptions:
    + + +
    t3lib_exception if the PHP installation does not provide ZIPArchive
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + +
    cleanUp ( performDeepCleanUp = FALSE ) 
    +
    +
    +

    Deletes all dummy records that have been added through this framework. For this, all records with the "is_dummy_record" flag set to 1 will be deleted from all tables that have been used within this instance of the testing framework.

    +

    If you set $performDeepCleanUp to TRUE, it will go through ALL tables to which the current instance of the testing framework has access. Please consider well, whether you want to do this as it's a huge performance issue.

    +
    Parameters:
    + + +
    boolean $performDeepCleanUp whether a deep clean up should be performed
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    cleanUpTableSet ( useSystemTables,
    performDeepCleanUp 
    ) [protected]
    +
    +
    +

    Deletes a set of records that have been added through this framework for a set of tables (either the test tables or the allowed system tables). For this, all records with the "is_dummy_record" flag set to 1 will be deleted from all tables that have been used within this instance of the testing framework.

    +

    If you set $performDeepCleanUp to TRUE, it will go through ALL tables to which the current instance of the testing framework has access. Please consider well, whether you want to do this as it's a huge performance issue.

    +
    Parameters:
    + + + +
    boolean $useSystemTables whether to clean up the system tables (TRUE) or the non-system test tables (FALSE)
    boolean $performDeepCleanUp whether a deep clean up should be performed
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    countRecords ( tableName,
    whereClause = '' 
    )
    +
    +
    +

    Counts the dummy records in the table given by the first parameter $tableName that match a given WHERE clause.

    +
    Parameters:
    + + + +
    string $tableName the name of the table to query, must not be empty
    string $whereClause the WHERE part of the query, may be empty (all records will be counted in that case)
    +
    +
    +
    Returns:
    integer the number of records that have been found, will be >= 0
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    createAndLoginFrontEndUser ( frontEndUserGroups = '',
    array $  recordData = array() 
    )
    +
    +
    +

    Creates and logs in an FE user.

    +
    Parameters:
    + + + +
    string $frontEndUserGroups comma-separated list of UIDs of the user groups to which the new user belongs, each must be > 0, may contain spaces; if empty a new front-end user group is created
    array $recordData associative array that contains the data to save in the new user record, may be empty, but must not contain the keys "uid" or "usergroup"
    +
    +
    +
    Returns:
    integer the UID of the new FE user, will be > 0
    + +
    +
    + +
    +
    + + + + + + + + + +
    createBackEndUser (array $  recordData = array() ) 
    +
    +
    +

    Creates a BE user record.

    +
    Parameters:
    + + +
    array $recordData associative array that contains the data to save in the new user record, may be empty, but must not contain the key "uid"
    +
    +
    +
    Returns:
    integer the UID of the new BE user, will be > 0
    + +
    +
    + +
    +
    + + + + + + + + + +
    createBackEndUserGroup (array $  recordData = array() ) 
    +
    +
    +

    Creates a BE user group.

    +
    Parameters:
    + + +
    array $recordData associative array that contains the data to save in the new user group record, may be empty, but must not contain the key "uid"
    +
    +
    +
    Returns:
    integer the UID of the new user group, will be > 0
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    createContentElement ( pageId = 0,
    array $  recordData = array() 
    )
    +
    +
    +

    Creates a FE content element on the page with the UID given by the first parameter $pageId.

    +

    Created content elements are text elements by default, but the content element's type can be overwritten by setting the key 'CType' in the parameter $recordData.

    +
    Parameters:
    + + + +
    integer $pageId UID of the page on which the content element should be created
    array $recordData associative array that contains the data to save in the content element, may be empty, but must not contain the keys "uid" or "pid"
    +
    +
    +
    Returns:
    integer the UID of the new content element, will be > 0
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    createDummyFile ( fileName = 'test.txt',
    content = '' 
    )
    +
    +
    +

    Creates an empty dummy file with a unique file name in the calling extension's upload directory.

    +
    Parameters:
    + + + +
    string $fileName path of the dummy file to create, relative to the calling extension's upload directory, must not be empty
    $content string content for the file to create, may be empty
    +
    +
    +
    Returns:
    string the absolute path of the created dummy file, will not be empty
    + +
    +
    + +
    +
    + + + + + + + + + +
    createDummyFolder ( folderName ) 
    +
    +
    +

    Creates a dummy folder with a unique folder name in the calling extension's upload directory.

    +
    Parameters:
    + + +
    string $folderName name of the dummy folder to create relative to $this->uploadFolderPath, must not be empty
    +
    +
    +
    Returns:
    string the absolute path of the created dummy folder, will not be empty
    + +
    +
    + +
    +
    + + + + + + + + +
    createDummyUploadFolder ( )  [protected]
    +
    +
    +

    Creates the upload folder if it does not exist yet.

    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    createDummyZipArchive ( fileName = 'test.zip',
    array $  filesToAddToArchive = array() 
    )
    +
    +
    +

    Creates a dummy ZIP archive with a unique file name in the calling extension's upload directory.

    +
    Exceptions:
    + + +
    t3lib_exception if the PHP installation does not provide ZIPArchive
    +
    +
    +
    Parameters:
    + + + +
    string $fileName path of the dummy ZIP archive to create, relative to the calling extension's upload directory, must not be empty
    array $filesToAddToArchive Absolute paths of the files to add to the ZIP archive. Note that the archives directory structure will be relative to the upload folder path, so only files within this folder or in sub-folders of this folder can be added. The provided array may be empty, but as ZIP archives cannot be empty, a content-less dummy text file will be added to the archive then.
    +
    +
    +
    Returns:
    string the absolute path of the created dummy ZIP archive, will not be empty
    + +
    +
    + +
    +
    + + + + + + + + + +
    createFakeFrontEnd ( pageUid = 0 ) 
    +
    +
    +

    Fakes a TYPO3 front end, using $pageUid as front-end page ID if provided.

    +

    If $pageUid is zero, the UID of the start page of the current domain will be used as page UID.

    +

    This function creates $GLOBALS['TSFE'] and $GLOBALS['TT'].

    +

    Note: This function does not set TYPO3_MODE to "FE" (because the value of a constant cannot be changed after it has once been set).

    +
    Parameters:
    + + +
    integer $pageUid UID of a page record to use, must be >= 0
    +
    +
    +
    Returns:
    integer the UID of the used front-end page, will be > 0
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    createFrontEndPage ( parentId = 0,
    array $  recordData = array() 
    )
    +
    +
    +

    Creates a front-end page on the page with the UID given by the first parameter $parentId.

    +
    Parameters:
    + + + +
    integer $parentId UID of the page on which the page should be created
    array $recordData associative array that contains the data to save in the new page, may be empty, but must not contain the keys "uid", "pid" or "doktype"
    +
    +
    +
    Returns:
    integer the UID of the new page, will be > 0
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    createFrontEndUser ( frontEndUserGroups = '',
    array $  recordData = array() 
    )
    +
    +
    +

    Creates a FE user record.

    +
    Parameters:
    + + + +
    string $frontEndUserGroups comma-separated list of UIDs of the user groups to which the new user belongs, each must be > 0, may contain spaces, if empty a new FE user group will be created
    array $recordData associative array that contains the data to save in the new user record, may be empty, but must not contain the keys "uid" or "usergroup"
    +
    +
    +
    Returns:
    integer the UID of the new FE user, will be > 0
    + +
    +
    + +
    +
    + + + + + + + + + +
    createFrontEndUserGroup (array $  recordData = array() ) 
    +
    +
    +

    Creates a FE user group.

    +
    Parameters:
    + + +
    array $recordData associative array that contains the data to save in the new user group record, may be empty, but must not contain the key "uid"
    +
    +
    +
    Returns:
    integer the UID of the new user group, will be > 0
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    createGeneralPageRecord ( documentType,
    parentId,
    array $  recordData 
    ) [protected]
    +
    +
    +

    Creates a page record with the document type given by the first parameter $documentType.

    +

    The record will be created on the page with the UID given by the second parameter $parentId.

    +
    Parameters:
    + + + + +
    integer $documentType document type of the record to create, must be > 0
    integer $parentId UID of the page on which the record should be created
    array $recordData associative array that contains the data to save in the record, may be empty, but must not contain the keys "uid", "pid" or "doktype"
    +
    +
    +
    Returns:
    integer the UID of the new record, will be > 0
    + +
    +
    + +
    +
    + + + + + + + + +
    createListOfAdditionalAllowedTables ( )  [protected]
    +
    +
    +

    Generates a list of additional allowed tables to which this instance of the testing framework has access to create/remove test records.

    +

    The generated list is based on the list of all tables that TYPO3 can access (which will be all tables in this database), filtered by the prefixes of additional extensions.

    +

    The array with the allowed table names is written directly to $this->additionalAllowedTables.

    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + +
    createListOfOwnAllowedTables ( )  [protected]
    +
    +
    +

    Generates a list of allowed tables to which this instance of the testing framework has access to create/remove test records.

    +

    The generated list is based on the list of all tables that TYPO3 can access (which will be all tables in this database), filtered by prefix of the extension to test.

    +

    The array with the allowed table names is written directly to $this->ownAllowedTables.

    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    createRecord ( tableName,
    array $  recordData = array() 
    )
    +
    +
    +

    Creates a new dummy record for unit tests.

    +

    If no record data for the new array is given, an empty record will be created. It will only contain a valid UID and the "is_dummy_record" flag will be set to 1.

    +

    Should there be any problem creating the record (wrong table name or a problem with the database), 0 instead of a valid UID will be returned.

    +
    Parameters:
    + + + +
    string $tableName the name of the table on which the record should be created, must not be empty
    array $recordData associative array that contains the data to save in the new record, may be empty, but must not contain the key "uid"
    +
    +
    +
    Returns:
    integer the UID of the new record, will be > 0
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    createRecordWithoutTableNameChecks ( tableName,
    array $  recordData 
    ) [protected]
    +
    +
    +

    Creates a new dummy record for unit tests without checks for the table name.

    +

    If no record data for the new array is given, an empty record will be created. It will only contain a valid UID and the "is_dummy_record" flag will be set to 1.

    +

    Should there be any problem creating the record (wrong table name or a problem with the database), 0 instead of a valid UID will be returned.

    +
    Parameters:
    + + + +
    string $tableName the name of the table on which the record should be created, must not be empty
    array $recordData associative array that contains the data to save in the new record, may be empty, but must not contain the key "uid"
    +
    +
    +
    Returns:
    integer the UID of the new record, will be > 0
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    createRelation ( tableName,
    uidLocal,
    uidForeign,
    sorting = 0 
    )
    +
    +
    +

    Creates a relation between two records on different tables (so called m:n relation).

    +
    Parameters:
    + + + + + +
    string $tableName name of the m:n table to which the record should be added, must not be empty
    integer $uidLocal UID of the local table, must be > 0
    integer $uidForeign UID of the foreign table, must be > 0
    integer $sorting sorting value of the relation, the default value is 0, which enables automatic sorting, a value >= 0 overwrites the automatic sorting
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    createRelationAndUpdateCounter ( tableName,
    uidLocal,
    uidForeign,
    columnName 
    )
    +
    +
    +

    Creates a relation between two records based on the rules defined in TCA regarding the relation.

    +
    Parameters:
    + + + + + +
    string $tableName name of the table from which a relation should be created, must not be empty
    integer $uidLocal UID of the record in the local table, must be > 0
    integer $uidForeign UID of the record in the foreign table, must be > 0
    string $columnName name of the column in which the relation counter should be updated, must not be empty
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    createSystemFolder ( parentId = 0,
    array $  recordData = array() 
    )
    +
    +
    +

    Creates a system folder on the page with the UID given by the first parameter $parentId.

    +
    Parameters:
    + + + +
    integer $parentId UID of the page on which the system folder should be created
    array $recordData associative array that contains the data to save in the new page, may be empty, but must not contain the keys "uid", "pid" or "doktype"
    +
    +
    +
    Returns:
    integer the UID of the new system folder, will be > 0
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    createTemplate ( pageId,
    array $  recordData = array() 
    )
    +
    +
    +

    Creates a template on the page with the UID given by the first parameter $pageId.

    +
    Parameters:
    + + + +
    integer $pageId UID of the page on which the template should be created, must be > 0
    array $recordData associative array that contains the data to save in the new template, may be empty, but must not contain the keys "uid" or "pid"
    +
    +
    +
    Returns:
    integer the UID of the new template, will be > 0
    + +
    +
    + +
    +
    + + + + + + + + +
    deleteAllDummyFoldersAndFiles ( )  [protected]
    +
    +
    +

    Deletes all dummy files and folders.

    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + +
    deleteDummyFile ( fileName ) 
    +
    +
    +

    Deletes the dummy file specified by the first parameter $fileName.

    +
    Parameters:
    + + +
    string $fileName the path to the file to delete relative to $this->uploadFolderPath, must not be empty
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + +
    deleteDummyFolder ( folderName ) 
    +
    +
    +

    Deletes the dummy folder specified in the first parameter $folderName. The folder must be empty (no files or subfolders).

    +
    Parameters:
    + + +
    string $folderName the path to the folder to delete relative to $this->uploadFolderPath, must not be empty
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    deleteRecord ( tableName,
    uid 
    )
    +
    +
    +

    Deletes a dummy record from the database.

    +

    Important: Only dummy records from non-system tables can be deleted with this method. Should there for any reason exist a real record with that UID, it won't be deleted.

    +
    Parameters:
    + + + +
    string $tableName name of the table from which the record should be deleted, must not be empty
    integer $uid UID of the record to delete, must be > 0
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + +
    discardFakeFrontEnd ( ) 
    +
    +
    +

    Discards the fake front end.

    +

    This function nulls out $GLOBALS['TSFE'] and $GLOBALS['TT']. In addition, any logged-in front-end user will be logged out.

    +

    The page record for the current front end will _not_ be deleted by this function, though.

    +

    If no fake front end has been created, this function does nothing.

    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    existsExactlyOneRecord ( tableName,
    whereClause = '' 
    )
    +
    +
    +

    Checks whether there is exactly one dummy record in the table given by the first parameter $tableName that matches a given WHERE clause.

    +
    Parameters:
    + + + +
    string $tableName the name of the table to query, must not be empty
    string $whereClause the WHERE part of the query, may be empty (all records will be counted in that case)
    +
    +
    +
    Returns:
    boolean TRUE if there is exactly one matching record, FALSE otherwise
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    existsRecord ( tableName,
    whereClause = '' 
    )
    +
    +
    +

    Checks whether there are any dummy records in the table given by the first parameter $tableName that match a given WHERE clause.

    +
    Parameters:
    + + + +
    string $tableName the name of the table to query, must not be empty
    string $whereClause the WHERE part of the query, may be empty (all records will be counted in that case)
    +
    +
    +
    Returns:
    boolean TRUE if there is at least one matching record, FALSE otherwise
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    existsRecordWithUid ( tableName,
    uid 
    )
    +
    +
    +

    Checks whether there is a dummy record in the table given by the first parameter $tableName that has the given UID.

    +
    Parameters:
    + + + +
    string $tableName the name of the table to query, must not be empty
    integer $uid the UID of the record to look up, must be > 0
    +
    +
    +
    Returns:
    boolean TRUE if there is a matching record, FALSE otherwise
    + +
    +
    + +
    +
    + + + + + + + + + +
    getAutoIncrement ( tableName ) 
    +
    +
    +

    Reads the current auto increment value for a given table.

    +

    This function is only valid for tables that actually have an auto increment value.

    +
    Parameters:
    + + +
    string $tableName the name of the table for which the auto increment value should be retrieved, must not be empty
    +
    +
    +
    Returns:
    integer the current auto_increment value of table $tableName, will be > 0
    + +
    +
    + +
    +
    + + + + + + + + + +
    getDummyColumnName ( tableName ) 
    +
    +
    +

    Returns the name of the column that marks a record as a dummy record.

    +

    On most tables this is "is_dummy_record", but on system tables like "pages" or "fe_users", the column is called "tx_phpunit_dummy_record".

    +

    On additional tables, the column is built using $this->tablePrefix as prefix e.g. "tx_seminars_is_dummy_record" if $this->tablePrefix = "tx_seminars".

    +
    Parameters:
    + + +
    string $tableName the table name to look up, must not be empty
    +
    +
    +
    Returns:
    string the name of the column that marks a record as dummy record
    + +
    +
    + +
    +
    + + + + + + + + +
    getHooks ( )  [protected]
    +
    +
    +

    Gets all hooks for this class.

    +
    Returns:
    array the hook objects, will be empty if no hooks have been set
    + +
    +
    + +
    +
    + + + + + + + + +
    getListOfAdditionalAllowedTableNames ( ) 
    +
    +
    +

    Returns the list of additional allowed table names.

    +
    Returns:
    array all additional allowed table names for this instance of the testing framework, may be empty
    + +
    +
    + +
    +
    + + + + + + + + +
    getListOfDirtySystemTables ( ) 
    +
    +
    +

    Returns the list of system tables that contain dummy records from testing. These tables are called "dirty tables" as they need to be cleaned up.

    +
    Returns:
    array associative array containing names of system database tables that need to be cleaned up
    + +
    +
    + +
    +
    + + + + + + + + +
    getListOfDirtyTables ( ) 
    +
    +
    +

    Returns the list of tables that contain dummy records from testing. These tables are called "dirty tables" as they need to be cleaned up.

    +
    Returns:
    array associative array containing names of database tables that need to be cleaned up
    + +
    +
    + +
    +
    + + + + + + + + +
    getListOfOwnAllowedTableNames ( ) 
    +
    +
    +

    Returns the list of allowed table names.

    +
    Returns:
    array all allowed table names for this instance of the testing framework
    + +
    +
    + +
    +
    + + + + + + + + + +
    getMaximumUidFromTable ( tableName )  [protected]
    +
    +
    +

    Reads the highest UID for a database table.

    +

    This function may only be called after that the provided table name has been checked to be non-empty, valid and pointing to an existing database table that has the "uid" column.

    +
    Parameters:
    + + +
    string $tableName the name of an existing table that has the "uid" column
    +
    +
    +
    Returns:
    integer the highest UID from this table, will be >= 0
    + +
    +
    + +
    +
    + + + + + + + + + +
    getPathRelativeToUploadDirectory ( absolutePath ) 
    +
    +
    +

    Returns the path relative to the calling extension's upload directory for a path given in the first parameter $absolutePath.

    +
    Parameters:
    + + +
    string $absolutePath the absolute path to process, must be within the calling extension's upload directory, must not be empty
    +
    +
    +
    Returns:
    string the path relative to the calling extension's upload directory
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    getRelationSorting ( tableName,
    uidLocal 
    )
    +
    +
    +

    Returns the next sorting value of the relation table which should be used.

    +

    TODO: This function doesn't take already existing relations in the database - which were created without using the testing framework - into account. So you always should create new dummy records and create a relation between these two dummy records, so you're sure there aren't already relations for a local UID in the database.

    +
    See also:
    https://bugs.oliverklee.com/show_bug.cgi?id=1423
    +
    Parameters:
    + + + +
    string $tableName the relation table, must not be empty
    integer $uidLocal UID of the local table, must be > 0
    +
    +
    +
    Returns:
    integer the next sorting value to use (> 0)
    + +
    +
    + +
    +
    + + + + + + + + + +
    getUniqueFileOrFolderPath ( path ) 
    +
    +
    +

    Returns a unique absolut path of a file or folder.

    +
    Parameters:
    + + +
    string $path the path of a file or folder relative to the calling extension's upload directory, must not be empty
    +
    +
    +
    Returns:
    string the unique absolut path of a file or folder
    + +
    +
    + +
    +
    + + + + + + + + +
    getUploadFolderPath ( ) 
    +
    +
    +

    Returns the absolute path to the upload folder of the extension to test.

    +
    Returns:
    string the absolute path to the upload folder of the extension to test, including the trailing slash
    + +
    +
    + +
    +
    + + + + + + + + +
    hasFakeFrontEnd ( ) 
    +
    +
    +

    Returns whether this testing framework instance has a fake front end.

    +
    Returns:
    boolean TRUE if this instance has a fake front end, FALSE otherwise
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    increaseRelationCounter ( tableName,
    uid,
    fieldName 
    )
    +
    +
    +

    Updates an integer field of a database table by one. This is mainly needed for counting up the relation counter when creating a database relation.

    +

    The field to update must be of type integer.

    +
    Parameters:
    + + + + +
    string $tableName name of the table, must not be empty
    integer $uid the UID of the record to modify, must be > 0
    string $fieldName the field name of the field to modify, must not be empty
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + +
    isAdditionalTableNameAllowed ( tableName )  [protected]
    +
    +
    +

    Checks whether the given table name is in the list of additional allowed tables for this instance of the testing framework.

    +
    Parameters:
    + + +
    string $tableName the name of the table to check, must not be empty
    +
    +
    +
    Returns:
    boolean TRUE if the name of the table is in the list of additional allowed tables, FALSE otherwise
    + +
    +
    + +
    +
    + + + + + + + + +
    isLoggedIn ( ) 
    +
    +
    +

    Checks whether a FE user is logged in.

    +
    Exceptions:
    + + +
    t3lib_exception if no front end has been created
    +
    +
    +
    Returns:
    boolean TRUE if a FE user is logged in, FALSE otherwise
    + +
    +
    + +
    +
    + + + + + + + + + +
    isNoneSystemTableNameAllowed ( tableName )  [protected]
    +
    +
    +

    Checks whether the given table name is in the list of allowed tables or additional allowed tables for this instance of the testing framework.

    +
    Parameters:
    + + +
    string $tableName the name of the table to check, must not be empty
    +
    +
    +
    Returns:
    boolean TRUE if the name of the table is in the list of allowed tables or additional allowed tables, FALSE otherwise
    + +
    +
    + +
    +
    + + + + + + + + + +
    isOwnTableNameAllowed ( tableName )  [protected]
    +
    +
    +

    Checks whether the given table name is in the list of allowed tables for this instance of the testing framework.

    +
    Parameters:
    + + +
    string $tableName the name of the table to check, must not be empty
    +
    +
    +
    Returns:
    boolean TRUE if the name of the table is in the list of allowed tables, FALSE otherwise
    + +
    +
    + +
    +
    + + + + + + + + + +
    isSystemTableNameAllowed ( tableName )  [protected]
    +
    +
    +

    Checks whether the given table name is in the list of allowed system tables for this instance of the testing framework.

    +
    Parameters:
    + + +
    string $tableName the name of the table to check, must not be empty
    +
    +
    +
    Returns:
    boolean TRUE if the name of the table is in the list of allowed system tables, FALSE otherwise
    + +
    +
    + +
    +
    + + + + + + + + + +
    isTableNameAllowed ( tableName )  [protected]
    +
    +
    +

    Checks whether the given table name is in the list of allowed tables, additional allowed tables or allowed system tables.

    +
    Parameters:
    + + +
    string $tableName the name of the table to check, must not be empty
    +
    +
    +
    Returns:
    boolean TRUE if the name of the table is in the list of allowed tables, additional allowed tables or allowed system tables, FALSE otherwise
    + +
    +
    + +
    +
    + + + + + + + + + +
    loginFrontEndUser ( userId ) 
    +
    +
    +

    Fakes that a front-end user has logged in.

    +

    If a front-end user currently is logged in, he/she will be logged out first.

    +

    Note: To set the logged-in users group data properly, the front-end user and his groups must actually exist in the database.

    +
    Exceptions:
    + + +
    t3lib_exception if no front end has been created
    +
    +
    +
    Parameters:
    + + +
    integer $userId UID of the FE user, must not necessarily exist in the database, must be > 0
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + +
    logoutFrontEndUser ( ) 
    +
    +
    +

    Logs out the current front-end user.

    +

    If no front-end user is logged in, this function does nothing.

    +
    Exceptions:
    + + +
    t3lib_exception if no front end has been created
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + +
    markTableAsDirty ( tableNames ) 
    +
    +
    +

    Puts one or multiple table names on the list of dirty tables (which represents a list of tables that were used for testing and contain dummy records and thus are called "dirty" until the next clean up).

    +
    Parameters:
    + + +
    string $tableNames the table name or a comma-separated list of table names to put on the list of dirty tables, must not be empty
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + +
    purgeHooks ( ) 
    +
    +
    +

    Purges the cached hooks.

    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    removeRelation ( tableName,
    uidLocal,
    uidForeign 
    )
    +
    +
    +

    Deletes a dummy relation from an m:n table in the database.

    +

    Important: Only dummy records can be deleted with this method. Should there for any reason exist a real record with that combination of local and foreign UID, it won't be deleted!

    +
    Parameters:
    + + + + +
    string $tableName name of the table from which the record should be deleted, must not be empty
    integer $uidLocal UID on the local table, must be > 0
    integer $uidForeign UID on the foreign table, must be > 0
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + +
    resetAutoIncrement ( tableName ) 
    +
    +
    +

    Eagerly resets the auto increment value for a given table to the highest existing UID + 1.

    +
    Parameters:
    + + +
    string $tableName the name of the table on which we're going to reset the auto increment entry, must not be empty
    +
    +
    +
    See also:
    resetAutoIncrementLazily
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + +
    resetAutoIncrementLazily ( tableName ) 
    +
    +
    +

    Resets the auto increment value for a given table to the highest existing UID + 1 if the current auto increment value is higher than a certain threshold over the current maximum UID.

    +

    The threshhold is 100 by default and can be set using setResetAutoIncrementThreshold.

    +
    Parameters:
    + + +
    string $tableName the name of the table on which we're going to reset the auto increment entry, must not be empty
    +
    +
    +
    See also:
    resetAutoIncrement
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + +
    setResetAutoIncrementThreshold ( threshold ) 
    +
    +
    +

    Sets the threshold for resetAutoIncrementLazily.

    +
    Parameters:
    + + +
    integer $threshold threshold, must be > 0
    +
    +
    +
    See also:
    resetAutoIncrementLazily
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + +
    setUploadFolderPath ( absolutePath ) 
    +
    +
    +

    Sets the upload folder path.

    +
    Exceptions:
    + + +
    t3lib_exception if there are dummy files within the current upload folder as these files could not be deleted if the upload folder path has changed
    +
    +
    +
    Parameters:
    + + +
    string $absolutePath absolute path to the folder where to work on during the tests, can be either an existing folder which will be cleaned up after the tests or a path of a folder to be created as soon as it is needed and deleted during cleanUp, must end with a trailing slash
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + +
    suppressFrontEndCookies ( )  [protected]
    +
    +
    +

    Makes sure that no FE login cookies will be sent.

    +
    Returns:
    void
    + +
    +
    +

    Field Documentation

    + +
    +
    + + + + +
    $allowedSystemTables [protected]
    +
    +
    +Initial value:
     array(
    +                'be_users', 'fe_groups', 'fe_users', 'pages', 'sys_template',
    +                'tt_content', 'be_groups'
    +        )
    +
    +
    +
    +
    The documentation for this class was generated from the following file:
      +
    • /home/klee/eclipse/phpunit/Classes/Framework.php
    • +
    +
    + + + diff --git a/typo3conf/ext/phpunit/doc/Framework/class_tx___phpunit___test_case.html b/typo3conf/ext/phpunit/doc/Framework/class_tx___phpunit___test_case.html new file mode 100644 index 0000000..f4c5758 --- /dev/null +++ b/typo3conf/ext/phpunit/doc/Framework/class_tx___phpunit___test_case.html @@ -0,0 +1,76 @@ + + + + +PHPUnit: Tx_Phpunit_TestCase Class Reference + + + + + + +
    + +
    +

    Tx_Phpunit_TestCase Class Reference

    +
    +
    + + + + + + +

    +Protected Member Functions

     simulateFrontendEnviroment ()

    +Protected Attributes

    $backupGlobals = FALSE
    $backupStaticAttributes = FALSE
    +

    Member Function Documentation

    + +
    +
    + + + + + + + + +
    simulateFrontendEnviroment ( )  [protected]
    +
    +
    +

    Roughly simulates the front end although being in the back end.

    +
    Deprecated:
    since 3.5.12, will be removed in 3.6.0. Use Tx_Phpunit_Framework::createFakeFrontEnd instead.
    +
    Returns:
    void
    + +
    +
    +
    The documentation for this class was generated from the following file:
      +
    • /home/klee/eclipse/phpunit/Classes/TestCase.php
    • +
    +
    + + + diff --git a/typo3conf/ext/phpunit/doc/Framework/class_tx___phpunit___testable_code.html b/typo3conf/ext/phpunit/doc/Framework/class_tx___phpunit___testable_code.html new file mode 100644 index 0000000..27ff668 --- /dev/null +++ b/typo3conf/ext/phpunit/doc/Framework/class_tx___phpunit___testable_code.html @@ -0,0 +1,462 @@ + + + + +PHPUnit: Tx_Phpunit_TestableCode Class Reference + + + + + + +
    + +
    +

    Tx_Phpunit_TestableCode Class Reference

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    +Public Member Functions

     getKey ()
     setKey ($key)
     getTitle ()
     setTitle ($title)
     getType ()
     setType ($type)
     getCodePath ()
     setCodePath ($codePath)
     getTestsPath ()
     setTestsPath ($testsPath)
     getBlacklist ()
     setBlacklist (array $files)
     getWhitelist ()
     setWhitelist (array $files)
     getIconPath ()
     setIconPath ($iconPath)

    +Data Fields

    +const TYPE_UNDEFINED = 0
    +const TYPE_EXTENSION = 1
    +const TYPE_CORE = 2
    +const CORE_KEY = 'typo3'

    +Protected Attributes

    $key = ''
    $title = ''
    $type = self::TYPE_UNDEFINED
    $codePath = ''
    $testsPath = ''
    $blacklist = array()
    $whitelist = array()
    $iconPath = ''
    +

    Member Function Documentation

    + +
    +
    + + + + + + + + +
    getBlacklist ( ) 
    +
    +
    +

    Returns the blacklist, i.e., the absolute paths to the files that should be excluded from the code coverage report.

    +
    Returns:
    array<string> the absolute paths to the blacklisted files, might be empty
    + +
    +
    + +
    +
    + + + + + + + + +
    getCodePath ( ) 
    +
    +
    +

    Returns the code path.

    +

    This is the absolute path of the code that is tested.

    +
    Returns:
    string the code path, will not be empty
    + +
    +
    + +
    +
    + + + + + + + + +
    getIconPath ( ) 
    +
    +
    +

    Returns the relative path to the icon associated with this testable code.

    +
    Returns:
    string the relative icon path, will not be empty
    + +
    +
    + +
    +
    + + + + + + + + +
    getKey ( ) 
    +
    +
    +

    Returns the key.

    +

    The key is intended to be used e.g., for drop-downs.

    +

    For extensions, this will be the extension key. For the TYPO3 core, this will be "typo3". For out-of-line tests, this will be full path to the tested code.

    +
    Returns:
    string the key, will not be empty
    + +
    +
    + +
    +
    + + + + + + + + +
    getTestsPath ( ) 
    +
    +
    +

    Returns the tests path.

    +

    This is the absolute path of the unit tests. Usually, this path is located within the code path.

    +
    Returns:
    string the tests path, will not be empty
    + +
    +
    + +
    +
    + + + + + + + + +
    getTitle ( ) 
    +
    +
    +

    Returns the display title.

    +
    Returns:
    string the title, might be empty
    + +
    +
    + +
    +
    + + + + + + + + +
    getType ( ) 
    +
    +
    +

    Returns the type of this testable code.

    +
    Returns:
    integer the type, will be either TYPE_UNDEFINED, TYPE_EXTENSION or TYPE_CORE
    + +
    +
    + +
    +
    + + + + + + + + +
    getWhitelist ( ) 
    +
    +
    +

    Returns the whitelist, i.e., the absolute paths to the files that should be included in the code coverage report.

    +
    Returns:
    array<string> the absolute paths to the whitelisted files, might be empty
    + +
    +
    + +
    +
    + + + + + + + + + +
    setBlacklist (array $  files ) 
    +
    +
    +

    Sets the blacklist, i.e., the absolute paths to the files that should be excluded from the code coverage report.

    +
    Parameters:
    + + +
    array<string> $files the absolute paths to the blacklisted files, may be empty
    +
    +
    +

    Å“return void

    + +
    +
    + +
    +
    + + + + + + + + + +
    setCodePath ( codePath ) 
    +
    +
    +

    Sets the code path.

    +

    This is the absolute path of the code that is tested.

    +
    Parameters:
    + + +
    string $codePath the code path, must not be empty
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + +
    setIconPath ( iconPath ) 
    +
    +
    +

    Sets the relative path to the icon associated with this testable code.

    +
    Parameters:
    + + +
    string $iconPath the icon path, must not be empty
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + +
    setKey ( key ) 
    +
    +
    +

    Sets the key.

    +

    The key is intended to be used e.g., for drop-downs.

    +

    For extensions, this must be the extension key. For the TYPO3 core, this must be "typo3". For out-of-line tests, this must be full path to the tested code.

    +
    Parameters:
    + + +
    string $key the key, must not be empty
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + +
    setTestsPath ( testsPath ) 
    +
    +
    +

    Sets the tests path.

    +

    This is the absolute path of the unit tests. Usually, this path is located within the code path.

    +
    Parameters:
    + + +
    string $testsPath the tests path, must not be empty
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + +
    setTitle ( title ) 
    +
    +
    +

    Sets the display title.

    +
    Parameters:
    + + +
    string $title the title, may be empty
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + +
    setType ( type ) 
    +
    +
    +

    Sets the type of this testable code.

    +
    Parameters:
    + + +
    integer the type, must be either TYPE_EXTENSION or TYPE_CORE
    +
    +
    +
    Returns:
    void
    + +
    +
    + +
    +
    + + + + + + + + + +
    setWhitelist (array $  files ) 
    +
    +
    +

    Sets the whitelist, i.e., the absolute paths to the files that should be included in the code coverage report.

    +
    Parameters:
    + + +
    array<string> $files the absolute paths to the whitelisted files, may be empty
    +
    +
    +

    Å“return void

    + +
    +
    +
    The documentation for this class was generated from the following file:
      +
    • /home/klee/eclipse/phpunit/Classes/TestableCode.php
    • +
    +
    + + + diff --git a/typo3conf/ext/phpunit/doc/Framework/classes.html b/typo3conf/ext/phpunit/doc/Framework/classes.html new file mode 100644 index 0000000..8e0e955 --- /dev/null +++ b/typo3conf/ext/phpunit/doc/Framework/classes.html @@ -0,0 +1,42 @@ + + + + +PHPUnit: Alphabetical List + + + + + + +
    +
    +

    Data Structure Index

    +
    + + + + diff --git a/typo3conf/ext/phpunit/doc/Framework/closed.png b/typo3conf/ext/phpunit/doc/Framework/closed.png new file mode 100644 index 0000000000000000000000000000000000000000..b7d4bd9fef2272c74b94762c9e2496177017775e GIT binary patch literal 126 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{VuAVNAAr*{o?>h22DDp4|bgj*t z)u^AqcA-V@guRYpb17F<&b?_~8HV>~XqWvB;^$!VVSTy0!eQcJp_yD7TIQA>7dijs YXf6~H5cs^Q6KEiVr>mdKI;Vst0NsWqGynhq literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/doc/Framework/deprecated.html b/typo3conf/ext/phpunit/doc/Framework/deprecated.html new file mode 100644 index 0000000..66df58a --- /dev/null +++ b/typo3conf/ext/phpunit/doc/Framework/deprecated.html @@ -0,0 +1,36 @@ + + + + +PHPUnit: Deprecated List + + + + + + +
    +
    +

    Deprecated List

    +
    +
    +

    +
    +
    Global Tx_Phpunit_TestCase::simulateFrontendEnviroment ()
    +
    since 3.5.12, will be removed in 3.6.0. Use Tx_Phpunit_Framework::createFakeFrontEnd instead.
    +
    +
    + + + diff --git a/typo3conf/ext/phpunit/doc/Framework/doxygen.css b/typo3conf/ext/phpunit/doc/Framework/doxygen.css new file mode 100644 index 0000000..658686f --- /dev/null +++ b/typo3conf/ext/phpunit/doc/Framework/doxygen.css @@ -0,0 +1,656 @@ +/* The standard CSS for doxygen */ + +body, table, div, p, dl { + font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; + font-size: 12px; +} + +/* @group Heading Levels */ + +h1 { + font-size: 150%; +} + +h2 { + font-size: 120%; +} + +h3 { + font-size: 100%; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd, p.starttd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + padding: 2px; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4665A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #ffffff; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code { + color: #4665A2; +} + +a.codeRef { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +.fragment { + font-family: monospace, fixed; + font-size: 105%; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 10px; + margin-right: 10px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memItemLeft, .memItemRight, .memTemplParams { + border-top: 1px solid #C4CFE5; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 3px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.memitem { + padding: 0; + margin-bottom: 10px; +} + +.memname { + white-space: nowrap; + font-weight: bold; + margin-left: 6px; +} + +.memproto { + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 8px; + -moz-border-radius-topleft: 8px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 8px; + -webkit-border-top-left-radius: 8px; + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + +} + +.memdoc { + border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 2px 5px; + background-color: #FBFCFD; + border-top-width: 0; + /* firefox specific markup */ + -moz-border-radius-bottomleft: 8px; + -moz-border-radius-bottomright: 8px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F7F8FB 95%, #EEF1F7); + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F7F8FB), to(#EEF1F7)); +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} + +/* @end */ + +/* @group Directory (tree) */ + +/* for the tree view */ + +.ftvtree { + font-family: sans-serif; + margin: 0px; +} + +/* these are for tree view when used as main index */ + +.directory { + font-size: 9pt; + font-weight: bold; + margin: 5px; +} + +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* +The following two styles can be used to replace the root node title +with an image of your choice. Simply uncomment the next two styles, +specify the name of your image and be sure to set 'height' to the +proper pixel height of your image. +*/ + +/* +.directory h3.swap { + height: 61px; + background-repeat: no-repeat; + background-image: url("yourimage.gif"); +} +.directory h3.swap span { + display: none; +} +*/ + +.directory > h3 { + margin-top: 0; +} + +.directory p { + margin: 0px; + white-space: nowrap; +} + +.directory div { + display: none; + margin: 0px; +} + +.directory img { + vertical-align: -30%; +} + +/* these are for tree view when not used as main index */ + +.directory-alt { + font-size: 100%; + font-weight: bold; +} + +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +.directory-alt > h3 { + margin-top: 0; +} + +.directory-alt p { + margin: 0px; + white-space: nowrap; +} + +.directory-alt div { + display: none; + margin: 0px; +} + +.directory-alt img { + vertical-align: -30%; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable { + border-collapse:collapse; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; +} + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right: 15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; +} + +.navpath a:hover +{ + color:#6884BD; +} + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 10px; +} + diff --git a/typo3conf/ext/phpunit/doc/Framework/doxygen.png b/typo3conf/ext/phpunit/doc/Framework/doxygen.png new file mode 100644 index 0000000000000000000000000000000000000000..635ed52fce7057ac24df92ec7664088a881fa5d0 GIT binary patch literal 3942 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 A+yDRo literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/doc/Framework/functions.html b/typo3conf/ext/phpunit/doc/Framework/functions.html new file mode 100644 index 0000000..23bbc13 --- /dev/null +++ b/typo3conf/ext/phpunit/doc/Framework/functions.html @@ -0,0 +1,358 @@ + + + + +PHPUnit: Data Fields + + + + + + +
    +Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: + +

    - _ -

    + + +

    - a -

    + + +

    - c -

    + + +

    - d -

    + + +

    - e -

    + + +

    - g -

    + + +

    - h -

    + + +

    - i -

    + + +

    - l -

    + + +

    - m -

    + + +

    - p -

    + + +

    - r -

    + + +

    - s -

    +
    + + + diff --git a/typo3conf/ext/phpunit/doc/Framework/functions_func.html b/typo3conf/ext/phpunit/doc/Framework/functions_func.html new file mode 100644 index 0000000..85845d0 --- /dev/null +++ b/typo3conf/ext/phpunit/doc/Framework/functions_func.html @@ -0,0 +1,358 @@ + + + + +PHPUnit: Data Fields - Functions + + + + + + +
    +  + +

    - _ -

    + + +

    - a -

    + + +

    - c -

    + + +

    - d -

    + + +

    - e -

    + + +

    - g -

    + + +

    - h -

    + + +

    - i -

    + + +

    - l -

    + + +

    - m -

    + + +

    - p -

    + + +

    - r -

    + + +

    - s -

    +
    + + + diff --git a/typo3conf/ext/phpunit/doc/Framework/index.html b/typo3conf/ext/phpunit/doc/Framework/index.html new file mode 100644 index 0000000..831a833 --- /dev/null +++ b/typo3conf/ext/phpunit/doc/Framework/index.html @@ -0,0 +1,32 @@ + + + + + +PHPUnit: Main Page + + + + + + +
    +
    +

    PHPUnit Documentation

    +
    +
    +
    + + + diff --git a/typo3conf/ext/phpunit/doc/Framework/namespace_t_y_p_o3.html b/typo3conf/ext/phpunit/doc/Framework/namespace_t_y_p_o3.html new file mode 100644 index 0000000..14306c1 --- /dev/null +++ b/typo3conf/ext/phpunit/doc/Framework/namespace_t_y_p_o3.html @@ -0,0 +1,62 @@ + + + + +PHPUnit: TYPO3 Namespace Reference + + + + + + +
    +
    +

    TYPO3 Namespace Reference

    +
    +
    + +
    +

    Detailed Description

    +

    This class provides various functions to handle dummy records in unit tests.

    +

    tx_phpunit

    +
    Author:
    Mario Rimann <typo3-coding@rimann.org>
    +
    +Oliver Klee <typo3-coding@oliverklee.de>
    +
    +Saskia Metzler <saskia@merlin.owl.de>
    +
    +Niels Pardon <mail@niels-pardon.de>
    +

    This class represents some code that can be tested.

    +

    tx_phpunit

    +
    Author:
    Oliver Klee <typo3-coding@oliverklee.de>
    +

    This class provides helper functions that might be convenient when testing in TYPO3. It extends PHPUnit_Framework_TestCase, so you have access to all of that class as well.

    +

    tx_phpunit

    +
    Author:
    Robert Lemke <robert@typo3.org>
    +
    +Kasper Ligaard <kasperligaard@gmail.com>
    +
    +Soren Soltveit <sso@systime.dk>
    +
    +Michael Klapper <michael.klapper@aoemedia.de>
    +
    +Oliver Klee <typo3-coding@oliverklee.de>
    +
    + + + diff --git a/typo3conf/ext/phpunit/doc/Framework/namespaces.html b/typo3conf/ext/phpunit/doc/Framework/namespaces.html new file mode 100644 index 0000000..34a428d --- /dev/null +++ b/typo3conf/ext/phpunit/doc/Framework/namespaces.html @@ -0,0 +1,39 @@ + + + + +PHPUnit: Namespace Index + + + + + + +
    +
    +

    Namespace List

    +
    +
    +Here is a list of all documented namespaces with brief descriptions: + +
    TYPO3
    +
    + + + diff --git a/typo3conf/ext/phpunit/doc/Framework/nav_f.png b/typo3conf/ext/phpunit/doc/Framework/nav_f.png new file mode 100644 index 0000000000000000000000000000000000000000..1b07a16207e67c95fe2ee17e7016e6d08ac7ac99 GIT binary patch literal 159 zcmeAS@N?(olHy`uVBq!ia0vp^j6iI`!2~2XGqLUlQfZzpjv*C{Z|{2YIT`Y>1X`Eg z-tTbne1`SITM8Q!Pb(<)UFZ(m>wMzvKZQqKM~~GcZ=A7j<~E6K62>ozFS=cD3)mf8 z9WX0+R&m(l9KUsLdTx4?9~({T__KA%`}olPJ^N;y|F^pHgs_K%!rj~{8>RwnWbkzL Kb6Mw<&;$VTdq1fF literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/doc/Framework/nav_h.png b/typo3conf/ext/phpunit/doc/Framework/nav_h.png new file mode 100644 index 0000000000000000000000000000000000000000..01f5fa6a596e36bd12c2d6ceff1b0169fda7e699 GIT binary patch literal 97 zcmeAS@N?(olHy`uVBq!ia0vp^j6lr8!2~3AUOE6t1`SUa$B+ufw|6&kG8phMJMJ~w va4>Y+bZ&9QY?(VEUPY_cGd9nQ`um^ZSUyYpAAuKhL7F^W{an^LB{Ts5DmojT literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/doc/Framework/open.png b/typo3conf/ext/phpunit/doc/Framework/open.png new file mode 100644 index 0000000000000000000000000000000000000000..7b35d2c2c389743089632fe24c3104f2173d97af GIT binary patch literal 118 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{Vww^AIAr*{o=Nbw!DDW^(zOibV zl!F8B0?t?i!vld4k#$~0_AX3zElaokn + + + +PHPUnit: Page Index + + + + + + +
    +
    +

    Related Pages

    +
    +
    +Here is a list of all related documentation pages: +
    + + + diff --git a/typo3conf/ext/phpunit/doc/Framework/tab_a.png b/typo3conf/ext/phpunit/doc/Framework/tab_a.png new file mode 100644 index 0000000000000000000000000000000000000000..2d99ef23fed78c7683f0b5aa803d937060d288c4 GIT binary patch literal 140 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!Qo)`sjv*C{Z|CmjY;X`^DSv)) z;hc^cTF;t%XWXdwWP5+kt?jQ5uhqKtjd^EY`^^-S;M%tFAj_l)EwVTK)E@1LSD0{e q?a6($SGQTzz1#QBzr0NMKf^0WCX-0bi?u-G89ZJ6T-G@yGywp8?ljB* literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/doc/Framework/tab_b.png b/typo3conf/ext/phpunit/doc/Framework/tab_b.png new file mode 100644 index 0000000000000000000000000000000000000000..b2c3d2be3c7e518fbca6bb30f571882e72fc506d GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!Qk9-Ajv*C{Z|~mbJ)|JfaM8Xd zIP7xAmLwau9@iXhZTrl-TjWj9jM#?{xt`6uU{<)jb9Suc^QnbhJ(o{ib8=j9u0_mE8M7kgF7f<7W7IEf=8(L_qx|g0H;V7iPxm&Q@G7p8W2Kx&iT|YUM=ITC zY<0Qbr;u&AtXD{o@41wH=7&d8=2Z_{M9Tsa=g*t*@A3H$UOlxZk7?f6RUWpx>Fc_L s#LQ{edY3MpIXkMeV^&YV=9fR%8Jv|Kya=#u06K}m)78&qol`;+0RKEt)&Kwi literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/doc/Framework/tab_s.png b/typo3conf/ext/phpunit/doc/Framework/tab_s.png new file mode 100644 index 0000000000000000000000000000000000000000..978943ac807718de0e69e5a585a8f0a1e5999285 GIT binary patch literal 189 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!QZ1e?jv*C{Z|}b5Yzkm-c<7z3 zq^cq0=~}Z;b(!Zvb5Z%sTRFKGlz1=qOFg;myyu?$r`wZb^irPsN1a)6)TwB0r+)wb zPL25;=adu89?fTK`qDR>$D*)b_WOmdKI;Vst02j(hg8%>k literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/doc/Framework/tabs.css b/typo3conf/ext/phpunit/doc/Framework/tabs.css new file mode 100644 index 0000000..2192056 --- /dev/null +++ b/typo3conf/ext/phpunit/doc/Framework/tabs.css @@ -0,0 +1,59 @@ +.tabs, .tabs2, .tabs3 { + background-image: url('tab_b.png'); + width: 100%; + z-index: 101; + font-size: 13px; +} + +.tabs2 { + font-size: 10px; +} +.tabs3 { + font-size: 9px; +} + +.tablist { + margin: 0; + padding: 0; + display: table; +} + +.tablist li { + float: left; + display: table-cell; + background-image: url('tab_b.png'); + line-height: 36px; + list-style: none; +} + +.tablist a { + display: block; + padding: 0 20px; + font-weight: bold; + background-image:url('tab_s.png'); + background-repeat:no-repeat; + background-position:right; + color: #283A5D; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; + outline: none; +} + +.tabs3 .tablist a { + padding: 0 10px; +} + +.tablist a:hover { + background-image: url('tab_h.png'); + background-repeat:repeat-x; + color: #fff; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); + text-decoration: none; +} + +.tablist li.current a { + background-image: url('tab_a.png'); + background-repeat:repeat-x; + color: #fff; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); +} diff --git a/typo3conf/ext/phpunit/doc/manual.sxw b/typo3conf/ext/phpunit/doc/manual.sxw new file mode 100644 index 0000000000000000000000000000000000000000..c14cb02620495233553ffe819ce77426a78c94c4 GIT binary patch literal 96971 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%0AQnabtMjF*UQ*7z|FoNt!n4N9UIt8x`zpY+cV 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 MM|azgTGMoY18EmTb^rhX literal 0 HcmV?d00001 diff --git a/typo3conf/ext/phpunit/ext_autoload.php b/typo3conf/ext/phpunit/ext_autoload.php new file mode 100644 index 0000000..cbf4b42 --- /dev/null +++ b/typo3conf/ext/phpunit/ext_autoload.php @@ -0,0 +1,32 @@ + $extensionPath . 'Classes/BackEnd/Ajax.php', + 'tx_phpunit_backend_module' => $extensionPath . 'Classes/BackEnd/Module.php', + 'tx_phpunit_backend_testlistener' => $extensionPath . 'Classes/BackEnd/TestListener.php', + 'tx_phpunit_cli_testrunner' => $extensionPath . 'Classes/Cli/TestRunner.php', + 'tx_phpunit_database_testcase' => $extensionPath . 'Classes/Database/TestCase.php', + 'tx_phpunit_exception_database' => $extensionPath . 'Classes/Exception/Database.php', + 'tx_phpunit_exception_emptyqueryresult' => $extensionPath . 'Classes/Exception/EmptyQueryResult.php', + 'tx_phpunit_exception_notestsdirectory' => $extensionPath . 'Classes/Exception/NoTestsDirectory.php', + 'tx_phpunit_framework' => $extensionPath . 'Classes/Framework.php', + 'tx_phpunit_interface_frameworkcleanuphook' => $extensionPath . 'Classes/Interface/FrameworkCleanupHook.php', + 'tx_phpunit_reports_status' => $extensionPath . 'Classes/Reports/Status.php', + 'tx_phpunit_selenium_testcase' => $extensionPath . 'Classes/Selenium/TestCase.php', + 'tx_phpunit_service_database' => $extensionPath . 'Classes/Service/Database.php', + 'tx_phpunit_service_testfinder' => $extensionPath . 'Classes/Service/TestFinder.php', + 'tx_phpunit_testablecode' => $extensionPath . 'Classes/TestableCode.php', + 'tx_phpunit_testcase' => $extensionPath . 'Classes/TestCase.php', + 'tx_phpunit_test_testsuite' => $extensionPath . 'Tests/tx_phpunit_testsuite.php', + 'vfsstream' => $vfsStreamPath . 'vfsStream.php', + 'vfsstreamabstractContent' => $vfsStreamPath . 'vfsStreamAbstractContent.php', + 'vfsstreamcontainer' => $vfsStreamPath . 'vfsStreamContainer.php', + 'vfsstreamcontaineriterator' => $vfsStreamPath . 'vfsStreamContainerIterator.php', + 'vfsstreamcontent' => $vfsStreamPath . 'vfsStreamContent.php', + 'vfsstreamdirectory' => $vfsStreamPath . 'vfsStreamDirectory.php', + 'vfsstreamexception' => $vfsStreamPath . 'vfsStreamException.php', + 'vfsstreamfile' => $vfsStreamPath . 'vfsStreamFile.php', + 'vfsstreamwrapper' => $vfsStreamPath . 'vfsStreamWrapper.php', +); +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/ext_conf_template.txt b/typo3conf/ext/phpunit/ext_conf_template.txt new file mode 100644 index 0000000..125b4ac --- /dev/null +++ b/typo3conf/ext/phpunit/ext_conf_template.txt @@ -0,0 +1,14 @@ + # cat=basic; type=string; label=Excluded extensions: You can exclude extensions from being search for tests by writing their extension key here. Seperate the entries with comma. +excludeextensions = lib, div + # cat=basic; type=string; label=Path to PHPUnit: The PHPUnit must be in a sub-directory named 'PHPUnit'. Point to directory just above that. Setting this will have preference over a PHPUnit from pear, even if pear is set. Remember that you can check the includepath used by phpunit in the 'About PHPUnit BE' drop-down in the PHPUnit module. +phpunitlib = + # cat=basic; type=boolean; label=Always load FE (simple) environment:This feature is DEPRECATED and will be removed. Please use the Tx_Phpunit_Framework::createFakeFrontEnd() instead. +alwaysSimulateFrontendEnvironment = 0 + # cat=selenium; type=short; label=Host of the Selenium RC server +selenium_host = localhost + # cat=selenium; type=int+; label=Port of the Selenium RC server +selenium_port = 4444 + # cat=selenium; type=short; label=Browser that should be used to run Selenium tests: Allowed values are *firefox, *mock, *firefoxproxy, *pifirefox, *chrome, *iexploreproxy, *iexplore, *firefox3, *safariproxy, *googlechrome, *konqueror, *firefox2, *safari, *piiexplore, *firefoxchrome, *opera, *iehta, *custom +selenium_browser = *firefox + # cat=selenium; type=short; label=Default Selenium Browser URL: Leave empty to use domain of this TYPO3 installation (TYPO3_SITE_URL) +selenium_browserurl = \ No newline at end of file diff --git a/typo3conf/ext/phpunit/ext_emconf.php b/typo3conf/ext/phpunit/ext_emconf.php new file mode 100644 index 0000000..0c6c6b0 --- /dev/null +++ b/typo3conf/ext/phpunit/ext_emconf.php @@ -0,0 +1,48 @@ + 'PHPUnit', + 'description' => 'TYPO3 unit testing UI based on PHPUnit by Sebastian Bergmann.', + 'category' => 'module', + 'shy' => 0, + 'version' => '3.5.14', + 'dependencies' => '', + 'conflicts' => '', + 'priority' => '', + 'loadOrder' => '', + 'module' => 'Classes/BackEnd', + 'state' => 'beta', + 'uploadfolder' => 1, + 'createDirs' => '', + 'modify_tables' => '', + 'clearcacheonload' => 0, + 'lockType' => '', + 'author' => 'Oliver Klee, Michael Klapper, Kasper Ligaard', + 'author_email' => 'typo3-coding@oliverklee.de', + 'author_company' => '', + 'CGLcompliance' => '', + 'CGLcompliance_note' => '', + 'constraints' => array( + 'depends' => array( + 'php' => '5.2.3-0.0.0', + 'typo3' => '4.3.0-0.0.0', + ), + 'conflicts' => array( + ), + 'suggests' => array( + ), + ), + '_md5_values_when_last_written' => 'a:944:{s:9:"Changelog";s:4:"8733";s:38:"class.tx_phpunit_database_testcase.php";s:4:"3dfb";s:38:"class.tx_phpunit_selenium_testcase.php";s:4:"3dfb";s:29:"class.tx_phpunit_testcase.php";s:4:"3dfb";s:16:"ext_autoload.php";s:4:"277c";s:21:"ext_conf_template.txt";s:4:"5495";s:12:"ext_icon.gif";s:4:"5f50";s:17:"ext_localconf.php";s:4:"5f10";s:14:"ext_tables.php";s:4:"c4a4";s:14:"ext_tables.sql";s:4:"8818";s:21:"Classes/Framework.php";s:4:"726f";s:20:"Classes/TestCase.php";s:4:"42da";s:24:"Classes/TestableCode.php";s:4:"b0e7";s:24:"Classes/BackEnd/Ajax.php";s:4:"a598";s:26:"Classes/BackEnd/Module.php";s:4:"a86f";s:32:"Classes/BackEnd/TestListener.php";s:4:"9600";s:24:"Classes/BackEnd/conf.php";s:4:"0c80";s:25:"Classes/BackEnd/index.php";s:4:"4975";s:26:"Classes/Cli/TestRunner.php";s:4:"98d2";s:29:"Classes/Database/TestCase.php";s:4:"ded4";s:30:"Classes/Exception/Database.php";s:4:"a2a3";s:38:"Classes/Exception/EmptyQueryResult.php";s:4:"e10f";s:38:"Classes/Exception/NoTestsDirectory.php";s:4:"0095";s:42:"Classes/Interface/FrameworkCleanupHook.php";s:4:"1faa";s:26:"Classes/Reports/Status.php";s:4:"d052";s:29:"Classes/Selenium/TestCase.php";s:4:"2479";s:28:"Classes/Service/Database.php";s:4:"1a9c";s:30:"Classes/Service/TestFinder.php";s:4:"ac96";s:25:"Configuration/TCA/TCA.php";s:4:"4bf6";s:13:"PEAR/PEAR.php";s:4:"513e";s:14:"PEAR/PEAR5.php";s:4:"1a8f";s:15:"PEAR/System.php";s:4:"a0d7";s:20:"PEAR/Archive/Tar.php";s:4:"7406";s:19:"PEAR/Cache/Lite.php";s:4:"7c2f";s:24:"PEAR/Cache/Lite/File.php";s:4:"3ed7";s:28:"PEAR/Cache/Lite/Function.php";s:4:"ce9f";s:26:"PEAR/Cache/Lite/Output.php";s:4:"5e15";s:23:"PEAR/Console/Getopt.php";s:4:"ed66";s:22:"PEAR/File/Iterator.php";s:4:"bb65";s:30:"PEAR/File/Iterator/Factory.php";s:4:"b94f";s:17:"PEAR/OS/Guess.php";s:4:"2ef8";s:24:"PEAR/PEAR/Autoloader.php";s:4:"2b4e";s:21:"PEAR/PEAR/Builder.php";s:4:"9087";s:25:"PEAR/PEAR/ChannelFile.php";s:4:"31fe";s:21:"PEAR/PEAR/Command.php";s:4:"2028";s:20:"PEAR/PEAR/Common.php";s:4:"da5d";s:20:"PEAR/PEAR/Config.php";s:4:"4afd";s:25:"PEAR/PEAR/Dependency2.php";s:4:"50ca";s:26:"PEAR/PEAR/DependencyDB.php";s:4:"5cbb";s:24:"PEAR/PEAR/Downloader.php";s:4:"8d0f";s:24:"PEAR/PEAR/ErrorStack.php";s:4:"413c";s:23:"PEAR/PEAR/Exception.php";s:4:"c39b";s:33:"PEAR/PEAR/FixPHP5PEARWarnings.php";s:4:"e0e4";s:22:"PEAR/PEAR/Frontend.php";s:4:"2cd5";s:23:"PEAR/PEAR/Installer.php";s:4:"08ca";s:25:"PEAR/PEAR/PackageFile.php";s:4:"af42";s:22:"PEAR/PEAR/Packager.php";s:4:"2c8b";s:18:"PEAR/PEAR/REST.php";s:4:"548b";s:22:"PEAR/PEAR/Registry.php";s:4:"b8ce";s:21:"PEAR/PEAR/RunTest.php";s:4:"0872";s:22:"PEAR/PEAR/Validate.php";s:4:"0206";s:23:"PEAR/PEAR/XMLParser.php";s:4:"bf49";s:32:"PEAR/PEAR/ChannelFile/Parser.php";s:4:"988f";s:26:"PEAR/PEAR/Command/Auth.php";s:4:"b1d6";s:26:"PEAR/PEAR/Command/Auth.xml";s:4:"8fd8";s:27:"PEAR/PEAR/Command/Build.php";s:4:"af0e";s:27:"PEAR/PEAR/Command/Build.xml";s:4:"7360";s:30:"PEAR/PEAR/Command/Channels.php";s:4:"1a7d";s:30:"PEAR/PEAR/Command/Channels.xml";s:4:"6d5a";s:28:"PEAR/PEAR/Command/Common.php";s:4:"830f";s:28:"PEAR/PEAR/Command/Config.php";s:4:"46ce";s:28:"PEAR/PEAR/Command/Config.xml";s:4:"91f1";s:29:"PEAR/PEAR/Command/Install.php";s:4:"e68c";s:29:"PEAR/PEAR/Command/Install.xml";s:4:"2db0";s:28:"PEAR/PEAR/Command/Mirror.php";s:4:"1864";s:28:"PEAR/PEAR/Command/Mirror.xml";s:4:"5cb6";s:29:"PEAR/PEAR/Command/Package.php";s:4:"df41";s:29:"PEAR/PEAR/Command/Package.xml";s:4:"9367";s:28:"PEAR/PEAR/Command/Pickle.php";s:4:"77da";s:28:"PEAR/PEAR/Command/Pickle.xml";s:4:"28dc";s:30:"PEAR/PEAR/Command/Registry.php";s:4:"9211";s:30:"PEAR/PEAR/Command/Registry.xml";s:4:"49b0";s:28:"PEAR/PEAR/Command/Remote.php";s:4:"1b18";s:28:"PEAR/PEAR/Command/Remote.xml";s:4:"29c0";s:26:"PEAR/PEAR/Command/Test.php";s:4:"8639";s:26:"PEAR/PEAR/Command/Test.xml";s:4:"a50c";s:32:"PEAR/PEAR/Downloader/Package.php";s:4:"582f";s:26:"PEAR/PEAR/Frontend/CLI.php";s:4:"39a0";s:28:"PEAR/PEAR/Installer/Role.php";s:4:"1c84";s:32:"PEAR/PEAR/Installer/Role/Cfg.php";s:4:"b2df";s:32:"PEAR/PEAR/Installer/Role/Cfg.xml";s:4:"d8c6";s:35:"PEAR/PEAR/Installer/Role/Common.php";s:4:"341d";s:33:"PEAR/PEAR/Installer/Role/Data.php";s:4:"bd2b";s:33:"PEAR/PEAR/Installer/Role/Data.xml";s:4:"89a4";s:32:"PEAR/PEAR/Installer/Role/Doc.php";s:4:"bbf1";s:32:"PEAR/PEAR/Installer/Role/Doc.xml";s:4:"b1ce";s:32:"PEAR/PEAR/Installer/Role/Ext.php";s:4:"54b4";s:32:"PEAR/PEAR/Installer/Role/Ext.xml";s:4:"af71";s:32:"PEAR/PEAR/Installer/Role/Php.php";s:4:"76b5";s:32:"PEAR/PEAR/Installer/Role/Php.xml";s:4:"ef88";s:35:"PEAR/PEAR/Installer/Role/Script.php";s:4:"4a9a";s:35:"PEAR/PEAR/Installer/Role/Script.xml";s:4:"7464";s:32:"PEAR/PEAR/Installer/Role/Src.php";s:4:"9189";s:32:"PEAR/PEAR/Installer/Role/Src.xml";s:4:"e147";s:33:"PEAR/PEAR/Installer/Role/Test.php";s:4:"1dd8";s:33:"PEAR/PEAR/Installer/Role/Test.xml";s:4:"a24b";s:32:"PEAR/PEAR/Installer/Role/Www.php";s:4:"2178";s:32:"PEAR/PEAR/Installer/Role/Www.xml";s:4:"7641";s:28:"PEAR/PEAR/PackageFile/v1.php";s:4:"7104";s:28:"PEAR/PEAR/PackageFile/v2.php";s:4:"af8d";s:38:"PEAR/PEAR/PackageFile/Generator/v1.php";s:4:"7b4e";s:38:"PEAR/PEAR/PackageFile/Generator/v2.php";s:4:"471c";s:35:"PEAR/PEAR/PackageFile/Parser/v1.php";s:4:"5e30";s:35:"PEAR/PEAR/PackageFile/Parser/v2.php";s:4:"4ed6";s:38:"PEAR/PEAR/PackageFile/v2/Validator.php";s:4:"ebb0";s:31:"PEAR/PEAR/PackageFile/v2/rw.php";s:4:"9e9c";s:21:"PEAR/PEAR/REST/10.php";s:4:"5967";s:21:"PEAR/PEAR/REST/11.php";s:4:"fe8e";s:21:"PEAR/PEAR/REST/13.php";s:4:"a6af";s:25:"PEAR/PEAR/Task/Common.php";s:4:"a3e8";s:36:"PEAR/PEAR/Task/Postinstallscript.php";s:4:"a089";s:26:"PEAR/PEAR/Task/Replace.php";s:4:"83ed";s:26:"PEAR/PEAR/Task/Unixeol.php";s:4:"a993";s:29:"PEAR/PEAR/Task/Windowseol.php";s:4:"24cc";s:39:"PEAR/PEAR/Task/Postinstallscript/rw.php";s:4:"6869";s:29:"PEAR/PEAR/Task/Replace/rw.php";s:4:"36f3";s:29:"PEAR/PEAR/Task/Unixeol/rw.php";s:4:"6360";s:32:"PEAR/PEAR/Task/Windowseol/rw.php";s:4:"feb5";s:28:"PEAR/PEAR/Validator/PECL.php";s:4:"b12f";s:25:"PEAR/PHP/CodeCoverage.php";s:4:"5a82";s:18:"PEAR/PHP/Timer.php";s:4:"0f3e";s:18:"PEAR/PHP/Token.php";s:4:"f0e4";s:32:"PEAR/PHP/CodeCoverage/Driver.php";s:4:"2c9c";s:32:"PEAR/PHP/CodeCoverage/Filter.php";s:4:"1752";s:30:"PEAR/PHP/CodeCoverage/Util.php";s:4:"a641";s:39:"PEAR/PHP/CodeCoverage/Driver/Xdebug.php";s:4:"1185";s:39:"PEAR/PHP/CodeCoverage/Report/Clover.php";s:4:"2f31";s:37:"PEAR/PHP/CodeCoverage/Report/HTML.php";s:4:"5333";s:42:"PEAR/PHP/CodeCoverage/Report/HTML/Node.php";s:4:"9bbe";s:52:"PEAR/PHP/CodeCoverage/Report/HTML/Node/Directory.php";s:4:"d0e9";s:47:"PEAR/PHP/CodeCoverage/Report/HTML/Node/File.php";s:4:"3030";s:51:"PEAR/PHP/CodeCoverage/Report/HTML/Node/Iterator.php";s:4:"bb1e";s:56:"PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.bar.js";s:4:"04b0";s:64:"PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.common.core.js";s:4:"7faf";s:68:"PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.common.tooltips.js";s:4:"8799";s:60:"PEAR/PHP/CodeCoverage/Report/HTML/Template/RGraph.scatter.js";s:4:"b038";s:53:"PEAR/PHP/CodeCoverage/Report/HTML/Template/butter.png";s:4:"521e";s:56:"PEAR/PHP/CodeCoverage/Report/HTML/Template/chameleon.png";s:4:"24ab";s:56:"PEAR/PHP/CodeCoverage/Report/HTML/Template/close12_1.gif";s:4:"770d";s:59:"PEAR/PHP/CodeCoverage/Report/HTML/Template/container-min.js";s:4:"5f92";s:56:"PEAR/PHP/CodeCoverage/Report/HTML/Template/container.css";s:4:"4b3e";s:62:"PEAR/PHP/CodeCoverage/Report/HTML/Template/dashboard.html.dist";s:4:"4d96";s:62:"PEAR/PHP/CodeCoverage/Report/HTML/Template/directory.html.dist";s:4:"d675";s:56:"PEAR/PHP/CodeCoverage/Report/HTML/Template/directory.png";s:4:"0c2e";s:67:"PEAR/PHP/CodeCoverage/Report/HTML/Template/directory_item.html.dist";s:4:"bce6";s:65:"PEAR/PHP/CodeCoverage/Report/HTML/Template/excanvas.compressed.js";s:4:"7306";s:57:"PEAR/PHP/CodeCoverage/Report/HTML/Template/file.html.dist";s:4:"c39e";s:51:"PEAR/PHP/CodeCoverage/Report/HTML/Template/file.png";s:4:"6983";s:62:"PEAR/PHP/CodeCoverage/Report/HTML/Template/file_item.html.dist";s:4:"2c1f";s:64:"PEAR/PHP/CodeCoverage/Report/HTML/Template/file_no_yui.html.dist";s:4:"8f11";s:52:"PEAR/PHP/CodeCoverage/Report/HTML/Template/glass.png";s:4:"d0bc";s:64:"PEAR/PHP/CodeCoverage/Report/HTML/Template/method_item.html.dist";s:4:"2c75";s:58:"PEAR/PHP/CodeCoverage/Report/HTML/Template/scarlet_red.png";s:4:"e7e9";s:51:"PEAR/PHP/CodeCoverage/Report/HTML/Template/snow.png";s:4:"3d0f";s:52:"PEAR/PHP/CodeCoverage/Report/HTML/Template/style.css";s:4:"bc0d";s:61:"PEAR/PHP/CodeCoverage/Report/HTML/Template/yahoo-dom-event.js";s:4:"cd9e";s:54:"PEAR/PHP/CodeCoverage/Report/HTML/Template/yui_item.js";s:4:"32c5";s:40:"PEAR/PHP/CodeCoverage/TextUI/Command.php";s:4:"156d";s:28:"PEAR/PHP/Token/Exception.php";s:4:"4ec2";s:25:"PEAR/PHP/Token/Stream.php";s:4:"cf48";s:40:"PEAR/PHP/Token/Stream/CachingFactory.php";s:4:"966e";s:40:"PEAR/PHP/Token/Stream/TextUI/Command.php";s:4:"b6dd";s:25:"PEAR/PHPUnit/Autoload.php";s:4:"4f00";s:26:"PEAR/PHPUnit/Framework.php";s:4:"142a";s:42:"PEAR/PHPUnit/Extensions/GroupTestSuite.php";s:4:"3b20";s:42:"PEAR/PHPUnit/Extensions/OutputTestCase.php";s:4:"871c";s:40:"PEAR/PHPUnit/Extensions/PhptTestCase.php";s:4:"5f7c";s:41:"PEAR/PHPUnit/Extensions/PhptTestSuite.php";s:4:"0b89";s:40:"PEAR/PHPUnit/Extensions/RepeatedTest.php";s:4:"9075";s:44:"PEAR/PHPUnit/Extensions/SeleniumTestCase.php";s:4:"47b3";s:41:"PEAR/PHPUnit/Extensions/TestDecorator.php";s:4:"e66d";s:42:"PEAR/PHPUnit/Extensions/TicketListener.php";s:4:"3b49";s:51:"PEAR/PHPUnit/Extensions/Database/AbstractTester.php";s:4:"01c7";s:50:"PEAR/PHPUnit/Extensions/Database/DefaultTester.php";s:4:"d875";s:58:"PEAR/PHPUnit/Extensions/Database/IDatabaseListConsumer.php";s:4:"f19b";s:44:"PEAR/PHPUnit/Extensions/Database/ITester.php";s:4:"1b13";s:45:"PEAR/PHPUnit/Extensions/Database/TestCase.php";s:4:"3259";s:62:"PEAR/PHPUnit/Extensions/Database/Constraint/DataSetIsEqual.php";s:4:"d541";s:60:"PEAR/PHPUnit/Extensions/Database/Constraint/TableIsEqual.php";s:4:"05f1";s:47:"PEAR/PHPUnit/Extensions/Database/DB/DataSet.php";s:4:"e5b3";s:65:"PEAR/PHPUnit/Extensions/Database/DB/DefaultDatabaseConnection.php";s:4:"ea1f";s:55:"PEAR/PHPUnit/Extensions/Database/DB/FilteredDataSet.php";s:4:"5792";s:59:"PEAR/PHPUnit/Extensions/Database/DB/IDatabaseConnection.php";s:4:"6417";s:49:"PEAR/PHPUnit/Extensions/Database/DB/IMetaData.php";s:4:"0fd6";s:48:"PEAR/PHPUnit/Extensions/Database/DB/MetaData.php";s:4:"0d0a";s:54:"PEAR/PHPUnit/Extensions/Database/DB/ResultSetTable.php";s:4:"a720";s:45:"PEAR/PHPUnit/Extensions/Database/DB/Table.php";s:4:"3d40";s:53:"PEAR/PHPUnit/Extensions/Database/DB/TableIterator.php";s:4:"0590";s:53:"PEAR/PHPUnit/Extensions/Database/DB/TableMetaData.php";s:4:"9432";s:66:"PEAR/PHPUnit/Extensions/Database/DB/MetaData/InformationSchema.php";s:4:"f4b1";s:54:"PEAR/PHPUnit/Extensions/Database/DB/MetaData/MySQL.php";s:4:"d341";s:52:"PEAR/PHPUnit/Extensions/Database/DB/MetaData/Oci.php";s:4:"8a88";s:54:"PEAR/PHPUnit/Extensions/Database/DB/MetaData/PgSQL.php";s:4:"9530";s:55:"PEAR/PHPUnit/Extensions/Database/DB/MetaData/Sqlite.php";s:4:"43f7";s:60:"PEAR/PHPUnit/Extensions/Database/DataSet/AbstractDataSet.php";s:4:"62c3";s:58:"PEAR/PHPUnit/Extensions/Database/DataSet/AbstractTable.php";s:4:"3085";s:66:"PEAR/PHPUnit/Extensions/Database/DataSet/AbstractTableMetaData.php";s:4:"5623";s:63:"PEAR/PHPUnit/Extensions/Database/DataSet/AbstractXmlDataSet.php";s:4:"a7e2";s:61:"PEAR/PHPUnit/Extensions/Database/DataSet/CompositeDataSet.php";s:4:"dc70";s:55:"PEAR/PHPUnit/Extensions/Database/DataSet/CsvDataSet.php";s:4:"1b1c";s:58:"PEAR/PHPUnit/Extensions/Database/DataSet/DataSetFilter.php";s:4:"20ab";s:59:"PEAR/PHPUnit/Extensions/Database/DataSet/DefaultDataSet.php";s:4:"e6ce";s:57:"PEAR/PHPUnit/Extensions/Database/DataSet/DefaultTable.php";s:4:"3bc6";s:65:"PEAR/PHPUnit/Extensions/Database/DataSet/DefaultTableIterator.php";s:4:"8321";s:65:"PEAR/PHPUnit/Extensions/Database/DataSet/DefaultTableMetaData.php";s:4:"0756";s:59:"PEAR/PHPUnit/Extensions/Database/DataSet/FlatXmlDataSet.php";s:4:"95b6";s:53:"PEAR/PHPUnit/Extensions/Database/DataSet/IDataSet.php";s:4:"1949";s:57:"PEAR/PHPUnit/Extensions/Database/DataSet/IPersistable.php";s:4:"b6ef";s:50:"PEAR/PHPUnit/Extensions/Database/DataSet/ISpec.php";s:4:"f407";s:51:"PEAR/PHPUnit/Extensions/Database/DataSet/ITable.php";s:4:"a9f5";s:59:"PEAR/PHPUnit/Extensions/Database/DataSet/ITableIterator.php";s:4:"4ffa";s:59:"PEAR/PHPUnit/Extensions/Database/DataSet/ITableMetaData.php";s:4:"93d8";s:60:"PEAR/PHPUnit/Extensions/Database/DataSet/MysqlXmlDataSet.php";s:4:"b9d3";s:57:"PEAR/PHPUnit/Extensions/Database/DataSet/QueryDataSet.php";s:4:"9ae4";s:55:"PEAR/PHPUnit/Extensions/Database/DataSet/QueryTable.php";s:4:"ce42";s:63:"PEAR/PHPUnit/Extensions/Database/DataSet/ReplacementDataSet.php";s:4:"9a6f";s:61:"PEAR/PHPUnit/Extensions/Database/DataSet/ReplacementTable.php";s:4:"a9ea";s:69:"PEAR/PHPUnit/Extensions/Database/DataSet/ReplacementTableIterator.php";s:4:"18a8";s:56:"PEAR/PHPUnit/Extensions/Database/DataSet/TableFilter.php";s:4:"a4de";s:64:"PEAR/PHPUnit/Extensions/Database/DataSet/TableMetaDataFilter.php";s:4:"2e83";s:55:"PEAR/PHPUnit/Extensions/Database/DataSet/XmlDataSet.php";s:4:"57d2";s:56:"PEAR/PHPUnit/Extensions/Database/DataSet/YamlDataSet.php";s:4:"554b";s:64:"PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Abstract.php";s:4:"0bca";s:63:"PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Factory.php";s:4:"04db";s:63:"PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/FlatXml.php";s:4:"8a60";s:64:"PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/MysqlXml.php";s:4:"aa35";s:59:"PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Xml.php";s:4:"005f";s:60:"PEAR/PHPUnit/Extensions/Database/DataSet/Persistors/Yaml.php";s:4:"a7d9";s:54:"PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Csv.php";s:4:"e303";s:58:"PEAR/PHPUnit/Extensions/Database/DataSet/Specs/DbQuery.php";s:4:"a377";s:58:"PEAR/PHPUnit/Extensions/Database/DataSet/Specs/DbTable.php";s:4:"cfea";s:58:"PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Factory.php";s:4:"0df2";s:58:"PEAR/PHPUnit/Extensions/Database/DataSet/Specs/FlatXml.php";s:4:"ce5c";s:59:"PEAR/PHPUnit/Extensions/Database/DataSet/Specs/IFactory.php";s:4:"455d";s:54:"PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Xml.php";s:4:"6813";s:55:"PEAR/PHPUnit/Extensions/Database/DataSet/Specs/Yaml.php";s:4:"e3d9";s:56:"PEAR/PHPUnit/Extensions/Database/Operation/Composite.php";s:4:"6d94";s:53:"PEAR/PHPUnit/Extensions/Database/Operation/Delete.php";s:4:"a502";s:56:"PEAR/PHPUnit/Extensions/Database/Operation/DeleteAll.php";s:4:"8aba";s:56:"PEAR/PHPUnit/Extensions/Database/Operation/Exception.php";s:4:"9647";s:54:"PEAR/PHPUnit/Extensions/Database/Operation/Factory.php";s:4:"f99f";s:65:"PEAR/PHPUnit/Extensions/Database/Operation/IDatabaseOperation.php";s:4:"9131";s:53:"PEAR/PHPUnit/Extensions/Database/Operation/Insert.php";s:4:"f25b";s:51:"PEAR/PHPUnit/Extensions/Database/Operation/Null.php";s:4:"4b69";s:54:"PEAR/PHPUnit/Extensions/Database/Operation/Replace.php";s:4:"39f7";s:55:"PEAR/PHPUnit/Extensions/Database/Operation/RowBased.php";s:4:"e1ba";s:55:"PEAR/PHPUnit/Extensions/Database/Operation/Truncate.php";s:4:"d6e3";s:53:"PEAR/PHPUnit/Extensions/Database/Operation/Update.php";s:4:"832c";s:47:"PEAR/PHPUnit/Extensions/Database/UI/Command.php";s:4:"99f4";s:47:"PEAR/PHPUnit/Extensions/Database/UI/Context.php";s:4:"65d4";s:47:"PEAR/PHPUnit/Extensions/Database/UI/IMedium.php";s:4:"235c";s:54:"PEAR/PHPUnit/Extensions/Database/UI/IMediumPrinter.php";s:4:"561d";s:45:"PEAR/PHPUnit/Extensions/Database/UI/IMode.php";s:4:"9409";s:52:"PEAR/PHPUnit/Extensions/Database/UI/IModeFactory.php";s:4:"6f79";s:60:"PEAR/PHPUnit/Extensions/Database/UI/InvalidModeException.php";s:4:"2bb2";s:51:"PEAR/PHPUnit/Extensions/Database/UI/ModeFactory.php";s:4:"71cc";s:52:"PEAR/PHPUnit/Extensions/Database/UI/Mediums/Text.php";s:4:"230f";s:59:"PEAR/PHPUnit/Extensions/Database/UI/Modes/ExportDataSet.php";s:4:"1cb0";s:69:"PEAR/PHPUnit/Extensions/Database/UI/Modes/ExportDataSet/Arguments.php";s:4:"1c56";s:47:"PEAR/PHPUnit/Extensions/PhptTestCase/Logger.php";s:4:"591f";s:51:"PEAR/PHPUnit/Extensions/SeleniumTestCase/Driver.php";s:4:"9f64";s:51:"PEAR/PHPUnit/Extensions/SeleniumTestCase/append.php";s:4:"f52d";s:61:"PEAR/PHPUnit/Extensions/SeleniumTestCase/phpunit_coverage.php";s:4:"5a01";s:52:"PEAR/PHPUnit/Extensions/SeleniumTestCase/prepend.php";s:4:"6eca";s:39:"PEAR/PHPUnit/Extensions/Story/Given.php";s:4:"1092";s:47:"PEAR/PHPUnit/Extensions/Story/ResultPrinter.php";s:4:"9145";s:42:"PEAR/PHPUnit/Extensions/Story/Scenario.php";s:4:"5205";s:50:"PEAR/PHPUnit/Extensions/Story/SeleniumTestCase.php";s:4:"8d74";s:38:"PEAR/PHPUnit/Extensions/Story/Step.php";s:4:"583f";s:42:"PEAR/PHPUnit/Extensions/Story/TestCase.php";s:4:"0dfa";s:38:"PEAR/PHPUnit/Extensions/Story/Then.php";s:4:"e118";s:38:"PEAR/PHPUnit/Extensions/Story/When.php";s:4:"64af";s:52:"PEAR/PHPUnit/Extensions/Story/ResultPrinter/HTML.php";s:4:"6bae";s:52:"PEAR/PHPUnit/Extensions/Story/ResultPrinter/Text.php";s:4:"d7f7";s:71:"PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/scenario.html.dist";s:4:"4595";s:78:"PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/scenario_header.html.dist";s:4:"967a";s:72:"PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/scenarios.html.dist";s:4:"be5e";s:67:"PEAR/PHPUnit/Extensions/Story/ResultPrinter/Template/step.html.dist";s:4:"3c26";s:49:"PEAR/PHPUnit/Extensions/TicketListener/GitHub.php";s:4:"b6a5";s:53:"PEAR/PHPUnit/Extensions/TicketListener/GoogleCode.php";s:4:"59fb";s:47:"PEAR/PHPUnit/Extensions/TicketListener/Trac.php";s:4:"417d";s:33:"PEAR/PHPUnit/Framework/Assert.php";s:4:"9fb0";s:47:"PEAR/PHPUnit/Framework/AssertionFailedError.php";s:4:"e546";s:44:"PEAR/PHPUnit/Framework/ComparisonFailure.php";s:4:"5ac5";s:37:"PEAR/PHPUnit/Framework/Constraint.php";s:4:"190b";s:32:"PEAR/PHPUnit/Framework/Error.php";s:4:"a345";s:36:"PEAR/PHPUnit/Framework/Exception.php";s:4:"4f90";s:53:"PEAR/PHPUnit/Framework/ExpectationFailedException.php";s:4:"2372";s:41:"PEAR/PHPUnit/Framework/IncompleteTest.php";s:4:"071c";s:46:"PEAR/PHPUnit/Framework/IncompleteTestError.php";s:4:"3520";s:41:"PEAR/PHPUnit/Framework/SelfDescribing.php";s:4:"2ad7";s:38:"PEAR/PHPUnit/Framework/SkippedTest.php";s:4:"0256";s:43:"PEAR/PHPUnit/Framework/SkippedTestError.php";s:4:"df44";s:48:"PEAR/PHPUnit/Framework/SkippedTestSuiteError.php";s:4:"9d23";s:41:"PEAR/PHPUnit/Framework/SyntheticError.php";s:4:"5af6";s:31:"PEAR/PHPUnit/Framework/Test.php";s:4:"16e3";s:35:"PEAR/PHPUnit/Framework/TestCase.php";s:4:"8bb0";s:38:"PEAR/PHPUnit/Framework/TestFailure.php";s:4:"2762";s:39:"PEAR/PHPUnit/Framework/TestListener.php";s:4:"df7b";s:37:"PEAR/PHPUnit/Framework/TestResult.php";s:4:"8013";s:36:"PEAR/PHPUnit/Framework/TestSuite.php";s:4:"91ca";s:34:"PEAR/PHPUnit/Framework/Warning.php";s:4:"5015";s:43:"PEAR/PHPUnit/Framework/Assert/Functions.php";s:4:"c65d";s:50:"PEAR/PHPUnit/Framework/ComparisonFailure/Array.php";s:4:"40b3";s:51:"PEAR/PHPUnit/Framework/ComparisonFailure/Object.php";s:4:"017e";s:51:"PEAR/PHPUnit/Framework/ComparisonFailure/Scalar.php";s:4:"9956";s:51:"PEAR/PHPUnit/Framework/ComparisonFailure/String.php";s:4:"c5dd";s:49:"PEAR/PHPUnit/Framework/ComparisonFailure/Type.php";s:4:"2457";s:41:"PEAR/PHPUnit/Framework/Constraint/And.php";s:4:"0185";s:49:"PEAR/PHPUnit/Framework/Constraint/ArrayHasKey.php";s:4:"7c93";s:47:"PEAR/PHPUnit/Framework/Constraint/Attribute.php";s:4:"d0a8";s:55:"PEAR/PHPUnit/Framework/Constraint/ClassHasAttribute.php";s:4:"1840";s:61:"PEAR/PHPUnit/Framework/Constraint/ClassHasStaticAttribute.php";s:4:"41c4";s:48:"PEAR/PHPUnit/Framework/Constraint/FileExists.php";s:4:"0f54";s:49:"PEAR/PHPUnit/Framework/Constraint/GreaterThan.php";s:4:"78df";s:48:"PEAR/PHPUnit/Framework/Constraint/IsAnything.php";s:4:"918a";s:45:"PEAR/PHPUnit/Framework/Constraint/IsEmpty.php";s:4:"4017";s:45:"PEAR/PHPUnit/Framework/Constraint/IsEqual.php";s:4:"3652";s:45:"PEAR/PHPUnit/Framework/Constraint/IsFalse.php";s:4:"6821";s:49:"PEAR/PHPUnit/Framework/Constraint/IsIdentical.php";s:4:"98f9";s:50:"PEAR/PHPUnit/Framework/Constraint/IsInstanceOf.php";s:4:"903c";s:44:"PEAR/PHPUnit/Framework/Constraint/IsNull.php";s:4:"cccf";s:44:"PEAR/PHPUnit/Framework/Constraint/IsTrue.php";s:4:"03ce";s:44:"PEAR/PHPUnit/Framework/Constraint/IsType.php";s:4:"c065";s:46:"PEAR/PHPUnit/Framework/Constraint/LessThan.php";s:4:"3142";s:41:"PEAR/PHPUnit/Framework/Constraint/Not.php";s:4:"be80";s:56:"PEAR/PHPUnit/Framework/Constraint/ObjectHasAttribute.php";s:4:"7eb3";s:40:"PEAR/PHPUnit/Framework/Constraint/Or.php";s:4:"fd8e";s:47:"PEAR/PHPUnit/Framework/Constraint/PCREMatch.php";s:4:"cdeb";s:52:"PEAR/PHPUnit/Framework/Constraint/StringContains.php";s:4:"faa8";s:52:"PEAR/PHPUnit/Framework/Constraint/StringEndsWith.php";s:4:"5f50";s:51:"PEAR/PHPUnit/Framework/Constraint/StringMatches.php";s:4:"ce4a";s:54:"PEAR/PHPUnit/Framework/Constraint/StringStartsWith.php";s:4:"e2e5";s:57:"PEAR/PHPUnit/Framework/Constraint/TraversableContains.php";s:4:"a595";s:61:"PEAR/PHPUnit/Framework/Constraint/TraversableContainsOnly.php";s:4:"b276";s:41:"PEAR/PHPUnit/Framework/Constraint/Xor.php";s:4:"5a23";s:39:"PEAR/PHPUnit/Framework/Error/Notice.php";s:4:"3aa0";s:40:"PEAR/PHPUnit/Framework/Error/Warning.php";s:4:"40da";s:47:"PEAR/PHPUnit/Framework/MockObject/Generator.php";s:4:"04c4";s:48:"PEAR/PHPUnit/Framework/MockObject/Invocation.php";s:4:"5a6b";s:54:"PEAR/PHPUnit/Framework/MockObject/InvocationMocker.php";s:4:"98ef";s:47:"PEAR/PHPUnit/Framework/MockObject/Invokable.php";s:4:"b670";s:45:"PEAR/PHPUnit/Framework/MockObject/Matcher.php";s:4:"370a";s:49:"PEAR/PHPUnit/Framework/MockObject/MockBuilder.php";s:4:"7099";s:48:"PEAR/PHPUnit/Framework/MockObject/MockObject.php";s:4:"2935";s:42:"PEAR/PHPUnit/Framework/MockObject/Stub.php";s:4:"0797";s:48:"PEAR/PHPUnit/Framework/MockObject/Verifiable.php";s:4:"eb36";s:54:"PEAR/PHPUnit/Framework/MockObject/Builder/Identity.php";s:4:"5abb";s:62:"PEAR/PHPUnit/Framework/MockObject/Builder/InvocationMocker.php";s:4:"c1b2";s:51:"PEAR/PHPUnit/Framework/MockObject/Builder/Match.php";s:4:"eed0";s:61:"PEAR/PHPUnit/Framework/MockObject/Builder/MethodNameMatch.php";s:4:"e15c";s:55:"PEAR/PHPUnit/Framework/MockObject/Builder/Namespace.php";s:4:"bf3d";s:61:"PEAR/PHPUnit/Framework/MockObject/Builder/ParametersMatch.php";s:4:"f78e";s:50:"PEAR/PHPUnit/Framework/MockObject/Builder/Stub.php";s:4:"18f4";s:65:"PEAR/PHPUnit/Framework/MockObject/Generator/mocked_class.tpl.dist";s:4:"26de";s:65:"PEAR/PHPUnit/Framework/MockObject/Generator/mocked_clone.tpl.dist";s:4:"747c";s:73:"PEAR/PHPUnit/Framework/MockObject/Generator/mocked_object_method.tpl.dist";s:4:"6cec";s:73:"PEAR/PHPUnit/Framework/MockObject/Generator/mocked_static_method.tpl.dist";s:4:"2854";s:67:"PEAR/PHPUnit/Framework/MockObject/Generator/unmocked_clone.tpl.dist";s:4:"24ed";s:63:"PEAR/PHPUnit/Framework/MockObject/Generator/wsdl_class.tpl.dist";s:4:"832a";s:64:"PEAR/PHPUnit/Framework/MockObject/Generator/wsdl_method.tpl.dist";s:4:"b87f";s:55:"PEAR/PHPUnit/Framework/MockObject/Invocation/Object.php";s:4:"99f8";s:55:"PEAR/PHPUnit/Framework/MockObject/Invocation/Static.php";s:4:"76ad";s:61:"PEAR/PHPUnit/Framework/MockObject/Matcher/AnyInvokedCount.php";s:4:"0fd0";s:59:"PEAR/PHPUnit/Framework/MockObject/Matcher/AnyParameters.php";s:4:"6d73";s:56:"PEAR/PHPUnit/Framework/MockObject/Matcher/Invocation.php";s:4:"e973";s:60:"PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedAtIndex.php";s:4:"0244";s:64:"PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedAtLeastOnce.php";s:4:"49c7";s:58:"PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedCount.php";s:4:"591d";s:61:"PEAR/PHPUnit/Framework/MockObject/Matcher/InvokedRecorder.php";s:4:"22bc";s:56:"PEAR/PHPUnit/Framework/MockObject/Matcher/MethodName.php";s:4:"d6cc";s:56:"PEAR/PHPUnit/Framework/MockObject/Matcher/Parameters.php";s:4:"52a1";s:65:"PEAR/PHPUnit/Framework/MockObject/Matcher/StatelessInvocation.php";s:4:"77e2";s:59:"PEAR/PHPUnit/Framework/MockObject/Stub/ConsecutiveCalls.php";s:4:"2d4a";s:52:"PEAR/PHPUnit/Framework/MockObject/Stub/Exception.php";s:4:"99e7";s:60:"PEAR/PHPUnit/Framework/MockObject/Stub/MatcherCollection.php";s:4:"aaf0";s:49:"PEAR/PHPUnit/Framework/MockObject/Stub/Return.php";s:4:"8ddc";s:57:"PEAR/PHPUnit/Framework/MockObject/Stub/ReturnArgument.php";s:4:"99a4";s:57:"PEAR/PHPUnit/Framework/MockObject/Stub/ReturnCallback.php";s:4:"1666";s:54:"PEAR/PHPUnit/Framework/Process/TestCaseMethod.tpl.dist";s:4:"adee";s:49:"PEAR/PHPUnit/Framework/TestSuite/DataProvider.php";s:4:"d406";s:38:"PEAR/PHPUnit/Runner/BaseTestRunner.php";s:4:"aff3";s:48:"PEAR/PHPUnit/Runner/IncludePathTestCollector.php";s:4:"b866";s:47:"PEAR/PHPUnit/Runner/StandardTestSuiteLoader.php";s:4:"51c2";s:37:"PEAR/PHPUnit/Runner/TestCollector.php";s:4:"841c";s:39:"PEAR/PHPUnit/Runner/TestSuiteLoader.php";s:4:"35b4";s:31:"PEAR/PHPUnit/Runner/Version.php";s:4:"e9dc";s:31:"PEAR/PHPUnit/TextUI/Command.php";s:4:"a18c";s:37:"PEAR/PHPUnit/TextUI/ResultPrinter.php";s:4:"2c6c";s:34:"PEAR/PHPUnit/TextUI/TestRunner.php";s:4:"ec82";s:27:"PEAR/PHPUnit/Util/Class.php";s:4:"f236";s:35:"PEAR/PHPUnit/Util/Configuration.php";s:4:"37f1";s:39:"PEAR/PHPUnit/Util/DeprecatedFeature.php";s:4:"d1a8";s:26:"PEAR/PHPUnit/Util/Diff.php";s:4:"20ca";s:34:"PEAR/PHPUnit/Util/ErrorHandler.php";s:4:"375b";s:26:"PEAR/PHPUnit/Util/File.php";s:4:"ca74";s:32:"PEAR/PHPUnit/Util/Fileloader.php";s:4:"1ba9";s:32:"PEAR/PHPUnit/Util/Filesystem.php";s:4:"e087";s:28:"PEAR/PHPUnit/Util/Filter.php";s:4:"a4e4";s:28:"PEAR/PHPUnit/Util/Getopt.php";s:4:"428d";s:33:"PEAR/PHPUnit/Util/GlobalState.php";s:4:"61af";s:43:"PEAR/PHPUnit/Util/InvalidArgumentHelper.php";s:4:"3979";s:25:"PEAR/PHPUnit/Util/PHP.php";s:4:"0429";s:29:"PEAR/PHPUnit/Util/Printer.php";s:4:"6d5d";s:30:"PEAR/PHPUnit/Util/Skeleton.php";s:4:"0f24";s:26:"PEAR/PHPUnit/Util/Test.php";s:4:"4ee8";s:39:"PEAR/PHPUnit/Util/TestSuiteIterator.php";s:4:"2bf8";s:26:"PEAR/PHPUnit/Util/Type.php";s:4:"c549";s:25:"PEAR/PHPUnit/Util/XML.php";s:4:"601d";s:46:"PEAR/PHPUnit/Util/DeprecatedFeature/Logger.php";s:4:"ead6";s:30:"PEAR/PHPUnit/Util/Log/DBUS.php";s:4:"759f";s:30:"PEAR/PHPUnit/Util/Log/JSON.php";s:4:"492d";s:31:"PEAR/PHPUnit/Util/Log/JUnit.php";s:4:"41ca";s:29:"PEAR/PHPUnit/Util/Log/TAP.php";s:4:"f651";s:32:"PEAR/PHPUnit/Util/Log/XHProf.php";s:4:"c24b";s:33:"PEAR/PHPUnit/Util/PHP/Default.php";s:4:"8c98";s:33:"PEAR/PHPUnit/Util/PHP/Windows.php";s:4:"f80c";s:36:"PEAR/PHPUnit/Util/Skeleton/Class.php";s:4:"ff45";s:35:"PEAR/PHPUnit/Util/Skeleton/Test.php";s:4:"a954";s:50:"PEAR/PHPUnit/Util/Skeleton/Template/Class.tpl.dist";s:4:"2bd8";s:65:"PEAR/PHPUnit/Util/Skeleton/Template/IncompleteTestMethod.tpl.dist";s:4:"4aae";s:51:"PEAR/PHPUnit/Util/Skeleton/Template/Method.tpl.dist";s:4:"0738";s:54:"PEAR/PHPUnit/Util/Skeleton/Template/TestClass.tpl.dist";s:4:"1b5e";s:55:"PEAR/PHPUnit/Util/Skeleton/Template/TestMethod.tpl.dist";s:4:"6141";s:59:"PEAR/PHPUnit/Util/Skeleton/Template/TestMethodBool.tpl.dist";s:4:"9a09";s:65:"PEAR/PHPUnit/Util/Skeleton/Template/TestMethodBoolStatic.tpl.dist";s:4:"9fa0";s:64:"PEAR/PHPUnit/Util/Skeleton/Template/TestMethodException.tpl.dist";s:4:"c08f";s:70:"PEAR/PHPUnit/Util/Skeleton/Template/TestMethodExceptionStatic.tpl.dist";s:4:"c021";s:61:"PEAR/PHPUnit/Util/Skeleton/Template/TestMethodStatic.tpl.dist";s:4:"4b31";s:44:"PEAR/PHPUnit/Util/TestDox/NamePrettifier.php";s:4:"b804";s:43:"PEAR/PHPUnit/Util/TestDox/ResultPrinter.php";s:4:"f9e0";s:48:"PEAR/PHPUnit/Util/TestDox/ResultPrinter/HTML.php";s:4:"2d58";s:48:"PEAR/PHPUnit/Util/TestDox/ResultPrinter/Text.php";s:4:"6d9b";s:25:"PEAR/Structures/Graph.php";s:4:"4f25";s:30:"PEAR/Structures/Graph/Node.php";s:4:"254e";s:49:"PEAR/Structures/Graph/Manipulator/AcyclicTest.php";s:4:"f0af";s:55:"PEAR/Structures/Graph/Manipulator/TopologicalSorter.php";s:4:"0492";s:38:"PEAR/SymfonyComponents/YAML/sfYaml.php";s:4:"2b71";s:44:"PEAR/SymfonyComponents/YAML/sfYamlDumper.php";s:4:"2819";s:44:"PEAR/SymfonyComponents/YAML/sfYamlInline.php";s:4:"cb97";s:44:"PEAR/SymfonyComponents/YAML/sfYamlParser.php";s:4:"d01f";s:22:"PEAR/Text/Template.php";s:4:"2be8";s:31:"PEAR/Text/Template/Autoload.php";s:4:"bb23";s:17:"PEAR/XML/Util.php";s:4:"9bb2";s:25:"PEAR/XML/RPC2/Backend.php";s:4:"263e";s:30:"PEAR/XML/RPC2/CachedClient.php";s:4:"31d9";s:30:"PEAR/XML/RPC2/CachedServer.php";s:4:"d2dd";s:24:"PEAR/XML/RPC2/Client.php";s:4:"4c01";s:30:"PEAR/XML/RPC2/ClientHelper.php";s:4:"028a";s:27:"PEAR/XML/RPC2/Exception.php";s:4:"1ec2";s:24:"PEAR/XML/RPC2/Server.php";s:4:"770d";s:23:"PEAR/XML/RPC2/Value.php";s:4:"7b6c";s:36:"PEAR/XML/RPC2/Backend/Php/Client.php";s:4:"21dc";s:37:"PEAR/XML/RPC2/Backend/Php/Request.php";s:4:"ef7b";s:38:"PEAR/XML/RPC2/Backend/Php/Response.php";s:4:"7dc0";s:36:"PEAR/XML/RPC2/Backend/Php/Server.php";s:4:"541f";s:35:"PEAR/XML/RPC2/Backend/Php/Value.php";s:4:"8d23";s:41:"PEAR/XML/RPC2/Backend/Php/Value/Array.php";s:4:"f538";s:42:"PEAR/XML/RPC2/Backend/Php/Value/Base64.php";s:4:"a85a";s:43:"PEAR/XML/RPC2/Backend/Php/Value/Boolean.php";s:4:"c8c6";s:44:"PEAR/XML/RPC2/Backend/Php/Value/Datetime.php";s:4:"8d7b";s:42:"PEAR/XML/RPC2/Backend/Php/Value/Double.php";s:4:"1f07";s:43:"PEAR/XML/RPC2/Backend/Php/Value/Integer.php";s:4:"4ed5";s:45:"PEAR/XML/RPC2/Backend/Php/Value/Integer64.php";s:4:"cca5";s:39:"PEAR/XML/RPC2/Backend/Php/Value/Nil.php";s:4:"10c0";s:42:"PEAR/XML/RPC2/Backend/Php/Value/Scalar.php";s:4:"b758";s:42:"PEAR/XML/RPC2/Backend/Php/Value/String.php";s:4:"f50b";s:42:"PEAR/XML/RPC2/Backend/Php/Value/Struct.php";s:4:"840d";s:42:"PEAR/XML/RPC2/Backend/Xmlrpcext/Client.php";s:4:"eab5";s:42:"PEAR/XML/RPC2/Backend/Xmlrpcext/Server.php";s:4:"9641";s:41:"PEAR/XML/RPC2/Backend/Xmlrpcext/Value.php";s:4:"f1b1";s:36:"PEAR/XML/RPC2/Server/CallHandler.php";s:4:"2bd6";s:30:"PEAR/XML/RPC2/Server/Input.php";s:4:"2524";s:31:"PEAR/XML/RPC2/Server/Method.php";s:4:"1a01";s:42:"PEAR/XML/RPC2/Server/CallHandler/Class.php";s:4:"97d8";s:45:"PEAR/XML/RPC2/Server/CallHandler/Instance.php";s:4:"b87b";s:39:"PEAR/XML/RPC2/Server/Input/PhpInput.php";s:4:"25b4";s:42:"PEAR/XML/RPC2/Server/Input/RawPostData.php";s:4:"e78c";s:34:"PEAR/XML/RPC2/Util/HTTPRequest.php";s:4:"e544";s:39:"PEAR/data/Base/design/class_diagram.png";s:4:"ab5f";s:32:"PEAR/data/Base/design/design.txt";s:4:"64db";s:47:"PEAR/data/ConsoleTools/design/class_diagram.png";s:4:"53a2";s:41:"PEAR/data/ConsoleTools/design/console.png";s:4:"b0e9";s:41:"PEAR/data/ConsoleTools/design/console.xml";s:4:"8ec7";s:52:"PEAR/data/ConsoleTools/design/console_parameters.png";s:4:"928f";s:44:"PEAR/data/ConsoleTools/design/design-1.3.txt";s:4:"b984";s:40:"PEAR/data/ConsoleTools/design/design.txt";s:4:"9f36";s:26:"PEAR/data/PEAR/package.dtd";s:4:"4a49";s:28:"PEAR/data/PEAR/template.spec";s:4:"acd0";s:34:"PEAR/data/Structures_Graph/LICENSE";s:4:"7fbc";s:27:"PEAR/data/XML_RPC2/Makefile";s:4:"b4c7";s:27:"PEAR/data/vfsStream/LICENSE";s:4:"d13f";s:27:"PEAR/data/vfsStream/VERSION";s:4:"3989";s:42:"PEAR/docs/Archive_Tar/docs/Archive_Tar.txt";s:4:"29b0";s:27:"PEAR/docs/Base/docs/CREDITS";s:4:"6a44";s:27:"PEAR/docs/Base/docs/LICENSE";s:4:"0d01";s:32:"PEAR/docs/Base/docs/tutorial.txt";s:4:"15e0";s:41:"PEAR/docs/Base/docs/tutorial_autoload.php";s:4:"c62a";s:43:"PEAR/docs/Base/docs/tutorial_example_01.php";s:4:"7a4a";s:43:"PEAR/docs/Base/docs/tutorial_example_02.php";s:4:"1493";s:43:"PEAR/docs/Base/docs/tutorial_example_03.php";s:4:"09dd";s:43:"PEAR/docs/Base/docs/tutorial_example_04.php";s:4:"c934";s:52:"PEAR/docs/Base/docs/tutorial_lazy_initialization.php";s:4:"f639";s:41:"PEAR/docs/Base/docs/repos/Me/myclass1.php";s:4:"1300";s:41:"PEAR/docs/Base/docs/repos/Me/myclass2.php";s:4:"9f53";s:44:"PEAR/docs/Base/docs/repos/You/yourclass1.php";s:4:"8a48";s:44:"PEAR/docs/Base/docs/repos/You/yourclass2.php";s:4:"2ff7";s:51:"PEAR/docs/Base/docs/repos/autoloads/my_autoload.php";s:4:"524b";s:53:"PEAR/docs/Base/docs/repos/autoloads/your_autoload.php";s:4:"bd6a";s:28:"PEAR/docs/Cache_Lite/LICENSE";s:4:"c73b";s:25:"PEAR/docs/Cache_Lite/TODO";s:4:"4c63";s:34:"PEAR/docs/Cache_Lite/docs/examples";s:4:"516b";s:35:"PEAR/docs/Cache_Lite/docs/technical";s:4:"9340";s:33:"PEAR/docs/Cache_Lite/tests/readme";s:4:"f7a9";s:35:"PEAR/docs/ConsoleTools/docs/CREDITS";s:4:"6a44";s:35:"PEAR/docs/ConsoleTools/docs/LICENSE";s:4:"0d01";s:45:"PEAR/docs/ConsoleTools/docs/example_input.php";s:4:"0ded";s:56:"PEAR/docs/ConsoleTools/docs/example_menu_dialog_full.php";s:4:"84de";s:46:"PEAR/docs/ConsoleTools/docs/example_output.php";s:4:"b5d0";s:51:"PEAR/docs/ConsoleTools/docs/example_progressbar.php";s:4:"0964";s:55:"PEAR/docs/ConsoleTools/docs/example_progressmonitor.php";s:4:"9519";s:71:"PEAR/docs/ConsoleTools/docs/example_question_dialog_collection_full.php";s:4:"7382";s:69:"PEAR/docs/ConsoleTools/docs/example_question_dialog_factory_yesno.php";s:4:"1695";s:65:"PEAR/docs/ConsoleTools/docs/example_question_dialog_type_full.php";s:4:"600a";s:49:"PEAR/docs/ConsoleTools/docs/example_statusbar.php";s:4:"e829";s:45:"PEAR/docs/ConsoleTools/docs/example_table.php";s:4:"1bf4";s:47:"PEAR/docs/ConsoleTools/docs/example_table_2.php";s:4:"6283";s:40:"PEAR/docs/ConsoleTools/docs/tutorial.txt";s:4:"d33d";s:49:"PEAR/docs/ConsoleTools/docs/tutorial_autoload.php";s:4:"c62a";s:64:"PEAR/docs/ConsoleTools/docs/tutorial_example_01_output_basic.php";s:4:"38c2";s:67:"PEAR/docs/ConsoleTools/docs/tutorial_example_02_output_advanced.php";s:4:"a9b5";s:66:"PEAR/docs/ConsoleTools/docs/tutorial_example_03_output_options.php";s:4:"5f25";s:63:"PEAR/docs/ConsoleTools/docs/tutorial_example_04_input_basic.php";s:4:"0afb";s:66:"PEAR/docs/ConsoleTools/docs/tutorial_example_05_input_advanced.php";s:4:"9c4d";s:69:"PEAR/docs/ConsoleTools/docs/tutorial_example_06_progressbar_basic.php";s:4:"2eb8";s:72:"PEAR/docs/ConsoleTools/docs/tutorial_example_07_progressbar_advanced.php";s:4:"ad54";s:61:"PEAR/docs/ConsoleTools/docs/tutorial_example_08_statusbar.php";s:4:"c930";s:63:"PEAR/docs/ConsoleTools/docs/tutorial_example_09_table_basic.php";s:4:"f2de";s:66:"PEAR/docs/ConsoleTools/docs/tutorial_example_10_table_advanced.php";s:4:"9c32";s:67:"PEAR/docs/ConsoleTools/docs/tutorial_example_11_progressmonitor.php";s:4:"4255";s:67:"PEAR/docs/ConsoleTools/docs/tutorial_example_12_input_arguments.php";s:4:"5642";s:67:"PEAR/docs/ConsoleTools/docs/tutorial_example_13_dialog_question.php";s:4:"9dc3";s:72:"PEAR/docs/ConsoleTools/docs/tutorial_example_14_dialog_yesnoquestion.php";s:4:"2fe7";s:63:"PEAR/docs/ConsoleTools/docs/tutorial_example_15_dialog_menu.php";s:4:"416a";s:63:"PEAR/docs/ConsoleTools/docs/tutorial_example_output_targets.php";s:4:"7e20";s:68:"PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_06.png";s:4:"e3f4";s:68:"PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_07.png";s:4:"9ef8";s:68:"PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_08.png";s:4:"3be4";s:68:"PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_09.png";s:4:"37c3";s:68:"PEAR/docs/ConsoleTools/docs/img/consoletools_tutorial_example_10.png";s:4:"4375";s:35:"PEAR/docs/DbUnit/ChangeLog.markdown";s:4:"8e25";s:24:"PEAR/docs/DbUnit/LICENSE";s:4:"2153";s:54:"PEAR/docs/DbUnit/Samples/BankAccountDB/BankAccount.php";s:4:"3a52";s:60:"PEAR/docs/DbUnit/Samples/BankAccountDB/BankAccountDBTest.php";s:4:"8416";s:65:"PEAR/docs/DbUnit/Samples/BankAccountDB/BankAccountDBTestMySQL.php";s:4:"7fa9";s:77:"PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-after-deposits.xml";s:4:"c0c4";s:80:"PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-after-new-account.xml";s:4:"2f81";s:80:"PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-after-withdrawals.xml";s:4:"b8fd";s:67:"PEAR/docs/DbUnit/Samples/BankAccountDB/_files/bank-account-seed.xml";s:4:"344f";s:22:"PEAR/docs/PEAR/INSTALL";s:4:"99aa";s:22:"PEAR/docs/PEAR/LICENSE";s:4:"45b4";s:21:"PEAR/docs/PEAR/README";s:4:"14c5";s:36:"PEAR/docs/PHPUnit/ChangeLog.markdown";s:4:"4d16";s:25:"PEAR/docs/PHPUnit/LICENSE";s:4:"46fb";s:33:"PEAR/docs/PHPUnit/README.markdown";s:4:"fa1c";s:47:"PEAR/docs/PHPUnit_MockObject/ChangeLog.markdown";s:4:"d3fa";s:36:"PEAR/docs/PHPUnit_MockObject/LICENSE";s:4:"abf9";s:45:"PEAR/docs/PHPUnit_Selenium/ChangeLog.markdown";s:4:"5a68";s:34:"PEAR/docs/PHPUnit_Selenium/LICENSE";s:4:"38a8";s:45:"PEAR/docs/PHP_CodeCoverage/ChangeLog.markdown";s:4:"6f9d";s:34:"PEAR/docs/PHP_CodeCoverage/LICENSE";s:4:"d7c5";s:43:"PEAR/docs/Structures_Graph/docs/generate.sh";s:4:"ce2d";s:69:"PEAR/docs/Structures_Graph/docs/html/classtrees_Structures_Graph.html";s:4:"238f";s:54:"PEAR/docs/Structures_Graph/docs/html/elementindex.html";s:4:"e302";s:71:"PEAR/docs/Structures_Graph/docs/html/elementindex_Structures_Graph.html";s:4:"c97e";s:48:"PEAR/docs/Structures_Graph/docs/html/errors.html";s:4:"6f58";s:47:"PEAR/docs/Structures_Graph/docs/html/index.html";s:4:"cf53";s:61:"PEAR/docs/Structures_Graph/docs/html/li_Structures_Graph.html";s:4:"b206";s:50:"PEAR/docs/Structures_Graph/docs/html/packages.html";s:4:"a88b";s:50:"PEAR/docs/Structures_Graph/docs/html/todolist.html";s:4:"6fdd";s:75:"PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph.html";s:4:"678c";s:99:"PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html";s:4:"686b";s:105:"PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.html";s:4:"08b0";s:80:"PEAR/docs/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Node.html";s:4:"3fa8";s:104:"PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Manipulator_AcyclicTest_php.html";s:4:"9cfe";s:110:"PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Manipulator_TopologicalSorter_php.html";s:4:"4faf";s:85:"PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Node_php.html";s:4:"0337";s:80:"PEAR/docs/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_php.html";s:4:"7c1f";s:88:"PEAR/docs/Structures_Graph/docs/html/Structures_Graph/tutorial_Structures_Graph.pkg.html";s:4:"fd9b";s:53:"PEAR/docs/Structures_Graph/docs/html/media/banner.css";s:4:"e43c";s:57:"PEAR/docs/Structures_Graph/docs/html/media/stylesheet.css";s:4:"296d";s:79:"PEAR/docs/Structures_Graph/docs/tutorials/Structures_Graph/Structures_Graph.pkg";s:4:"628e";s:46:"PEAR/docs/XML_RPC2/docs/tutorials/XML_RPC2.lyx";s:4:"5a82";s:39:"PEAR/docs/XML_Util/examples/example.php";s:4:"06b6";s:40:"PEAR/docs/XML_Util/examples/example2.php";s:4:"7735";s:22:"PEAR/docs/YAML/LICENSE";s:4:"4828";s:30:"PEAR/docs/YAML/README.markdown";s:4:"872d";s:36:"PEAR/docs/vfsStream/docs/metrics.xml";s:4:"1c91";s:36:"PEAR/docs/vfsStream/docs/pmd-cpd.xml";s:4:"6387";s:32:"PEAR/docs/vfsStream/docs/pmd.xml";s:4:"50e5";s:39:"PEAR/docs/vfsStream/docs/api/blank.html";s:4:"40e7";s:55:"PEAR/docs/vfsStream/docs/api/classtrees_bovigo_vfs.html";s:4:"6334";s:46:"PEAR/docs/vfsStream/docs/api/elementindex.html";s:4:"3b25";s:57:"PEAR/docs/vfsStream/docs/api/elementindex_bovigo_vfs.html";s:4:"b146";s:40:"PEAR/docs/vfsStream/docs/api/errors.html";s:4:"f7d2";s:39:"PEAR/docs/vfsStream/docs/api/index.html";s:4:"9f0d";s:47:"PEAR/docs/vfsStream/docs/api/li_bovigo_vfs.html";s:4:"259c";s:42:"PEAR/docs/vfsStream/docs/api/packages.html";s:4:"8ae9";s:42:"PEAR/docs/vfsStream/docs/api/todolist.html";s:4:"b1f6";s:80:"PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStream.php.html";s:4:"a945";s:95:"PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamAbstractContent.php.html";s:4:"2c69";s:89:"PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamContainer.php.html";s:4:"9819";s:97:"PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamContainerIterator.php.html";s:4:"4e8b";s:87:"PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamContent.php.html";s:4:"9627";s:89:"PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamDirectory.php.html";s:4:"fc56";s:89:"PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamException.php.html";s:4:"6991";s:84:"PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamFile.php.html";s:4:"afd3";s:87:"PEAR/docs/vfsStream/docs/api/__filesource/fsource_bovigo_vfs__vfsStreamWrapper.php.html";s:4:"587d";s:59:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStream.php.html";s:4:"63e4";s:74:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamAbstractContent.php.html";s:4:"14b7";s:68:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamContainer.php.html";s:4:"3d9e";s:76:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamContainerIterator.php.html";s:4:"2f9c";s:66:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamContent.php.html";s:4:"c18e";s:68:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamDirectory.php.html";s:4:"3d2d";s:68:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamException.php.html";s:4:"3c42";s:63:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamFile.php.html";s:4:"572e";s:66:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/_vfsStreamWrapper.php.html";s:4:"b237";s:54:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStream.html";s:4:"d5d8";s:69:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamAbstractContent.html";s:4:"a86d";s:63:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamContainer.html";s:4:"9c57";s:71:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamContainerIterator.html";s:4:"adf3";s:61:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamContent.html";s:4:"72d2";s:63:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamDirectory.html";s:4:"7af5";s:63:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamException.html";s:4:"b9dd";s:58:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamFile.html";s:4:"1f9c";s:61:"PEAR/docs/vfsStream/docs/api/bovigo_vfs/vfsStreamWrapper.html";s:4:"ab5d";s:45:"PEAR/docs/vfsStream/docs/api/media/banner.css";s:4:"3671";s:49:"PEAR/docs/vfsStream/docs/api/media/stylesheet.css";s:4:"0d7e";s:59:"PEAR/docs/vfsStream/docs/api/media/images/AbstractClass.png";s:4:"4bbf";s:64:"PEAR/docs/vfsStream/docs/api/media/images/AbstractClass_logo.png";s:4:"9ef5";s:60:"PEAR/docs/vfsStream/docs/api/media/images/AbstractMethod.png";s:4:"029c";s:66:"PEAR/docs/vfsStream/docs/api/media/images/AbstractPrivateClass.png";s:4:"8fd0";s:71:"PEAR/docs/vfsStream/docs/api/media/images/AbstractPrivateClass_logo.png";s:4:"dfae";s:67:"PEAR/docs/vfsStream/docs/api/media/images/AbstractPrivateMethod.png";s:4:"4e97";s:51:"PEAR/docs/vfsStream/docs/api/media/images/Class.png";s:4:"61a3";s:56:"PEAR/docs/vfsStream/docs/api/media/images/Class_logo.png";s:4:"b54c";s:54:"PEAR/docs/vfsStream/docs/api/media/images/Constant.png";s:4:"7081";s:57:"PEAR/docs/vfsStream/docs/api/media/images/Constructor.png";s:4:"4d46";s:56:"PEAR/docs/vfsStream/docs/api/media/images/Destructor.png";s:4:"a5bf";s:54:"PEAR/docs/vfsStream/docs/api/media/images/Function.png";s:4:"493f";s:52:"PEAR/docs/vfsStream/docs/api/media/images/Global.png";s:4:"52b1";s:47:"PEAR/docs/vfsStream/docs/api/media/images/I.png";s:4:"8cdb";s:51:"PEAR/docs/vfsStream/docs/api/media/images/Index.png";s:4:"4f8f";s:55:"PEAR/docs/vfsStream/docs/api/media/images/Interface.png";s:4:"f17a";s:60:"PEAR/docs/vfsStream/docs/api/media/images/Interface_logo.png";s:4:"b54c";s:47:"PEAR/docs/vfsStream/docs/api/media/images/L.png";s:4:"9c75";s:52:"PEAR/docs/vfsStream/docs/api/media/images/Lminus.png";s:4:"10d4";s:51:"PEAR/docs/vfsStream/docs/api/media/images/Lplus.png";s:4:"498f";s:52:"PEAR/docs/vfsStream/docs/api/media/images/Method.png";s:4:"126f";s:50:"PEAR/docs/vfsStream/docs/api/media/images/Page.png";s:4:"6e72";s:55:"PEAR/docs/vfsStream/docs/api/media/images/Page_logo.png";s:4:"a539";s:58:"PEAR/docs/vfsStream/docs/api/media/images/PrivateClass.png";s:4:"c9be";s:63:"PEAR/docs/vfsStream/docs/api/media/images/PrivateClass_logo.png";s:4:"8c42";s:59:"PEAR/docs/vfsStream/docs/api/media/images/PrivateMethod.png";s:4:"4d8a";s:61:"PEAR/docs/vfsStream/docs/api/media/images/PrivateVariable.png";s:4:"32f2";s:58:"PEAR/docs/vfsStream/docs/api/media/images/StaticMethod.png";s:4:"126f";s:60:"PEAR/docs/vfsStream/docs/api/media/images/StaticVariable.png";s:4:"127c";s:47:"PEAR/docs/vfsStream/docs/api/media/images/T.png";s:4:"6346";s:52:"PEAR/docs/vfsStream/docs/api/media/images/Tminus.png";s:4:"83ce";s:51:"PEAR/docs/vfsStream/docs/api/media/images/Tplus.png";s:4:"f0b0";s:54:"PEAR/docs/vfsStream/docs/api/media/images/Variable.png";s:4:"127c";s:51:"PEAR/docs/vfsStream/docs/api/media/images/blank.png";s:4:"9dc3";s:58:"PEAR/docs/vfsStream/docs/api/media/images/class_folder.png";s:4:"dbfb";s:51:"PEAR/docs/vfsStream/docs/api/media/images/empty.png";s:4:"2b6d";s:50:"PEAR/docs/vfsStream/docs/api/media/images/file.png";s:4:"8c09";s:52:"PEAR/docs/vfsStream/docs/api/media/images/folder.png";s:4:"3a95";s:61:"PEAR/docs/vfsStream/docs/api/media/images/function_folder.png";s:4:"bc31";s:51:"PEAR/docs/vfsStream/docs/api/media/images/minus.gif";s:4:"b8b0";s:57:"PEAR/docs/vfsStream/docs/api/media/images/next_button.png";s:4:"c6ec";s:66:"PEAR/docs/vfsStream/docs/api/media/images/next_button_disabled.png";s:4:"f47b";s:53:"PEAR/docs/vfsStream/docs/api/media/images/package.png";s:4:"5e4e";s:60:"PEAR/docs/vfsStream/docs/api/media/images/package_folder.png";s:4:"11a3";s:50:"PEAR/docs/vfsStream/docs/api/media/images/plus.gif";s:4:"5782";s:61:"PEAR/docs/vfsStream/docs/api/media/images/previous_button.png";s:4:"0c31";s:70:"PEAR/docs/vfsStream/docs/api/media/images/previous_button_disabled.png";s:4:"0352";s:64:"PEAR/docs/vfsStream/docs/api/media/images/private_class_logo.png";s:4:"8c42";s:54:"PEAR/docs/vfsStream/docs/api/media/images/tutorial.png";s:4:"8ef8";s:61:"PEAR/docs/vfsStream/docs/api/media/images/tutorial_folder.png";s:4:"eaf9";s:55:"PEAR/docs/vfsStream/docs/api/media/images/up_button.png";s:4:"31e9";s:51:"PEAR/docs/vfsStream/docs/api/media/lib/classTree.js";s:4:"edb1";s:44:"PEAR/docs/vfsStream/docs/coverage/butter.png";s:4:"521e";s:47:"PEAR/docs/vfsStream/docs/coverage/chameleon.png";s:4:"24ab";s:47:"PEAR/docs/vfsStream/docs/coverage/close12_1.gif";s:4:"770d";s:50:"PEAR/docs/vfsStream/docs/coverage/container-min.js";s:4:"cac1";s:47:"PEAR/docs/vfsStream/docs/coverage/container.css";s:4:"30d9";s:43:"PEAR/docs/vfsStream/docs/coverage/glass.png";s:4:"d0bc";s:44:"PEAR/docs/vfsStream/docs/coverage/index.html";s:4:"f7a2";s:49:"PEAR/docs/vfsStream/docs/coverage/scarlet_red.png";s:4:"e7e9";s:42:"PEAR/docs/vfsStream/docs/coverage/snow.png";s:4:"3d0f";s:43:"PEAR/docs/vfsStream/docs/coverage/style.css";s:4:"5170";s:52:"PEAR/docs/vfsStream/docs/coverage/vfsStream.php.html";s:4:"d283";s:67:"PEAR/docs/vfsStream/docs/coverage/vfsStreamAbstractContent.php.html";s:4:"749b";s:69:"PEAR/docs/vfsStream/docs/coverage/vfsStreamContainerIterator.php.html";s:4:"a236";s:61:"PEAR/docs/vfsStream/docs/coverage/vfsStreamDirectory.php.html";s:4:"f8c4";s:56:"PEAR/docs/vfsStream/docs/coverage/vfsStreamFile.php.html";s:4:"492e";s:59:"PEAR/docs/vfsStream/docs/coverage/vfsStreamWrapper.php.html";s:4:"69f2";s:52:"PEAR/docs/vfsStream/docs/coverage/yahoo-dom-event.js";s:4:"3ae3";s:40:"PEAR/docs/vfsStream/examples/Example.php";s:4:"5750";s:54:"PEAR/docs/vfsStream/examples/ExampleTestCaseOldWay.php";s:4:"c129";s:61:"PEAR/docs/vfsStream/examples/ExampleTestCaseWithVfsStream.php";s:4:"5737";s:47:"PEAR/docs/vfsStream/examples/FailureExample.php";s:4:"6593";s:55:"PEAR/docs/vfsStream/examples/FailureExampleTestCase.php";s:4:"3ba7";s:62:"PEAR/docs/vfsStream/examples/FileModeExampleTestCaseOldWay.php";s:4:"f2f0";s:55:"PEAR/docs/vfsStream/examples/FilePermissionsExample.php";s:4:"253d";s:63:"PEAR/docs/vfsStream/examples/FilePermissionsExampleTestCase.php";s:4:"75fc";s:48:"PEAR/docs/vfsStream/examples/FilemodeExample.php";s:4:"7d23";s:69:"PEAR/docs/vfsStream/examples/FilemodeExampleTestCaseWithVfsStream.php";s:4:"a873";s:22:"PEAR/ezc/Base/base.php";s:4:"3c4c";s:31:"PEAR/ezc/Base/base_autoload.php";s:4:"bf57";s:31:"PEAR/ezc/Base/ezc_bootstrap.php";s:4:"88d0";s:26:"PEAR/ezc/Base/features.php";s:4:"6fd9";s:22:"PEAR/ezc/Base/file.php";s:4:"dbe0";s:22:"PEAR/ezc/Base/init.php";s:4:"0cca";s:26:"PEAR/ezc/Base/metadata.php";s:4:"a6c7";s:25:"PEAR/ezc/Base/options.php";s:4:"89b1";s:24:"PEAR/ezc/Base/struct.php";s:4:"d817";s:37:"PEAR/ezc/Base/exceptions/autoload.php";s:4:"4cbf";s:59:"PEAR/ezc/Base/exceptions/double_class_repository_prefix.php";s:4:"26ae";s:38:"PEAR/ezc/Base/exceptions/exception.php";s:4:"1b1d";s:48:"PEAR/ezc/Base/exceptions/extension_not_found.php";s:4:"d9b8";s:43:"PEAR/ezc/Base/exceptions/file_exception.php";s:4:"8388";s:36:"PEAR/ezc/Base/exceptions/file_io.php";s:4:"2a2d";s:43:"PEAR/ezc/Base/exceptions/file_not_found.php";s:4:"cee7";s:44:"PEAR/ezc/Base/exceptions/file_permission.php";s:4:"249c";s:56:"PEAR/ezc/Base/exceptions/functionality_not_supported.php";s:4:"f914";s:53:"PEAR/ezc/Base/exceptions/init_callback_configured.php";s:4:"9ae4";s:51:"PEAR/ezc/Base/exceptions/invalid_callback_class.php";s:4:"f4f5";s:49:"PEAR/ezc/Base/exceptions/invalid_parent_class.php";s:4:"416b";s:47:"PEAR/ezc/Base/exceptions/property_not_found.php";s:4:"e614";s:48:"PEAR/ezc/Base/exceptions/property_permission.php";s:4:"58e2";s:46:"PEAR/ezc/Base/exceptions/setting_not_found.php";s:4:"8b95";s:42:"PEAR/ezc/Base/exceptions/setting_value.php";s:4:"a9dd";s:34:"PEAR/ezc/Base/exceptions/value.php";s:4:"ba9f";s:37:"PEAR/ezc/Base/exceptions/whatever.php";s:4:"990f";s:54:"PEAR/ezc/Base/interfaces/configuration_initializer.php";s:4:"dc2e";s:39:"PEAR/ezc/Base/interfaces/exportable.php";s:4:"9f7c";s:40:"PEAR/ezc/Base/interfaces/persistable.php";s:4:"916e";s:31:"PEAR/ezc/Base/metadata/pear.php";s:4:"71fc";s:34:"PEAR/ezc/Base/metadata/tarball.php";s:4:"988b";s:34:"PEAR/ezc/Base/options/autoload.php";s:4:"cb22";s:43:"PEAR/ezc/Base/structs/file_find_context.php";s:4:"23ef";s:46:"PEAR/ezc/Base/structs/repository_directory.php";s:4:"6dd2";s:42:"PEAR/ezc/ConsoleTools/console_autoload.php";s:4:"a5d0";s:39:"PEAR/ezc/ConsoleTools/dialog_viewer.php";s:4:"131b";s:31:"PEAR/ezc/ConsoleTools/input.php";s:4:"35da";s:32:"PEAR/ezc/ConsoleTools/output.php";s:4:"f7b9";s:37:"PEAR/ezc/ConsoleTools/progressbar.php";s:4:"7de9";s:41:"PEAR/ezc/ConsoleTools/progressmonitor.php";s:4:"f3b0";s:35:"PEAR/ezc/ConsoleTools/statusbar.php";s:4:"d6a5";s:31:"PEAR/ezc/ConsoleTools/table.php";s:4:"a787";s:44:"PEAR/ezc/ConsoleTools/dialog/menu_dialog.php";s:4:"4c8d";s:48:"PEAR/ezc/ConsoleTools/dialog/question_dialog.php";s:4:"a0f9";s:63:"PEAR/ezc/ConsoleTools/dialog/validators/menu_dialog_default.php";s:4:"e168";s:70:"PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_collection.php";s:4:"bb23";s:67:"PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_mapping.php";s:4:"6bf4";s:65:"PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_regex.php";s:4:"4426";s:64:"PEAR/ezc/ConsoleTools/dialog/validators/question_dialog_type.php";s:4:"67f5";s:45:"PEAR/ezc/ConsoleTools/exceptions/argument.php";s:4:"76cf";s:64:"PEAR/ezc/ConsoleTools/exceptions/argument_already_registered.php";s:4:"e76f";s:65:"PEAR/ezc/ConsoleTools/exceptions/argument_mandatory_violation.php";s:4:"b9e1";s:54:"PEAR/ezc/ConsoleTools/exceptions/argument_too_many.php";s:4:"0165";s:60:"PEAR/ezc/ConsoleTools/exceptions/argument_type_violation.php";s:4:"a928";s:49:"PEAR/ezc/ConsoleTools/exceptions/dialog_abort.php";s:4:"dfaf";s:46:"PEAR/ezc/ConsoleTools/exceptions/exception.php";s:4:"3a09";s:56:"PEAR/ezc/ConsoleTools/exceptions/invalid_option_name.php";s:4:"55ec";s:58:"PEAR/ezc/ConsoleTools/exceptions/invalid_output_target.php";s:4:"8387";s:55:"PEAR/ezc/ConsoleTools/exceptions/no_position_stored.php";s:4:"adf2";s:59:"PEAR/ezc/ConsoleTools/exceptions/no_valid_dialog_result.php";s:4:"26c6";s:43:"PEAR/ezc/ConsoleTools/exceptions/option.php";s:4:"1342";s:62:"PEAR/ezc/ConsoleTools/exceptions/option_already_registered.php";s:4:"1c82";s:63:"PEAR/ezc/ConsoleTools/exceptions/option_arguments_violation.php";s:4:"920d";s:64:"PEAR/ezc/ConsoleTools/exceptions/option_dependency_violation.php";s:4:"524d";s:63:"PEAR/ezc/ConsoleTools/exceptions/option_exclusion_violation.php";s:4:"9929";s:63:"PEAR/ezc/ConsoleTools/exceptions/option_mandatory_violation.php";s:4:"1f5f";s:57:"PEAR/ezc/ConsoleTools/exceptions/option_missing_value.php";s:4:"1775";s:52:"PEAR/ezc/ConsoleTools/exceptions/option_no_alias.php";s:4:"bcef";s:54:"PEAR/ezc/ConsoleTools/exceptions/option_not_exists.php";s:4:"779c";s:65:"PEAR/ezc/ConsoleTools/exceptions/option_string_not_wellformed.php";s:4:"22cb";s:59:"PEAR/ezc/ConsoleTools/exceptions/option_too_many_values.php";s:4:"e65a";s:58:"PEAR/ezc/ConsoleTools/exceptions/option_type_violation.php";s:4:"c1b9";s:40:"PEAR/ezc/ConsoleTools/input/argument.php";s:4:"a3c5";s:41:"PEAR/ezc/ConsoleTools/input/arguments.php";s:4:"64be";s:38:"PEAR/ezc/ConsoleTools/input/option.php";s:4:"464b";s:56:"PEAR/ezc/ConsoleTools/input/help_generators/standard.php";s:4:"1358";s:51:"PEAR/ezc/ConsoleTools/input/validators/standard.php";s:4:"3d2a";s:43:"PEAR/ezc/ConsoleTools/interfaces/dialog.php";s:4:"da15";s:53:"PEAR/ezc/ConsoleTools/interfaces/dialog_validator.php";s:4:"fbc7";s:57:"PEAR/ezc/ConsoleTools/interfaces/input_help_generator.php";s:4:"1e0b";s:52:"PEAR/ezc/ConsoleTools/interfaces/input_validator.php";s:4:"2e5f";s:58:"PEAR/ezc/ConsoleTools/interfaces/menu_dialog_validator.php";s:4:"e7e4";s:62:"PEAR/ezc/ConsoleTools/interfaces/question_dialog_validator.php";s:4:"8e2d";s:40:"PEAR/ezc/ConsoleTools/options/dialog.php";s:4:"c8c8";s:45:"PEAR/ezc/ConsoleTools/options/menu_dialog.php";s:4:"6f57";s:40:"PEAR/ezc/ConsoleTools/options/output.php";s:4:"c048";s:45:"PEAR/ezc/ConsoleTools/options/progressbar.php";s:4:"3e68";s:49:"PEAR/ezc/ConsoleTools/options/progressmonitor.php";s:4:"dc17";s:49:"PEAR/ezc/ConsoleTools/options/question_dialog.php";s:4:"069e";s:43:"PEAR/ezc/ConsoleTools/options/statusbar.php";s:4:"70d3";s:39:"PEAR/ezc/ConsoleTools/options/table.php";s:4:"7426";s:45:"PEAR/ezc/ConsoleTools/structs/option_rule.php";s:4:"7725";s:47:"PEAR/ezc/ConsoleTools/structs/output_format.php";s:4:"a7ef";s:48:"PEAR/ezc/ConsoleTools/structs/output_formats.php";s:4:"fe2a";s:36:"PEAR/ezc/ConsoleTools/table/cell.php";s:4:"84ed";s:35:"PEAR/ezc/ConsoleTools/table/row.php";s:4:"2d99";s:38:"PEAR/ezc/ConsoleTools/tools/string.php";s:4:"1f23";s:35:"PEAR/ezc/autoload/base_autoload.php";s:4:"bf57";s:38:"PEAR/ezc/autoload/console_autoload.php";s:4:"a5d0";s:28:"PEAR/vfsStream/vfsStream.php";s:4:"6297";s:43:"PEAR/vfsStream/vfsStreamAbstractContent.php";s:4:"8601";s:37:"PEAR/vfsStream/vfsStreamContainer.php";s:4:"e3c5";s:45:"PEAR/vfsStream/vfsStreamContainerIterator.php";s:4:"fb27";s:35:"PEAR/vfsStream/vfsStreamContent.php";s:4:"514f";s:37:"PEAR/vfsStream/vfsStreamDirectory.php";s:4:"6c12";s:37:"PEAR/vfsStream/vfsStreamException.php";s:4:"4755";s:32:"PEAR/vfsStream/vfsStreamFile.php";s:4:"01f9";s:35:"PEAR/vfsStream/vfsStreamWrapper.php";s:4:"b1cc";s:48:"Resources/Private/Language/locallang_backend.xml";s:4:"49f3";s:47:"Resources/Private/Language/locallang_report.xml";s:4:"e804";s:32:"Resources/Public/CSS/BackEnd.css";s:4:"3055";s:40:"Resources/Public/Icons/BackEndModule.gif";s:4:"9d0b";s:33:"Resources/Public/Icons/Runner.gif";s:4:"9644";s:40:"Resources/Public/Icons/RunnerRunning.gif";s:4:"19bd";s:32:"Resources/Public/Icons/Typo3.png";s:4:"ac48";s:38:"Resources/Public/JavaScript/BackEnd.js";s:4:"9b07";s:33:"Resources/Public/YUI/base-min.css";s:4:"0188";s:38:"Resources/Public/YUI/connection-min.js";s:4:"baf5";s:32:"Resources/Public/YUI/json-min.js";s:4:"2b78";s:42:"Resources/Public/YUI/reset-fonts-grids.css";s:4:"b09b";s:39:"Resources/Public/YUI/yahoo-dom-event.js";s:4:"8be2";s:23:"Tests/FrameworkTest.php";s:4:"4fa4";s:22:"Tests/TestCaseTest.php";s:4:"ec56";s:26:"Tests/TestableCodeTest.php";s:4:"018e";s:23:"Tests/VfsStreamTest.php";s:4:"b292";s:30:"Tests/tx_phpunit_testsuite.php";s:4:"fe1d";s:26:"Tests/BackEnd/AjaxTest.php";s:4:"0b38";s:28:"Tests/BackEnd/ModuleTest.php";s:4:"4f56";s:34:"Tests/BackEnd/TestListenerTest.php";s:4:"0ccb";s:50:"Tests/BackEnd/Fixtures/AnotherDataProviderTest.php";s:4:"dbd1";s:43:"Tests/BackEnd/Fixtures/DataProviderTest.php";s:4:"7fad";s:33:"Tests/BackEnd/Fixtures/LoadMe.php";s:4:"5bae";s:36:"Tests/BackEnd/Fixtures/LoadMeToo.php";s:4:"dceb";s:31:"Tests/Database/TestCaseTest.php";s:4:"5cb3";s:35:"Tests/Database/Fixtures/DataSet.xml";s:4:"5594";s:32:"Tests/Exception/DatabaseTest.php";s:4:"fe90";s:40:"Tests/Exception/EmptyQueryResultTest.php";s:4:"7890";s:40:"Tests/Exception/NoTestsDirectoryTest.php";s:4:"b6fe";s:25:"Tests/Fixtures/LoadMe.php";s:4:"0d19";s:23:"Tests/Fixtures/test.png";s:4:"c7b6";s:44:"Tests/Fixtures/Extensions/aaa/ext_emconf.php";s:4:"c526";s:42:"Tests/Fixtures/Extensions/aaa/ext_icon.gif";s:4:"5f50";s:44:"Tests/Fixtures/Extensions/aaa/ext_tables.php";s:4:"2980";s:44:"Tests/Fixtures/Extensions/aaa/ext_tables.sql";s:4:"1764";s:50:"Tests/Fixtures/Extensions/aaa/icon_tx_aaa_test.gif";s:4:"475a";s:46:"Tests/Fixtures/Extensions/aaa/locallang_db.xml";s:4:"9d47";s:37:"Tests/Fixtures/Extensions/aaa/tca.php";s:4:"61a5";s:44:"Tests/Fixtures/Extensions/bbb/ext_emconf.php";s:4:"00bd";s:42:"Tests/Fixtures/Extensions/bbb/ext_icon.gif";s:4:"5f50";s:44:"Tests/Fixtures/Extensions/bbb/ext_tables.php";s:4:"12d2";s:44:"Tests/Fixtures/Extensions/bbb/ext_tables.sql";s:4:"717c";s:50:"Tests/Fixtures/Extensions/bbb/icon_tx_bbb_test.gif";s:4:"475a";s:46:"Tests/Fixtures/Extensions/bbb/locallang_db.xml";s:4:"7f20";s:37:"Tests/Fixtures/Extensions/bbb/tca.php";s:4:"a22f";s:44:"Tests/Fixtures/Extensions/ccc/ext_emconf.php";s:4:"1dc9";s:42:"Tests/Fixtures/Extensions/ccc/ext_icon.gif";s:4:"5f50";s:44:"Tests/Fixtures/Extensions/ccc/ext_tables.php";s:4:"70fc";s:44:"Tests/Fixtures/Extensions/ccc/ext_tables.sql";s:4:"ed29";s:50:"Tests/Fixtures/Extensions/ccc/icon_tx_ccc_data.gif";s:4:"475a";s:50:"Tests/Fixtures/Extensions/ccc/icon_tx_ccc_test.gif";s:4:"475a";s:46:"Tests/Fixtures/Extensions/ccc/locallang_db.xml";s:4:"4f69";s:37:"Tests/Fixtures/Extensions/ccc/tca.php";s:4:"5789";s:44:"Tests/Fixtures/Extensions/ddd/ext_emconf.php";s:4:"e6a7";s:42:"Tests/Fixtures/Extensions/ddd/ext_icon.gif";s:4:"5f50";s:44:"Tests/Fixtures/Extensions/ddd/ext_tables.php";s:4:"dc4b";s:44:"Tests/Fixtures/Extensions/ddd/ext_tables.sql";s:4:"df94";s:50:"Tests/Fixtures/Extensions/ddd/icon_tx_ddd_test.gif";s:4:"475a";s:46:"Tests/Fixtures/Extensions/ddd/locallang_db.xml";s:4:"0b54";s:37:"Tests/Fixtures/Extensions/ddd/tca.php";s:4:"f356";s:57:"Tests/Fixtures/Extensions/user_phpunittest/ext_emconf.php";s:4:"0f06";s:55:"Tests/Fixtures/Extensions/user_phpunittest/ext_icon.gif";s:4:"5f50";s:57:"Tests/Fixtures/Extensions/user_phpunittest/ext_tables.php";s:4:"2cf2";s:57:"Tests/Fixtures/Extensions/user_phpunittest/ext_tables.sql";s:4:"6ab4";s:71:"Tests/Fixtures/Extensions/user_phpunittest/icon_user_oelibtest_test.gif";s:4:"475a";s:59:"Tests/Fixtures/Extensions/user_phpunittest/locallang_db.xml";s:4:"11cf";s:50:"Tests/Fixtures/Extensions/user_phpunittest/tca.php";s:4:"3d92";s:58:"Tests/Fixtures/Extensions/user_phpunittest2/ext_emconf.php";s:4:"a6ae";s:56:"Tests/Fixtures/Extensions/user_phpunittest2/ext_icon.gif";s:4:"5f50";s:58:"Tests/Fixtures/Extensions/user_phpunittest2/ext_tables.php";s:4:"8063";s:58:"Tests/Fixtures/Extensions/user_phpunittest2/ext_tables.sql";s:4:"c44c";s:73:"Tests/Fixtures/Extensions/user_phpunittest2/icon_user_oelibtest2_test.gif";s:4:"bd58";s:60:"Tests/Fixtures/Extensions/user_phpunittest2/locallang_db.xml";s:4:"d4dc";s:51:"Tests/Fixtures/Extensions/user_phpunittest2/tca.php";s:4:"5d2a";s:31:"Tests/Selenium/TestCaseTest.php";s:4:"9ae8";s:30:"Tests/Service/DatabaseTest.php";s:4:"7684";s:32:"Tests/Service/TestFinderTest.php";s:4:"b308";s:34:"Tests/Service/Fixtures/OneTest.php";s:4:"4529";s:32:"Tests/Service/Fixtures/XTest.php";s:4:"4529";s:43:"Tests/Service/Fixtures/NonPhpFiles/test.txt";s:4:"25f7";s:47:"Tests/Service/Fixtures/NonTestFiles/Nothing.php";s:4:"4529";s:48:"Tests/Service/Fixtures/Subfolder/AnotherTest.php";s:4:"4529";s:14:"doc/manual.sxw";s:4:"593b";s:28:"doc/Framework/annotated.html";s:4:"5e98";s:22:"doc/Framework/bc_s.png";s:4:"3928";s:49:"doc/Framework/class_tx___phpunit___framework.html";s:4:"0a96";s:49:"doc/Framework/class_tx___phpunit___test_case.html";s:4:"a532";s:53:"doc/Framework/class_tx___phpunit___testable_code.html";s:4:"99b7";s:26:"doc/Framework/classes.html";s:4:"15fd";s:24:"doc/Framework/closed.png";s:4:"b86c";s:29:"doc/Framework/deprecated.html";s:4:"f90c";s:25:"doc/Framework/doxygen.css";s:4:"9aef";s:25:"doc/Framework/doxygen.png";s:4:"1308";s:28:"doc/Framework/functions.html";s:4:"a9fc";s:33:"doc/Framework/functions_func.html";s:4:"076a";s:24:"doc/Framework/index.html";s:4:"da0b";s:37:"doc/Framework/namespace_t_y_p_o3.html";s:4:"fa26";s:29:"doc/Framework/namespaces.html";s:4:"9381";s:23:"doc/Framework/nav_f.png";s:4:"0d76";s:23:"doc/Framework/nav_h.png";s:4:"fa55";s:22:"doc/Framework/open.png";s:4:"89b7";s:24:"doc/Framework/pages.html";s:4:"fef7";s:23:"doc/Framework/tab_a.png";s:4:"ef28";s:23:"doc/Framework/tab_b.png";s:4:"657c";s:23:"doc/Framework/tab_h.png";s:4:"1c9e";s:23:"doc/Framework/tab_s.png";s:4:"f0f5";s:22:"doc/Framework/tabs.css";s:4:"eda2";}', +); + +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/ext_icon.gif b/typo3conf/ext/phpunit/ext_icon.gif new file mode 100644 index 0000000000000000000000000000000000000000..ef451bc8a5acc0b3a09b9c9966cac4279f72eceb GIT binary patch literal 630 zcmV-+0*U=cNk%w1VG;lk0LFg+?(g@RqW_MOr-q2OiI)Ds#{X}86nmZAUp`um)w|H8z~>FVvVvbuhOnTC@3R9u+c-Q&&8|NZ^{tg`>??ek}G%(J`y zq^P$ilU`=4@$vJxxxayi$e5X*hm`+ub(H)2{Lj(a#>exBij|g^ z!)I)sl9Zvcxc`ip|72^TVQat8(Eo9Cq>h;GoSmwCh1s#Q!u0j{thN7gcAK`l|Gd5S zVP%PKaf@ngjE<0?^Yr(mrnRZ6w1biViHx7o(%6KO|FO6Ko1fi$fTetXmdMG?xWNC4 zkk_lU|GdBdU0-OMrvL2i?}v$;kdd5KTaL-j|AL9wV`z`Kxx{R5kdTw6mY1V#ah$uq z|DmY=!o<Mtf>lWl0sa0cN7ziE^QS_OKOYu!@WZg-91b1U zd>Dj;gpCDGwqV%EF-RCCimF60!bMJjF(6VFhy#IAmKRb6 \ No newline at end of file diff --git a/typo3conf/ext/phpunit/ext_tables.php b/typo3conf/ext/phpunit/ext_tables.php new file mode 100644 index 0000000..ec28722 --- /dev/null +++ b/typo3conf/ext/phpunit/ext_tables.php @@ -0,0 +1,52 @@ + array( + 'title' => 'LLL:EXT:phpunit/locallang_db.xml:tx_phpunit_test', + 'readOnly' => 1, + 'adminOnly' => 1, + 'rootLevel' => 1, + 'label' => 'title', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'cruser_id' => 'cruser_id', + 'versioningWS' => FALSE, + 'default_sortby' => 'ORDER BY uid', + 'delete' => 'deleted', + 'enablecolumns' => array( + 'disabled' => 'hidden', + 'starttime' => 'starttime', + 'endtime' => 'endtime', + ), + 'dynamicConfigFile' => t3lib_extMgm::extPath($_EXTKEY) . 'Configuration/TCA/TCA.php', + 'iconfile' => t3lib_extMgm::extRelPath($_EXTKEY) . 'ext_icon.gif', + ) +); + +//$TCA['tx_phpunit_testchild'] = array( +// 'ctrl' => array( +// 'title' => 'LLL:EXT:phpunit/locallang_db.xml:tx_phpunit_test', +// 'readOnly' => 1, +// 'adminOnly' => 1, +// 'rootLevel' => 1, +// 'label' => 'title', +// 'tstamp' => 'tstamp', +// 'crdate' => 'crdate', +// 'cruser_id' => 'cruser_id', +// 'versioningWS' => FALSE, +// 'default_sortby' => 'ORDER BY uid', +// 'delete' => 'deleted', +// 'dynamicConfigFile' => t3lib_extMgm::extPath($_EXTKEY) . 'Configuration/TCA/TCA.php', +// 'iconfile' => t3lib_extMgm::extRelPath($_EXTKEY) . 'ext_icon.gif', +// ) +//); + +if (TYPO3_MODE === 'BE') { + t3lib_extMgm::addModule('tools', 'txphpunitbeM1', '', t3lib_extMgm::extPath($_EXTKEY) . 'Classes/BackEnd/'); + + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['reports']['tx_reports']['status']['providers']['PHPUnit'][] = 'Tx_Phpunit_Reports_Status'; +} +?> \ No newline at end of file diff --git a/typo3conf/ext/phpunit/ext_tables.sql b/typo3conf/ext/phpunit/ext_tables.sql new file mode 100644 index 0000000..54d1b2c --- /dev/null +++ b/typo3conf/ext/phpunit/ext_tables.sql @@ -0,0 +1,120 @@ +# +# Table structure for table 'tx_phpunit_test' +# +CREATE TABLE tx_phpunit_test ( + uid int(11) unsigned DEFAULT '0' NOT NULL auto_increment, + pid int(11) unsigned DEFAULT '0' NOT NULL, + tstamp int(11) unsigned DEFAULT '0' NOT NULL, + crdate int(11) unsigned DEFAULT '0' NOT NULL, + cruser_id int(11) unsigned DEFAULT '0' NOT NULL, + sorting int(11) unsigned DEFAULT '0' NOT NULL, + deleted tinyint(4) unsigned DEFAULT '0' NOT NULL, + is_dummy_record tinyint(1) unsigned DEFAULT '0' NOT NULL, + hidden tinyint(4) unsigned DEFAULT '0' NOT NULL, + starttime int(11) unsigned DEFAULT '0' NOT NULL, + endtime int(11) unsigned DEFAULT '0' NOT NULL, + title tinytext, + related_records int(11) unsigned DEFAULT '0' NOT NULL, + bidirectional int(11) unsigned DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid), + KEY parent (pid), + KEY phpunit_dummy (is_dummy_record) +); + + +# +# Table structure for table 'tx_phpunit_testchild' +# +CREATE TABLE tx_phpunit_testchild ( + uid int(11) unsigned DEFAULT '0' NOT NULL auto_increment, + pid int(11) unsigned DEFAULT '0' NOT NULL, + tstamp int(11) unsigned DEFAULT '0' NOT NULL, + crdate int(11) unsigned DEFAULT '0' NOT NULL, + cruser_id int(11) unsigned DEFAULT '0' NOT NULL, + sorting int(11) unsigned DEFAULT '0' NOT NULL, + deleted tinyint(4) unsigned DEFAULT '0' NOT NULL, + is_dummy_record tinyint(1) unsigned DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid), + KEY parent (pid), + KEY phpunit_dummy (is_dummy_record) +); + + +# +# Table structure for table 'tx_phpunit_test_article_mm' +# +CREATE TABLE tx_phpunit_test_article_mm ( + uid_local int(11) unsigned DEFAULT '0' NOT NULL, + uid_foreign int(11) unsigned DEFAULT '0' NOT NULL, + sorting int(11) unsigned DEFAULT '0' NOT NULL, + is_dummy_record tinyint(1) unsigned DEFAULT '0' NOT NULL, + + KEY uid_local (uid_local), + KEY uid_foreign (uid_foreign), + KEY phpunit_dummy (is_dummy_record) +); + + +# +# Table structure for table 'be_users' +# +CREATE TABLE be_users ( + tx_phpunit_is_dummy_record tinyint(1) unsigned DEFAULT '0' NOT NULL, + KEY phpunit_dummy (tx_phpunit_is_dummy_record) +); + + +# +# Table structure for table 'be_groups' +# +CREATE TABLE be_groups ( + tx_phpunit_is_dummy_record tinyint(1) unsigned DEFAULT '0' NOT NULL, + KEY phpunit_dummy (tx_phpunit_is_dummy_record) +); + + +# +# Table structure for table 'fe_groups' +# +CREATE TABLE fe_groups ( + tx_phpunit_is_dummy_record tinyint(1) unsigned DEFAULT '0' NOT NULL, + KEY phpunit_dummy (tx_phpunit_is_dummy_record) +); + + +# +# Table structure for table 'fe_users' +# +CREATE TABLE fe_users ( + tx_phpunit_is_dummy_record tinyint(1) unsigned DEFAULT '0' NOT NULL, + KEY phpunit_dummy (tx_phpunit_is_dummy_record) +); + + +# +# Table structure for table 'pages' +# +CREATE TABLE pages ( + tx_phpunit_is_dummy_record tinyint(1) unsigned DEFAULT '0' NOT NULL, + KEY phpunit_dummy (tx_phpunit_is_dummy_record) +); + + +# +# Table structure for table 'sys_template' +# +CREATE TABLE sys_template ( + tx_phpunit_is_dummy_record tinyint(1) unsigned DEFAULT '0' NOT NULL, + KEY phpunit_dummy (tx_phpunit_is_dummy_record) +); + + +# +# Table structure for table 'tt_content' +# +CREATE TABLE tt_content ( + tx_phpunit_is_dummy_record tinyint(1) unsigned DEFAULT '0' NOT NULL, + KEY phpunit_dummy (tx_phpunit_is_dummy_record) +); diff --git a/typo3conf/localconf.php b/typo3conf/localconf.php new file mode 100644 index 0000000..ac353ad --- /dev/null +++ b/typo3conf/localconf.php @@ -0,0 +1,55 @@ +=4.3, disable for production sites + + // Required for Fluidpages Extension +$TYPO3_CONF_VARS['FE']['addRootLineFields'] = 'backend_layout'; + +$TYPO3_CONF_VARS['FE']['lifetime'] = '604800'; +$TYPO3_CONF_VARS['FE']['logfile_dir'] = 'localsettings/logs/'; +$TYPO3_CONF_VARS['FE']['pageNotFound_handling'] = '/404/'; + +$TYPO3_CONF_VARS['GFX']['im_version_5'] = 'im6'; +$TYPO3_CONF_VARS['GFX']['TTFdpi'] = '96'; +$TYPO3_CONF_VARS['GFX']['jpg_quality'] = '80'; +$TYPO3_CONF_VARS['GFX']['thumbnails_png'] = '1'; +$TYPO3_CONF_VARS['GFX']['gblib_png'] = '1'; +$TYPO3_CONF_VARS['GFX']['im_path'] = '/usr/bin/'; +$TYPO3_CONF_VARS['GFX']['im_noScaleUp'] = '1'; + +$TYPO3_CONF_VARS['EXT']['extList'] = 'info,perm,func,filelist,about,tsconfig_help,context_help,extra_page_cm_options,impexp,sys_note,tstemplate,tstemplate_ceditor,tstemplate_info,tstemplate_objbrowser,tstemplate_analyzer,func_wizards,wizard_crpages,wizard_sortpages,lowlevel,install,belog,beuser,aboutmodules,setup,taskcenter,info_pagetsconfig,viewpage,rtehtmlarea,css_styled_content,t3skin,t3editor,reports,felogin,form,phpunit'; + +$TYPO3_CONF_VARS['BE']['createGroup'] = 'vagrant'; + +$GLOBALS['TYPO3_CONF_VARS']['SYS']['enable_DLOG'] = 0; + +## INSTALL SCRIPT EDIT POINT TOKEN - all lines after this points may be changed by the install script! +?> \ No newline at end of file

    2rY1I0$^?8BIy@~aU2aQpq19EGh71L69`EiSR$xD zwNKCtqJ|L-7ELo3(JNcz(wHeuX}DSb+NxF33G}nl=P-p)retd=jT;c7S0076$z+YuT6cyhl zNM_-3<4{Q>yN9grcT zzY>#SERUjH?bW}3_mCOdA54)%0h4bXK22Z$H-Q)w!r37Pwv2GTHTuYhii)FbS|qU} z0V3JL`u@hnW@0i02mu-E_(j*O;1+!Z1+5j`WfN$wC3JF&{5T= z{?p~)XuV)2^xOvoBsl;njOKPWxy7!e?B5JCK-&K+yMl)Hdm50TD7@JJV79d_w3x*esXMImD=j*j>ub~gCQ zZ_$RW94f~sq6e-0gtX)F#njDqjJS~B&th9owu7Xmq7O^#5(XtN;1$hS!3`R}^Xr2a zAF+^eRLZkT2Z!jC-0z#tzMTnJR>c1Wja7 z2ug)E;zD+_`Zxqu4)i$>B>SiBH$F;AYb@C2|DJ2auD>Jf+W?l8cDA z-qf5u6ll#bB2btzxLlEUK7Xv%nB%D>x_f^5qth@o|-fmE>bH|5hjqrh`KKtZ}%Is9e>4XwU%gfGu?53L8mF8SPgBv z!|zI?(*>QDcBza!qdl6M-)F)RR~8K$sWuuB@`<>0SV23mHR>tEh6^8s4X_~8dM?mU zU<4i--bUq!4Ma*UOA7(B!n4=begiM`gH%T6OZR;f8KeodCoPG`-?1+J-kLVFa-H5} z@tsNNm%SZfAJmyR51xnw}m>q)e15o?>>HJJ(sMd zKC@=Kw>*wFIl#kW?>L{*ib58482x0S%T8tyGUFilhYuATji=l7^^(jp+Dn#|+)9P_ zG+1ro=j@LV->vw870tU{vnNfmyY{I^OftT}Yqik-PdMI;aE^|Rg4y?s9+9T%{2i|& z;;^tZAHl@T2#c;+^|`-Eckdeeo`NLR9W!QP%X5Jb5_Qw�EOfG>{&Qh|fJ3Z@s$? z#a}^iIg6GY*0)O3dzO5f*u1=Ud^38cYB2a+<-&m1xj^N95lU(Quy&>>X-KL&9HbIouD4``q5d)V<77USM_BDtoUZ zMARPR*dF5Z#Lo~)M1oN3eWl9|JKd?Nsb7<0J0sAr3)xc(dHw&aqr^M&-J6;gAfzN5 zL)peZ!9i6|bM2>0di%brs&j)bzYOYFd+*+mQNH2HnXSfZjr02FkCUDYT6nZt zI_S`^{kC`L_{&cR?0-M|LzA)NVqLw}b=w&H5z?=(x6+kcN_Fe*&Tm^;rn$KJoLerh zR?TQSd39`hOy2X=0aiMz16Jqe_eIB(7Tj-1-XZqz#-E$Jm1t@wcZ;pk+`X|%`Re7k z#6)Mt8tq0$!I?n2L2XjDhj>60il~lBJ~UE;j9g+mtr+oF033DqC>wDcXaa%K?=4!4 zCD&aN^Hy0VH;orhn8Y1Xwwq$yp(h?hB*({h%C{AV9Ml_h^B+TD17+fYKv6vCUZK5G znqL_mIUS11edeRPlgq~x z0w=YA9^OFq)eBAOjI~ETo4?|7eLp1ee5JF+Z*sgncwiCv!v4|fotHE)hNe)_B=ahC zUvfU!M&p&@Jrdygw@?0tKfpb70eiu~Dm37Ez5Y;A9+1O*;%=ick^273u>7*U6xa}{=lx{J@Ye=EYPa&s4lh>ZN z?(5Rh8ien>@0d$dx`0J388CWg;V3?i%st2Cd|QJiUC}k=4Jp5F83?AvB+z6K;FAX4 z&I|HrF+LdA^i8<+^hbQ=PP8_1=O&UuhrA=b*#%xegVPnX)~^pu9$7To+`>YeLY2Zb z;(SxpWI7>a>aNUuhNSB8vI0E;v$cz;H0rK-oEEbiqe98?Uc5MM({=d~n(Aqi9!L7F z=Ha|qX&A}s#8p8rKTm78_*lQQ!4uTkM;N9%F;3a-#MnJuXCs8=xII)-CYbrV4?2Yg zeQZ*+$DYG~%#HDG(jpxkj66#sy(wZh8A;tqYWgGHnpthO|Vfg8Lf<)_no- zcEqk_NzG)?p7$(*9B@x~XGVnfjCu1r<#o6I`9~o+eKU@2WB!kabN7*L+L5`X#fI<$ zyc*ZC)a~4^gTWM@yVMFlH|ym@VZytO-q4_l^m;JfVM6s}izU%7H*VgI(|6QCHy&x+Hl-oYV9_$47^{aH>VSw2H1)z*f zL$vi`O)EF@|EnYX`zg(!>unp}an1llFX-NKw`!@r+^aYg@QYfeGamEkUEJfqJ9;Ke z`3n%?k5;Yp_{6Tqe&lpaE1|oY8KByzsEe`v^tr#-BdVrnx*ga#%1#j3r4m5A{ixQHf^!LV_zI={G1&W^tgO2fjMhr}A1UrB74|!K;Z}v) z6uV`v**@gekF?d{m_sw&6-3utU|!@4g9o$wTf-vDWVhv~D&P#|BVaA6SMllrqmwPT z5|+ZFHLYdP;nfkPDYdtinn1jpqScOBAGXB1bnbt6ENGBVL^NQ0&KK zuTKZs=w9n?xk!7=tu4ZXq>;hSB9v@9yz%g!ZEuMbE@~UPp(0x`lO? zRsycKU&DYZ3xyam!^j0%kQ|5+%)1`L;YRyWSnbL5^%AOV+jC9#8|eOFy!SA ztcAWYRel=qU~+B?1-X+$ehnC=7i`26{j�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