11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ciconst common = require('../common');
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ciif (common.isIBMi)
51cb0ef41Sopenharmony_ci  common.skip('IBMi does not support `fs.watch()`');
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci// Tests if `filename` is provided to watcher on supported platforms
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ciconst fs = require('fs');
101cb0ef41Sopenharmony_ciconst assert = require('assert');
111cb0ef41Sopenharmony_ciconst { join } = require('path');
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ciclass WatchTestCase {
141cb0ef41Sopenharmony_ci  constructor(shouldInclude, dirName, fileName, field) {
151cb0ef41Sopenharmony_ci    this.dirName = dirName;
161cb0ef41Sopenharmony_ci    this.fileName = fileName;
171cb0ef41Sopenharmony_ci    this.field = field;
181cb0ef41Sopenharmony_ci    this.shouldSkip = !shouldInclude;
191cb0ef41Sopenharmony_ci  }
201cb0ef41Sopenharmony_ci  get dirPath() { return join(tmpdir.path, this.dirName); }
211cb0ef41Sopenharmony_ci  get filePath() { return join(this.dirPath, this.fileName); }
221cb0ef41Sopenharmony_ci}
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ciconst cases = [
251cb0ef41Sopenharmony_ci  // Watch on a file should callback with a filename on supported systems
261cb0ef41Sopenharmony_ci  new WatchTestCase(
271cb0ef41Sopenharmony_ci    common.isLinux || common.isOSX || common.isWindows || common.isAIX,
281cb0ef41Sopenharmony_ci    'watch1',
291cb0ef41Sopenharmony_ci    'foo',
301cb0ef41Sopenharmony_ci    'filePath'
311cb0ef41Sopenharmony_ci  ),
321cb0ef41Sopenharmony_ci  // Watch on a directory should callback with a filename on supported systems
331cb0ef41Sopenharmony_ci  new WatchTestCase(
341cb0ef41Sopenharmony_ci    common.isLinux || common.isOSX || common.isWindows,
351cb0ef41Sopenharmony_ci    'watch2',
361cb0ef41Sopenharmony_ci    'bar',
371cb0ef41Sopenharmony_ci    'dirPath'
381cb0ef41Sopenharmony_ci  ),
391cb0ef41Sopenharmony_ci];
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ciconst tmpdir = require('../common/tmpdir');
421cb0ef41Sopenharmony_citmpdir.refresh();
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_cifor (const testCase of cases) {
451cb0ef41Sopenharmony_ci  if (testCase.shouldSkip) continue;
461cb0ef41Sopenharmony_ci  fs.mkdirSync(testCase.dirPath);
471cb0ef41Sopenharmony_ci  // Long content so it's actually flushed.
481cb0ef41Sopenharmony_ci  const content1 = Date.now() + testCase.fileName.toLowerCase().repeat(1e4);
491cb0ef41Sopenharmony_ci  fs.writeFileSync(testCase.filePath, content1);
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci  let interval;
521cb0ef41Sopenharmony_ci  const pathToWatch = testCase[testCase.field];
531cb0ef41Sopenharmony_ci  const watcher = fs.watch(pathToWatch);
541cb0ef41Sopenharmony_ci  watcher.on('error', (err) => {
551cb0ef41Sopenharmony_ci    if (interval) {
561cb0ef41Sopenharmony_ci      clearInterval(interval);
571cb0ef41Sopenharmony_ci      interval = null;
581cb0ef41Sopenharmony_ci    }
591cb0ef41Sopenharmony_ci    assert.fail(err);
601cb0ef41Sopenharmony_ci  });
611cb0ef41Sopenharmony_ci  watcher.on('close', common.mustCall(() => {
621cb0ef41Sopenharmony_ci    watcher.close(); // Closing a closed watcher should be a noop
631cb0ef41Sopenharmony_ci  }));
641cb0ef41Sopenharmony_ci  watcher.on('change', common.mustCall(function(eventType, argFilename) {
651cb0ef41Sopenharmony_ci    if (interval) {
661cb0ef41Sopenharmony_ci      clearInterval(interval);
671cb0ef41Sopenharmony_ci      interval = null;
681cb0ef41Sopenharmony_ci    }
691cb0ef41Sopenharmony_ci    if (common.isOSX)
701cb0ef41Sopenharmony_ci      assert.strictEqual(['rename', 'change'].includes(eventType), true);
711cb0ef41Sopenharmony_ci    else
721cb0ef41Sopenharmony_ci      assert.strictEqual(eventType, 'change');
731cb0ef41Sopenharmony_ci    assert.strictEqual(argFilename, testCase.fileName);
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci    watcher.close();
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci    // We document that watchers cannot be used anymore when it's closed,
781cb0ef41Sopenharmony_ci    // here we turn the methods into noops instead of throwing
791cb0ef41Sopenharmony_ci    watcher.close(); // Closing a closed watcher should be a noop
801cb0ef41Sopenharmony_ci  }));
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci  // Long content so it's actually flushed. toUpperCase so there's real change.
831cb0ef41Sopenharmony_ci  const content2 = Date.now() + testCase.fileName.toUpperCase().repeat(1e4);
841cb0ef41Sopenharmony_ci  interval = setInterval(() => {
851cb0ef41Sopenharmony_ci    fs.writeFileSync(testCase.filePath, '');
861cb0ef41Sopenharmony_ci    fs.writeFileSync(testCase.filePath, content2);
871cb0ef41Sopenharmony_ci  }, 100);
881cb0ef41Sopenharmony_ci}
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci[false, 1, {}, [], null, undefined].forEach((input) => {
911cb0ef41Sopenharmony_ci  assert.throws(
921cb0ef41Sopenharmony_ci    () => fs.watch(input, common.mustNotCall()),
931cb0ef41Sopenharmony_ci    {
941cb0ef41Sopenharmony_ci      code: 'ERR_INVALID_ARG_TYPE',
951cb0ef41Sopenharmony_ci      name: 'TypeError'
961cb0ef41Sopenharmony_ci    }
971cb0ef41Sopenharmony_ci  );
981cb0ef41Sopenharmony_ci});
99