{"id":34808256,"url":"https://github.com/elgopher/unitron","last_synced_at":"2025-12-25T12:11:07.865Z","repository":{"id":260792832,"uuid":"781567785","full_name":"elgopher/unitron","owner":"elgopher","description":"Unit Testing in Picotron. Make sure your code works as expected.","archived":false,"fork":false,"pushed_at":"2024-12-05T22:35:10.000Z","size":135,"stargazers_count":6,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-14T10:17:54.242Z","etag":null,"topics":["picotron","testing","testing-framework","testing-tools","unit-testing","unit-testing-framework"],"latest_commit_sha":null,"homepage":"","language":"Lua","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/elgopher.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"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}},"created_at":"2024-04-03T16:19:03.000Z","updated_at":"2025-11-06T16:19:02.000Z","dependencies_parsed_at":"2024-11-23T22:48:54.730Z","dependency_job_id":null,"html_url":"https://github.com/elgopher/unitron","commit_stats":null,"previous_names":["elgopher/unitron"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/elgopher/unitron","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elgopher%2Funitron","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elgopher%2Funitron/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elgopher%2Funitron/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elgopher%2Funitron/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elgopher","download_url":"https://codeload.github.com/elgopher/unitron/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elgopher%2Funitron/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28028980,"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-12-25T02:00:05.988Z","response_time":58,"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":["picotron","testing","testing-framework","testing-tools","unit-testing","unit-testing-framework"],"created_at":"2025-12-25T12:11:07.099Z","updated_at":"2025-12-25T12:11:07.854Z","avatar_url":"https://github.com/elgopher.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"unitron \n=======\n\nUnit testing in Picotron. Make sure your code works as expected.\n\n![Screenshot](https://www.lexaloffle.com/media/81157/unitron-0.3.0.gif \"unitron\")\n\nHow to use?\n===========\n\n* download cart png from [releases page](https://github.com/elgopher/unitron/releases) and put it somewhere on Picotron drive (desktop for example)\n* run the cart by double clicking \n* create a Lua file with following test code:\n\n```lua\nassert_eq(\"hello\", \"hello\")\n```\n\n* drag and drop the file to unitron window\n* **see [examples](examples) folder for details how to write tests**\n\nWhy to write unit tests?\n========================\n\nBecause you want to make sure that the functions you use in your game work as intended and do not cause errors that the player himself will notice. By observing the operation of the entire program, it is difficult to verify whether a function used somewhere at the bottom of your program actually works. Unit tests allow you to verify whether a function works as intended and how it deals with edge cases.\n\nOver time, the code of your functions becomes more and more complex. Functions that were simple at the beginning start to look like spaghetti - whether it's due to subsequent if statements added or optimizations you introduced to make the game run at 60 fps. So you need to go back to that code every now and then and clean it up. However, making changes to existing code involves the risk of making mistakes. So you have to be very careful when making changes and then manually verifying them. However, if you have unit tests for this code, you just need to run these tests again after each change to the code. The tests are quick and will give you results in a fraction of a second. Manual testing would take much longer. Having unit tests actually encourages you to come back to your code often and improve it.\n\nWhich code should be unit tested?\n=================================\n\nOnly the code whose behavior changes very rarely. Behavior describes the effect of executing some code - for example, running the `add` function on two numbers adds these numbers together and returns the result. What the result will be is predetermined - the arithmetic will never change here. Any reusable functions and objects that you currently use in multiple places in your games are potentially code that you can write unit tests against. They are so generic that they are unlikely to change very often. Moreover, over time, your game's code will become more and more stable - that is, it will not change significantly. Then you can extract functions and objects from it and write tests for them. \n\nIn my opinion, writing tests while prototyping a game makes no sense. The only exception is writing tests just for educational purposes :)\n\nTest API\n========\n\n* [Introduction](#introduction)\n* [test](#test)\n* [assert_eq](#assert_eq)\n* [assert_not_eq](#assert_not_eq)\n* [assert_close](#assert_close)\n* [assert_not_close](#assert_not_close)\n* [assert_nil](#assert_nil)\n* [assert_not_nil](#assert_not_nil)\n* [test_helper](#test_helper)\n* [test_fail](#test_fail)\n\nIntroduction \n------------\n\nTest API provides functions for writing your own tests. You don't have to `include` any Lua files in your test files. Unitron automatically includes all the necessary files for you, when you drag and drop your file into unitron's window.\n\nTests can be slow. That's why unitron runs them in the background - in a separate process. Thanks to that unitron window is always responsive.\n\nTests can do whatever they want - they can use any function provided by Picotron. For example, they can draw on screen. The effect will not be visible, because tests are executed in a separate process.\n\nWhen assertion inside test failed, the test is stopped immediately. Functions stop and no more code is executed from the test. If test had more assertions they are not executed. If test had more subtests they are not executed as well. Parent test is marked as failed, as well as parent of the parent (all way up to the root). On the other hand, parent's subtests are executed normally.\n\nSee [examples](examples) for tutorial-like instructions how to write unit tests in unitron.\n\n[Back to TOC](#test-api)\n\ntest\n----\n\n**syntax:** *test(name_of_the_test, function() ... end)*\n\nStarts a test with a given name and code. Test code is inside anonymous function.\n\n```lua\ntest(\"name of the test\", function()\n    -- here goes the test code\nend)\n```\n\nTests are executed sequentially.\n\nTests can be nested. When nested test fails, the parent also fails.\n\n[Back to TOC](#test-api)\n\nassert_eq\n---------\n\n**syntax:** *assert_eq(expected, actual, message?)*\n\nAsserts that `expected` and `actual` are equal. Values must have the same type.\n\nFor strings, numbers and booleans `==` operator is used.\n\nFor tables, all keys and values are compared deeply. \nIf you want to check if two variables reference to the same table in memory\nplease use `assert(a==b)` instead.\nTables could have cycles.\n\nFor userdata, all data is compared and userdata must be of the same type, width and height.\n\n[Back to TOC](#test-api)\n\nassert_not_eq\n-------------\n\n**syntax:** *assert_not_eq(expected, actual, message?)*\n\nAsserts that `expected` and `actual` are **not** equal. The function has similar behavior to [assert_eq](#assert_eq).\n\n[Back to TOC](#test-api)\n\nassert_close\n------------\n\n**syntax:** *assert_close(expected, actual, delta, message?)*\n\nAsserts that `expected` number is close to `actual` number. The maximum error is `delta`.\n\n[Back to TOC](#test-api)\n\nassert_not_close\n----------------\n\n**syntax:** *assert_not_close(not_expected, actual, delta, message?)*\n\nAsserts that `not_expected` number is not close to `actual` number. \n\n[Back to TOC](#test-api)\n\nassert_nil\n----------\n\n**syntax:** *assert_nil(actual, message?)*\n\nAsserts that `actual` is `nil`.\n\n[Back to TOC](#test-api)\n\nassert_not_nil\n--------------\n\n**syntax:** *assert_not_nil(actual, message?)*\n\nAsserts that `actual` is not `nil`.\n\n[Back to TOC](#test-api)\n\ntest_helper\n-----------\n\n**syntax:** *test_helper()*\n\n`test_helper` marks the calling function as a test helper function.\nWhen printing file and line information in GUI, that function will be\nskipped.\n\n[Back to TOC](#test-api)\n\ntest_fail\n---------\n\n**syntax:** *test_fail(err)*\n\nGenerates test error which stops current test execution and shows error to\nthe user. In the GUI, the error will be presented together with a file name\nand line number where the `test_fail` function was executed. If you run\n`test_fail` from your own assert function, and want to see a place where this\nassert function was executed instead, please run the [test_helper()](#test_helper) function in the beginning of your assert function:\n```lua\nfunction custom_assert(....)\n    test_helper() -- mark custom_assert function as test helper\n    if .... then\n        test_fail(\"message\")\n    end\nend\n```\n\n`err` is an error message as a string or a table. All table fields will be presented in the GUI. Table could contain special `msg` field which will always be presented first.\n\n[Back to TOC](#test-api)\n\nDevelopment - how to work on unitron\n====================================\n\n* clone repository to Picotron drive and name it unitron.src.p64\n    * `git clone https://github.com/elgopher/unitron unitron.src.p64`\n    * edit the source code in editor of choice (such as VS Code with sumneko's Lua Language Server)\n* to release cartridge\n    * go to Picotron terminal and type\n        * `cp unitron.src.p64 unitron.p64.png`\n    * publish post on BBS\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felgopher%2Funitron","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felgopher%2Funitron","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felgopher%2Funitron/lists"}