From 729f5357e1561760fd78427a643013bd9aad529e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?=
 =?UTF-8?q?arcadier-Muller?= <rmuller@amazon.com>
Date: Wed, 24 Apr 2019 14:53:17 +0200
Subject: [PATCH] Add new unit testing for new feature surface

---
 .../assets/test/fs/test.fs-fingerprint.ts     | 242 +++++++++++-------
 .../@aws-cdk/assets/test/fs/test.utils.ts     |  92 +++++++
 2 files changed, 238 insertions(+), 96 deletions(-)
 create mode 100644 packages/@aws-cdk/assets/test/fs/test.utils.ts

diff --git a/packages/@aws-cdk/assets/test/fs/test.fs-fingerprint.ts b/packages/@aws-cdk/assets/test/fs/test.fs-fingerprint.ts
index 87cf001562055..8d4f76ce617d4 100644
--- a/packages/@aws-cdk/assets/test/fs/test.fs-fingerprint.ts
+++ b/packages/@aws-cdk/assets/test/fs/test.fs-fingerprint.ts
@@ -2,107 +2,157 @@ import fs = require('fs');
 import { Test } from 'nodeunit';
 import os = require('os');
 import path = require('path');
-import { copyDirectory } from '../../lib/fs/copy';
-import { fingerprint } from '../../lib/fs/fingerprint';
+import libfs = require('../../lib/fs');
 
 export = {
-  'single file'(test: Test) {
-    // GIVEN
-    const workdir = fs.mkdtempSync(path.join(os.tmpdir(), 'hash-tests'));
-    const content = 'Hello, world!';
-    const input1 = path.join(workdir, 'input1.txt');
-    const input2 = path.join(workdir, 'input2.txt');
-    const input3 = path.join(workdir, 'input3.txt');
-    fs.writeFileSync(input1, content);
-    fs.writeFileSync(input2, content);
-    fs.writeFileSync(input3, content + '.'); // add one character, hash should be different
-
-    // WHEN
-    const hash1 = fingerprint(input1);
-    const hash2 = fingerprint(input2);
-    const hash3 = fingerprint(input3);
-
-    // THEN
-    test.deepEqual(hash1, hash2);
-    test.notDeepEqual(hash3, hash1);
-    test.done();
+  files: {
+    'does not change with the file name'(test: Test) {
+      // GIVEN
+      const workdir = fs.mkdtempSync(path.join(os.tmpdir(), 'hash-tests'));
+      const content = 'Hello, world!';
+      const input1 = path.join(workdir, 'input1.txt');
+      const input2 = path.join(workdir, 'input2.txt');
+      const input3 = path.join(workdir, 'input3.txt');
+      fs.writeFileSync(input1, content);
+      fs.writeFileSync(input2, content);
+      fs.writeFileSync(input3, content + '.'); // add one character, hash should be different
+
+      // WHEN
+      const hash1 = libfs.fingerprint(input1);
+      const hash2 = libfs.fingerprint(input2);
+      const hash3 = libfs.fingerprint(input3);
+
+      // THEN
+      test.deepEqual(hash1, hash2);
+      test.notDeepEqual(hash3, hash1);
+      test.done();
+    },
+
+    'works on empty files'(test: Test) {
+      // GIVEN
+      const workdir = fs.mkdtempSync(path.join(os.tmpdir(), 'hash-tests'));
+      const input1 = path.join(workdir, 'empty');
+      const input2 = path.join(workdir, 'empty');
+      fs.writeFileSync(input1, '');
+      fs.writeFileSync(input2, '');
+
+      // WHEN
+      const hash1 = libfs.fingerprint(input1);
+      const hash2 = libfs.fingerprint(input2);
+
+      // THEN
+      test.deepEqual(hash1, hash2);
+      test.done();
+    },
   },
 
-  'empty file'(test: Test) {
-    // GIVEN
-    const workdir = fs.mkdtempSync(path.join(os.tmpdir(), 'hash-tests'));
-    const input1 = path.join(workdir, 'empty');
-    const input2 = path.join(workdir, 'empty');
-    fs.writeFileSync(input1, '');
-    fs.writeFileSync(input2, '');
-
-    // WHEN
-    const hash1 = fingerprint(input1);
-    const hash2 = fingerprint(input2);
-
-    // THEN
-    test.deepEqual(hash1, hash2);
-    test.done();
+  directories: {
+    'works on directories'(test: Test) {
+      // GIVEN
+      const srcdir = path.join(__dirname, 'fixtures', 'symlinks');
+      const outdir = fs.mkdtempSync(path.join(os.tmpdir(), 'copy-tests'));
+      libfs.copyDirectory(srcdir, outdir);
+
+      // WHEN
+      const hashSrc = libfs.fingerprint(srcdir);
+      const hashCopy = libfs.fingerprint(outdir);
+
+      // THEN
+      test.deepEqual(hashSrc, hashCopy);
+      test.done();
+    },
+
+    'ignores requested files'(test: Test) {
+      // GIVEN
+      const srcdir = path.join(__dirname, 'fixtures', 'symlinks');
+      const outdir = fs.mkdtempSync(path.join(os.tmpdir(), 'copy-tests'));
+      libfs.copyDirectory(srcdir, outdir);
+
+      // WHEN
+      const hashSrc = libfs.fingerprint(srcdir);
+
+      fs.writeFileSync(path.join(outdir, `${hashSrc}.ignoreme`), 'Ignore me!');
+      const hashCopy = libfs.fingerprint(outdir, { exclude: ['*.ignoreme'] });
+
+      // THEN
+      test.deepEqual(hashSrc, hashCopy);
+      test.done();
+    },
+
+    'changes with file names'(test: Test) {
+      // GIVEN
+      const srcdir = path.join(__dirname, 'fixtures', 'symlinks');
+      const cpydir = fs.mkdtempSync(path.join(os.tmpdir(), 'fingerprint-tests'));
+      libfs.copyDirectory(srcdir, cpydir);
+
+      // be careful not to break a symlink
+      fs.renameSync(path.join(cpydir, 'normal-dir', 'file-in-subdir.txt'), path.join(cpydir, 'move-me.txt'));
+
+      // WHEN
+      const hashSrc = libfs.fingerprint(srcdir);
+      const hashCopy = libfs.fingerprint(cpydir);
+
+      // THEN
+      test.notDeepEqual(hashSrc, hashCopy);
+      test.done();
+    },
   },
 
-  'directory'(test: Test) {
-    // GIVEN
-    const srcdir = path.join(__dirname, 'fixtures', 'symlinks');
-    const outdir = fs.mkdtempSync(path.join(os.tmpdir(), 'copy-tests'));
-    copyDirectory(srcdir, outdir);
-
-    // WHEN
-    const hashSrc = fingerprint(srcdir);
-    const hashCopy = fingerprint(outdir);
-
-    // THEN
-    test.deepEqual(hashSrc, hashCopy);
-    test.done();
-  },
-
-  'directory, rename files (fingerprint should change)'(test: Test) {
-    // GIVEN
-    const srcdir = path.join(__dirname, 'fixtures', 'symlinks');
-    const cpydir = fs.mkdtempSync(path.join(os.tmpdir(), 'fingerprint-tests'));
-    copyDirectory(srcdir, cpydir);
-
-    // be careful not to break a symlink
-    fs.renameSync(path.join(cpydir, 'normal-dir', 'file-in-subdir.txt'), path.join(cpydir, 'move-me.txt'));
-
-    // WHEN
-    const hashSrc = fingerprint(srcdir);
-    const hashCopy = fingerprint(cpydir);
-
-    // THEN
-    test.notDeepEqual(hashSrc, hashCopy);
-    test.done();
-  },
-
-  'external symlink content changes (fingerprint should change)'(test: Test) {
-    // GIVEN
-    const dir1 = fs.mkdtempSync(path.join(os.tmpdir(), 'fingerprint-tests'));
-    const dir2 = fs.mkdtempSync(path.join(os.tmpdir(), 'fingerprint-tests'));
-    const target = path.join(dir1, 'boom.txt');
-    const content = 'boom';
-    fs.writeFileSync(target, content);
-    fs.symlinkSync(target, path.join(dir2, 'link-to-boom.txt'));
-
-    // now dir2 contains a symlink to a file in dir1
-
-    // WHEN
-    const original = fingerprint(dir2);
-
-    // now change the contents of the target
-    fs.writeFileSync(target, 'changning you!');
-    const afterChange = fingerprint(dir2);
-
-    // revert the content to original and expect hash to be reverted
-    fs.writeFileSync(target, content);
-    const afterRevert = fingerprint(dir2);
-
-    // THEN
-    test.notDeepEqual(original, afterChange);
-    test.deepEqual(afterRevert, original);
-    test.done();
+  symlinks: {
+    'changes with the contents of followed symlink referent'(test: Test) {
+      // GIVEN
+      const dir1 = fs.mkdtempSync(path.join(os.tmpdir(), 'fingerprint-tests'));
+      const dir2 = fs.mkdtempSync(path.join(os.tmpdir(), 'fingerprint-tests'));
+      const target = path.join(dir1, 'boom.txt');
+      const content = 'boom';
+      fs.writeFileSync(target, content);
+      fs.symlinkSync(target, path.join(dir2, 'link-to-boom.txt'));
+
+      // now dir2 contains a symlink to a file in dir1
+
+      // WHEN
+      const original = libfs.fingerprint(dir2);
+
+      // now change the contents of the target
+      fs.writeFileSync(target, 'changning you!');
+      const afterChange = libfs.fingerprint(dir2);
+
+      // revert the content to original and expect hash to be reverted
+      fs.writeFileSync(target, content);
+      const afterRevert = libfs.fingerprint(dir2);
+
+      // THEN
+      test.notDeepEqual(original, afterChange);
+      test.deepEqual(afterRevert, original);
+      test.done();
+    },
+
+    'does not change with the contents of un-followed symlink referent'(test: Test) {
+      // GIVEN
+      const dir1 = fs.mkdtempSync(path.join(os.tmpdir(), 'fingerprint-tests'));
+      const dir2 = fs.mkdtempSync(path.join(os.tmpdir(), 'fingerprint-tests'));
+      const target = path.join(dir1, 'boom.txt');
+      const content = 'boom';
+      fs.writeFileSync(target, content);
+      fs.symlinkSync(target, path.join(dir2, 'link-to-boom.txt'));
+
+      // now dir2 contains a symlink to a file in dir1
+
+      // WHEN
+      const original = libfs.fingerprint(dir2, { follow: libfs.FollowMode.Never });
+
+      // now change the contents of the target
+      fs.writeFileSync(target, 'changning you!');
+      const afterChange = libfs.fingerprint(dir2, { follow: libfs.FollowMode.Never });
+
+      // revert the content to original and expect hash to be reverted
+      fs.writeFileSync(target, content);
+      const afterRevert = libfs.fingerprint(dir2, { follow: libfs.FollowMode.Never });
+
+      // THEN
+      test.deepEqual(original, afterChange);
+      test.deepEqual(afterRevert, original);
+      test.done();
+    }
   }
 };
diff --git a/packages/@aws-cdk/assets/test/fs/test.utils.ts b/packages/@aws-cdk/assets/test/fs/test.utils.ts
new file mode 100644
index 0000000000000..ac42ea75ba29e
--- /dev/null
+++ b/packages/@aws-cdk/assets/test/fs/test.utils.ts
@@ -0,0 +1,92 @@
+import { Test } from 'nodeunit';
+import path = require('path');
+import util = require('../../lib/fs/utils');
+import { FollowMode } from '../../lib/fs';
+
+export = {
+  shouldExclude: {
+    'excludes nothing by default'(test: Test) {
+      test.ok(!util.shouldExclude([], path.join('some', 'file', 'path')));
+      test.done();
+    },
+
+    'excludes requested files'(test: Test) {
+      const exclusions = ['*.ignored'];
+      test.ok(util.shouldExclude(exclusions, path.join('some', 'file.ignored')));
+      test.ok(!util.shouldExclude(exclusions, path.join('some', 'important', 'file')));
+      test.done();
+    },
+
+    'does not exclude whitelisted files'(test: Test) {
+      const exclusions = ['*.ignored', '!important.*'];
+      test.ok(!util.shouldExclude(exclusions, path.join('some', 'important.ignored')));
+      test.done();
+    },
+  },
+
+  shouldFollow: {
+    always: {
+      'follows internal'(test: Test) {
+        const sourceRoot = path.join('source', 'root');
+        const linkTarget = path.join(sourceRoot, 'referent');
+        test.ok(util.shouldFollow(FollowMode.Always, sourceRoot, linkTarget));
+        test.done();
+      },
+
+      'follows external'(test: Test) {
+        const sourceRoot = path.join('source', 'root');
+        const linkTarget = path.join('alternate', 'referent');
+        test.ok(util.shouldFollow(FollowMode.Always, sourceRoot, linkTarget));
+        test.done();
+      },
+    },
+
+    external: {
+      'does not follow internal'(test: Test) {
+        const sourceRoot = path.join('source', 'root');
+        const linkTarget = path.join(sourceRoot, 'referent');
+        test.ok(!util.shouldFollow(FollowMode.External, sourceRoot, linkTarget));
+        test.done();
+      },
+
+      'follows external'(test: Test) {
+        const sourceRoot = path.join('source', 'root');
+        const linkTarget = path.join('alternate', 'referent');
+        test.ok(util.shouldFollow(FollowMode.External, sourceRoot, linkTarget));
+        test.done();
+      },
+    },
+
+    blockExternal: {
+      'follows internal'(test: Test) {
+        const sourceRoot = path.join('source', 'root');
+        const linkTarget = path.join(sourceRoot, 'referent');
+        test.ok(!util.shouldFollow(FollowMode.Never, sourceRoot, linkTarget));
+        test.done();
+      },
+
+      'does not follow external'(test: Test) {
+        const sourceRoot = path.join('source', 'root');
+        const linkTarget = path.join('alternate', 'referent');
+        test.ok(!util.shouldFollow(FollowMode.BlockExternal, sourceRoot, linkTarget));
+        test.done();
+      },
+    },
+
+    never: {
+      'does not follow internal'(test: Test) {
+        const sourceRoot = path.join('source', 'root');
+        const linkTarget = path.join(sourceRoot, 'referent');
+        test.ok(!util.shouldFollow(FollowMode.Never, sourceRoot, linkTarget));
+        test.done();
+      },
+
+      'does not follow external'(test: Test) {
+        const sourceRoot = path.join('source', 'root');
+        const linkTarget = path.join('alternate', 'referent');
+        test.ok(!util.shouldFollow(FollowMode.Never, sourceRoot, linkTarget));
+        test.done();
+      },
+    }
+  },
+};