// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import 'package:test/test.dart'; import 'package:unified_analytics/src/asserts.dart'; void main() { test('Failure if client_id top level key is missing', () { final body = {}; final expectedErrorMessage = 'client_id missing from top level keys'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test('Failure if events top level key is missing', () { final body = {'client_id': 'xxxxxxx'}; final expectedErrorMessage = 'events missing from top level keys'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test('Failure if user_properties top level key is missing', () { final body = {'client_id': 'xxxxxxx', 'events': []}; final expectedErrorMessage = 'user_properties missing from top level keys'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test('Failure if more than 25 events found in events list', () { final body = { 'client_id': 'xxxxxxx', 'events': >[], 'user_properties': {} }; // Add more than the 25 allowed events for (var i = 0; i < 30; i++) { (body['events'] as List).add({'name': i}); } final expectedErrorMessage = '25 is the max number of events'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test('Failure when event name is greater than 40 chars', () { final body = { 'client_id': 'xxxxxxx', 'events': >[ { 'name': 'hot_reload_timehot_reload_timehot_reload_timehot_reload_time', 'params': {'time_ms': 133, 'count': 1999000} } ], 'user_properties': {} }; final expectedErrorMessage = 'Limit event names to 40 chars or less\n' 'Event name: ' '"hot_reload_timehot_reload_timehot_reload_timehot_reload_time"' ' is too long'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test('Failure when event name has invalid chars', () { final body = { 'client_id': 'xxxxxxx', 'events': >[ { 'name': 'hot_reload_time!!', 'params': {'time_ms': 133, 'count': 1999000} } ], 'user_properties': {} }; final expectedErrorMessage = 'Event name can only have alphanumeric chars and underscores\n' 'Event name: "hot_reload_time!!" contains invalid characters'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test('Failure when event name does not start with alphabetic char', () { final body = { 'client_id': 'xxxxxxx', 'events': >[ { 'name': '2hot_reload_time', 'params': {'time_ms': 133, 'count': 1999000} } ], 'user_properties': {} }; final expectedErrorMessage = 'Event name first char must be alphabetic char\n' 'Event name: "2hot_reload_time" must begin with a valid character'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test('Failure when an event has more than 25 event params', () { final body = { 'client_id': 'xxxxxxx', 'events': >[ { 'name': 'hot_reload_time', // 'params': {...} SUBBING THIS VALUE OUT 30 Maps } ], 'user_properties': {} }; final params = {}; for (var i = 0; i < 30; i++) { params['$i'] = i; } // Add the params to the first event in the body ((body['events'] as List).first as Map)['params'] = params; final expectedErrorMessage = 'Limit params for each event to less than 25\n' 'Event: "hot_reload_time" has too many parameters'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test('Failure when an value for event params is not a supported type (list)', () { final body = { 'client_id': 'xxxxxxx', 'events': >[ { 'name': 'hot_reload_time', 'params': { 'time_ms': 133, // Lists and Maps are not supported 'count': [1999000], } } ], 'user_properties': {} }; final expectedErrorMessage = 'Values for event params have to be String, int, double, or bool\n' 'Value for "count" is not a valid type for event: "hot_reload_time"'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test('Failure when an value for event params is not a supported type (map)', () { final body = { 'client_id': 'xxxxxxx', 'events': >[ { 'name': 'hot_reload_time', 'params': { 'time_ms': 133, // Lists and Maps are not supported 'count': {5: 20}, } } ], 'user_properties': {} }; final expectedErrorMessage = 'Values for event params have to be String, int, double, or bool\n' 'Value for "count" is not a valid type for event: "hot_reload_time"'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test('Failure when event param name is more than 40 chars', () { final body = { 'client_id': 'xxxxxxx', 'events': >[ { 'name': 'hot_reload_time', 'params': {'time_mstime_mstime_mstime_mstime_mstime_ms': 133} } ], 'user_properties': {} }; final expectedErrorMessage = 'Limit event param names to 40 chars or less\n' 'The key: "time_mstime_mstime_mstime_mstime_mstime_ms" ' 'under the event: "hot_reload_time" is too long'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test('Failure for event param name that has invalid chars', () { final body = { 'client_id': 'xxxxxxx', 'events': >[ { 'name': 'hot_reload_time', 'params': {'time_ns!': 133} } ], 'user_properties': {} }; final expectedErrorMessage = 'Event param name can only have alphanumeric chars and underscores\n' 'The key: "time_ns!" under the event: "hot_reload_time" contains ' 'invalid characters'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test( 'Failure for event param name that does not start with an alphabetic char', () { final body = { 'client_id': 'xxxxxxx', 'events': >[ { 'name': 'hot_reload_time', 'params': {'22time_ns': 133} } ], 'user_properties': {} }; final expectedErrorMessage = 'Event param name first char must be alphabetic char\n' 'The key: "22time_ns" under the event: "hot_reload_time" must begin ' 'in a valid character'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }, ); test('Failure for event param values that are greater than 100 chars', () { final body = { 'client_id': 'xxxxxxx', 'events': >[ { 'name': 'hot_reload_time', 'params': { 'time_ns': 'dsfjlksdjfajlfdsfjlks' 'djfajlfdsfjlksdjfajlfdsfjlksdjfaj' 'lfdsfjlksdjfajlfdsfjlksdjfajlfdsf' 'jlksdjfajlfdsfjlksdjfajlf' } } ], 'user_properties': {} }; final expectedErrorMessage = 'Limit characters in event param value to 100 chars or less\n' 'Value for "time_ns" is too long, value="' 'dsfjlksdjfajlfdsfjlks' 'djfajlfdsfjlksdjfajlfdsfjlksdjfaj' 'lfdsfjlksdjfajlfdsfjlksdjfajlfdsf' 'jlksdjfajlfdsfjlksdjfajlf"'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test('Failure when body has more than 25 user properties', () { final body = { 'client_id': 'xxxxxxx', 'events': >[ { 'name': 'hot_reload_time', 'params': {'time_ns': 123} } ], 'user_properties': {} }; for (var i = 0; i < 30; i++) { (body['user_properties']! as Map)['$i'] = i; } final expectedErrorMessage = 'Limit user properties to 25 or less'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test('Failure when user properties names are greater than 24 chars', () { final body = { 'client_id': 'xxxxxxx', 'events': >[ { 'name': 'hot_reload_time', 'params': {'time_ns': 123} } ], 'user_properties': { 'testtesttesttesttesttesttest': {}, // TOO LONG } }; final expectedErrorMessage = 'Limit user property names to 24 chars or less\n' 'The user property key: "testtesttesttesttesttesttest" is too long'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test('Failure when user properties values are greater than 36 chars', () { final body = { 'client_id': 'xxxxxxx', 'events': >[ { 'name': 'hot_reload_time', 'params': {'time_ns': 123} } ], 'user_properties': { 'test': { 'value': 'testtesttesttesttesttesttesttesttesttest' // TOO LONG }, } }; final expectedErrorMessage = 'Limit user property values to 36 chars or less\n' 'For the user property key "test", the value ' '"testtesttesttesttesttesttesttesttesttest" is too long'; expect( () => checkBody(body), throwsA(predicate( (AnalyticsException e) => e.message == expectedErrorMessage, expectedErrorMessage))); }); test('Successful body passes all asserts', () { final body = { 'client_id': '46cc0ba6-f604-4fd9-aa2f-8a20beb24cd4', 'events': [ { 'name': 'testing', 'params': {'time_ns': 345} } ], 'user_properties': { 'session_id': {'value': 1673466750423}, 'flutter_channel': {'value': 'ey-test-channel'}, 'host': {'value': 'macos'}, 'flutter_version': {'value': 'Flutter 3.6.0-7.0.pre.47'}, 'dart_version': {'value': 'Dart 2.19.0'}, 'tool': {'value': 'flutter-tools'}, 'local_time': {'value': '2023-01-11 14:53:31.471816 -0500'} } }; expect(() => checkBody(body), returnsNormally); }); }