Enhancement: goal Error UX Improvement#4951
Conversation
goal Error UXgoal Error UX
goal Error UXgoal Error UX Improvements
Codecov Report
@@ Coverage Diff @@
## master #4951 +/- ##
==========================================
+ Coverage 53.62% 53.65% +0.02%
==========================================
Files 432 432
Lines 54060 54068 +8
==========================================
+ Hits 28991 29011 +20
+ Misses 22824 22810 -14
- Partials 2245 2247 +2
📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
goal Error UX Improvementsgoal Error UX Improvement
algochoi
left a comment
There was a problem hiding this comment.
Looking good, I agree that returning a clearer error for an empty program seems better from a UX perspective 👍
| // assemble reads text from an input and accumulates the program | ||
| func (ops *OpStream) assemble(text string) error { | ||
| if strings.TrimSpace(text) == "" { | ||
| ops.errorf("Cannot assemble empty program text") |
There was a problem hiding this comment.
I didn't want to return right away because I want to let the assembler do it's thing and report number of errors. I.e., if I return right away instead of getting the following message:
clear_state_program.teal: 0: Cannot assemble empty program text
clear_state_program.teal: 1 error
I would get the following:
clear_state_program.teal: 0: Cannot assemble empty program text
clear_state_program.teal: 0: Cannot assemble empty program text
There was a problem hiding this comment.
It should be ok to:
return ops.errorf("Cannot assemble empty program text")
since that's how the Version check works a couple lines lower.
return ops.errorf("Can not assemble version %d", ops.Version)
That must show the same problem in the context you're looking at.
Perhaps we can change ops.ReportProblems to only report the underlying errors if there's more than 1? Rename to ops.MultpleErrors?
There was a problem hiding this comment.
This worked with the following error goal messages:
clear_state_program.teal: 1 error
clear_state_program.teal: 0: Cannot assemble empty program text
There was a problem hiding this comment.
After modifying as above, test/scripts/e2e_subs/e2e-teal.sh started failing as the original error wasn't reported for goal clerk compile a logic sig (bad compiler version). So I modified ops.MultipleErrors() to also report the original unique error along with the count in the same line (only in the case of exactly 1 error and no warnings). Now the error looks like:
clear_state_program.teal: 1 error: 0: Cannot assemble empty program text
clear_state_program.teal: 0: Cannot assemble empty program text… 1 error to _not_ report the actual errors, but "1 error" instead
| } | ||
|
|
||
| func TestMultipleErrors(t *testing.T) { | ||
| func TestSeveralErrors(t *testing.T) { |
There was a problem hiding this comment.
Renaming as the natural name of a new unit test for renamed function func(ops *OpStream) MultipleErrors is this one.
| if strings.TrimSpace(text) == "" { | ||
| return ops.errorf("Cannot assemble empty program text") | ||
| } |
There was a problem hiding this comment.
| if strings.TrimSpace(text) == "" { | |
| return ops.errorf("Cannot assemble empty program text") | |
| } | |
| // version check | |
| ... | |
| trimmed := strings.TrimSpace(text) | |
| if trimmed == "" { | |
| return ops.errorf("Cannot assemble empty program text") | |
| } | |
| fin := strings.NewReader(trimmed) |
There was a problem hiding this comment.
I am reverting this change. Though I agree that passing on trimmed seems sensible, it is breaking tests, and the asserted behavior is there for a reason. For example, when providing this TEAL input:
int 1
#pragma version 2
This test case is failing:
This is because it is expecting the error:
{l: 3, s: "#pragma version is only allowed before instructions"}but now, since we removed the empty line, it becomes
{l: 2, s: "#pragma version is only allowed before instructions"}From a user's perspective, I believe the original error is more correct.
|
Update: The recent changes are causing test failures. I will investigate further. |
| emptyExpect := Expect{0, "Cannot assemble empty program text"} | ||
| emptyPrograms := []string{ | ||
| "", | ||
| " ", |
There was a problem hiding this comment.
What about "label:" or " //"
There was a problem hiding this comment.
The goal of the PR was to address the original concern (see #2585 ) which is when someone basically accidentally puts in a blank program for assembly. I expanded the definition to include any program that consists of all whitespace. We can expand even further, but it does seem to me to be a can of worms that I am inclined to push back against... However, I'm more than happy to test this out experimentally in our pair programming project.
Changed assembler functionality so that logic.assemble errors when receiving empty input
Summary
Changing assembler functionality so that
data/transactions/logic/assembler.go::assemble()errors when receiving empty input.For example, here's what occurs when the clear program is empty (but approval is fine):
Question for Consideration
Related, to this. Consider the following empty'ish program:
Currently (and this PR doesn't change the behavior) we get the following error when attempting to run
goal app create:So we're perfectly happy to start the evaluator and immediately stop it, then declare a rejection. The PR here doesn't adhere to this pattern.
Even if the answer to the above is "yes, it is good to allow empty programs to be assembled because ..." there is still the counterargument that we want to fail as fast as possible and not create extra work for the node to evaluate guaranteed-to-fail transactions.
Issues
Test Plan