From 851f1148f3bd95863e25c8cd1b566a1c69429d23 Mon Sep 17 00:00:00 2001 From: Mac Date: Tue, 23 Jun 2026 12:25:09 -0600 Subject: [PATCH] feat(shorebird_code_push_protocol): patch install/download metric envelope (#3824) --- .../lib/shorebird_code_push_protocol.dart | 13 +++ .../messages/get_patch_metric_response.dart | 104 +++++++++++++++++ .../get_app_patch_downloads_parameter2.dart | 37 ++++++ .../get_app_patch_downloads_parameter3.dart | 35 ++++++ .../get_app_patch_installs_parameter2.dart | 37 ++++++ .../get_app_patch_installs_parameter3.dart | 35 ++++++ ...et_release_patch_downloads_parameter2.dart | 37 ++++++ ...et_release_patch_downloads_parameter3.dart | 35 ++++++ ...get_release_patch_installs_parameter2.dart | 37 ++++++ ...get_release_patch_installs_parameter3.dart | 35 ++++++ .../models/patch_metric_breakdown_entry.dart | 90 +++++++++++++++ .../models/patch_metric_current_window.dart | 108 ++++++++++++++++++ .../patch_metric_time_series_entry.dart | 64 +++++++++++ .../lib/src/models/patch_metric_window.dart | 92 +++++++++++++++ .../get_patch_metric_response_test.dart | 35 ++++++ ...t_app_patch_downloads_parameter2_test.dart | 44 +++++++ ...t_app_patch_downloads_parameter3_test.dart | 44 +++++++ ...et_app_patch_installs_parameter2_test.dart | 44 +++++++ ...et_app_patch_installs_parameter3_test.dart | 44 +++++++ ...lease_patch_downloads_parameter2_test.dart | 44 +++++++ ...lease_patch_downloads_parameter3_test.dart | 44 +++++++ ...elease_patch_installs_parameter2_test.dart | 44 +++++++ ...elease_patch_installs_parameter3_test.dart | 44 +++++++ .../patch_metric_breakdown_entry_test.dart | 31 +++++ .../patch_metric_current_window_test.dart | 31 +++++ .../patch_metric_time_series_entry_test.dart | 30 +++++ .../models/patch_metric_window_test.dart | 31 +++++ 27 files changed, 1269 insertions(+) create mode 100644 packages/shorebird_code_push_protocol/lib/src/messages/get_patch_metric_response.dart create mode 100644 packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_downloads_parameter2.dart create mode 100644 packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_downloads_parameter3.dart create mode 100644 packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_installs_parameter2.dart create mode 100644 packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_installs_parameter3.dart create mode 100644 packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_downloads_parameter2.dart create mode 100644 packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_downloads_parameter3.dart create mode 100644 packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_installs_parameter2.dart create mode 100644 packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_installs_parameter3.dart create mode 100644 packages/shorebird_code_push_protocol/lib/src/models/patch_metric_breakdown_entry.dart create mode 100644 packages/shorebird_code_push_protocol/lib/src/models/patch_metric_current_window.dart create mode 100644 packages/shorebird_code_push_protocol/lib/src/models/patch_metric_time_series_entry.dart create mode 100644 packages/shorebird_code_push_protocol/lib/src/models/patch_metric_window.dart create mode 100644 packages/shorebird_code_push_protocol/test/generated/messages/get_patch_metric_response_test.dart create mode 100644 packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_downloads_parameter2_test.dart create mode 100644 packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_downloads_parameter3_test.dart create mode 100644 packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_installs_parameter2_test.dart create mode 100644 packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_installs_parameter3_test.dart create mode 100644 packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_downloads_parameter2_test.dart create mode 100644 packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_downloads_parameter3_test.dart create mode 100644 packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_installs_parameter2_test.dart create mode 100644 packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_installs_parameter3_test.dart create mode 100644 packages/shorebird_code_push_protocol/test/generated/models/patch_metric_breakdown_entry_test.dart create mode 100644 packages/shorebird_code_push_protocol/test/generated/models/patch_metric_current_window_test.dart create mode 100644 packages/shorebird_code_push_protocol/test/generated/models/patch_metric_time_series_entry_test.dart create mode 100644 packages/shorebird_code_push_protocol/test/generated/models/patch_metric_window_test.dart diff --git a/packages/shorebird_code_push_protocol/lib/shorebird_code_push_protocol.dart b/packages/shorebird_code_push_protocol/lib/shorebird_code_push_protocol.dart index 6f970a76..22e2aa71 100644 --- a/packages/shorebird_code_push_protocol/lib/shorebird_code_push_protocol.dart +++ b/packages/shorebird_code_push_protocol/lib/shorebird_code_push_protocol.dart @@ -31,6 +31,7 @@ export 'package:shorebird_code_push_protocol/src/messages/get_organization_apps/ export 'package:shorebird_code_push_protocol/src/messages/get_organization_users/get_organization_users_response.dart'; export 'package:shorebird_code_push_protocol/src/messages/get_organizations_response.dart'; export 'package:shorebird_code_push_protocol/src/messages/get_patch_adoption/get_patch_adoption_response.dart'; +export 'package:shorebird_code_push_protocol/src/messages/get_patch_metric_response.dart'; export 'package:shorebird_code_push_protocol/src/messages/get_release/get_release_response.dart'; export 'package:shorebird_code_push_protocol/src/messages/get_release_artifacts/get_release_artifacts_response.dart'; export 'package:shorebird_code_push_protocol/src/messages/get_release_patches/get_release_patches_response.dart'; @@ -48,7 +49,15 @@ export 'package:shorebird_code_push_protocol/src/models/app.dart'; export 'package:shorebird_code_push_protocol/src/models/app_collaborator_role.dart'; export 'package:shorebird_code_push_protocol/src/models/app_metadata.dart'; export 'package:shorebird_code_push_protocol/src/models/channel.dart'; +export 'package:shorebird_code_push_protocol/src/models/get_app_patch_downloads_parameter2.dart'; +export 'package:shorebird_code_push_protocol/src/models/get_app_patch_downloads_parameter3.dart'; +export 'package:shorebird_code_push_protocol/src/models/get_app_patch_installs_parameter2.dart'; +export 'package:shorebird_code_push_protocol/src/models/get_app_patch_installs_parameter3.dart'; export 'package:shorebird_code_push_protocol/src/models/get_patch_adoption_parameter3.dart'; +export 'package:shorebird_code_push_protocol/src/models/get_release_patch_downloads_parameter2.dart'; +export 'package:shorebird_code_push_protocol/src/models/get_release_patch_downloads_parameter3.dart'; +export 'package:shorebird_code_push_protocol/src/models/get_release_patch_installs_parameter2.dart'; +export 'package:shorebird_code_push_protocol/src/models/get_release_patch_installs_parameter3.dart'; export 'package:shorebird_code_push_protocol/src/models/get_unique_users_parameter2.dart'; export 'package:shorebird_code_push_protocol/src/models/get_unique_users_parameter3.dart'; export 'package:shorebird_code_push_protocol/src/models/latest_release.dart'; @@ -62,6 +71,10 @@ export 'package:shorebird_code_push_protocol/src/models/patch_adoption_entry.dar export 'package:shorebird_code_push_protocol/src/models/patch_adoption_point.dart'; export 'package:shorebird_code_push_protocol/src/models/patch_artifact.dart'; export 'package:shorebird_code_push_protocol/src/models/patch_check_metadata.dart'; +export 'package:shorebird_code_push_protocol/src/models/patch_metric_breakdown_entry.dart'; +export 'package:shorebird_code_push_protocol/src/models/patch_metric_current_window.dart'; +export 'package:shorebird_code_push_protocol/src/models/patch_metric_time_series_entry.dart'; +export 'package:shorebird_code_push_protocol/src/models/patch_metric_window.dart'; export 'package:shorebird_code_push_protocol/src/models/pending_release.dart'; export 'package:shorebird_code_push_protocol/src/models/private_user.dart'; export 'package:shorebird_code_push_protocol/src/models/public_user.dart'; diff --git a/packages/shorebird_code_push_protocol/lib/src/messages/get_patch_metric_response.dart b/packages/shorebird_code_push_protocol/lib/src/messages/get_patch_metric_response.dart new file mode 100644 index 00000000..606b2614 --- /dev/null +++ b/packages/shorebird_code_push_protocol/lib/src/messages/get_patch_metric_response.dart @@ -0,0 +1,104 @@ +import 'package:meta/meta.dart'; +import 'package:shorebird_code_push_protocol/model_helpers.dart'; +import 'package:shorebird_code_push_protocol/src/models/patch_metric_current_window.dart'; +import 'package:shorebird_code_push_protocol/src/models/patch_metric_window.dart'; + +/// {@template get_patch_metric_response} +/// The response body for the patch-installs and patch-downloads metric +/// endpoints (app- and release-scoped): a current/previous envelope. +/// `previous` covers the equal-length window immediately preceding +/// `current`; period-over-period deltas are client display logic over the +/// two totals. `previous` is omitted only when the prior window predates +/// the data floor (no comparison data exists). When it reaches past the +/// plan's metrics-history horizon, `previous` is still present with its +/// total — the delta renders — but without a `time_series` (no +/// prior-window overlay): granular history is the resolution the horizon +/// gates, the scalar comparison is not. +/// {@endtemplate} +@immutable +class GetPatchMetricResponse { + /// {@macro get_patch_metric_response} + const GetPatchMetricResponse({ + required this.asOf, + required this.granularity, + required this.current, + this.previous, + }); + + /// Converts a `Map` to a [GetPatchMetricResponse]. + factory GetPatchMetricResponse.fromJson(Map json) { + return parseFromJson( + 'GetPatchMetricResponse', + json, + () => GetPatchMetricResponse( + asOf: DateTime.parse(json['as_of'] as String), + granularity: checkedKey(json, 'granularity') as String?, + current: PatchMetricCurrentWindow.fromJson( + json['current'] as Map, + ), + previous: PatchMetricWindow.maybeFromJson( + json['previous'] as Map?, + ), + ), + ); + } + + /// Convenience to create a nullable type from a nullable json object. + /// Useful when parsing optional fields. + static GetPatchMetricResponse? maybeFromJson(Map? json) { + if (json == null) { + return null; + } + return GetPatchMetricResponse.fromJson(json); + } + + /// Server's UTC timestamp at the moment the response was constructed. + /// Not a freshness indicator for the underlying data, which is + /// refreshed by an hourly scheduled job and may lag by up to ~1 hour. + final DateTime asOf; + + /// The time-series bucket resolution (`hour`, `day`, or `week`), or + /// null when no time series was requested. Applies to both windows. + final String? granularity; + + /// The `current` window of the patch-metric envelope: the base window atom + /// plus the optional `breakdown`. Only `current` carries a breakdown — no + /// chart renders a previous-window breakdown, so the asymmetry is declared + /// in the contract rather than left as an optional-but-never-populated + /// field. + final PatchMetricCurrentWindow current; + + /// One window of the patch-metric envelope: the summed count over the + /// window's effective range, with a per-bucket series when a `granularity` + /// was requested. This base atom is the full shape of `previous`; + /// `current` extends it (see PatchMetricCurrentWindow). + final PatchMetricWindow? previous; + + /// Converts a [GetPatchMetricResponse] to a `Map`. + Map toJson() { + return { + 'as_of': asOf.toIso8601String(), + 'granularity': granularity, + 'current': current.toJson(), + 'previous': previous?.toJson(), + }; + } + + @override + int get hashCode => Object.hashAll([ + asOf, + granularity, + current, + previous, + ]); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + return other is GetPatchMetricResponse && + asOf == other.asOf && + granularity == other.granularity && + current == other.current && + previous == other.previous; + } +} diff --git a/packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_downloads_parameter2.dart b/packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_downloads_parameter2.dart new file mode 100644 index 00000000..bc91903e --- /dev/null +++ b/packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_downloads_parameter2.dart @@ -0,0 +1,37 @@ +enum GetAppPatchDownloadsParameter2 { + hour._('hour'), + day._('day'), + week._('week'); + + const GetAppPatchDownloadsParameter2._(this.value); + + /// Creates a GetAppPatchDownloadsParameter2 from a json value. + factory GetAppPatchDownloadsParameter2.fromJson(String json) { + return GetAppPatchDownloadsParameter2.values.firstWhere( + (value) => value.value == json, + orElse: () => throw FormatException( + 'Unknown GetAppPatchDownloadsParameter2 value: $json', + ), + ); + } + + /// Convenience to create a nullable type from a nullable json value. + /// Useful when parsing optional fields. + static GetAppPatchDownloadsParameter2? maybeFromJson(String? json) { + if (json == null) { + return null; + } + return GetAppPatchDownloadsParameter2.fromJson(json); + } + + /// The value of the enum. This is the exact value + /// from the OpenAPI spec and will be used for network transport. + final String value; + + /// Converts the enum to its json value. + String toJson() => value; + + /// Returns the string form of the enum. + @override + String toString() => value; +} diff --git a/packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_downloads_parameter3.dart b/packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_downloads_parameter3.dart new file mode 100644 index 00000000..ec6ac80d --- /dev/null +++ b/packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_downloads_parameter3.dart @@ -0,0 +1,35 @@ +enum GetAppPatchDownloadsParameter3 { + release._('release'); + + const GetAppPatchDownloadsParameter3._(this.value); + + /// Creates a GetAppPatchDownloadsParameter3 from a json value. + factory GetAppPatchDownloadsParameter3.fromJson(String json) { + return GetAppPatchDownloadsParameter3.values.firstWhere( + (value) => value.value == json, + orElse: () => throw FormatException( + 'Unknown GetAppPatchDownloadsParameter3 value: $json', + ), + ); + } + + /// Convenience to create a nullable type from a nullable json value. + /// Useful when parsing optional fields. + static GetAppPatchDownloadsParameter3? maybeFromJson(String? json) { + if (json == null) { + return null; + } + return GetAppPatchDownloadsParameter3.fromJson(json); + } + + /// The value of the enum. This is the exact value + /// from the OpenAPI spec and will be used for network transport. + final String value; + + /// Converts the enum to its json value. + String toJson() => value; + + /// Returns the string form of the enum. + @override + String toString() => value; +} diff --git a/packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_installs_parameter2.dart b/packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_installs_parameter2.dart new file mode 100644 index 00000000..54f79e0f --- /dev/null +++ b/packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_installs_parameter2.dart @@ -0,0 +1,37 @@ +enum GetAppPatchInstallsParameter2 { + hour._('hour'), + day._('day'), + week._('week'); + + const GetAppPatchInstallsParameter2._(this.value); + + /// Creates a GetAppPatchInstallsParameter2 from a json value. + factory GetAppPatchInstallsParameter2.fromJson(String json) { + return GetAppPatchInstallsParameter2.values.firstWhere( + (value) => value.value == json, + orElse: () => throw FormatException( + 'Unknown GetAppPatchInstallsParameter2 value: $json', + ), + ); + } + + /// Convenience to create a nullable type from a nullable json value. + /// Useful when parsing optional fields. + static GetAppPatchInstallsParameter2? maybeFromJson(String? json) { + if (json == null) { + return null; + } + return GetAppPatchInstallsParameter2.fromJson(json); + } + + /// The value of the enum. This is the exact value + /// from the OpenAPI spec and will be used for network transport. + final String value; + + /// Converts the enum to its json value. + String toJson() => value; + + /// Returns the string form of the enum. + @override + String toString() => value; +} diff --git a/packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_installs_parameter3.dart b/packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_installs_parameter3.dart new file mode 100644 index 00000000..9a620112 --- /dev/null +++ b/packages/shorebird_code_push_protocol/lib/src/models/get_app_patch_installs_parameter3.dart @@ -0,0 +1,35 @@ +enum GetAppPatchInstallsParameter3 { + release._('release'); + + const GetAppPatchInstallsParameter3._(this.value); + + /// Creates a GetAppPatchInstallsParameter3 from a json value. + factory GetAppPatchInstallsParameter3.fromJson(String json) { + return GetAppPatchInstallsParameter3.values.firstWhere( + (value) => value.value == json, + orElse: () => throw FormatException( + 'Unknown GetAppPatchInstallsParameter3 value: $json', + ), + ); + } + + /// Convenience to create a nullable type from a nullable json value. + /// Useful when parsing optional fields. + static GetAppPatchInstallsParameter3? maybeFromJson(String? json) { + if (json == null) { + return null; + } + return GetAppPatchInstallsParameter3.fromJson(json); + } + + /// The value of the enum. This is the exact value + /// from the OpenAPI spec and will be used for network transport. + final String value; + + /// Converts the enum to its json value. + String toJson() => value; + + /// Returns the string form of the enum. + @override + String toString() => value; +} diff --git a/packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_downloads_parameter2.dart b/packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_downloads_parameter2.dart new file mode 100644 index 00000000..1bbd5a66 --- /dev/null +++ b/packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_downloads_parameter2.dart @@ -0,0 +1,37 @@ +enum GetReleasePatchDownloadsParameter2 { + hour._('hour'), + day._('day'), + week._('week'); + + const GetReleasePatchDownloadsParameter2._(this.value); + + /// Creates a GetReleasePatchDownloadsParameter2 from a json value. + factory GetReleasePatchDownloadsParameter2.fromJson(String json) { + return GetReleasePatchDownloadsParameter2.values.firstWhere( + (value) => value.value == json, + orElse: () => throw FormatException( + 'Unknown GetReleasePatchDownloadsParameter2 value: $json', + ), + ); + } + + /// Convenience to create a nullable type from a nullable json value. + /// Useful when parsing optional fields. + static GetReleasePatchDownloadsParameter2? maybeFromJson(String? json) { + if (json == null) { + return null; + } + return GetReleasePatchDownloadsParameter2.fromJson(json); + } + + /// The value of the enum. This is the exact value + /// from the OpenAPI spec and will be used for network transport. + final String value; + + /// Converts the enum to its json value. + String toJson() => value; + + /// Returns the string form of the enum. + @override + String toString() => value; +} diff --git a/packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_downloads_parameter3.dart b/packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_downloads_parameter3.dart new file mode 100644 index 00000000..e011735b --- /dev/null +++ b/packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_downloads_parameter3.dart @@ -0,0 +1,35 @@ +enum GetReleasePatchDownloadsParameter3 { + patch._('patch'); + + const GetReleasePatchDownloadsParameter3._(this.value); + + /// Creates a GetReleasePatchDownloadsParameter3 from a json value. + factory GetReleasePatchDownloadsParameter3.fromJson(String json) { + return GetReleasePatchDownloadsParameter3.values.firstWhere( + (value) => value.value == json, + orElse: () => throw FormatException( + 'Unknown GetReleasePatchDownloadsParameter3 value: $json', + ), + ); + } + + /// Convenience to create a nullable type from a nullable json value. + /// Useful when parsing optional fields. + static GetReleasePatchDownloadsParameter3? maybeFromJson(String? json) { + if (json == null) { + return null; + } + return GetReleasePatchDownloadsParameter3.fromJson(json); + } + + /// The value of the enum. This is the exact value + /// from the OpenAPI spec and will be used for network transport. + final String value; + + /// Converts the enum to its json value. + String toJson() => value; + + /// Returns the string form of the enum. + @override + String toString() => value; +} diff --git a/packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_installs_parameter2.dart b/packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_installs_parameter2.dart new file mode 100644 index 00000000..a6a7d6a9 --- /dev/null +++ b/packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_installs_parameter2.dart @@ -0,0 +1,37 @@ +enum GetReleasePatchInstallsParameter2 { + hour._('hour'), + day._('day'), + week._('week'); + + const GetReleasePatchInstallsParameter2._(this.value); + + /// Creates a GetReleasePatchInstallsParameter2 from a json value. + factory GetReleasePatchInstallsParameter2.fromJson(String json) { + return GetReleasePatchInstallsParameter2.values.firstWhere( + (value) => value.value == json, + orElse: () => throw FormatException( + 'Unknown GetReleasePatchInstallsParameter2 value: $json', + ), + ); + } + + /// Convenience to create a nullable type from a nullable json value. + /// Useful when parsing optional fields. + static GetReleasePatchInstallsParameter2? maybeFromJson(String? json) { + if (json == null) { + return null; + } + return GetReleasePatchInstallsParameter2.fromJson(json); + } + + /// The value of the enum. This is the exact value + /// from the OpenAPI spec and will be used for network transport. + final String value; + + /// Converts the enum to its json value. + String toJson() => value; + + /// Returns the string form of the enum. + @override + String toString() => value; +} diff --git a/packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_installs_parameter3.dart b/packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_installs_parameter3.dart new file mode 100644 index 00000000..a23bdbec --- /dev/null +++ b/packages/shorebird_code_push_protocol/lib/src/models/get_release_patch_installs_parameter3.dart @@ -0,0 +1,35 @@ +enum GetReleasePatchInstallsParameter3 { + patch._('patch'); + + const GetReleasePatchInstallsParameter3._(this.value); + + /// Creates a GetReleasePatchInstallsParameter3 from a json value. + factory GetReleasePatchInstallsParameter3.fromJson(String json) { + return GetReleasePatchInstallsParameter3.values.firstWhere( + (value) => value.value == json, + orElse: () => throw FormatException( + 'Unknown GetReleasePatchInstallsParameter3 value: $json', + ), + ); + } + + /// Convenience to create a nullable type from a nullable json value. + /// Useful when parsing optional fields. + static GetReleasePatchInstallsParameter3? maybeFromJson(String? json) { + if (json == null) { + return null; + } + return GetReleasePatchInstallsParameter3.fromJson(json); + } + + /// The value of the enum. This is the exact value + /// from the OpenAPI spec and will be used for network transport. + final String value; + + /// Converts the enum to its json value. + String toJson() => value; + + /// Returns the string form of the enum. + @override + String toString() => value; +} diff --git a/packages/shorebird_code_push_protocol/lib/src/models/patch_metric_breakdown_entry.dart b/packages/shorebird_code_push_protocol/lib/src/models/patch_metric_breakdown_entry.dart new file mode 100644 index 00000000..a1236c2f --- /dev/null +++ b/packages/shorebird_code_push_protocol/lib/src/models/patch_metric_breakdown_entry.dart @@ -0,0 +1,90 @@ +import 'package:meta/meta.dart'; +import 'package:shorebird_code_push_protocol/model_helpers.dart'; +import 'package:shorebird_code_push_protocol/src/models/patch_metric_time_series_entry.dart'; + +/// {@template patch_metric_breakdown_entry} +/// A patch metric for one value of the `group_by` dimension (one release +/// at app scope, or one patch at release scope), optionally with its own +/// time series. +/// {@endtemplate} +@immutable +class PatchMetricBreakdownEntry { + /// {@macro patch_metric_breakdown_entry} + const PatchMetricBreakdownEntry({ + required this.groupBy, + required this.groupValue, + required this.count, + this.timeSeries, + }); + + /// Converts a `Map` to a [PatchMetricBreakdownEntry]. + factory PatchMetricBreakdownEntry.fromJson(Map json) { + return parseFromJson( + 'PatchMetricBreakdownEntry', + json, + () => PatchMetricBreakdownEntry( + groupBy: json['group_by'] as String, + groupValue: json['group_value'] as String, + count: json['count'] as int, + timeSeries: (json['time_series'] as List?) + ?.map( + (e) => PatchMetricTimeSeriesEntry.fromJson( + e as Map, + ), + ) + .toList(), + ), + ); + } + + /// Convenience to create a nullable type from a nullable json object. + /// Useful when parsing optional fields. + static PatchMetricBreakdownEntry? maybeFromJson(Map? json) { + if (json == null) { + return null; + } + return PatchMetricBreakdownEntry.fromJson(json); + } + + /// The dimension this entry breaks down by ("release" or "patch"). + final String groupBy; + + /// The value within `group_by`: the release version, or the patch + /// number as a string. + final String groupValue; + + /// The summed count for this group over the window. + final int count; + + /// Per-bucket series for this group, present only when a `granularity` + /// was requested; otherwise null. + final List? timeSeries; + + /// Converts a [PatchMetricBreakdownEntry] to a `Map`. + Map toJson() { + return { + 'group_by': groupBy, + 'group_value': groupValue, + 'count': count, + 'time_series': timeSeries?.map((e) => e.toJson()).toList(), + }; + } + + @override + int get hashCode => Object.hashAll([ + groupBy, + groupValue, + count, + listHash(timeSeries), + ]); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + return other is PatchMetricBreakdownEntry && + groupBy == other.groupBy && + groupValue == other.groupValue && + count == other.count && + listsEqual(timeSeries, other.timeSeries); + } +} diff --git a/packages/shorebird_code_push_protocol/lib/src/models/patch_metric_current_window.dart b/packages/shorebird_code_push_protocol/lib/src/models/patch_metric_current_window.dart new file mode 100644 index 00000000..049534c7 --- /dev/null +++ b/packages/shorebird_code_push_protocol/lib/src/models/patch_metric_current_window.dart @@ -0,0 +1,108 @@ +import 'package:meta/meta.dart'; +import 'package:shorebird_code_push_protocol/model_helpers.dart'; +import 'package:shorebird_code_push_protocol/src/models/metrics_range.dart'; +import 'package:shorebird_code_push_protocol/src/models/patch_metric_breakdown_entry.dart'; +import 'package:shorebird_code_push_protocol/src/models/patch_metric_time_series_entry.dart'; + +/// {@template patch_metric_current_window} +/// The `current` window of the patch-metric envelope: the base window atom +/// plus the optional `breakdown`. Only `current` carries a breakdown — no +/// chart renders a previous-window breakdown, so the asymmetry is declared +/// in the contract rather than left as an optional-but-never-populated +/// field. +/// {@endtemplate} +@immutable +class PatchMetricCurrentWindow { + /// {@macro patch_metric_current_window} + const PatchMetricCurrentWindow({ + required this.count, + required this.range, + this.timeSeries, + this.breakdown, + }); + + /// Converts a `Map` to a [PatchMetricCurrentWindow]. + factory PatchMetricCurrentWindow.fromJson(Map json) { + return parseFromJson( + 'PatchMetricCurrentWindow', + json, + () => PatchMetricCurrentWindow( + count: json['count'] as int, + range: MetricsRange.fromJson(json['range'] as Map), + timeSeries: (json['time_series'] as List?) + ?.map( + (e) => PatchMetricTimeSeriesEntry.fromJson( + e as Map, + ), + ) + .toList(), + breakdown: (json['breakdown'] as List?) + ?.map( + (e) => + PatchMetricBreakdownEntry.fromJson(e as Map), + ) + .toList(), + ), + ); + } + + /// Convenience to create a nullable type from a nullable json object. + /// Useful when parsing optional fields. + static PatchMetricCurrentWindow? maybeFromJson(Map? json) { + if (json == null) { + return null; + } + return PatchMetricCurrentWindow.fromJson(json); + } + + /// The summed count (installs or downloads) over this window. Unlike + /// the HLL-based metrics, per-bucket `time_series` values sum to this + /// total. + final int count; + + /// The effective (post-default, post-clamp) window a metrics response — + /// or one window of a metrics envelope — covers. Always echoed by the + /// server; clients must treat it as authoritative rather than reusing + /// the requested range. + final MetricsRange range; + + /// Per-bucket series for this window, present only when a + /// `granularity` was requested; otherwise null. On `previous`, also + /// null when the prior window reaches past the plan's metrics-history + /// horizon (the total is still present — only the granular overlay is + /// withheld). Empty buckets are omitted — gap-fill against this + /// window's `range`. + final List? timeSeries; + + /// Per-group counts for this window, present only when a + /// `group_by` was requested; otherwise null. + final List? breakdown; + + /// Converts a [PatchMetricCurrentWindow] to a `Map`. + Map toJson() { + return { + 'count': count, + 'range': range.toJson(), + 'time_series': timeSeries?.map((e) => e.toJson()).toList(), + 'breakdown': breakdown?.map((e) => e.toJson()).toList(), + }; + } + + @override + int get hashCode => Object.hashAll([ + count, + range, + listHash(timeSeries), + listHash(breakdown), + ]); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + return other is PatchMetricCurrentWindow && + count == other.count && + range == other.range && + listsEqual(timeSeries, other.timeSeries) && + listsEqual(breakdown, other.breakdown); + } +} diff --git a/packages/shorebird_code_push_protocol/lib/src/models/patch_metric_time_series_entry.dart b/packages/shorebird_code_push_protocol/lib/src/models/patch_metric_time_series_entry.dart new file mode 100644 index 00000000..5dd4b5d3 --- /dev/null +++ b/packages/shorebird_code_push_protocol/lib/src/models/patch_metric_time_series_entry.dart @@ -0,0 +1,64 @@ +import 'package:meta/meta.dart'; +import 'package:shorebird_code_push_protocol/model_helpers.dart'; + +/// {@template patch_metric_time_series_entry} +/// One bucket of a patch-metric time series: the summed count (installs or +/// downloads, per the endpoint) in the bucket starting at `period`. +/// {@endtemplate} +@immutable +class PatchMetricTimeSeriesEntry { + /// {@macro patch_metric_time_series_entry} + const PatchMetricTimeSeriesEntry({ + required this.period, + required this.count, + }); + + /// Converts a `Map` to a [PatchMetricTimeSeriesEntry]. + factory PatchMetricTimeSeriesEntry.fromJson(Map json) { + return parseFromJson( + 'PatchMetricTimeSeriesEntry', + json, + () => PatchMetricTimeSeriesEntry( + period: DateTime.parse(json['period'] as String), + count: json['count'] as int, + ), + ); + } + + /// Convenience to create a nullable type from a nullable json object. + /// Useful when parsing optional fields. + static PatchMetricTimeSeriesEntry? maybeFromJson(Map? json) { + if (json == null) { + return null; + } + return PatchMetricTimeSeriesEntry.fromJson(json); + } + + /// The bucket start (UTC). + final DateTime period; + + /// The summed count in this bucket. + final int count; + + /// Converts a [PatchMetricTimeSeriesEntry] to a `Map`. + Map toJson() { + return { + 'period': period.toIso8601String(), + 'count': count, + }; + } + + @override + int get hashCode => Object.hashAll([ + period, + count, + ]); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + return other is PatchMetricTimeSeriesEntry && + period == other.period && + count == other.count; + } +} diff --git a/packages/shorebird_code_push_protocol/lib/src/models/patch_metric_window.dart b/packages/shorebird_code_push_protocol/lib/src/models/patch_metric_window.dart new file mode 100644 index 00000000..f6fe2caf --- /dev/null +++ b/packages/shorebird_code_push_protocol/lib/src/models/patch_metric_window.dart @@ -0,0 +1,92 @@ +import 'package:meta/meta.dart'; +import 'package:shorebird_code_push_protocol/model_helpers.dart'; +import 'package:shorebird_code_push_protocol/src/models/metrics_range.dart'; +import 'package:shorebird_code_push_protocol/src/models/patch_metric_time_series_entry.dart'; + +/// {@template patch_metric_window} +/// One window of the patch-metric envelope: the summed count over the +/// window's effective range, with a per-bucket series when a `granularity` +/// was requested. This base atom is the full shape of `previous`; +/// `current` extends it (see PatchMetricCurrentWindow). +/// {@endtemplate} +@immutable +class PatchMetricWindow { + /// {@macro patch_metric_window} + const PatchMetricWindow({ + required this.count, + required this.range, + this.timeSeries, + }); + + /// Converts a `Map` to a [PatchMetricWindow]. + factory PatchMetricWindow.fromJson(Map json) { + return parseFromJson( + 'PatchMetricWindow', + json, + () => PatchMetricWindow( + count: json['count'] as int, + range: MetricsRange.fromJson(json['range'] as Map), + timeSeries: (json['time_series'] as List?) + ?.map( + (e) => PatchMetricTimeSeriesEntry.fromJson( + e as Map, + ), + ) + .toList(), + ), + ); + } + + /// Convenience to create a nullable type from a nullable json object. + /// Useful when parsing optional fields. + static PatchMetricWindow? maybeFromJson(Map? json) { + if (json == null) { + return null; + } + return PatchMetricWindow.fromJson(json); + } + + /// The summed count (installs or downloads) over this window. Unlike + /// the HLL-based metrics, per-bucket `time_series` values sum to this + /// total. + final int count; + + /// The effective (post-default, post-clamp) window a metrics response — + /// or one window of a metrics envelope — covers. Always echoed by the + /// server; clients must treat it as authoritative rather than reusing + /// the requested range. + final MetricsRange range; + + /// Per-bucket series for this window, present only when a + /// `granularity` was requested; otherwise null. On `previous`, also + /// null when the prior window reaches past the plan's metrics-history + /// horizon (the total is still present — only the granular overlay is + /// withheld). Empty buckets are omitted — gap-fill against this + /// window's `range`. + final List? timeSeries; + + /// Converts a [PatchMetricWindow] to a `Map`. + Map toJson() { + return { + 'count': count, + 'range': range.toJson(), + 'time_series': timeSeries?.map((e) => e.toJson()).toList(), + }; + } + + @override + int get hashCode => Object.hashAll([ + count, + range, + listHash(timeSeries), + ]); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + return other is PatchMetricWindow && + count == other.count && + range == other.range && + listsEqual(timeSeries, other.timeSeries); + } +} diff --git a/packages/shorebird_code_push_protocol/test/generated/messages/get_patch_metric_response_test.dart b/packages/shorebird_code_push_protocol/test/generated/messages/get_patch_metric_response_test.dart new file mode 100644 index 00000000..b4a99253 --- /dev/null +++ b/packages/shorebird_code_push_protocol/test/generated/messages/get_patch_metric_response_test.dart @@ -0,0 +1,35 @@ +// GENERATED — do not hand-edit. +import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart'; +import 'package:test/test.dart'; + +void main() { + group('GetPatchMetricResponse', () { + test('round-trips via maybeFromJson/toJson', () { + final instance = GetPatchMetricResponse( + asOf: DateTime.utc(2024), + granularity: 'example', + current: PatchMetricCurrentWindow( + count: 0, + range: MetricsRange( + start: DateTime.utc(2024), + end: DateTime.utc(2024), + ), + ), + ); + final parsed = GetPatchMetricResponse.maybeFromJson(instance.toJson()); + expect(parsed, equals(instance)); + expect(parsed.hashCode, equals(instance.hashCode)); + }); + + test('maybeFromJson returns null on null input', () { + expect(GetPatchMetricResponse.maybeFromJson(null), isNull); + }); + + test('maybeFromJson throws FormatException on invalid input', () { + expect( + () => GetPatchMetricResponse.maybeFromJson({}), + throwsFormatException, + ); + }); + }); +} diff --git a/packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_downloads_parameter2_test.dart b/packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_downloads_parameter2_test.dart new file mode 100644 index 00000000..f6e3691d --- /dev/null +++ b/packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_downloads_parameter2_test.dart @@ -0,0 +1,44 @@ +// GENERATED — do not hand-edit. +import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart'; +import 'package:test/test.dart'; + +void main() { + group('GetAppPatchDownloadsParameter2', () { + test('round-trips via maybeFromJson/toJson', () { + final instance = GetAppPatchDownloadsParameter2.values.first; + final parsed = GetAppPatchDownloadsParameter2.maybeFromJson( + instance.toJson(), + ); + expect(parsed, equals(instance)); + expect(parsed.hashCode, equals(instance.hashCode)); + }); + + test('maybeFromJson returns null on null input', () { + expect(GetAppPatchDownloadsParameter2.maybeFromJson(null), isNull); + }); + + test('maybeFromJson throws FormatException on invalid input', () { + expect( + () => GetAppPatchDownloadsParameter2.maybeFromJson( + '__invalid_enum_value__', + ), + throwsFormatException, + ); + }); + + test('toString matches toJson for every value', () { + for (final value in GetAppPatchDownloadsParameter2.values) { + expect(value.toString(), equals(value.toJson())); + } + }); + + test('fromJson round-trips every value', () { + for (final value in GetAppPatchDownloadsParameter2.values) { + expect( + GetAppPatchDownloadsParameter2.fromJson(value.toJson()), + equals(value), + ); + } + }); + }); +} diff --git a/packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_downloads_parameter3_test.dart b/packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_downloads_parameter3_test.dart new file mode 100644 index 00000000..5f3f8c1d --- /dev/null +++ b/packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_downloads_parameter3_test.dart @@ -0,0 +1,44 @@ +// GENERATED — do not hand-edit. +import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart'; +import 'package:test/test.dart'; + +void main() { + group('GetAppPatchDownloadsParameter3', () { + test('round-trips via maybeFromJson/toJson', () { + final instance = GetAppPatchDownloadsParameter3.values.first; + final parsed = GetAppPatchDownloadsParameter3.maybeFromJson( + instance.toJson(), + ); + expect(parsed, equals(instance)); + expect(parsed.hashCode, equals(instance.hashCode)); + }); + + test('maybeFromJson returns null on null input', () { + expect(GetAppPatchDownloadsParameter3.maybeFromJson(null), isNull); + }); + + test('maybeFromJson throws FormatException on invalid input', () { + expect( + () => GetAppPatchDownloadsParameter3.maybeFromJson( + '__invalid_enum_value__', + ), + throwsFormatException, + ); + }); + + test('toString matches toJson for every value', () { + for (final value in GetAppPatchDownloadsParameter3.values) { + expect(value.toString(), equals(value.toJson())); + } + }); + + test('fromJson round-trips every value', () { + for (final value in GetAppPatchDownloadsParameter3.values) { + expect( + GetAppPatchDownloadsParameter3.fromJson(value.toJson()), + equals(value), + ); + } + }); + }); +} diff --git a/packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_installs_parameter2_test.dart b/packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_installs_parameter2_test.dart new file mode 100644 index 00000000..756af06b --- /dev/null +++ b/packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_installs_parameter2_test.dart @@ -0,0 +1,44 @@ +// GENERATED — do not hand-edit. +import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart'; +import 'package:test/test.dart'; + +void main() { + group('GetAppPatchInstallsParameter2', () { + test('round-trips via maybeFromJson/toJson', () { + final instance = GetAppPatchInstallsParameter2.values.first; + final parsed = GetAppPatchInstallsParameter2.maybeFromJson( + instance.toJson(), + ); + expect(parsed, equals(instance)); + expect(parsed.hashCode, equals(instance.hashCode)); + }); + + test('maybeFromJson returns null on null input', () { + expect(GetAppPatchInstallsParameter2.maybeFromJson(null), isNull); + }); + + test('maybeFromJson throws FormatException on invalid input', () { + expect( + () => GetAppPatchInstallsParameter2.maybeFromJson( + '__invalid_enum_value__', + ), + throwsFormatException, + ); + }); + + test('toString matches toJson for every value', () { + for (final value in GetAppPatchInstallsParameter2.values) { + expect(value.toString(), equals(value.toJson())); + } + }); + + test('fromJson round-trips every value', () { + for (final value in GetAppPatchInstallsParameter2.values) { + expect( + GetAppPatchInstallsParameter2.fromJson(value.toJson()), + equals(value), + ); + } + }); + }); +} diff --git a/packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_installs_parameter3_test.dart b/packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_installs_parameter3_test.dart new file mode 100644 index 00000000..8117adf4 --- /dev/null +++ b/packages/shorebird_code_push_protocol/test/generated/models/get_app_patch_installs_parameter3_test.dart @@ -0,0 +1,44 @@ +// GENERATED — do not hand-edit. +import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart'; +import 'package:test/test.dart'; + +void main() { + group('GetAppPatchInstallsParameter3', () { + test('round-trips via maybeFromJson/toJson', () { + final instance = GetAppPatchInstallsParameter3.values.first; + final parsed = GetAppPatchInstallsParameter3.maybeFromJson( + instance.toJson(), + ); + expect(parsed, equals(instance)); + expect(parsed.hashCode, equals(instance.hashCode)); + }); + + test('maybeFromJson returns null on null input', () { + expect(GetAppPatchInstallsParameter3.maybeFromJson(null), isNull); + }); + + test('maybeFromJson throws FormatException on invalid input', () { + expect( + () => GetAppPatchInstallsParameter3.maybeFromJson( + '__invalid_enum_value__', + ), + throwsFormatException, + ); + }); + + test('toString matches toJson for every value', () { + for (final value in GetAppPatchInstallsParameter3.values) { + expect(value.toString(), equals(value.toJson())); + } + }); + + test('fromJson round-trips every value', () { + for (final value in GetAppPatchInstallsParameter3.values) { + expect( + GetAppPatchInstallsParameter3.fromJson(value.toJson()), + equals(value), + ); + } + }); + }); +} diff --git a/packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_downloads_parameter2_test.dart b/packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_downloads_parameter2_test.dart new file mode 100644 index 00000000..ebe24eec --- /dev/null +++ b/packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_downloads_parameter2_test.dart @@ -0,0 +1,44 @@ +// GENERATED — do not hand-edit. +import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart'; +import 'package:test/test.dart'; + +void main() { + group('GetReleasePatchDownloadsParameter2', () { + test('round-trips via maybeFromJson/toJson', () { + final instance = GetReleasePatchDownloadsParameter2.values.first; + final parsed = GetReleasePatchDownloadsParameter2.maybeFromJson( + instance.toJson(), + ); + expect(parsed, equals(instance)); + expect(parsed.hashCode, equals(instance.hashCode)); + }); + + test('maybeFromJson returns null on null input', () { + expect(GetReleasePatchDownloadsParameter2.maybeFromJson(null), isNull); + }); + + test('maybeFromJson throws FormatException on invalid input', () { + expect( + () => GetReleasePatchDownloadsParameter2.maybeFromJson( + '__invalid_enum_value__', + ), + throwsFormatException, + ); + }); + + test('toString matches toJson for every value', () { + for (final value in GetReleasePatchDownloadsParameter2.values) { + expect(value.toString(), equals(value.toJson())); + } + }); + + test('fromJson round-trips every value', () { + for (final value in GetReleasePatchDownloadsParameter2.values) { + expect( + GetReleasePatchDownloadsParameter2.fromJson(value.toJson()), + equals(value), + ); + } + }); + }); +} diff --git a/packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_downloads_parameter3_test.dart b/packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_downloads_parameter3_test.dart new file mode 100644 index 00000000..40c48f23 --- /dev/null +++ b/packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_downloads_parameter3_test.dart @@ -0,0 +1,44 @@ +// GENERATED — do not hand-edit. +import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart'; +import 'package:test/test.dart'; + +void main() { + group('GetReleasePatchDownloadsParameter3', () { + test('round-trips via maybeFromJson/toJson', () { + final instance = GetReleasePatchDownloadsParameter3.values.first; + final parsed = GetReleasePatchDownloadsParameter3.maybeFromJson( + instance.toJson(), + ); + expect(parsed, equals(instance)); + expect(parsed.hashCode, equals(instance.hashCode)); + }); + + test('maybeFromJson returns null on null input', () { + expect(GetReleasePatchDownloadsParameter3.maybeFromJson(null), isNull); + }); + + test('maybeFromJson throws FormatException on invalid input', () { + expect( + () => GetReleasePatchDownloadsParameter3.maybeFromJson( + '__invalid_enum_value__', + ), + throwsFormatException, + ); + }); + + test('toString matches toJson for every value', () { + for (final value in GetReleasePatchDownloadsParameter3.values) { + expect(value.toString(), equals(value.toJson())); + } + }); + + test('fromJson round-trips every value', () { + for (final value in GetReleasePatchDownloadsParameter3.values) { + expect( + GetReleasePatchDownloadsParameter3.fromJson(value.toJson()), + equals(value), + ); + } + }); + }); +} diff --git a/packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_installs_parameter2_test.dart b/packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_installs_parameter2_test.dart new file mode 100644 index 00000000..b3a26672 --- /dev/null +++ b/packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_installs_parameter2_test.dart @@ -0,0 +1,44 @@ +// GENERATED — do not hand-edit. +import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart'; +import 'package:test/test.dart'; + +void main() { + group('GetReleasePatchInstallsParameter2', () { + test('round-trips via maybeFromJson/toJson', () { + final instance = GetReleasePatchInstallsParameter2.values.first; + final parsed = GetReleasePatchInstallsParameter2.maybeFromJson( + instance.toJson(), + ); + expect(parsed, equals(instance)); + expect(parsed.hashCode, equals(instance.hashCode)); + }); + + test('maybeFromJson returns null on null input', () { + expect(GetReleasePatchInstallsParameter2.maybeFromJson(null), isNull); + }); + + test('maybeFromJson throws FormatException on invalid input', () { + expect( + () => GetReleasePatchInstallsParameter2.maybeFromJson( + '__invalid_enum_value__', + ), + throwsFormatException, + ); + }); + + test('toString matches toJson for every value', () { + for (final value in GetReleasePatchInstallsParameter2.values) { + expect(value.toString(), equals(value.toJson())); + } + }); + + test('fromJson round-trips every value', () { + for (final value in GetReleasePatchInstallsParameter2.values) { + expect( + GetReleasePatchInstallsParameter2.fromJson(value.toJson()), + equals(value), + ); + } + }); + }); +} diff --git a/packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_installs_parameter3_test.dart b/packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_installs_parameter3_test.dart new file mode 100644 index 00000000..41540f90 --- /dev/null +++ b/packages/shorebird_code_push_protocol/test/generated/models/get_release_patch_installs_parameter3_test.dart @@ -0,0 +1,44 @@ +// GENERATED — do not hand-edit. +import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart'; +import 'package:test/test.dart'; + +void main() { + group('GetReleasePatchInstallsParameter3', () { + test('round-trips via maybeFromJson/toJson', () { + final instance = GetReleasePatchInstallsParameter3.values.first; + final parsed = GetReleasePatchInstallsParameter3.maybeFromJson( + instance.toJson(), + ); + expect(parsed, equals(instance)); + expect(parsed.hashCode, equals(instance.hashCode)); + }); + + test('maybeFromJson returns null on null input', () { + expect(GetReleasePatchInstallsParameter3.maybeFromJson(null), isNull); + }); + + test('maybeFromJson throws FormatException on invalid input', () { + expect( + () => GetReleasePatchInstallsParameter3.maybeFromJson( + '__invalid_enum_value__', + ), + throwsFormatException, + ); + }); + + test('toString matches toJson for every value', () { + for (final value in GetReleasePatchInstallsParameter3.values) { + expect(value.toString(), equals(value.toJson())); + } + }); + + test('fromJson round-trips every value', () { + for (final value in GetReleasePatchInstallsParameter3.values) { + expect( + GetReleasePatchInstallsParameter3.fromJson(value.toJson()), + equals(value), + ); + } + }); + }); +} diff --git a/packages/shorebird_code_push_protocol/test/generated/models/patch_metric_breakdown_entry_test.dart b/packages/shorebird_code_push_protocol/test/generated/models/patch_metric_breakdown_entry_test.dart new file mode 100644 index 00000000..6c1fa3e5 --- /dev/null +++ b/packages/shorebird_code_push_protocol/test/generated/models/patch_metric_breakdown_entry_test.dart @@ -0,0 +1,31 @@ +// GENERATED — do not hand-edit. +import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart'; +import 'package:test/test.dart'; + +void main() { + group('PatchMetricBreakdownEntry', () { + test('round-trips via maybeFromJson/toJson', () { + final instance = PatchMetricBreakdownEntry( + groupBy: 'example', + groupValue: 'example', + count: 0, + ); + final parsed = PatchMetricBreakdownEntry.maybeFromJson( + instance.toJson(), + ); + expect(parsed, equals(instance)); + expect(parsed.hashCode, equals(instance.hashCode)); + }); + + test('maybeFromJson returns null on null input', () { + expect(PatchMetricBreakdownEntry.maybeFromJson(null), isNull); + }); + + test('maybeFromJson throws FormatException on invalid input', () { + expect( + () => PatchMetricBreakdownEntry.maybeFromJson({}), + throwsFormatException, + ); + }); + }); +} diff --git a/packages/shorebird_code_push_protocol/test/generated/models/patch_metric_current_window_test.dart b/packages/shorebird_code_push_protocol/test/generated/models/patch_metric_current_window_test.dart new file mode 100644 index 00000000..bc41d3fc --- /dev/null +++ b/packages/shorebird_code_push_protocol/test/generated/models/patch_metric_current_window_test.dart @@ -0,0 +1,31 @@ +// GENERATED — do not hand-edit. +import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart'; +import 'package:test/test.dart'; + +void main() { + group('PatchMetricCurrentWindow', () { + test('round-trips via maybeFromJson/toJson', () { + final instance = PatchMetricCurrentWindow( + count: 0, + range: MetricsRange( + start: DateTime.utc(2024), + end: DateTime.utc(2024), + ), + ); + final parsed = PatchMetricCurrentWindow.maybeFromJson(instance.toJson()); + expect(parsed, equals(instance)); + expect(parsed.hashCode, equals(instance.hashCode)); + }); + + test('maybeFromJson returns null on null input', () { + expect(PatchMetricCurrentWindow.maybeFromJson(null), isNull); + }); + + test('maybeFromJson throws FormatException on invalid input', () { + expect( + () => PatchMetricCurrentWindow.maybeFromJson({}), + throwsFormatException, + ); + }); + }); +} diff --git a/packages/shorebird_code_push_protocol/test/generated/models/patch_metric_time_series_entry_test.dart b/packages/shorebird_code_push_protocol/test/generated/models/patch_metric_time_series_entry_test.dart new file mode 100644 index 00000000..5233fe80 --- /dev/null +++ b/packages/shorebird_code_push_protocol/test/generated/models/patch_metric_time_series_entry_test.dart @@ -0,0 +1,30 @@ +// GENERATED — do not hand-edit. +import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart'; +import 'package:test/test.dart'; + +void main() { + group('PatchMetricTimeSeriesEntry', () { + test('round-trips via maybeFromJson/toJson', () { + final instance = PatchMetricTimeSeriesEntry( + period: DateTime.utc(2024), + count: 0, + ); + final parsed = PatchMetricTimeSeriesEntry.maybeFromJson( + instance.toJson(), + ); + expect(parsed, equals(instance)); + expect(parsed.hashCode, equals(instance.hashCode)); + }); + + test('maybeFromJson returns null on null input', () { + expect(PatchMetricTimeSeriesEntry.maybeFromJson(null), isNull); + }); + + test('maybeFromJson throws FormatException on invalid input', () { + expect( + () => PatchMetricTimeSeriesEntry.maybeFromJson({}), + throwsFormatException, + ); + }); + }); +} diff --git a/packages/shorebird_code_push_protocol/test/generated/models/patch_metric_window_test.dart b/packages/shorebird_code_push_protocol/test/generated/models/patch_metric_window_test.dart new file mode 100644 index 00000000..02c0ebdd --- /dev/null +++ b/packages/shorebird_code_push_protocol/test/generated/models/patch_metric_window_test.dart @@ -0,0 +1,31 @@ +// GENERATED — do not hand-edit. +import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart'; +import 'package:test/test.dart'; + +void main() { + group('PatchMetricWindow', () { + test('round-trips via maybeFromJson/toJson', () { + final instance = PatchMetricWindow( + count: 0, + range: MetricsRange( + start: DateTime.utc(2024), + end: DateTime.utc(2024), + ), + ); + final parsed = PatchMetricWindow.maybeFromJson(instance.toJson()); + expect(parsed, equals(instance)); + expect(parsed.hashCode, equals(instance.hashCode)); + }); + + test('maybeFromJson returns null on null input', () { + expect(PatchMetricWindow.maybeFromJson(null), isNull); + }); + + test('maybeFromJson throws FormatException on invalid input', () { + expect( + () => PatchMetricWindow.maybeFromJson({}), + throwsFormatException, + ); + }); + }); +}