-
Notifications
You must be signed in to change notification settings - Fork 249
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
compose: Enforce max topic/content length by code points, following API #1239
compose: Enforce max topic/content length by code points, following API #1239
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR! I read all the commits and it looks good to me overall. Left some comments.
test/widgets/compose_box_test.dart
Outdated
@@ -95,6 +95,23 @@ void main() { | |||
..url.path.equals('/api/v1/users/me/${narrow.streamId}/topics'); | |||
} | |||
|
|||
/// Set the content input's text to [content], using [WidgetTester.enterText]. | |||
Future<void> enterContent(WidgetTester tester, { | |||
required ChannelNarrow narrow, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this is unused. For entering content, just having await tester.enterText(contentInputFinder, content);
should be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It gets two callers in this commit, and two more in a later commit.
At the branch tip:
$ git grep enterContent -- test/widgets/compose_box_test.dart
test/widgets/compose_box_test.dart: Future<void> enterContent(WidgetTester tester, {
test/widgets/compose_box_test.dart: await enterContent(tester, narrow: narrow, content: content);
test/widgets/compose_box_test.dart: await enterContent(tester, narrow: narrow, content: 'a' * kMaxMessageLengthCodePoints);
test/widgets/compose_box_test.dart: await enterContent(tester, narrow: narrow, content: 'some content');
test/widgets/compose_box_test.dart: await enterContent(tester, narrow: narrow, content: 'some content');
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the clear parallelism when it's used alongside enterTopic
:
await enterTopic(tester, narrow: narrow, topic: 'some topic');
await enterContent(tester, narrow: narrow, content: content);
lib/widgets/compose_box.dart
Outdated
/// is more expensive than getting the number of UTF-16 code units | ||
/// ([String.length]), so we avoid it when the result definitely won't exceed | ||
/// [maxLengthUnicodeCodePoints]. | ||
int? get lengthUnicodeCodePointsIfLong => _lengthUnicodeCodePointsIfLong; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if we maintain the length internally, and expose only a method that tests if the content is too long? We already have access to the length limit via maxLengthUnicodeCodePoints
and hiding this cache might simplify the checks a bit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, makes sense; I can remove this public getter.
and expose only a method that tests if the content is too long
How about keeping the validationErrors
getter as the way consumers get this information, without adding a new method?
e18196d
to
fe080cb
Compare
Thanks for the review! Revision pushed, this time atop #1290 for the sake of CI. |
Thanks! This revision looks good to me. |
Thanks for the review! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for fixing this! The implementation all looks good to me; small comments on the tests.
test/widgets/compose_box_test.dart
Outdated
@@ -95,6 +96,23 @@ void main() { | |||
..url.path.equals('/api/v1/users/me/${narrow.streamId}/topics'); | |||
} | |||
|
|||
/// Set the content input's text to [content], using [WidgetTester.enterText]. | |||
Future<void> enterContent(WidgetTester tester, { | |||
required ChannelNarrow narrow, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This parameter doesn't seem to be used.
(Maybe that's what @PIG208 meant at https://github.com/zulip/zulip-flutter/pull/1239/files#r1901513335 ?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right. I thought I was referring to the helper as a whole when re-reviewing, but initially the comment was brought up because of this parameter.
test/widgets/compose_box_test.dart
Outdated
final contentInputFinder = find.byWidgetPredicate( | ||
(widget) => widget is TextField && widget.controller is ComposeContentController); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final contentInputFinder = find.byWidgetPredicate( | |
(widget) => widget is TextField && widget.controller is ComposeContentController); |
This is equivalent to the finder already defined above, right?
test/widgets/compose_box_test.dart
Outdated
doTest('too-long content is rejected', | ||
content: makeStringWithCodePoints(kMaxMessageLengthCodePoints + 1), expectError: true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: since this helper creates a test case, find a name for it starting with "test", like test
and testWidgets
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(But also this is probably clearer if the logic these tests have in common goes into a helper function they each call, rather than having them wrapped like this.)
test/widgets/compose_box_test.dart
Outdated
content: makeStringWithCodePoints(kMaxMessageLengthCodePoints + 1), expectError: true); | ||
|
||
doTest('max-length content not rejected', | ||
content: makeStringWithCodePoints(kMaxMessageLengthCodePoints), expectError: false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: lines too long: the key information at expectError:
is past 80 columns
const graphemeCluster = '👨👩👦'; | ||
assert(graphemeCluster.runes.length == 5); | ||
assert(graphemeCluster.length == 8); | ||
assert(graphemeCluster.characters.length == 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fact about .characters
isn't really used here, right? This could be any single emoji code point (for any of the emoji of the past decade or so, in the range U+10000 and up) and it'd have more UTF-16 code units than code points.
I guess it is helpful that the tests below confirm that at M+1 code points we start rejecting the value even when it's less than M "characters" / grapheme clusters. So maybe the thing to do is to just add that to this function's doc: the number of characters in that sense is less than [n].
fe080cb
to
c2e7a38
Compare
Thanks for the review! Revision pushed. |
We have the same comment where we check the content length: if (textNormalized.length > kMaxMessageLengthCodePoints) and it applies here, too; the API doc on max_topic_length in /register also says it's in Unicode code points: https://zulip.com/api/register-queue And give our max-topic-length variable a more descriptive name, again like we do with kMaxMessageLengthCodePoints.
With zulip#996, these tests will have to start checking for separate per-platform flavors of alert dialog. Best if they all do so through this one codepath.
c2e7a38
to
a23309a
Compare
Thanks! All looks good; merging. |
Fixes #1238.
Done by computing
String.runes
(the number of Unicode code points) unless we know that the result can't exceed the threshold number of code points. In particular, we don't compute it unlessString.length
(the number of UTF-16 code units) exceeds the threshold number of code points.