Add unit tests, simplify findFidlSource.

The findFidlSource function is moved to its own source file so that it
can be tested without bringing in a dependency on vscode.

Once there were tests I was able to simplify the function by making the
regular expressions consistent.

Change-Id: I842ad5bcaf387e4e0cc9b828d6fa506c02971565
diff --git a/package.json b/package.json
index 2dc8d8f..c5cb57b 100644
--- a/package.json
+++ b/package.json
@@ -53,12 +53,16 @@
         "vscode:prepublish": "npm run compile",
         "compile": "tsc -p ./",
         "watch": "tsc -watch -p ./",
-        "postinstall": "node ./node_modules/vscode/bin/install"
+        "postinstall": "node ./node_modules/vscode/bin/install",
+        "test": "mocha --require ts-node/register ./test/*.test.ts"
     },
     "devDependencies": {
-        "typescript": "^2.6.1",
-        "vscode": "^1.1.6",
+        "@types/mocha": "^2.2.48",
+        "@types/node": "^7.0.43",
+        "mocha": "^5.0.1",
+        "ts-node": "^5.0.1",
         "tslint": "^5.8.0",
-        "@types/node": "^7.0.43"
+        "typescript": "^2.6.1",
+        "vscode": "^1.1.6"
     }
 }
\ No newline at end of file
diff --git a/src/extension.ts b/src/extension.ts
index fc204cf..c912af9 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -2,24 +2,7 @@
 
 import * as vscode from 'vscode';
 import * as fs from 'fs';
-
-function findFidlSource(generatedSourcePath: string): string | void {
-    // TODO: establish a non-regex way of finding the source FIDL path.
-    const cxx_dart_match = generatedSourcePath.match(/(^.*\/)(?:out\/[^/]+\/gen\/)(.*\.fidl)[\._-][^/]*$/);
-    if (cxx_dart_match) {
-        return `${cxx_dart_match[1]}${cxx_dart_match[2]}`;
-    }
-
-    const go_match = generatedSourcePath.match(/(^.*\/)(?:out\/[^/]+\/gen\/go\/src\/)(.*\/)([^/]+)\/\3\.core\.go$/);
-    if (go_match) {
-        return `${go_match[1]}${go_match[2]}${go_match[3]}.fidl`;
-    }
-
-    const rust_match = generatedSourcePath.match(/(^.*\/)(?:out\/[^/]+\/gen\/)(.*).rs$/);
-    if (rust_match) {
-        return `${rust_match[1]}/${rust_match[2]}.fidl`;
-    }
-}
+import { findFidlSource } from './findFidlSource';
 
 export function activate(context: vscode.ExtensionContext) {
     let disposable = vscode.commands.registerCommand('extension.goToFidlSource', () => {
diff --git a/src/findFidlSource.ts b/src/findFidlSource.ts
new file mode 100644
index 0000000..436e407
--- /dev/null
+++ b/src/findFidlSource.ts
@@ -0,0 +1,19 @@
+// TODO: establish a non-regex way of finding the source FIDL path.
+
+// These regular expressions match FIDL generated binding source files in the
+// Fuchsia tree. They all capture three groups:
+// 1. The path to the root of the Fuchsia tree
+// 2. The path within the Fuchsia tree of the directory containing the FIDL
+// 3. The name of the FIDL source file, without ".fidl"
+const cxx_dart_re = /(^.+)\/(?:out\/[^/]+\/gen\/)(.+)\/([^\/]+)\.fidl[\._-][^/]*$/;
+const go_re = /(^.+)\/(?:out\/[^/]+\/gen\/go\/src\/)(.+)\/([^/]+)\/\3\.core\.go$/;
+const rust_re = /(^.+)\/(?:out\/[^/]+\/gen\/)(.+)\/([^/]+)\.rs$/;
+
+export function findFidlSource(generatedSourcePath: string): string | void {
+    const match = generatedSourcePath.match(cxx_dart_re)
+        || generatedSourcePath.match(go_re)
+        || generatedSourcePath.match(rust_re);
+    if (match) {
+        return `${match[1]}/${match[2]}/${match[3]}.fidl`;
+    }
+}
diff --git a/test/goToFidlSource.test.ts b/test/goToFidlSource.test.ts
new file mode 100644
index 0000000..a7d245a
--- /dev/null
+++ b/test/goToFidlSource.test.ts
@@ -0,0 +1,49 @@
+
+// var assert = require('assert');
+
+import 'mocha';
+import * as assert from 'assert';
+
+import { findFidlSource } from '../src/findFidlSource';
+
+describe('findFidlSource', function () {
+    it("should return null when the input isn't a generated FIDL file", () => {
+        assert.equal(null, findFidlSource("/var/log/syslog"));
+    });
+
+    it("should return null when the input isn't in the Fuchsia out dir", () => {
+        assert.equal(null, findFidlSource("/some/path/file.fidl.dart"));
+    });
+
+    it("should support Dart bindings", () => {
+        assert.equal("/home/user/fuchsia/layer/public/lib/foo/fidl/interface.fidl",
+            findFidlSource("/home/user/fuchsia/out/debug-x86-64/gen/layer/public/lib/foo/fidl/interface.fidl.dart"));
+    });
+
+    it("should support Go bindings", () => {
+        assert.equal("/home/user/fuchsia/layer/public/lib/foo/fidl/interface.fidl",
+            findFidlSource("/home/user/fuchsia/out/debug-x86-64/gen/go/src/layer/public/lib/foo/fidl/interface/interface.core.go"));
+    });
+
+    it("should support Rust bindings", () => {
+        assert.equal("/home/user/fuchsia/layer/public/lib/foo/fidl/interface.fidl",
+            findFidlSource("/home/user/fuchsia/out/debug-x86-64/gen/layer/public/lib/foo/fidl/interface.rs"));
+    });
+
+    it("should support C++ bindings", () => {
+        assert.equal("/home/user/fuchsia/layer/public/lib/foo/fidl/interface.fidl",
+            findFidlSource("/home/user/fuchsia/out/debug-x86-64/gen/layer/public/lib/foo/fidl/interface.fidl.cc"));
+        assert.equal("/home/user/fuchsia/layer/public/lib/foo/fidl/interface.fidl",
+            findFidlSource("/home/user/fuchsia/out/debug-x86-64/gen/layer/public/lib/foo/fidl/interface.fidl-common.cc"));
+        assert.equal("/home/user/fuchsia/layer/public/lib/foo/fidl/interface.fidl",
+            findFidlSource("/home/user/fuchsia/out/debug-x86-64/gen/layer/public/lib/foo/fidl/interface.fidl-common.h"));
+        assert.equal("/home/user/fuchsia/layer/public/lib/foo/fidl/interface.fidl",
+            findFidlSource("/home/user/fuchsia/out/debug-x86-64/gen/layer/public/lib/foo/fidl/interface.fidl.h"));
+        assert.equal("/home/user/fuchsia/layer/public/lib/foo/fidl/interface.fidl",
+            findFidlSource("/home/user/fuchsia/out/debug-x86-64/gen/layer/public/lib/foo/fidl/interface.fidl-internal.h"));
+        assert.equal("/home/user/fuchsia/layer/public/lib/foo/fidl/interface.fidl",
+            findFidlSource("/home/user/fuchsia/out/debug-x86-64/gen/layer/public/lib/foo/fidl/interface.fidl-sync.cc"));
+        assert.equal("/home/user/fuchsia/layer/public/lib/foo/fidl/interface.fidl",
+            findFidlSource("/home/user/fuchsia/out/debug-x86-64/gen/layer/public/lib/foo/fidl/interface.fidl-sync.h"));
+    });
+});