Skip to content

feat(assignments): add Testbench model for autograded test suites - #7836

Open
magic-peach wants to merge 2 commits into
CircuitVerse:masterfrom
magic-peach:feat/testbench-model
Open

feat(assignments): add Testbench model for autograded test suites#7836
magic-peach wants to merge 2 commits into
CircuitVerse:masterfrom
magic-peach:feat/testbench-model

Conversation

@magic-peach

@magic-peach magic-peach commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes part of #7412

Describe the changes you have made in this PR -

This pr adds a Testbench model which is basically one JSONB-backed row per assignment that holds the test suite an instructor authors and the autograder later feeds to the simulator. This is the data layer everything else in the autograding phase builds on but nothing runs a testbench yet, this PR just makes sure a saved one is actually runnable before it's allowed to exist.

Screenshots of the UI changes (If any) -

none


Code Understanding and AI Usage

**Did you use AI generated code (ChatGPT, Claude, Copilot, etc.) in any part of this PR? **

  • No, I wrote all the code myself
  • Yes, I used AI assistance (continue below)

If you used AI assistance:

  • I have reviewed every single line of the AI-generated code
  • I can explain the purpose and logic of each function/component I added
  • I have tested edge cases and understand how the code handles them
  • I have modified the AI output to follow this project's coding standards and conventions

Explain your implementation approach:

Describe in your own words:

  • What problem does your code solve?
    Before the pr runner or the grading job can do anything, there has to be somewhere to store the instructor's test suite and a guarantee that what's stored is well-formed enough to run. Without validation at the model layer, a malformed suite (missing a group, an output with fewer values than test cases, a bad bit width) would only surface when the simulator chokes on it mid-run which reads to the student as their circuit being wrong, not the test data being broken. This PR pushes that check as early as possible in order to save time.

  • What alternative approaches did you consider?

  • Storing the suite as a column on Assignment itself: simpler schema, but confuses "what the assignment is" with "how it's graded," and would make the has-one relationship to a runner-facing testbench harder to reason about once the editor and versioning land.

  • Validating the suite shape only at the point of use (in the runner): rejected, because that pushes bad data into production and only fails at run time, per-submission, instead of at authoring time.

  • Why did you choose this specific implementation?
    assignment_id is unique, and it's enforced in two places: the database (a unique index) and the model (a validation).
    Validation happens in three steps that mirrors how a testbench is actually structured , So when something's wrong, the error points to the exact broken signal.

  • What are the key functions/components and what do they do?

  • Testbench : belongs to Assignment

  • #data_is_runnable : the top-level validation: checks data is a Hash, its type is one the simulator supports, and it has at least one group.

  • #validate_group(group) : checks each group has a positive case count (n) and at least one input and one output signal.

  • #validate_signal(signal, cases) : checks each signal has a label so the simulator can bind it to the right pin, a positive bitWidth, and exactly as many values as the group's case count.


Checklist before requesting a review

  • I have added proper PR title and linked to the issue
  • I have performed a self-review of my code
  • I can explain the purpose of every function, class, and logic block I added
  • I understand why my changes work and have tested them thoroughly
  • I have considered potential edge cases and how my code handles them
  • If it is a core feature, I have added thorough tests
  • My code follows the project's style guidelines and conventions

Note: Please check Allow edits from maintainers if you would like us to assist in the PR.

Summary by CodeRabbit

  • New Features
    • Added support for associating one testbench with each assignment.
    • Added validation for runnable combinational and sequential testbench configurations, including groups, cases, signals, and signal values.
    • Testbench data can now be accessed for simulator and autograder execution.
  • Data & Reliability
    • Added persistent storage for testbench configurations with assignment uniqueness enforcement.
    • Added validation coverage for valid and invalid testbench structures.

Stores the simulator's testbench JSON per assignment and validates it is
runnable before the autograder feeds it to the simulator.

