diff --git a/src/discordcommandhandler.ts b/src/discordcommandhandler.ts
index efcb53fc637140d1663042d2b88b44aa3d04bede..042ec66ca8a5d4604c8add86cc13fbd02c96b4c6 100644
--- a/src/discordcommandhandler.ts
+++ b/src/discordcommandhandler.ts
@@ -1,3 +1,19 @@
+/*
+Copyright 2019 matrix-appservice-discord
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 import { DiscordBot } from "./bot";
 import * as Discord from "discord.js";
 import { Util, ICommandActions, ICommandParameters, CommandPermissonCheck } from "./util";
diff --git a/src/matrixcommandhandler.ts b/src/matrixcommandhandler.ts
index b2bbcf040a959d60547099fbed09493835974541..0660d331f888833158f0edf7a3c5b20cb4890742 100644
--- a/src/matrixcommandhandler.ts
+++ b/src/matrixcommandhandler.ts
@@ -1,3 +1,19 @@
+/*
+Copyright 2019 matrix-appservice-discord
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 import { DiscordBot } from "./bot";
 import { Log } from "./log";
 import { DiscordBridgeConfig } from "./config";
diff --git a/test/test_util.ts b/test/test_util.ts
index 5f294efe3f2b63137e7494bbcc39366f3feb4115..ed109f1aacb8234b0536e2af4000ab6ca458f668 100644
--- a/test/test_util.ts
+++ b/test/test_util.ts
@@ -60,35 +60,72 @@ describe("Util", () => {
             Chai.assert.equal(args[1], "arg2");
         });
     });
-    describe("ParseCommand", () => {
-        it("parses commands", async () => {
-            const actions: ICommandActions = {
-                action: {
-                    params: ["param1", "param2"],
-                    run: async ({param1, param2}) => {
-                        return `param1: ${param1}\nparam2: ${param2}`;
-                    },
+    describe("Command Stuff", () => {
+        const actions: ICommandActions = {
+            action: {
+                description: "floof",
+                help: "Fox goes floof!",
+                params: ["param1", "param2"],
+                run: async ({param1, param2}) => {
+                    return `param1: ${param1}\nparam2: ${param2}`;
                 },
-            };
-            const parameters: ICommandParameters = {
-                param1: {
-                    get: async (param: string) => {
-                        return "param1_" + param;
-                    },
+            },
+        };
+        const parameters: ICommandParameters = {
+            param1: {
+                description: "1",
+                get: async (param: string) => {
+                    return "param1_" + param;
                 },
-                param2: {
-                    get: async (param: string) => {
-                        return "param2_" + param;
-                    },
+            },
+            param2: {
+                description: "2",
+                get: async (param: string) => {
+                    return "param2_" + param;
                 },
-            };
-            const retStr = await Util.ParseCommand(
-                "!fox",
-                "!fox action hello world",
-                actions,
-                parameters,
-            );
-            expect(retStr).equal("param1: param1_hello\nparam2: param2_world");
+            },
+        };
+        describe("ParseHelpMessage", () => {
+            it("parses general help message", async () => {
+                const {command, args} = Util.MsgToArgs("!fox help", "!fox");
+                const retStr = await Util.ParseHelpMessage(
+                    "!fox",
+                    actions,
+                    parameters,
+                    args,
+                );
+                expect(retStr).to.equal(
+`Available Commands:
+ - \`!fox action <param1> <param2>\`: floof
+
+Parameters:
+ - \`<param1>\`: 1
+ - \`<param2>\`: 2
+`);
+            });
+            it("parses specific help message", async () => {
+                const {command, args} = Util.MsgToArgs("!fox help action", "!fox");
+                const retStr = await Util.ParseHelpMessage(
+                    "!fox",
+                    actions,
+                    parameters,
+                    args,
+                );
+                expect(retStr).to.equal(
+`\`!fox action <param1> <param2>\`: floof
+Fox goes floof!`);
+            });
+        });
+        describe("ParseCommand", () => {
+            it("parses commands", async () => {
+                const retStr = await Util.ParseCommand(
+                    "!fox",
+                    "!fox action hello world",
+                    actions,
+                    parameters,
+                );
+                expect(retStr).equal("param1: param1_hello\nparam2: param2_world");
+            });
         });
     });
     describe("GetMxidFromName", () => {
@@ -194,4 +231,84 @@ describe("Util", () => {
             expect(Date.now()).to.be.greaterThan(t + DELAY_FOR - 1);
         });
     });
+    describe("CheckMatrixPermission", () => {
+        const PERM_LEVEL = 50;
+        it("should deny", async () => {
+            const ret = await Util.CheckMatrixPermission(
+                {
+                    getStateEvent: async () => {
+                        return {
+                            blah: {
+                                blubb: PERM_LEVEL,
+                            },
+                        };
+                    },
+                } as any,
+                "@user:localhost",
+                "",
+                PERM_LEVEL,
+                "blah",
+                "blubb",
+            );
+            expect(ret).to.be.false;
+        });
+        it("should allow cat/subcat", async () => {
+            const ret = await Util.CheckMatrixPermission(
+                {
+                    getStateEvent: async () => {
+                        return {
+                            blah: {
+                                blubb: PERM_LEVEL,
+                            },
+                            users: {
+                                "@user:localhost": PERM_LEVEL,
+                            },
+                        };
+                    },
+                } as any,
+                "@user:localhost",
+                "",
+                PERM_LEVEL,
+                "blah",
+                "blubb",
+            );
+            expect(ret).to.be.true;
+        });
+        it("should allow cat", async () => {
+            const ret = await Util.CheckMatrixPermission(
+                {
+                    getStateEvent: async () => {
+                        return {
+                            blah: PERM_LEVEL,
+                            users: {
+                                "@user:localhost": PERM_LEVEL,
+                            },
+                        };
+                    },
+                } as any,
+                "@user:localhost",
+                "",
+                PERM_LEVEL,
+                "blah",
+            );
+            expect(ret).to.be.true;
+        });
+        it("should allow based on default", async () => {
+            const ret = await Util.CheckMatrixPermission(
+                {
+                    getStateEvent: async () => {
+                        return {
+                            blah: PERM_LEVEL,
+                            users_default: PERM_LEVEL,
+                        };
+                    },
+                } as any,
+                "@user:localhost",
+                "",
+                PERM_LEVEL,
+                "blah",
+            );
+            expect(ret).to.be.true;
+        });
+    });
 });