<!DOCTYPE html>
<meta charset=utf-8>
<title>Blob constructor: endings option</title>
<link rel=help href="https://w3c.github.io/FileAPI/#constructorBlob">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>

// Windows platforms use CRLF as the native line ending. All others use LF.
const crlf = navigator.platform.startsWith('Win');
const native_ending = crlf ? '\r\n' : '\n';

function readBlobAsPromise(blob) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsText(blob);
    reader.onload = e => resolve(reader.result);
    reader.onerror = e => reject(reader.error);
  });
}

[
  'transparent',
  'native'
].forEach(value => test(t => {
  assert_class_string(new Blob([], {endings: value}), 'Blob',
                      `Constructor should allow "${value}" endings`);
}, `Valid "endings" value: ${JSON.stringify(value)}`));

[
  null,
  '',
  'invalidEnumValue',
  'Transparent',
  'NATIVE',
  0,
  {}
].forEach(value => test(t => {
  assert_throws_js(TypeError, () => new Blob([], {endings: value}),
                   'Blob constructor should throw');
}, `Invalid "endings" value: ${JSON.stringify(value)}`));

test(t => {
  const test_error = {name: 'test'};
  assert_throws_exactly(
    test_error,
    () => new Blob([], { get endings() { throw test_error; }}),
    'Blob constructor should propagate exceptions from "endings" property');
}, 'Exception propagation from options');

test(t => {
  let got = false;
  new Blob([], { get endings() { got = true; } });
  assert_true(got, 'The "endings" property was accessed during construction.');
}, 'The "endings" options property is used');

[
  {name: 'LF', input: '\n', native: native_ending},
  {name: 'CR', input: '\r', native: native_ending},

  {name: 'CRLF', input: '\r\n', native: native_ending},
  {name: 'CRCR', input: '\r\r', native: native_ending.repeat(2)},
  {name: 'LFCR', input: '\n\r', native: native_ending.repeat(2)},
  {name: 'LFLF', input: '\n\n', native: native_ending.repeat(2)},

  {name: 'CRCRLF', input: '\r\r\n', native: native_ending.repeat(2)},
  {name: 'CRLFLF', input: '\r\n\n', native: native_ending.repeat(2)},
  {name: 'CRLFCR', input: '\r\n\r\n', native: native_ending.repeat(2)},

  {name: 'CRLFCRLF', input: '\r\n\r\n', native: native_ending.repeat(2)},
  {name: 'LFCRLFCR', input: '\n\r\n\r', native: native_ending.repeat(3)},

].forEach(testCase => {
  promise_test(async t => {
    const blob = new Blob([testCase.input]);
    assert_equals(
      await readBlobAsPromise(blob), testCase.input,
      'Newlines should not change with endings unspecified');
  }, `Input ${testCase.name} with endings unspecified`);

  promise_test(async t => {
    const blob = new Blob([testCase.input], {endings: 'transparent'});
    assert_equals(
      await readBlobAsPromise(blob), testCase.input,
      'Newlines should not change with endings "transparent"');
  }, `Input ${testCase.name} with endings 'transparent'`);

  promise_test(async t => {
    const blob = new Blob([testCase.input], {endings: 'native'});
    assert_equals(
      await readBlobAsPromise(blob), testCase.native,
      'Newlines should match the platform with endings "native"');
  }, `Input ${testCase.name} with endings 'native'`);
});

promise_test(async t => {
  const blob = new Blob(['\r', '\n'], {endings: 'native'});
  const expected = native_ending.repeat(2);
  assert_equals(
    await readBlobAsPromise(blob), expected,
    'CR/LF in adjacent strings should be converted to two platform newlines');
}, `CR/LF in adjacent input strings`);

</script>
