{"id":21502401,"url":"https://github.com/fixrb/test_tube","last_synced_at":"2025-10-11T17:33:00.417Z","repository":{"id":59157695,"uuid":"378287143","full_name":"fixrb/test_tube","owner":"fixrb","description":"A test tube to conduct software experiments 🧪","archived":false,"fork":false,"pushed_at":"2024-12-31T21:46:05.000Z","size":371,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-09T23:12:56.192Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fixrb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-06-18T23:46:16.000Z","updated_at":"2024-12-31T21:46:07.000Z","dependencies_parsed_at":"2025-07-16T02:09:55.986Z","dependency_job_id":"7d2acd51-603b-4839-8fd7-77e960ec45bc","html_url":"https://github.com/fixrb/test_tube","commit_stats":{"total_commits":12,"total_committers":1,"mean_commits":12.0,"dds":0.0,"last_synced_commit":"cfd0d891b605b251146e992ec81e04a5251ad4a2"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/fixrb/test_tube","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fixrb%2Ftest_tube","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fixrb%2Ftest_tube/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fixrb%2Ftest_tube/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fixrb%2Ftest_tube/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fixrb","download_url":"https://codeload.github.com/fixrb/test_tube/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fixrb%2Ftest_tube/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279007496,"owners_count":26084313,"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","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-11-23T18:14:46.930Z","updated_at":"2025-10-11T17:33:00.402Z","avatar_url":"https://github.com/fixrb.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Test Tube\n\n[![Version](https://img.shields.io/github/v/tag/fixrb/test_tube?label=Version\u0026logo=github)](https://github.com/fixrb/test_tube/tags)\n[![Yard documentation](https://img.shields.io/badge/Yard-documentation-blue.svg?logo=github)](https://rubydoc.info/github/fixrb/test_tube/main)\n[![License](https://img.shields.io/github/license/fixrb/test_tube?label=License\u0026logo=github)](https://github.com/fixrb/test_tube/raw/main/LICENSE.md)\n\n\u003e A test tube to conduct software experiments safely 🧪\n\nTestTube is a Ruby library designed to safely execute and evaluate code experiments. It provides:\n- Complete exception handling (including SystemExit and other system-level exceptions)\n- A flexible matcher-based testing approach\n- Two distinct testing methods: code execution (`invoke`) and value testing (`pass`)\n- Clear experiment results with actual values, errors, and matcher results\n\n![A researcher experimenting with Ruby code](https://github.com/fixrb/test_tube/raw/main/img/social-media-preview.png)\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem \"test_tube\"\n```\n\nAnd then execute:\n\n```sh\nbundle install\n```\n\nOr install it yourself as:\n\n```sh\ngem install test_tube\n```\n\n## Usage\n\n### Basic Usage\n\nFirst, make TestTube available:\n\n```ruby\nrequire \"test_tube\"\n```\n\nTestTube provides two main ways to conduct experiments:\n\n1. **Execute and test code** with `invoke`:\n   - Safely executes blocks of code\n   - Catches ALL exceptions, including system-level ones\n   - Perfect for testing potentially dangerous operations\n\n2. **Test direct values** with `pass`:\n   - Tests pre-computed values\n   - Simpler and more direct approach\n   - Ideal when you already have the value to test\n\n### Simple Example\n\nLet's test if a value equals 42 using a custom matcher:\n\n```ruby\nclass BeTheAnswer\n  def match?\n    42.equal?(yield)\n  end\nend\n\n# Using invoke to execute code\nexperiment = TestTube.invoke(matcher: BeTheAnswer.new, negate: false) do\n  \"101010\".to_i(2) # Converting binary to decimal\nend\nexperiment.got    # =\u003e true\nexperiment.actual # =\u003e 42\nexperiment.error  # =\u003e nil\n\n# Or using pass with a direct value\nexperiment = TestTube.pass(42, matcher: BeTheAnswer.new, negate: false)\nexperiment.got    # =\u003e true\nexperiment.actual # =\u003e 42\nexperiment.error  # =\u003e nil\n```\n\n### Integration with Matchi\n\nTestTube works seamlessly with the [Matchi](https://github.com/fixrb/matchi/) matcher library:\n\n```sh\ngem install matchi\n```\n\n```ruby\nrequire \"matchi\"\n\n# Testing for exceptions\nexperiment = TestTube.invoke(\n  matcher: Matchi::RaiseException.new(:NoMethodError),\n  negate:  false\n) { \"foo\".blank? }\nexperiment.got    # =\u003e true\nexperiment.actual # =\u003e #\u003cNoMethodError: undefined method `blank?' for \"foo\":String\u003e\n\n# Testing floating-point arithmetic\nexperiment = TestTube.invoke(\n  matcher: Matchi::Be.new(0.3),\n  negate:  false\n) { 0.1 + 0.2 }\nexperiment.got    # =\u003e false\nexperiment.actual # =\u003e 0.30000000000000004\n\n# Handling errors gracefully\nexperiment = TestTube.invoke(\n  matcher: Matchi::Match.new(/^foo$/),\n  negate:  false\n) { BOOM }\nexperiment.got    # =\u003e nil\nexperiment.error  # =\u003e #\u003cNameError: uninitialized constant BOOM\u003e\nexperiment.actual # =\u003e nil\n```\n\n## Key Features\n\n- **Safe Execution**: Catches all exceptions, including system-level ones\n- **Flexible Testing**: Support for custom matchers and the Matchi library\n- **Clear Results**: Easy access to actual values, errors, and test results\n- **Two Testing Modes**: Choose between code execution and direct value testing\n- **Framework Friendly**: Perfect for building testing frameworks and tools\n\n## Contact\n\n* Source code: https://github.com/fixrb/test_tube\n* Chinese blog post: https://ruby-china.org/topics/41390\n* Japanese blog post: https://qiita.com/cyril/items/36174b619ff1852c80ec\n\n## Versioning\n\nTest Tube follows [Semantic Versioning 2.0](https://semver.org/).\n\n## License\n\nThe [gem](https://rubygems.org/gems/test_tube) is available as open source under the terms of the [MIT License](https://github.com/fixrb/test_tube/raw/main/LICENSE.md).\n\n## Sponsors\n\nThis project is sponsored by [Sashité](https://sashite.com/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffixrb%2Ftest_tube","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffixrb%2Ftest_tube","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffixrb%2Ftest_tube/lists"}