Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## 0.3.1

- `StatboticsTeamEvent.toJson` now serializes `team_name`, so the
round-trip `toJson` advertises through `fromJson` actually preserves the
nickname. Previously the field was decoded but left out of `toJson`, so a
Comment on lines +5 to +7

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Correct the malformed round-trip sentence.

Line 6 is not grammatical and does not clearly describe the serialization contract. Use a direct toJson/fromJson statement.

Proposed wording
 - `StatboticsTeamEvent.toJson` now serializes `team_name`, so the
-  round-trip `toJson` advertises through `fromJson` actually preserves the
+  `toJson`/`fromJson` round trip now preserves the
   nickname.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- `StatboticsTeamEvent.toJson` now serializes `team_name`, so the
round-trip `toJson` advertises through `fromJson` actually preserves the
nickname. Previously the field was decoded but left out of `toJson`, so a
- `StatboticsTeamEvent.toJson` now serializes `team_name`, so the
`toJson`/`fromJson` round trip now preserves the
nickname.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 5 - 7, Rewrite the changelog sentence about
StatboticsTeamEvent.toJson and fromJson so it is grammatical and directly states
that toJson serializes team_name and fromJson preserves it during round trips.
Keep the existing context about nickname preservation without adding unrelated
details.

cached record came back from the on-device last-good cache with an empty
`teamName` even though `/team_events` had carried one. Only `team_name` was at
risk; every other field already round-tripped.

## 0.3.0

- `StatboticsTeamEvent.teamName` exposes the nickname `/team_events` already
Expand Down
1 change: 1 addition & 0 deletions lib/src/statbotics_models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ class StatboticsTeamEvent {
'team': team,
'event': event,
'event_name': eventName,
'team_name': teamName,
'year': year,
'wins': wins,
'losses': losses,
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: statbotics_client
description: A typed Dart client for the Statbotics API v3 (FRC EPA statistics, events, matches). Pure Dart, no Flutter dependency.
version: 0.3.0
version: 0.3.1
repository: https://github.com/Project516/statbotics_client

topics:
Expand Down
52 changes: 52 additions & 0 deletions test/statbotics_client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,58 @@ void main() {
expect(te.teamName, isEmpty);
});

test('StatboticsTeamEvent.toJson round-trips team_name', () {
// toJson advertised a round-trip for the on-device last-good cache, but
// omitted team_name, so a cached StatboticsTeamEvent came back with an
// empty nickname. The cache key Statbotics itself does not store is the
// one event-scoped name source (/teams ignores its event param), so the
// loss was silent.
final original = StatboticsTeamEvent.fromJson(<String, dynamic>{
'team': 3847,
'event': '2026txhou',
'event_name': 'Houston',
'team_name': 'Spectrum',
'year': 2026,
'wins': 1,
'losses': 0,
'ties': 0,
'rank': 7,
'num_teams': 42,
'epa': <String, dynamic>{
'total_points': <String, dynamic>{'mean': 41.2, 'sd': 2.9},
'auto_points': <String, dynamic>{'mean': 9.5},
},
});
final restored = StatboticsTeamEvent.fromJson(original.toJson());
expect(restored.teamName, 'Spectrum');
expect(restored.team, 3847);
expect(restored.event, '2026txhou');
expect(restored.eventName, 'Houston');
expect(restored.year, 2026);
expect(restored.wins, 1);
expect(restored.losses, 0);
expect(restored.ties, 0);
expect(restored.rank, 7);
expect(restored.numTeams, 42);
expect(restored.epa.totalPointsMean, closeTo(41.2, 0.01));
expect(restored.epa.autoPointsMean, closeTo(9.5, 0.01));
});

test('StatboticsTeamEvent.toJson round-trips an empty team_name', () {
final original = StatboticsTeamEvent.fromJson(<String, dynamic>{
'team': 111,
'event': '2026x',
'event_name': 'X',
'year': 2026,
'wins': 0,
'losses': 0,
'ties': 0,
'epa': <String, dynamic>{},
});
final restored = StatboticsTeamEvent.fromJson(original.toJson());
expect(restored.teamName, isEmpty);
});

test('StatboticsTeamEvent.record omits ties when zero', () {
final te = StatboticsTeamEvent.fromJson(<String, dynamic>{
'team': 1234,
Expand Down