Skip to content

[go_router] #127016 preserved route name case when caching _nameToPath #4196

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 13, 2023
4 changes: 4 additions & 0 deletions packages/go_router/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 8.0.3

- Makes namedLocation and route name related APIs case sensitive.

## 8.0.2

- Fixes a bug in `debugLogDiagnostics` to support StatefulShellRoute.
Expand Down
7 changes: 3 additions & 4 deletions packages/go_router/lib/src/configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,8 @@ class RouteConfiguration {
'${queryParameters.isEmpty ? '' : ', queryParameters: $queryParameters'}');
return true;
}());
final String keyName = name.toLowerCase();
assert(_nameToPath.containsKey(keyName), 'unknown route name: $name');
final String path = _nameToPath[keyName]!;
assert(_nameToPath.containsKey(name), 'unknown route name: $name');
final String path = _nameToPath[name]!;
assert(() {
// Check that all required params are present
final List<String> paramNames = <String>[];
Expand Down Expand Up @@ -564,7 +563,7 @@ class RouteConfiguration {
final String fullPath = concatenatePaths(parentFullPath, route.path);

if (route.name != null) {
final String name = route.name!.toLowerCase();
final String name = route.name!;
assert(
!_nameToPath.containsKey(name),
'duplication fullpaths for name '
Expand Down
2 changes: 1 addition & 1 deletion packages/go_router/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: go_router
description: A declarative router for Flutter based on Navigation 2 supporting
deep linking, data-driven routes and more
version: 8.0.2
version: 8.0.3
repository: https://github.com/flutter/packages/tree/main/packages/go_router
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22

Expand Down
14 changes: 10 additions & 4 deletions packages/go_router/test/go_router_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1493,8 +1493,7 @@ void main() {
}, throwsA(isAssertionError));
});

testWidgets('match case insensitive w/ params',
(WidgetTester tester) async {
testWidgets('cannot match case insensitive', (WidgetTester tester) async {
final List<GoRoute> routes = <GoRoute>[
GoRoute(
name: 'home',
Expand Down Expand Up @@ -1524,8 +1523,15 @@ void main() {
];

final GoRouter router = await createRouter(routes, tester);
router.goNamed('person',
pathParameters: <String, String>{'fid': 'f2', 'pid': 'p1'});
expect(
() {
router.goNamed(
'person',
pathParameters: <String, String>{'fid': 'f2', 'pid': 'p1'},
);
},
throwsAssertionError,
);
});

testWidgets('too few params', (WidgetTester tester) async {
Expand Down
66 changes: 66 additions & 0 deletions packages/go_router/test/name_case_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2013 The Flutter Authors. 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:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:go_router/go_router.dart';

void main() {
testWidgets(
'Route names are case sensitive',
(WidgetTester tester) async {
// config router with 2 routes with the same name but different case (Name, name)
final GoRouter router = GoRouter(
routes: <GoRoute>[
GoRoute(
path: '/',
name: 'Name',
builder: (_, __) => const ScreenA(),
),
GoRoute(
path: '/path',
name: 'name',
builder: (_, __) => const ScreenB(),
),
],
);

// run MaterialApp, initial screen path is '/' -> ScreenA
await tester.pumpWidget(
MaterialApp.router(
routerConfig: router,
title: 'GoRouter Testcase',
),
);

// go to ScreenB
router.goNamed('name');
await tester.pumpAndSettle();
expect(find.byType(ScreenB), findsOneWidget);

// go to ScreenA
router.goNamed('Name');
await tester.pumpAndSettle();
expect(find.byType(ScreenA), findsOneWidget);
},
);
}

class ScreenA extends StatelessWidget {
const ScreenA({super.key});

@override
Widget build(BuildContext context) {
return Container();
}
}

class ScreenB extends StatelessWidget {
const ScreenB({super.key});

@override
Widget build(BuildContext context) {
return Container();
}
}
3 changes: 0 additions & 3 deletions packages/go_router/test/parser_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,8 @@ void main() {
);

expect(configuration.namedLocation('lowercase'), '/abc');
expect(configuration.namedLocation('LOWERCASE'), '/abc');
expect(configuration.namedLocation('camelCase'), '/efg');
expect(configuration.namedLocation('camelcase'), '/efg');
expect(configuration.namedLocation('snake_case'), '/hij');
expect(configuration.namedLocation('SNAKE_CASE'), '/hij');

// With query parameters
expect(configuration.namedLocation('lowercase'), '/abc');
Expand Down