Files
weevil/templates/testing/QUICKSTART.md
Eric Ratliff 60679e097f feat: Add template system to weevil new command
Implements template-based project creation allowing teams to start with
professional example code instead of empty projects.

Features:
- Two templates: 'basic' (minimal) and 'testing' (45-test showcase)
- Template variable substitution ({{PROJECT_NAME}}, etc.)
- Template validation with helpful error messages
- `weevil new --list-templates` command
- Template files embedded in binary at compile time

Technical details:
- Templates stored in templates/basic/ and templates/testing/
- Files ending in .template have variables replaced
- Uses include_dir! macro to embed templates in binary
- Returns file count for user feedback

Testing template includes:
- 3 complete subsystems (MotorCycler, WallApproach, TurnController)
- Hardware abstraction layer with mock implementations
- 45 comprehensive tests (unit, integration, system)
- Professional documentation (DESIGN_AND_TEST_PLAN.md, etc.)

Usage:
  weevil new my-robot                    # basic template
  weevil new my-robot --template testing # testing showcase
  weevil new --list-templates            # show available templates

This enables FTC teams to learn from working code and best practices
rather than starting from scratch.
2026-02-02 22:31:08 -06:00

5.0 KiB

Quick Reference Guide

Project Commands

Testing (Windows JRE - No Robot Needed)

gradlew test                    # Run all tests
gradlew test --tests MotorCyclerTest  # Run specific test

Building for Robot

build.bat                       # Build APK (Windows)
./build.sh                      # Build APK (Linux/Mac)

Deployment

deploy.bat                      # Deploy to robot (Windows)
./deploy.sh                     # Deploy to robot (Linux/Mac)

Project Structure Quick View

my-robot/
│
├── src/main/java/robot/
│   ├── hardware/                    # Hardware abstractions
│   │   ├── MotorController.java       [Interface - No FTC deps]
│   │   └── FtcMotorController.java    [FTC SDK wrapper]
│   │
│   ├── subsystems/                  # Business logic
│   │   └── MotorCycler.java           [Pure Java - Testable!]
│   │
│   └── opmodes/                     # FTC integration
│       └── MotorCycleOpMode.java      [Glue code]
│
├── src/test/java/robot/
│   ├── hardware/
│   │   └── MockMotorController.java   [Test mock]
│   └── subsystems/
│       └── MotorCyclerTest.java       [Unit tests]
│
├── build.gradle.kts                 # Build configuration
├── build.bat / build.sh             # Build scripts
└── deploy.bat / deploy.sh           # Deploy scripts

Code Flow

  1. OpMode starts → Creates FtcMotorController from hardware map
  2. OpMode.init() → Creates MotorCycler, passes controller
  3. OpMode.loop() → Calls motorCycler.update(currentTime)
  4. MotorCycler → Updates state, controls motor via interface
  5. MotorController → Abstraction hides whether it's real or mock

Testing Flow

  1. Test creates → MockMotorController
  2. Test creates → MotorCycler with mock
  3. Test calls → motorCycler.init()
  4. Test calls → motorCycler.update() with simulated time
  5. Test verifies → Mock motor received correct commands

Key Design Patterns

Dependency Injection

// Good: Pass dependencies in constructor
MotorCycler cycler = new MotorCycler(motorController, 2000, 1000);

// Bad: Create dependencies internally
// class MotorCycler { 
//     DcMotor motor = hardwareMap.get(...); // Hard to test!
// }

Interface Abstraction

// Good: Program to interface
MotorController motor = new FtcMotorController(dcMotor);

// Bad: Program to implementation
// FtcMotorController motor = new FtcMotorController(dcMotor);

Time-Based State Machine

// Good: Pass time as parameter (testable)
void update(long currentTimeMs) { ... }

// Bad: Read time internally (hard to test)
// void update() { 
//     long time = System.currentTimeMillis(); 
// }

Common Tasks

Add a New Subsystem

  1. Create interface in hardware/ (e.g., ServoController.java)
  2. Create FTC implementation (e.g., FtcServoController.java)
  3. Create business logic in subsystems/ (e.g., ClawController.java)
  4. Create mock in test/hardware/ (e.g., MockServoController.java)
  5. Create tests in test/subsystems/ (e.g., ClawControllerTest.java)
  6. Wire into OpMode

Run a Specific Test

gradlew test --tests "MotorCyclerTest.testFullCycle"

Debug Test Failure

  1. Look at test output (shows which assertion failed)
  2. Check expected vs actual values
  3. Add println() to MotorCycler if needed
  4. Re-run test instantly (no robot deploy needed!)

Modify Timing

Edit MotorCycleOpMode.java line 20:

// Change from 2000, 1000 to whatever you want
motorCycler = new MotorCycler(motorController, 2000, 1000, 0.5);
//                                             ^^^^  ^^^^  ^^^
//                                             on-ms off-ms power

Hardware Configuration

Your FTC Robot Configuration needs:

  • One DC Motor named "motor" (exact spelling matters!)

Troubleshooting

"Could not find motor"

→ Check hardware configuration has motor named "motor"

"Tests won't run"

→ Make sure you're using gradlew test not gradlew build → Tests run on PC, build needs FTC SDK

"Build can't find FTC SDK"

→ Check .weevil.toml has correct ftc_sdk_path → Run weevil init if SDK is missing

"Motor not cycling"

→ Check OpMode is selected and started on Driver Station → Verify motor is plugged in and configured correctly

Learning More

  • Read ARCHITECTURE.md for deep dive into design decisions
  • Read README.md for overview
  • Look at tests to see how each component works
  • Modify values and re-run tests to see behavior change

Best Practices

✓ Write tests first (they're fast!) ✓ Keep subsystems independent ✓ Use interfaces for hardware ✓ Pass time as parameters ✓ Mock everything external

✗ Don't put hardware maps in subsystems ✗ Don't read System.currentTimeMillis() in logic ✗ Don't skip tests ✗ Don't mix hardware and logic code


Remember: Test locally, deploy confidently!