Fix and test permissive compare in proto3json (#329)
diff --git a/protobuf/CHANGELOG.md b/protobuf/CHANGELOG.md
index 2c7037f..c88b6e9 100644
--- a/protobuf/CHANGELOG.md
+++ b/protobuf/CHANGELOG.md
@@ -1,6 +1,8 @@
## 1.0.2
* Fix hashcode of bytes fields.
+* Fix issue with the `permissiveEnums` option to `mergeFromProto3Json`.
+ The comparison did not work properly.
## 1.0.1
diff --git a/protobuf/lib/protobuf.dart b/protobuf/lib/protobuf.dart
index 4f2332f..aaad732 100644
--- a/protobuf/lib/protobuf.dart
+++ b/protobuf/lib/protobuf.dart
@@ -14,6 +14,7 @@
import 'package:fixnum/fixnum.dart' show Int64;
import 'src/protobuf/json_parsing_context.dart';
+import 'src/protobuf/permissive_compare.dart';
import 'src/protobuf/type_registry.dart';
export 'src/protobuf/type_registry.dart' show TypeRegistry;
diff --git a/protobuf/lib/src/protobuf/permissive_compare.dart b/protobuf/lib/src/protobuf/permissive_compare.dart
new file mode 100644
index 0000000..e31103a
--- /dev/null
+++ b/protobuf/lib/src/protobuf/permissive_compare.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, 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.
+
+/// Returns true if [a] and [b] are the same ignoring case and all instances of
+/// `-` and `_`.
+///
+/// This is specialized code for comparing enum names.
+/// Works only for ascii strings containing letters and `_` and `-`.
+bool permissiveCompare(String a, String b) {
+ const dash = 45;
+ const underscore = 95;
+
+ int i = 0;
+ int j = 0;
+
+ while (true) {
+ int ca, cb;
+ do {
+ ca = i < a.length ? a.codeUnitAt(i++) : -1;
+ } while (ca == dash || ca == underscore);
+ do {
+ cb = j < b.length ? b.codeUnitAt(j++) : -1;
+ } while (cb == dash || cb == underscore);
+ if (ca == cb) {
+ if (ca == -1) return true; // Both at end
+ continue;
+ }
+ if (ca ^ cb != 0x20 || !_isAsciiLetter(ca)) {
+ return false;
+ }
+ }
+}
+
+bool _isAsciiLetter(int char) {
+ const lowerA = 97;
+ const lowerZ = 122;
+ const capitalA = 65;
+ char |= lowerA ^ capitalA;
+ return lowerA <= char && char <= lowerZ;
+}
diff --git a/protobuf/lib/src/protobuf/proto3_json.dart b/protobuf/lib/src/protobuf/proto3_json.dart
index 8f08cd0..bf76d56 100644
--- a/protobuf/lib/src/protobuf/proto3_json.dart
+++ b/protobuf/lib/src/protobuf/proto3_json.dart
@@ -198,7 +198,7 @@
// TODO(sigurdm): Do we want to avoid linear search here? Measure...
final result = permissiveEnums
? fieldInfo.enumValues.firstWhere(
- (e) => _permissiveCompare(e.name, value),
+ (e) => permissiveCompare(e.name, value),
orElse: () => null)
: fieldInfo.enumValues
.firstWhere((e) => e.name == value, orElse: () => null);
@@ -405,42 +405,3 @@
recursionHelper(json, fieldSet);
}
-
-bool _isAsciiLetter(int char) {
- const lowerA = 97;
- const lowerZ = 122;
- const capitalA = 65;
- char |= lowerA ^ capitalA;
- return lowerA <= char && char <= lowerZ;
-}
-
-/// Returns true if [a] and [b] are the same ignoring case and all instances of
-/// `-` and `_`.
-bool _permissiveCompare(String a, String b) {
- const dash = 45;
- const underscore = 95;
-
- // Enum names are always ascii.
- int i = 0;
- int j = 0;
-
- outer:
- while (i < a.length && j < b.length) {
- int ca = a.codeUnitAt(i);
- if (ca == dash || ca == underscore) {
- i++;
- continue;
- }
- int cb = b.codeUnitAt(j);
- while (cb == dash || cb == underscore) {
- j++;
- if (j == b.length) break outer;
- cb = b.codeUnitAt(j);
- }
-
- if (ca != cb && (ca ^ cb != 0x20 || !_isAsciiLetter(ca))) return false;
- i++;
- j++;
- }
- return true;
-}
diff --git a/protobuf/test/permissive_compare_test.dart b/protobuf/test/permissive_compare_test.dart
new file mode 100644
index 0000000..76b1731
--- /dev/null
+++ b/protobuf/test/permissive_compare_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2019, 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:protobuf/src/protobuf/permissive_compare.dart';
+
+void main() {
+ void symmetric(String a, String b, bool expected) {
+ expect(permissiveCompare(a, b), expected);
+ expect(permissiveCompare(b, a), expected);
+ }
+
+ List<String> variationsFromSeed(String seed) {
+ final result = [
+ seed,
+ seed.toUpperCase(),
+ '-$seed',
+ '-${seed.toUpperCase()}',
+ '_$seed',
+ '_${seed.toUpperCase()}',
+ '$seed-',
+ '${seed}_',
+ ];
+ if (2 <= seed.length) {
+ result.add('${seed.substring(0, 1)}_${seed.substring(1)}');
+ result.add('${seed.substring(0, 1)}-${seed.substring(1)}');
+ result.add('${seed.substring(0, 1).toUpperCase()}${seed.substring(1)}');
+ result.add('${seed.substring(0, 1)}${seed.substring(1).toUpperCase()}');
+ }
+ return result;
+ }
+
+ test('permissive compare', () {
+ final seeds = ['', 'a', 'b', 'aa', 'ab', 'bb', 'aaaa'];
+ for (final a in seeds) {
+ for (final aVariant in variationsFromSeed(a)) {
+ for (final b in seeds) {
+ for (final bVariant in variationsFromSeed(b)) {
+ symmetric(aVariant, bVariant, a == b);
+ }
+ }
+ }
+ }
+ });
+}