summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/xpcshell/test_locale_converter.js
blob: 2c57b6bf312f9e521e43a0ead8b11bc427d292c6 (plain)
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
"use strict";

const convService = Cc["@mozilla.org/streamConverters;1"].getService(
  Ci.nsIStreamConverterService
);

const UUID = "72b61ee3-aceb-476c-be1b-0822b036c9f1";
const ADDON_ID = "test@web.extension";
const URI = NetUtil.newURI(`moz-extension://${UUID}/file.css`);

const FROM_TYPE = "application/vnd.mozilla.webext.unlocalized";
const TO_TYPE = "text/css";

function StringStream(string) {
  let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
    Ci.nsIStringInputStream
  );

  stream.data = string;
  return stream;
}

// Initialize the policy service with a stub localizer for our
// add-on ID.
add_task(async function init() {
  let policy = new WebExtensionPolicy({
    id: ADDON_ID,
    mozExtensionHostname: UUID,
    baseURL: "file:///",

    allowedOrigins: new MatchPatternSet([]),

    localizeCallback(string) {
      return string.replace(/__MSG_(.*?)__/g, "<localized-$1>");
    },
  });

  policy.active = true;

  registerCleanupFunction(() => {
    policy.active = false;
  });
});

// Test that the synchronous converter works as expected with a
// simple string.
add_task(async function testSynchronousConvert() {
  let stream = StringStream("Foo __MSG_xxx__ bar __MSG_yyy__ baz");

  let resultStream = convService.convert(stream, FROM_TYPE, TO_TYPE, URI);

  let result = NetUtil.readInputStreamToString(
    resultStream,
    resultStream.available()
  );

  equal(result, "Foo <localized-xxx> bar <localized-yyy> baz");
});

// Test that the asynchronous converter works as expected with input
// split into multiple chunks, and a boundary in the middle of a
// replacement token.
add_task(async function testAsyncConvert() {
  let listener;
  let awaitResult = new Promise((resolve, reject) => {
    listener = {
      QueryInterface: ChromeUtils.generateQI(["nsIStreamListener"]),

      onDataAvailable(request, inputStream, offset, count) {
        this.resultParts.push(
          NetUtil.readInputStreamToString(inputStream, count)
        );
      },

      onStartRequest() {
        ok(!("resultParts" in this));
        this.resultParts = [];
      },

      onStopRequest(request, context, statusCode) {
        if (!Components.isSuccessCode(statusCode)) {
          reject(new Error(statusCode));
        }

        resolve(this.resultParts.join("\n"));
      },
    };
  });

  let parts = ["Foo __MSG_x", "xx__ bar __MSG_yyy__ baz"];

  let converter = convService.asyncConvertData(
    FROM_TYPE,
    TO_TYPE,
    listener,
    URI
  );
  converter.onStartRequest(null, null);

  for (let part of parts) {
    converter.onDataAvailable(null, StringStream(part), 0, part.length);
  }

  converter.onStopRequest(null, null, Cr.NS_OK);

  let result = await awaitResult;
  equal(result, "Foo <localized-xxx> bar <localized-yyy> baz");
});

// Test that attempting to initialize a converter with the URI of a
// nonexistent WebExtension fails.
add_task(async function testInvalidUUID() {
  let uri = NetUtil.newURI(
    "moz-extension://eb4f3be8-41c9-4970-aa6d-b84d1ecc02b2/file.css"
  );
  let stream = StringStream("Foo __MSG_xxx__ bar __MSG_yyy__ baz");

  // Assert.throws raise a TypeError exception when the expected param
  // is an arrow function. (See Bug 1237961 for rationale)
  let expectInvalidContextException = function (e) {
    return e.result === Cr.NS_ERROR_INVALID_ARG && /Invalid context/.test(e);
  };

  Assert.throws(() => {
    convService.convert(stream, FROM_TYPE, TO_TYPE, uri);
  }, expectInvalidContextException);

  Assert.throws(() => {
    let listener = {
      QueryInterface: ChromeUtils.generateQI(["nsIStreamListener"]),
    };

    convService.asyncConvertData(FROM_TYPE, TO_TYPE, listener, uri);
  }, expectInvalidContextException);
});

// Test that an empty stream does not throw an NS_ERROR_ILLEGAL_VALUE.
add_task(async function testEmptyStream() {
  let stream = StringStream("");
  let resultStream = convService.convert(stream, FROM_TYPE, TO_TYPE, URI);
  equal(
    resultStream.available(),
    0,
    "Size of output stream should match size of input stream"
  );
});