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.
This commit is contained in:
173
templates/testing/QUICKSTART.md
Normal file
173
templates/testing/QUICKSTART.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# Quick Reference Guide
|
||||
|
||||
## Project Commands
|
||||
|
||||
### Testing (Windows JRE - No Robot Needed)
|
||||
```bash
|
||||
gradlew test # Run all tests
|
||||
gradlew test --tests MotorCyclerTest # Run specific test
|
||||
```
|
||||
|
||||
### Building for Robot
|
||||
```bash
|
||||
build.bat # Build APK (Windows)
|
||||
./build.sh # Build APK (Linux/Mac)
|
||||
```
|
||||
|
||||
### Deployment
|
||||
```bash
|
||||
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
|
||||
```java
|
||||
// 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
|
||||
```java
|
||||
// Good: Program to interface
|
||||
MotorController motor = new FtcMotorController(dcMotor);
|
||||
|
||||
// Bad: Program to implementation
|
||||
// FtcMotorController motor = new FtcMotorController(dcMotor);
|
||||
```
|
||||
|
||||
### Time-Based State Machine
|
||||
```java
|
||||
// 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
|
||||
```bash
|
||||
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:
|
||||
```java
|
||||
// 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!**
|
||||
Reference in New Issue
Block a user