• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// META: global=window,worker
2'use strict';
3
4// Tests which patch the global environment are kept separate to avoid
5// interfering with other tests.
6
7const ReadableStream_prototype_locked_get =
8      Object.getOwnPropertyDescriptor(ReadableStream.prototype, 'locked').get;
9
10// Verify that |rs| passes the brand check as a readable stream.
11function isReadableStream(rs) {
12  try {
13    ReadableStream_prototype_locked_get.call(rs);
14    return true;
15  } catch (e) {
16    return false;
17  }
18}
19
20test(t => {
21  const rs = new ReadableStream();
22
23  const trappedProperties = ['highWaterMark', 'size', 'start', 'type', 'mode'];
24  for (const property of trappedProperties) {
25    // eslint-disable-next-line no-extend-native, accessor-pairs
26    Object.defineProperty(Object.prototype, property, {
27      get() { throw new Error(`${property} getter called`); },
28      configurable: true
29    });
30  }
31  t.add_cleanup(() => {
32    for (const property of trappedProperties) {
33      delete Object.prototype[property];
34    }
35  });
36
37  const [branch1, branch2] = rs.tee();
38  assert_true(isReadableStream(branch1), 'branch1 should be a ReadableStream');
39  assert_true(isReadableStream(branch2), 'branch2 should be a ReadableStream');
40}, 'ReadableStream tee() should not touch Object.prototype properties');
41
42test(t => {
43  const rs = new ReadableStream();
44
45  const oldReadableStream = self.ReadableStream;
46
47  self.ReadableStream = function() {
48    throw new Error('ReadableStream called on global object');
49  };
50
51  t.add_cleanup(() => {
52    self.ReadableStream = oldReadableStream;
53  });
54
55  const [branch1, branch2] = rs.tee();
56
57  assert_true(isReadableStream(branch1), 'branch1 should be a ReadableStream');
58  assert_true(isReadableStream(branch2), 'branch2 should be a ReadableStream');
59}, 'ReadableStream tee() should not call the global ReadableStream');
60
61promise_test(async t => {
62  const rs = new ReadableStream({
63    start(c) {
64      c.enqueue(1);
65      c.enqueue(2);
66      c.enqueue(3);
67      c.close();
68    }
69  });
70
71  const oldReadableStreamGetReader = ReadableStream.prototype.getReader;
72
73  const ReadableStreamDefaultReader = (new ReadableStream()).getReader().constructor;
74  const oldDefaultReaderRead = ReadableStreamDefaultReader.prototype.read;
75  const oldDefaultReaderCancel = ReadableStreamDefaultReader.prototype.cancel;
76  const oldDefaultReaderReleaseLock = ReadableStreamDefaultReader.prototype.releaseLock;
77
78  self.ReadableStream.prototype.getReader = function() {
79    throw new Error('patched getReader() called');
80  };
81
82  ReadableStreamDefaultReader.prototype.read = function() {
83    throw new Error('patched read() called');
84  };
85  ReadableStreamDefaultReader.prototype.cancel = function() {
86    throw new Error('patched cancel() called');
87  };
88  ReadableStreamDefaultReader.prototype.releaseLock = function() {
89    throw new Error('patched releaseLock() called');
90  };
91
92  t.add_cleanup(() => {
93    self.ReadableStream.prototype.getReader = oldReadableStreamGetReader;
94
95    ReadableStreamDefaultReader.prototype.read = oldDefaultReaderRead;
96    ReadableStreamDefaultReader.prototype.cancel = oldDefaultReaderCancel;
97    ReadableStreamDefaultReader.prototype.releaseLock = oldDefaultReaderReleaseLock;
98  });
99
100  // read the first chunk, then cancel
101  for await (const chunk of rs) {
102    break;
103  }
104
105  // should be able to acquire a new reader
106  const reader = oldReadableStreamGetReader.call(rs);
107  // stream should be cancelled
108  await reader.closed;
109}, 'ReadableStream async iterator should use the original values of getReader() and ReadableStreamDefaultReader ' +
110   'methods');
111
112test(t => {
113  const oldPromiseThen = Promise.prototype.then;
114  Promise.prototype.then = () => {
115    throw new Error('patched then() called');
116  };
117  t.add_cleanup(() => {
118    Promise.prototype.then = oldPromiseThen;
119  });
120  const [branch1, branch2] = new ReadableStream().tee();
121  assert_true(isReadableStream(branch1), 'branch1 should be a ReadableStream');
122  assert_true(isReadableStream(branch2), 'branch2 should be a ReadableStream');
123}, 'tee() should not call Promise.prototype.then()');
124
125test(t => {
126  const oldPromiseThen = Promise.prototype.then;
127  Promise.prototype.then = () => {
128    throw new Error('patched then() called');
129  };
130  t.add_cleanup(() => {
131    Promise.prototype.then = oldPromiseThen;
132  });
133  let readableController;
134  const rs = new ReadableStream({
135    start(c) {
136      readableController = c;
137    }
138  });
139  const ws = new WritableStream();
140  rs.pipeTo(ws);
141  readableController.close();
142}, 'pipeTo() should not call Promise.prototype.then()');
143