arblant
firefox-vpn-client / app / test / country_names_test.dart
country_names_test.dart152 lines · 5.8 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:firefox_vpn/app_settings.dart';
import 'package:firefox_vpn/core/models.dart';
import 'package:firefox_vpn/l10n/app_localizations.dart';
import 'package:firefox_vpn/ui/local_country_names.dart';
import 'package:firefox_vpn/ui/widgets.dart';

/// Every country in Mozilla's server list, and the others the exit or the
/// user's region can be in.
const _codes = [
  ...['ZA', 'PE', 'BR', 'KR', 'GH', 'AR', 'PH', 'GB', 'FR', 'CA', 'SG'],
  ...['SE', 'FI', 'NZ', 'DK', 'CL', 'NO', 'NL', 'BE', 'MY', 'ES', 'AT'],
  ...['AU', 'PT', 'JP', 'MX', 'CO', 'IT', 'IE', 'DE', 'US', 'TH', 'BG'],
  ...['IR', 'TR', 'AE', 'CH', 'PL', 'IN', 'CN', 'HK', 'TW', 'RU', 'UA'],
];

void main() {
  test('every app language names every country', () {
    for (final language in AppSettings.supportedLanguages) {
      final l = lookupAppLocalizations(AppSettings.localeOf(language));
      if (language == 'en') continue;
      expect(localCountryNames.keys, contains(l.localeName));
      for (final code in _codes) {
        final name = countryName(l, code, 'Server list name');
        expect(name, isNot('Server list name'), reason: '$language $code');
        expect(name, isNotEmpty, reason: '$language $code');
      }
      // Nothing beyond the languages and codes the app knows.
      expect(localCountryNames[l.localeName]!.keys.toSet(), _codes.toSet());
    }
  });

  test('English keeps the server list name; others fall back to it', () {
    final en = lookupAppLocalizations(const Locale('en'));
    expect(countryName(en, 'GB', 'United Kingdom'), 'United Kingdom');
    expect(countryName(en, 'de'), 'Germany');
    final fa = lookupAppLocalizations(const Locale('fa'));
    expect(countryName(fa, 'de', 'Germany'), 'آلمان');
    expect(countryName(fa, 'GB'), 'انگلیس');
    // A country without a translation: the server list's name, else the
    // English name of its code, else the code.
    expect(countryName(fa, 'IS', 'Iceland (server)'), 'Iceland (server)');
    expect(countryName(fa, 'IS'), 'Iceland');
    expect(countryName(fa, 'QQ'), 'QQ');
    // The core sends the code as the name of a country its server list does
    // not name: that is no name.
    expect(countryName(fa, 'IS', 'IS'), 'Iceland');
    expect(countryName(en, 'de', 'DE'), 'Germany');
    final zhHant = lookupAppLocalizations(AppSettings.localeOf('zh_Hant'));
    expect(countryName(zhHant, 'US'), '美國');
    // The recommended location keeps its own name.
    expect(
      locationName(fa, 'REC', 'Recomended Location'),
      fa.recommendedLocation,
    );
    expect(locationName(fa, 'NL', 'Netherlands'), 'هلند');
  });

  test('names sort as people of each language expect', () {
    List<String> sorted(String language, List<String> names) => [...names]
      ..sort(
        (a, b) => nameSortKey(language, a).compareTo(nameSortKey(language, b)),
      );
    // پ comes right after ب, and ک before ه, not after every Arabic letter.
    expect(sorted('fa', ['هلند', 'پرتغال', 'بلژیک', 'کانادا']), [
      'بلژیک',
      'پرتغال',
      'کانادا',
      'هلند',
    ]);
    // Accented letters next to their base letter.
    expect(sorted('fr', ['Ukraine', 'États-Unis', 'Espagne']), [
      'Espagne',
      'États-Unis',
      'Ukraine',
    ]);
    expect(sorted('tr', ['Yeni Zelanda', 'İspanya', 'Hollanda']), [
      'Hollanda',
      'İspanya',
      'Yeni Zelanda',
    ]);
    expect(sorted('vi', ['Úc', 'Đức', 'Anh']), ['Anh', 'Đức', 'Úc']);
    // Arabic: أ and إ are alif, and ه comes before و.
    expect(
      sorted('ar', [
        'اليابان',
        'الولايات المتحدة',
        'ألمانيا',
        'الهند',
        'أستراليا',
        'إسبانيا',
      ]),
      [
        'إسبانيا',
        'أستراليا',
        'ألمانيا',
        'الهند',
        'الولايات المتحدة',
        'اليابان',
      ],
    );
  });

  test('with every account turned off, the hint says to turn one on', () {
    final fa = lookupAppLocalizations(const Locale('fa'));
    PhaseLook look(int total) => PhaseLook.of(
      fa,
      CoreStatus.fromJson({
        'state': {
          'phase': 'waiting',
          'code': 'no_accounts',
          'message': 'Add an account in the dashboard to start the proxy',
        },
        'accounts': {'total': total},
      }),
    );
    expect(look(0).hint, fa.waitingForAccount);
    expect(look(2).hint, fa.waitingForEnabledAccount);
  });

  // Persian and Arabic names start with a letter of their script, so that
  // a text beginning with a name (the exit mismatch, the tray, a
  // notification) still reads right to left.
  test('RTL country names read right to left', () {
    final arabicLetter = RegExp('^[\u0600-\u06FF]');
    for (final language in ['fa', 'ar']) {
      for (final name in localCountryNames[language]!.values) {
        expect(name, matches(arabicLetter), reason: '$language $name');
        expect(name, isNot(contains('\u0654')), reason: name);
      }
    }
    final fa = lookupAppLocalizations(const Locale('fa'));
    final status = CoreStatus.fromJson({
      'state': {'phase': 'running'},
      'selection': 'gb',
      'exit_mismatch': {
        'chosen_country_code': 'GB',
        'chosen_country_name': 'United Kingdom',
        'exit_country_code': 'DE',
      },
    });
    final text = exitMismatchText(fa, status)!;
    expect(text, 'انگلیس را انتخاب کردید، اما IP شما مال آلمان است.');
    expect(text, matches(arabicLetter));
    final en = lookupAppLocalizations(const Locale('en'));
    expect(
      exitMismatchText(en, status),
      'You chose United Kingdom, but your IP is in Germany.',
    );
  });
}