Evaluating Code Generation Benchmarks
Functional correctness measures whether code performs its intended functionality, and it is treated as the ultimate metric for evaluating an application.
Why Running Code Beats Reading It
Suppose a model hands you a function that looks clean, well named, and sensible. It is tempting to conclude that the code is good. But when a model generates code, the first question is not whether the code looks reasonable. The question is whether it does what it was supposed to do. Answering that question requires a different kind of check than reading the code, and for code generation that check can often be performed automatically.
This article focuses on the code case, where functional correctness can be measured automatically. We will start with a concrete run of a checking program so you can see what a functional correctness report looks like, then build up the ideas behind it: what a test case is, how a harness decides between pass and fail, and how public benchmarks use the same idea to score AI systems.
Functional Correctness as the Ultimate Metric
Functional correctness measures whether code performs its intended functionality. It is treated as the ultimate metric for evaluating an application, because the purpose of an application is to do its job.
Functional correctness evaluation means evaluating a system based on whether it performs the intended functionality. The idea is not special to code. The same question applies to any system you ask a model to build or operate, and the check is always about the outcome the system is supposed to produce.
If you ask a model to build a website, you check whether the website meets your requirements. If you ask it to make a restaurant reservation, you check whether the reservation succeeds. In both cases the judgment rests on the result the system delivers, not on how the underlying work appears.
Coding platforms apply the same logic. Functional correctness evaluation is how coding platforms like LeetCode and HackerRank validate submitted solutions, and long before AI was used to write code, automatically verifying functional correctness was standard practice in software engineering.
A Checking Program in Action
Consider a program that checks a generated gcd function against a list of input pairs, where each pair has an expected greatest common divisor. The program prints one result per pair, and it labels each mismatch with the expected value and the value the function actually produced. The function below is a deliberately flawed candidate, written for this lesson, that returns the smaller of its two inputs instead of computing the greatest common divisor. The harness runs it on four pairs.
candidate_gcdis the generated function under test- Each tuple is one test case: two inputs followed by the expected result
- The conditional expression chooses the label by comparing actual with expected
- The print statement reports the input pair, the expected value, and the value produced
What do you think happens?
What lines does the harness print?
Reveal answer
FAIL (12, 8): expected 4, got 8FAIL (15, 20): expected 5, got 15PASS (8, 4): expected 4, got 4FAIL (9, 6): expected 3, got 6
min returns the smaller input. For (12, 8) that is 8, but the greatest common divisor is 4. For (15, 20) it returns 15 instead of 5. For (8, 4) it returns 4, which happens to equal the correct answer, so that line passes. For (9, 6) it returns 6 instead of 3.
Reading the Report Line by Line
Read the report one line at a time. Each line beginning with FAIL names one input pair, then states the expected value and the value the function produced. A line such as FAIL (15, 20): expected 5, got 15 is a mismatch: the correct greatest common divisor of 15 and 20 is 5, so a function that returns anything other than 5 for that pair is wrong. The report shows exactly where the function diverged from the expected result, which is the information a developer needs in order to debug it.
Tracing the FAIL line for (15, 20)
The harness reaches the test tuple (15, 20, 5). What exactly does it compute and print?
- 1Unpack the tuple
The loop assigns a = 15, b = 20, and expected = 5.
- 2Run the candidate
candidate_gcd(15, 20)evaluatesmin(15, 20), which is 15. So actual = 15. - 3Compare
actual == expected asks whether 15 equals 5. It does not, so the condition is False and status becomes 'FAIL'.
- 4Print
The f-string fills in the pair (15, 20), the expected value 5, and the actual value 15, producing FAIL (15, 20): expected 5, got 15.
The harness prints FAIL (15, 20): expected 5, got 15, which identifies the exact input where the function diverges.
The PASS line in the report deserves attention too. The pair (8, 4) passes only because the smaller input happens to be the greatest common divisor for that pair. One matching line is not evidence that the function is correct. A single successful check tells you about that one scenario, and nothing more.
Two Questions: Validity and Correctness
A measurement of functional correctness has two stages. First, the generated code is input into a Python interpreter to check whether it is valid. If the code is not valid, it cannot be run at all. If it is valid, the next question is whether it outputs the correct result for a given input pair.
In the candidate_gcd example, every line of the program runs without error. The FAIL lines are not crashes. They are correctness failures, and only the comparison step reveals them.
How the Harness Decides on One Test
The diagram below traces one test. The test case supplies an input pair and the expected value. The generated function receives the input and returns an actual value. The comparison step then decides between the two terminal results: PASS when the actual value matches the expected value, and FAIL when it does not. The same flow repeats for every test case in the set, which is why a single function can produce several FAIL lines in one report.
Trace the diagram with the (15, 20) pair. The test case supplies the inputs 15 and 20 with expected value 5. The function returns 15. The comparison finds that 15 is different from 5, so the path leads to FAIL. The harness then moves to the next test in the set, and the loop continues until every case has been checked.
Anatomy of a Test Case
A test case is a scenario plus its expected output. The scenario is the situation the code is executed in: the inputs it receives. The expected output is what the code should return for that scenario. A unit test executes code in a scenario and compares the actual output to the expected output. Each scenario is one test, and the whole set of scenarios gives the measurement its coverage.
In the tuple (12, 8, 4) from the harness, the first two values form the scenario and the last value is the expected output. Reading the case this way makes the mapping explicit: the function is run on the scenario (12, 8), and its actual return value is checked against the expected output 4.
Unit Tests and Coverage
Code is typically validated with unit tests, in which the code is executed in different scenarios to ensure that it generates the expected outputs. Unit testing is a standard practice in software engineering. Each scenario is one test, and the whole set of scenarios is what gives a measurement of functional correctness its coverage.
Coverage therefore depends on the test set. A function checked on only one pair has been measured in one scenario. The four pairs in the harness are a small set, and the flawed candidate was caught by three of them. A larger and more varied set of scenarios gives a broader measurement, while a narrow set can let a wrong function pass.
Mistakes When Reading Test Results
Common mistake Judging code by how reasonable it looks
What it looks likeA function is clean and well named, so it is accepted without running any test.
Why it failsThe first question is whether the code does what it was supposed to do, and appearance does not answer that.
Do this insteadRun the code against test cases and compare its actual outputs with the expected outputs.
Common mistake Treating a program that runs without error as correct
What it looks likecandidate_gcd executes every line without an exception, yet three of its four pairs print FAIL.
Why it failsValidity and correctness are separate stages. Code can be valid and still return the wrong answer.
Do this insteadCheck the comparison result for each test case, not only whether the program finished.
Common mistake Treating one passing line as proof of correctness
What it looks likeThe pair (8, 4) passes, so the candidate might seem correct.
Why it failsThe pass happens because
min(8, 4)equals the correct answer in that one scenario. One scenario says nothing about the others.Do this insteadRead the whole report and rely on the full set of test cases for coverage.
Common mistake Ignoring the FAIL lines because the program did not crash
Functional Correctness Versus Surface Comparison
It helps to contrast functional correctness with judging code by its text or structure. A surface-level judgment asks whether the code looks like an acceptable answer. A functional judgment asks whether running the code produces the right results. The table below sets the two side by side.
| Aspect | Surface-level judgment | Functional correctness |
|---|---|---|
| Guiding question | Does the code look reasonable? | Does it do what it was supposed to do? |
| What is examined | The text or structure of the code | The output produced when the code runs on test inputs |
| Basis for the decision | Appearance or resemblance to a reference | Whether actual output matches expected output |
| Typical evidence | A reading of the code | A test report with PASS and FAIL lines |
Two ways to judge generated code
How Benchmarks Apply This Idea
A benchmark is a standardized dataset and metric used to evaluate AI models on a task. For code generation, a benchmark problem comes with a set of test cases, and the generated code is checked against them. The pipeline below shows the path a problem takes from prompt to final score.
Trying the Harness Yourself
Suppose you change candidate_gcd so that it returns max(a, b) instead of min(a, b), and keep the same four test tuples. Before running anything, predict which lines print PASS and which print FAIL. Then explain why the (8, 4) pair that passed before now behaves differently.
Hints
- For each pair, compute max of the two inputs and compare that value with the expected value in the tuple.
- For (8, 4), max returns 8, while the expected value is 4.
- A PASS requires actual == expected, so check every line against that rule.
Key Takeaways
- Functional correctness measures whether code performs its intended functionality, and it is treated as the ultimate metric for evaluating an application.
- A measurement of functional correctness has two stages: first check that the code is valid, then check that its output matches the expected output for each input. Running without error does not establish correctness.
- A test case is a scenario plus its expected output. A harness runs the generated code on each scenario, compares actual with expected, and reports PASS or FAIL.
- Benchmarks such as HumanEval and MBPP for Python, and Spider, BIRD-SQL, and WikiSQL for text-to-SQL, use functional correctness and their test cases to decide whether generated output is accepted.