ek9_add_program
Appends the program (or @Test program) to the file's 'defines program' block, created if absent, with a stub body that references every parameter and injection; answers status, edits[] and summary.
When to use it
'Add a program Main that prints X' is one call with file, name and statements:['stdout <- Stdout()', 'stdout.println(...)'] - the body included, nothing left to fill; isTest:true makes it a @Test program.
When not to use it
- Authoring any OTHER top-level construct (class/record/trait/function/component/type/constant/service) - use
ek9_new_construct. - Authoring the DI application a program binds to via 'application' - use
ek9_add_applicationfirst, then reference it here by name. - Anchoring a @Test program that ALREADY exists to a requirement - use
ek9_anchor_test(requirementId here is for a freshly-scaffolded test).
Details
parameters[].type must be one of the 18 whitelisted CLI arg types (String/Integer/Float/Boolean/Character/Bits/Date/Time/DateTime/Duration/Millisecond/Money/Colour/Resolution/Dimension/RegEx/GUID/List of String) — an invalid type (E07600), a typed primitive mixed with 'List of String' (E07610), or a program name already taken in the module all surface as would-fail from the dry-run gate. Programs may return only Integer (process exit code — E07590).
Arguments
| Argument | Type | Required | What it is |
|---|---|---|---|
application | string | Application to bind for DI — renders 'with application of <App>'. The application must resolve (define it with ek9_add_application first). | |
file | string | yes | Workspace-relative path to the .ek9 module file the program is appended to (the 'defines program' block is created if absent). For isTest:true this must be a dev source (dev/ subdirectory or QA####_dev_ file). |
injections | array of any | Components pulled from the application by injection, each ONE item as DATA - {name:'code', type:'Integer'} - never a {name} and a {type} as two items, and never with '->' or '<-' in it; the tool writes the arrows and the layout. ('code as Integer' is also accepted.) A malformed item is rejected before anything is rendered. ('logger as Logger' or 'logger as Logger!' both render 'logger as Logger!'). Each is referenced in the stub (an unused injection is E11018). | |
isTest | boolean | When true, prepend the @Test directive and emit an assert-based stub. Only legal in a dev source (E81015). | |
name | string | yes | Program name (PascalCase), e.g. 'ShowInjection' or 'GreetingTest'. |
parameters | array of any | Typed CLI argument parameters, each ONE item as DATA - {name:'code', type:'Integer'} - never a {name} and a {type} as two items, and never with '->' or '<-' in it; the tool writes the arrows and the layout. ('code as Integer' is also accepted.) A malformed item is rejected before anything is rendered. Each is referenced in the stub so it compiles (an unused arg is E08091). | |
requirementId | string | Requirement id this test anchors, e.g. 'REQ:velocity-limit' - renders '@Test: "REQ:velocity-limit"'. Requires isTest:true; supplying it for a non-test program is rejected rather than ignored. The requirement need not exist yet (writing the test first is legitimate); ek9_check_requirements reports an id that names nothing as a dangling anchor. | |
statements | array of string | The program's body, one statement or one block per entry ('stdout <- Stdout()', 'stdout.println(...)'): the program is complete in this call - no stub, no ek9_insert_statements after it. Parsed alone first; a problem names the entry and its fix. |
It also takes the arguments every tool takes.
Recorded calls
Real calls, recorded against small projects and checked on every build - a changed answer fails it. 3 of the 12 recorded are shown.
Test program non dev rejected
Request
{
"dryRun" : true,
"file" : "main.ek9",
"isTest" : true,
"name" : "BadTest"
}
Response
{
"conflicts" : [ ],
"edits" : [ ],
"error" : {
"message" : "@Test programs are only allowed in a dev source — move the target into a 'dev/' subdirectory or rename it to the QA####_dev_ pattern (E81015). Got: main.ek9"
},
"meta" : {
"serverMs" : "<timing>"
},
"status" : "error",
"summary" : "@Test programs are only allowed in a dev source — move the target into a 'dev/' subdirectory or rename it to the QA####_dev_ pattern (E81015). Got: main.ek9",
"wouldBeDiagnostics" : [ ],
"written" : false
}
Requirement without istest rejected
Request
{
"dryRun" : true,
"file" : "main.ek9",
"name" : "NotATest",
"requirementRef" : "REQ:velocity-limit"
}
Response
{
"conflicts" : [ ],
"edits" : [ ],
"error" : {
"message" : "'requirementId' anchors a @Test to a requirement, so it needs isTest: true. A plain program is an entry point and cannot anchor anything. Got: REQ:velocity-limit"
},
"meta" : {
"serverMs" : "<timing>"
},
"status" : "error",
"summary" : "'requirementId' anchors a @Test to a requirement, so it needs isTest: true. A plain program is an entry point and cannot anchor anything. Got: REQ:velocity-limit",
"wouldBeDiagnostics" : [ ],
"written" : false
}
Requirement malformed rejected
Request
{
"dryRun" : true,
"file" : "dev/tests.ek9",
"isTest" : true,
"name" : "TypoTest",
"requirementRef" : "RREQ:velocity-limit"
}
Response
{
"conflicts" : [ ],
"edits" : [ ],
"error" : {
"message" : "'RREQ:velocity-limit' is not a valid requirement id. Expected <PREFIX>:<slug> with PREFIX one of REQ, CTRL, CAP, CON and slug matching [a-z0-9-]+, e.g. 'REQ:velocity-limit'."
},
"meta" : {
"serverMs" : "<timing>"
},
"status" : "error",
"summary" : "'RREQ:velocity-limit' is not a valid requirement id. Expected <PREFIX>:<slug> with PREFIX one of REQ, CTRL, CAP, CON and slug matching [a-z0-9-]+, e.g. 'REQ:velocity-limit'.",
"wouldBeDiagnostics" : [ ],
"written" : false
}
See also
- Show me in the IDE: Chapter 16: a class, built
- Show me in the IDE: Chapter 4: a function, built
- Show me in the IDE: Chapter 14: an enumeration, built
- Show me in the IDE: Chapter 14: a record, built
- Show me in the IDE: Chapter 17: an abstract type and its subtypes, built
- Show me in the IDE: Chapter 18: traits and delegation, built
- Show me in the IDE: Chapter 21: operators, built
- Show me in the IDE: Chapter 21: promotion, #^
- Show me in the IDE: Chapter 19: a component, built
- Show me in the IDE: Chapter 5: tests, built
- Show me in the IDE: Chapter 2: values, reshaped
- Show me in the IDE: Chapter 12: a pipeline, built
- Show me in the IDE: Chapter 10: guards, reshaped
- Show me in the IDE: Chapter 11: Optional and Result, built
- Show me in the IDE: Chapter 15: a constrained type, built
- Show me in the IDE: Chapter 7: asking about a type
- Show me in the IDE: Chapter 8: a text type, built
- Show me in the IDE: Chapter 9: collections, asked about
- Show me in the IDE: Chapter 20: a generic type, read
- Show me in the IDE: Chapter 22: a program with arguments, built
- Show me in the IDE: Chapter 23: the game, built and played