Groundwork for the headless runner and GradingResult PRs that follow.
@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds a Testbench model linked one-to-one with Assignment. The model validates runnable combinational and sequential testbench data and exposes its groups. A migration and schema update add JSONB persistence, timestamps, uniqueness, and foreign-key constraints. Factory data and model specs cover associations and validation cases.

Merge Risk: 🔵 Low · up to 25784

The PR adds persisted testbench data and validates its structure, but signal labels can still accept non-string values that may fail when the simulator uses them. The change is mergeable with explicit owner awareness and follow-up to tighten the testbench contract.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 6 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: adding the Testbench model for autograded test suites.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: dabde971-c705-457a-9bcb-d3a874ac19b4

📥 Commits

Reviewing files that changed from the base of the PR and between 79bd963 and 25784e7.

📒 Files selected for processing (6)
  • app/models/assignment.rb
  • app/models/testbench.rb
  • db/migrate/20260814120000_create_testbenches.rb
  • db/schema.rb
  • spec/factories/testbenches.rb
  • spec/models/testbench_spec.rb

Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review.

Comment thread app/models/testbench.rb
end

def validate_signal(signal, cases)
return errors.add(:data, "every signal needs a label") unless signal.is_a?(Hash) && signal["label"].present?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

printf '%s\n' '--- applicable repository guidance ---'
find /tmp/coderabbit-repo-knowledge/circuitverse-circuitverse-08827a34 -maxdepth 2 -type f -name '*.md' -print
printf '%s\n' '--- testbench model ---'
cat -n app/models/testbench.rb | sed -n '1,120p'
printf '%s\n' '--- focused diff ---'
git diff -- app/models/testbench.rb

Repository: CircuitVerse/CircuitVerse

Length of output: 2569


🏁 Script executed:

printf '%s\n' '--- Rails version and focused test files ---'
rg -n '^\s*gem ["'\'']rails|rails \(' Gemfile Gemfile.lock 2>/dev/null || true
fd -i 'testbench' .
printf '%s\n' '--- label consumers and validation references ---'
rg -n 'bitWidth|signal\[["'\'']label["'\'']\]|\.label|signal.*label|every signal needs a label' app test spec 2>/dev/null | head -160

Repository: CircuitVerse/CircuitVerse

Length of output: 7827


🏁 Script executed:

printf '%s\n' '--- model specs ---'
cat -n spec/models/testbench_spec.rb | sed -n '1,130p'
printf '%s\n' '--- controller and simulator entry points ---'
cat -n app/controllers/testbench_controller.rb | sed -n '1,180p'
cat -n simulator/src/testbench.js | sed -n '1,220p'
printf '%s\n' '--- simulator binding references ---'
rg -n -C 3 'label|inputs|outputs|bitWidth' simulator/src/testbench simulator/src/testbench.js

Repository: CircuitVerse/CircuitVerse

Length of output: 50381


🌐 Web query:

Rails 8.1 ActiveSupport Object#present? String#blank? Numeric#blank? official API documentation

💡 Result:

In Ruby on Rails 8.1, the methods present? and blank? are provided by ActiveSupport as core extensions to the Object class, making them available across virtually all objects [1][2][3]. Object#present? The present? method returns true if an object is not blank [4][3]. It is defined as the negation of blank? [4][1]: def present?!blank? end String#blank? For strings, the blank? method returns true if the string is empty or contains only whitespace characters (including Unicode whitespace) [5][6][7]. It is implemented as: def blank? empty? || BLANK_RE.match?(self) # (with rescue handling for encoding) end Numeric#blank? In Rails 8.1, the Numeric class defines blank? to always return false, as numbers are considered to be present [8]: def blank? false end These methods are standard throughout the Rails framework for checking the presence of data, such as parameters or model attributes [4][9]. Official documentation can be found in the Ruby on Rails API guides and class references [4][9][5].

Citations:


Require signal labels to be strings.

present? rejects whitespace-only strings, but it accepts non-string JSON values such as 1. The simulator later calls .trim() on each label, so a numeric label can pass model validation and raise a JavaScript TypeError. Require label.is_a?(String) && label.present?, and add a regression example for a numeric label.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant