test-intl.cc 8.72 KB
Newer Older
1 2 3 4 5 6
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef V8_INTL_SUPPORT

7
#include "src/objects/intl-objects.h"
8 9 10 11
#include "src/objects/js-break-iterator.h"
#include "src/objects/js-collator.h"
#include "src/objects/js-date-time-format.h"
#include "src/objects/js-list-format.h"
12
#include "src/objects/js-number-format.h"
13 14 15
#include "src/objects/js-plural-rules.h"
#include "src/objects/js-relative-time-format.h"
#include "src/objects/js-segmenter.h"
16
#include "src/objects/lookup.h"
17
#include "src/objects/objects-inl.h"
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
#include "test/cctest/cctest.h"

namespace v8 {
namespace internal {

// This operator overloading enables CHECK_EQ to be used with
// std::vector<NumberFormatSpan>
bool operator==(const NumberFormatSpan& lhs, const NumberFormatSpan& rhs) {
  return memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
}
template <typename _CharT, typename _Traits>
std::basic_ostream<_CharT, _Traits>& operator<<(
    std::basic_ostream<_CharT, _Traits>& self, const NumberFormatSpan& part) {
  return self << "{" << part.field_id << "," << part.begin_pos << ","
              << part.end_pos << "}";
}

void test_flatten_regions_to_parts(
    const std::vector<NumberFormatSpan>& regions,
    const std::vector<NumberFormatSpan>& expected_parts) {
  std::vector<NumberFormatSpan> mutable_regions = regions;
  std::vector<NumberFormatSpan> parts = FlattenRegionsToParts(&mutable_regions);
  CHECK_EQ(expected_parts, parts);
}

TEST(FlattenRegionsToParts) {
  test_flatten_regions_to_parts(
      std::vector<NumberFormatSpan>{
          NumberFormatSpan(-1, 0, 10), NumberFormatSpan(1, 2, 8),
          NumberFormatSpan(2, 2, 4), NumberFormatSpan(3, 6, 8),
      },
      std::vector<NumberFormatSpan>{
          NumberFormatSpan(-1, 0, 2), NumberFormatSpan(2, 2, 4),
          NumberFormatSpan(1, 4, 6), NumberFormatSpan(3, 6, 8),
          NumberFormatSpan(-1, 8, 10),
      });
  test_flatten_regions_to_parts(
      std::vector<NumberFormatSpan>{
          NumberFormatSpan(0, 0, 1),
      },
      std::vector<NumberFormatSpan>{
          NumberFormatSpan(0, 0, 1),
      });
  test_flatten_regions_to_parts(
      std::vector<NumberFormatSpan>{
          NumberFormatSpan(-1, 0, 1), NumberFormatSpan(0, 0, 1),
      },
      std::vector<NumberFormatSpan>{
          NumberFormatSpan(0, 0, 1),
      });
  test_flatten_regions_to_parts(
      std::vector<NumberFormatSpan>{
          NumberFormatSpan(0, 0, 1), NumberFormatSpan(-1, 0, 1),
      },
      std::vector<NumberFormatSpan>{
          NumberFormatSpan(0, 0, 1),
      });
  test_flatten_regions_to_parts(
      std::vector<NumberFormatSpan>{
          NumberFormatSpan(-1, 0, 10), NumberFormatSpan(1, 0, 1),
          NumberFormatSpan(2, 0, 2), NumberFormatSpan(3, 0, 3),
          NumberFormatSpan(4, 0, 4), NumberFormatSpan(5, 0, 5),
          NumberFormatSpan(15, 5, 10), NumberFormatSpan(16, 6, 10),
          NumberFormatSpan(17, 7, 10), NumberFormatSpan(18, 8, 10),
          NumberFormatSpan(19, 9, 10),
      },
      std::vector<NumberFormatSpan>{
          NumberFormatSpan(1, 0, 1), NumberFormatSpan(2, 1, 2),
          NumberFormatSpan(3, 2, 3), NumberFormatSpan(4, 3, 4),
          NumberFormatSpan(5, 4, 5), NumberFormatSpan(15, 5, 6),
          NumberFormatSpan(16, 6, 7), NumberFormatSpan(17, 7, 8),
          NumberFormatSpan(18, 8, 9), NumberFormatSpan(19, 9, 10),
      });

  //              :          4
  //              :      22 33    3
  //              :      11111   22
  // input regions:     0000000  111
  //              :     ------------
  // output parts:      0221340--231
  test_flatten_regions_to_parts(
      std::vector<NumberFormatSpan>{
          NumberFormatSpan(-1, 0, 12), NumberFormatSpan(0, 0, 7),
          NumberFormatSpan(1, 9, 12), NumberFormatSpan(1, 1, 6),
          NumberFormatSpan(2, 9, 11), NumberFormatSpan(2, 1, 3),
          NumberFormatSpan(3, 10, 11), NumberFormatSpan(3, 4, 6),
          NumberFormatSpan(4, 5, 6),
      },
      std::vector<NumberFormatSpan>{
          NumberFormatSpan(0, 0, 1), NumberFormatSpan(2, 1, 3),
          NumberFormatSpan(1, 3, 4), NumberFormatSpan(3, 4, 5),
          NumberFormatSpan(4, 5, 6), NumberFormatSpan(0, 6, 7),
          NumberFormatSpan(-1, 7, 9), NumberFormatSpan(2, 9, 10),
          NumberFormatSpan(3, 10, 11), NumberFormatSpan(1, 11, 12),
      });
}

115
TEST(GetStringOption) {
116 117 118 119 120 121
  LocalContext env;
  Isolate* isolate = CcTest::i_isolate();
  v8::Isolate* v8_isolate = env->GetIsolate();
  v8::HandleScope handle_scope(v8_isolate);

  Handle<JSObject> options = isolate->factory()->NewJSObjectWithNullProto();
122 123 124 125 126 127 128 129 130 131
  {
    // No value found
    std::unique_ptr<char[]> result = nullptr;
    Maybe<bool> found =
        Intl::GetStringOption(isolate, options, "foo",
                              std::vector<const char*>{}, "service", &result);
    CHECK(!found.FromJust());
    CHECK_NULL(result);
  }

132
  Handle<String> key = isolate->factory()->NewStringFromAsciiChecked("foo");
133
  LookupIterator it(isolate, options, key);
134
  CHECK(Object::SetProperty(&it, Handle<Smi>(Smi::FromInt(42), isolate),
135
                            StoreOrigin::kMaybeKeyed,
136
                            Just(ShouldThrow::kThrowOnError))
137
            .FromJust());
138 139 140 141 142 143 144 145 146 147 148 149

  {
    // Value found
    std::unique_ptr<char[]> result = nullptr;
    Maybe<bool> found =
        Intl::GetStringOption(isolate, options, "foo",
                              std::vector<const char*>{}, "service", &result);
    CHECK(found.FromJust());
    CHECK_NOT_NULL(result);
    CHECK_EQ(0, strcmp("42", result.get()));
  }

150
  {
151 152 153 154 155
    // No expected value in values array
    std::unique_ptr<char[]> result = nullptr;
    Maybe<bool> found = Intl::GetStringOption(isolate, options, "foo",
                                              std::vector<const char*>{"bar"},
                                              "service", &result);
156
    CHECK(isolate->has_pending_exception());
157 158
    CHECK(found.IsNothing());
    CHECK_NULL(result);
159 160 161
    isolate->clear_pending_exception();
  }

162 163 164 165 166 167 168 169 170 171 172
  {
    // Expected value in values array
    std::unique_ptr<char[]> result = nullptr;
    Maybe<bool> found = Intl::GetStringOption(isolate, options, "foo",
                                              std::vector<const char*>{"42"},
                                              "service", &result);
    CHECK(found.FromJust());
    CHECK_NOT_NULL(result);
    CHECK_EQ(0, strcmp("42", result.get()));
  }
}
173

174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
TEST(GetBoolOption) {
  LocalContext env;
  Isolate* isolate = CcTest::i_isolate();
  v8::Isolate* v8_isolate = env->GetIsolate();
  v8::HandleScope handle_scope(v8_isolate);

  Handle<JSObject> options = isolate->factory()->NewJSObjectWithNullProto();
  {
    bool result = false;
    Maybe<bool> found =
        Intl::GetBoolOption(isolate, options, "foo", "service", &result);
    CHECK(!found.FromJust());
    CHECK(!result);
  }

  Handle<String> key = isolate->factory()->NewStringFromAsciiChecked("foo");
  {
191
    LookupIterator it(isolate, options, key);
192 193
    Handle<Object> false_value =
        handle(i::ReadOnlyRoots(isolate).false_value(), isolate);
194
    Object::SetProperty(isolate, options, key, false_value,
195 196
                        StoreOrigin::kMaybeKeyed,
                        Just(ShouldThrow::kThrowOnError))
197 198 199 200 201 202 203 204 205
        .Assert();
    bool result = false;
    Maybe<bool> found =
        Intl::GetBoolOption(isolate, options, "foo", "service", &result);
    CHECK(found.FromJust());
    CHECK(!result);
  }

  {
206
    LookupIterator it(isolate, options, key);
207 208
    Handle<Object> true_value =
        handle(i::ReadOnlyRoots(isolate).true_value(), isolate);
209
    Object::SetProperty(isolate, options, key, true_value,
210 211
                        StoreOrigin::kMaybeKeyed,
                        Just(ShouldThrow::kThrowOnError))
212 213 214 215 216 217 218
        .Assert();
    bool result = false;
    Maybe<bool> found =
        Intl::GetBoolOption(isolate, options, "foo", "service", &result);
    CHECK(found.FromJust());
    CHECK(result);
  }
219 220
}

221 222 223
TEST(GetAvailableLocales) {
  std::set<std::string> locales;

224
  locales = JSV8BreakIterator::GetAvailableLocales();
225 226 227
  CHECK(locales.count("en-US"));
  CHECK(!locales.count("abcdefg"));

228
  locales = JSCollator::GetAvailableLocales();
229 230
  CHECK(locales.count("en-US"));

231
  locales = JSDateTimeFormat::GetAvailableLocales();
232 233
  CHECK(locales.count("en-US"));

234
  locales = JSListFormat::GetAvailableLocales();
235
  CHECK(locales.count("en-US"));
236

237
  locales = JSNumberFormat::GetAvailableLocales();
238 239
  CHECK(locales.count("en-US"));

240
  locales = JSPluralRules::GetAvailableLocales();
241
  CHECK(locales.count("en"));
242 243 244 245 246 247 248

  locales = JSRelativeTimeFormat::GetAvailableLocales();
  CHECK(locales.count("en-US"));

  locales = JSSegmenter::GetAvailableLocales();
  CHECK(locales.count("en-US"));
  CHECK(!locales.count("abcdefg"));
249 250
}

251 252 253 254
}  // namespace internal
}  // namespace v8

#endif  // V8_INTL_SUPPORT