{"id":17959651,"url":"https://github.com/imjoehaines/dottie","last_synced_at":"2026-01-19T01:33:33.214Z","repository":{"id":46561276,"uuid":"306885576","full_name":"imjoehaines/dottie","owner":"imjoehaines","description":"Dottie is a test runner for PHPT-like tests","archived":false,"fork":false,"pushed_at":"2024-08-02T00:28:01.000Z","size":150,"stargazers_count":3,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-24T03:36:34.859Z","etag":null,"topics":["php","ruby","testing"],"latest_commit_sha":null,"homepage":"https://imjoehaines.github.io/dottie/","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/imjoehaines.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-10-24T13:07:38.000Z","updated_at":"2023-02-09T13:40:11.000Z","dependencies_parsed_at":"2023-02-08T03:16:35.987Z","dependency_job_id":null,"html_url":"https://github.com/imjoehaines/dottie","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imjoehaines%2Fdottie","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imjoehaines%2Fdottie/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imjoehaines%2Fdottie/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imjoehaines%2Fdottie/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/imjoehaines","download_url":"https://codeload.github.com/imjoehaines/dottie/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245394654,"owners_count":20608118,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["php","ruby","testing"],"created_at":"2024-10-29T11:03:59.875Z","updated_at":"2025-11-11T19:33:23.559Z","avatar_url":"https://github.com/imjoehaines.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Dottie\n\nDottie is a test runner for PHPT-like tests that currently supports PHP and Ruby\n\n## What is a PHPT test?\n\nPHPT is a file format that includes:\n\n- a test name\n- some code to run\n- the expected output of that code\n\nFor example:\n\n```phpt\n--TEST--\nTest 'echo'\n--FILE--\n\u003c?php\necho \"Hello, World!\\n\";\n?\u003e\n--EXPECT--\nHello, World!\n```\n\nPHPT tests are used to test the PHP interpreter, but can be run by other PHP testing tools. However, support for similar formats does not appear to exist in most other languages\n\n## Writing tests with Dottie\n\nDottie supports running PHPT tests using the `.phpt` file extension and Ruby tests using the `.rubyt` file extension\n\nBy default, Dottie will attempt to run every file ending in `.\u003csomething\u003et`, where `\u003csomething\u003e` is `php` or `ruby`. Support for additional languages is planned when Dottie is a bit more mature\n\nDottie executes tests using your system-wide `php` and `ruby` binaries. Support for running with custom commands is planned, but not currently implemented\n\n### The TEST section\n\n**This section is required**\n\nUse the `--TEST--` section to give a short description of your test. Dottie prints this when running the test, so make sure it isn't too long!\n\n### The FILE section\n\n**This section is required**\n\nThe `--FILE--` section is the code that will be executed, for example\n\n```phpt\n--TEST--\nTest 'echo'\n--FILE--\n\u003c?php\necho \"Hello, World!\\n\";\n?\u003e\n--EXPECT--\nHello, World!\n```\n\nWith this test file, PHP will execute `\u003c?php echo \"Hello, World!\\n\"; ?\u003e`. Note: for PHP to execute code, it must be begin with an opening PHP tag!\n\nAn equivalent Ruby test would look like this:\n\n```rubyt\n--TEST--\nTest 'puts'\n--FILE--\nputs \"Hello, World!\"\n--EXPECT--\nHello, World!\n```\n\n### The EXPECT section\n\n**Either an EXPECT, EXPECTF or EXPECTREGEX section is required**\n\nThe `--EXPECT--` section contains the exact text that should have been printed to stdout/stderr by the `--FILE--` section\n\nFor example, the following RubyT test expects to see `Hello, World!` printed to stdout:\n\n```rubyt\n--TEST--\nTest 'puts'\n--FILE--\nputs \"Hello, World!\"\n--EXPECT--\nHello, World!\n```\n\nThis **must exactly match** the combined output of stdout \u0026 stderr. If you need to test something that cannot be exactly matched (such as the current time), use `EXPECTF` or `EXPECTREGEX` instead\n\n### The EXPECTF section\n\n**Either an EXPECT, EXPECTF or EXPECTREGEX section is required**\n\nThe `--EXPECTF--` section contains text that should have been printed to stdout/stderr by the `--FILE--` section, with support for pattern matching, rather than being an exact match\n\nFor example, the following RubyT test expects to see `Hello, `, followed by any number of characters printed to stdout:\n\n```rubyt\n--TEST--\nTest EXPECTF\n--FILE--\nputs \"Hello, #{rand \u003e 0.5 ? 'bob' : 'sally'}\"\n--EXPECTF--\nHello, %s\n```\n\nThis is useful when matching against things that may change between test runs, such as the current time or file paths\n\n`--EXPECTF--` is also available as `--EXPECT_FORMAT--`\n\n#### Supported PHPT format specifiers:\n\n- %d: an unsigned integer\n- %i: a signed integer\n- %f: a float\n- %c: a single character\n- %s: one or more of anything until a newline\n- %S: zero or more of anything until a newline\n- %a: one or more of anything including newlines\n- %A: zero or more of anything including newlines\n- %w: zero or more whitespace characters\n- %x: one or more hexadecimal character (a-f, A-F, 0-9)\n\n#### Unsupported PHPT format specifiers:\n\n- %r...%r: a regular expression\n\n### The EXPECTREGEX section\n\n**Either an EXPECT, EXPECTF or EXPECTREGEX section is required**\n\nThe `--EXPECTREGEX--` section contains a regular expression that should match the text printed to stdout/stderr by the `--FILE--` section\n\nFor example, the following RubyT test expects to see output matching the regular expression `/^Hello, .*!$/` printed to stdout:\n\n```rubyt\n--TEST--\nTest EXPECTREGEX\n--FILE--\ngreeting = [\"world\", \"friend\", \"there\"].sample\n\nputs \"Hello, #{greeting}!\"\n--EXPECTREGEX--\n^Hello, .*!$\n```\n\nThis is useful in similar scenarios to `EXPECTF`, but can be stricter with the allowed output\n\n`--EXPECTREGEX--` is also available as `--EXPECT_REGEX--`\n\n### The SKIPIF section\n\nThe `--SKIPIF--` section allows conditionally skipping a test. This is useful if a test only runs in a certain environment\n\nA `--SKIPIF--` section contains some code to run and must output \"skip\" in order to mark the test as skipped. Other output is allowed (e.g. to give a reason for skipping), but \"skip\" must be output first\n\nFor example, the following PHPT test will be skipped on Windows:\n\n```phpt\n--TEST--\nTest SKIPIF\n--FILE--\n\u003c?php\necho 'Hello'\n?\u003e\n--EXPECT--\nHello\n--SKIPIF--\n\u003c?php\nif (PHP_OS_FAMILY === 'Windows') {\n    echo 'SKIP - this test does not run on windows';\n}\n?\u003e\n```\n\n`--SKIPIF--` is also available as `--SKIP_IF--`\n\n### The XFAIL section\n\nThe `--XFAIL--` section marks the test as being expected to fail, so the test will not be counted as a failure\n\nThis is useful if a test exists to verify a bug, for example:\n\n```phpt\n--TEST--\nTest XFAIL\n--FILE--\n\u003c?php\necho 'Hello'\n?\u003e\n--EXPECT--\nGoodbye\n--XFAIL--\nThis test doesn't work because \"Hello\" is output!\n```\n\n### The CLEAN section\n\nThe `--CLEAN--` section allows a test to clean up after itself. For example, if a test creates a file it can use `--CLEAN--` to ensure the file is deleted after the test runs\n\nFor maximum flexibility, any code can be run in a `--CLEAN--` section so that any resource used in the test can be cleaned (e.g. files, shared memory, a database etc...)\n\nFor example, the following RubyT test creates a file that is removed after the test runs:\n\n```rubyt\n--TEST--\nTest CLEAN\n--FILE--\nFile.open(\"abc\", \"w+\") do |file|\n  file.puts(\"hello from file 'abc'\")\nend\n\nputs File.read(\"abc\")\n--EXPECT--\nhello from file 'abc'\n--CLEAN--\nFile.delete(\"abc\")\n```\n\n## Currently implemented test sections\n\n- [x] TEST\n- [x] FILE\n- [x] EXPECT\n- [x] EXPECTF (also available as EXPECT_FORMAT)\n- [x] EXPECTREGEX (also available as EXPECT_REGEX)\n- [x] SKIPIF (also available as SKIP_IF)\n- [x] ENV\n- [ ] ARGS\n- [x] XFAIL\n- [x] CLEAN\n- [ ] DESCRIPTION\n\nAdditional sections do exist in the PHPT format ([see the PHP QA reference](https://qa.php.net/phpt_details.php)) but are not planned to be supported by Dottie as they are somewhat PHP specific\n\n## Why Dottie?\n\nBecause Dottie runs `.*t` (dot t) files\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimjoehaines%2Fdottie","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fimjoehaines%2Fdottie","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimjoehaines%2Fdottie/lists"}