Skip to content

Commit

Permalink
v2.3.0 - Merge pull request #130 from osu-cascades/dev
Browse files Browse the repository at this point in the history
  • Loading branch information
ctsstc committed Oct 10, 2020
2 parents cca963a + 801f04a commit ecb66e5
Show file tree
Hide file tree
Showing 34 changed files with 324 additions and 27 deletions.
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v13.7
v14.13.1
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodejs 14.13.1
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
|Staging Build|[![Build Status](https://travis-ci.org/osu-cascades/hackbot.svg?branch=dev)](https://travis-ci.org/osu-cascades/hackbot)|
|Maintainability|[![Maintainability](https://api.codeclimate.com/v1/badges/96320fe592c30381915f/maintainability)](https://codeclimate.com/github/osu-cascades/hackbot)|
|Test Coverage|[![Test Coverage](https://api.codeclimate.com/v1/badges/96320fe592c30381915f/test_coverage)](https://codeclimate.com/github/osu-cascades/hackbot)|
|GreenKeeper|[![Greenkeeper badge](https://badges.greenkeeper.io/osu-cascades/hackbot.svg)](https://greenkeeper.io/)|
|Snyk|[![Known Vulnerabilities](https://snyk.io/test/github/osu-cascades/hackbot/badge.svg?targetFile=package.json)](https://snyk.io/test/github/osu-cascades/hackbot?targetFile=package.json)|



A Discord bot for the Cascades Tech Club [Discord](http://discordapp.com) server. To add a command, see the [Commands](#commands) section below.

Expand Down
5 changes: 4 additions & 1 deletion __tests__/__mocks__/axios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ export default {
}),
request: jest.fn().mockResolvedValue({
data: {}
})
}),
post: jest.fn().mockResolvedValue({
data: {}
}),
};
17 changes: 17 additions & 0 deletions __tests__/commands/hacktoberfest.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Hacktoberfest from '@/commands/hacktoberfest';

import { message as mockMessage, MockedMessage } from '../mocks/discord';

let sendMock: MockedMessage;
beforeEach(() => {
sendMock = jest.fn();
mockMessage.channel.send = sendMock;
});

describe('Hacktoberfest command', () => {
test('hacktoberfest', () => {
Hacktoberfest.execute([], mockMessage);
const sentMessage = sendMock.mock.calls[0][0];
expect(sentMessage.includes('Hacktoberfest')).toEqual(true);
});
});
21 changes: 21 additions & 0 deletions __tests__/commands/run.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Run from '@/commands/run';
import { message as mockMessage, MockedMessage } from '../mocks/discord';

let sendMock: MockedMessage;
beforeEach(() => {
sendMock = jest.fn();
mockMessage.channel.send = sendMock;
mockMessage.reply = sendMock;
});

test('Malformed message', () => {
mockMessage.content = "Wow this is nowhere near the correct content";
Run.execute([], mockMessage);
expect(sendMock).lastCalledWith("Sorry, I ran into some problems understanding your message. Here is the error stopping me.\nError: Unable to extract code from Wow this is nowhere near the correct content");
});

test('Unknown language', () => {
mockMessage.content = "```invalidLanguage\nblahblahblah```";
Run.execute([], mockMessage);
expect(sendMock).lastCalledWith("Unknown language: invalidLanguage")
});
2 changes: 1 addition & 1 deletion __tests__/commands/source.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { message as mockMessage, MockedMessage } from '../mocks/discord';
import Source from '@/commands/source';
import { message as mockMessage, MockedMessage } from '../mocks/discord';

let sendMock: MockedMessage;
beforeEach(() => {
Expand Down
2 changes: 1 addition & 1 deletion __tests__/commands/version.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Version from '@/commands/version';
import { Message } from 'discord.js';
import { message as mockMessage, MockedMessage } from '../mocks/discord';
import Version from '@/commands/version';

let sendMock: MockedMessage;
beforeEach(() => {
Expand Down
21 changes: 21 additions & 0 deletions __tests__/languages/rust.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Rust from '@/runners/rust';
import axiosMock from '../__mocks__/axios';

jest.mock('axios');

test('valid code', async () => {
const code = "testCode";
let mockResponse = Promise.resolve({ data: { success: true, stdout: "test", stderr: " Compiling playground v0.0.1 (/playground)\n Finished dev [unoptimized + debuginfo] target(s) in 0.43s\n Running `target/debug/playground`\n" } });
axiosMock.post.mockResolvedValueOnce(mockResponse);
let result = await Rust.execute(code);
expect(result).toEqual({ success: true, output: "test" });
})

test('invalid code', async () => {
const code = "testCode";
const errorResult = "bad code";
let mockResponse = Promise.resolve({ data: { success: false, stdout: "", stderr: errorResult } });
axiosMock.post.mockResolvedValueOnce(mockResponse);
let result = await Rust.execute(code);
expect(result).toEqual({ success: false, output: errorResult });
})
2 changes: 1 addition & 1 deletion __tests__/library/commandLoader.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import glob from 'glob';
import CommandLoader, { ICommandClasses } from '@/library/commandLoader';
import glob from 'glob';

describe('CommandLoader', () => {
let commandClasses: ICommandClasses;
Expand Down
31 changes: 31 additions & 0 deletions __tests__/library/languages.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Languages from '@/library/languages';
import IRunner from '@/library/interfaces/iRunner';
import { ILanguageRunners } from '@/library/languageLoader';

describe('Languages', () => {
let mockLanguageRunner: IRunner;
let languageRunners: ILanguageRunners;
let languages: Languages;

beforeEach(() => {
mockLanguageRunner = {
execute: jest.fn()
};

languageRunners = {
testLang: mockLanguageRunner,
};

languages = new Languages(languageRunners);
});

test('.names returns language names', () => {
const languageNames = ['testLang'];
expect(languages.names).toEqual(languageNames);
});

test('Can fetch a command', () => {
const testLang = languages.get('testLang');
expect(testLang).toBe(mockLanguageRunner);
});
})
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hackbot",
"version": "2.2.0",
"version": "2.3.0",
"description": "Discord bot for the Cascades Tech Club Discord server.",
"repository": {
"type": "git",
Expand All @@ -22,7 +22,7 @@
"author": "osu-cascades",
"license": "MIT",
"engines": {
"node": "13.7.x"
"node": "14.13.x"
},
"dependencies": {
"@types/axios": "^0.14.0",
Expand Down
2 changes: 1 addition & 1 deletion src/commands/add.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Message } from "discord.js";
import ICommand from "@/library/interfaces/iCommand";
import { Message } from "discord.js";

let Add: ICommand;

Expand Down
2 changes: 1 addition & 1 deletion src/commands/format.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Message } from 'discord.js';
import ICommand from '@/library/interfaces/iCommand';
import { Message } from 'discord.js';

// Hack for implementing with static properties/methods
let Format: ICommand;
Expand Down
2 changes: 1 addition & 1 deletion src/commands/gitProfile.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ICommand from '@/library/interfaces/iCommand';
import axios from 'axios';
import { Message } from 'discord.js';
import moment from 'moment';
import ICommand from '@/library/interfaces/iCommand';
import IGithubProfile from './interfaces/iGithubProfile';

let GitProfile: ICommand;
Expand Down
17 changes: 17 additions & 0 deletions src/commands/hacktoberfest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import ICommand from '@/library/interfaces/iCommand';
import { Message } from 'discord.js';

// Hack for implementing with static properties/methods
let Hacktoberfest: ICommand;
export default Hacktoberfest = class {

static get description(): string {
return 'Lists information on how to participate in Hacktoberfest 2020';
}

public static execute(args: string[], msg: Message) {
const content = "Hacktoberfest has officially begun! Find out more information at\nhttps://hacktoberfest.digitalocean.com\nand stay tuned for opportunities and workshops from tech club members.";
return msg.channel.send(content);
}

};
2 changes: 1 addition & 1 deletion src/commands/help.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Message } from 'discord.js';
import config from '@/config';
import Commands from '@/library/commands';
import ICommand from '@/library/interfaces/iCommand';
import { Message } from 'discord.js';

let Help: ICommand;

Expand Down
2 changes: 1 addition & 1 deletion src/commands/lmgtfy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Message } from 'discord.js';
import ICommand from '@/library/interfaces/iCommand';
import { Message } from 'discord.js';

let Lmgtfy: ICommand;

Expand Down
2 changes: 1 addition & 1 deletion src/commands/magic8ball.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Message } from 'discord.js';
import ICommand from '@/library/interfaces/iCommand';
import { Message } from 'discord.js';

let Magic8Ball: ICommand;

Expand Down
2 changes: 1 addition & 1 deletion src/commands/rules.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Message } from 'discord.js';
import ICommand from '@/library/interfaces/iCommand';
import { Message } from 'discord.js';

let Rules: ICommand;

Expand Down
61 changes: 61 additions & 0 deletions src/commands/run.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import ICommand from '@/library/interfaces/iCommand';
import Languages from '@/library/languages';
import { Message } from 'discord.js';

const languages = new Languages();

// Hack for implementing with static properties/methods
let Run: ICommand;
export default Run = class {


/* istanbul ignore next */
static get description(): string {
return 'Executes provided code using a LanguageRunner';
}

public static execute(args: string[], msg: Message) {

let parseResponse;

try {
parseResponse = this.parseCode(msg.content);
if (!languages.get(parseResponse.language)) {
msg.channel.send(`Unknown language: ${parseResponse.language}`);
return;
}
} catch (e) {
msg.channel.send("Sorry, I ran into some problems understanding your message. Here is the error stopping me.\n" + e);
return;
}

const codeRunnerResponse = languages.get(parseResponse.language).execute(parseResponse.code);

codeRunnerResponse.then((response: { success: any; output: string; }) => {
if (response.success) {
msg.channel.send("```" + response.output + "```");
} else {
msg.channel.send(
"Unfortunately I was unable to run your code. Here is the error I received.\n```" +
response.output +
"```"
);
}
});

}

// Tries to pull language and source code out of message
private static parseCode(messageText: string): { language: string, code: string } {
const codeRegex = /(```(.[^\n]*))(\n(.*))(```)/s;
const match = codeRegex.exec(messageText);

// Group 2 = language, group 4 = code
if (match && match[2] && match[4]) {
return { language: match[2], code: match[4] };
} else {
throw new Error(`Unable to extract code from ${messageText}`);
}
}

};
2 changes: 1 addition & 1 deletion src/commands/say.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Message } from 'discord.js';
import ICommand from '@/library/interfaces/iCommand';
import { Message } from 'discord.js';

let Say: ICommand;

Expand Down
2 changes: 1 addition & 1 deletion src/commands/source.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Message } from 'discord.js';
import ICommand from '@/library/interfaces/iCommand';
import { Message } from 'discord.js';

let Source: ICommand;

Expand Down
2 changes: 1 addition & 1 deletion src/commands/version.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import config from '@/config';
import ICommand from '@/library/interfaces/iCommand';
import { version } from '@root/package.json';
import { Message } from 'discord.js';
import ICommand from '@/library/interfaces/iCommand';

let Version: ICommand;

Expand Down
4 changes: 2 additions & 2 deletions src/commands/weather.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios, { AxiosResponse } from 'axios';
import { Message } from 'discord.js';
import config from '@/config';
import ICommand from '@/library/interfaces/iCommand';
import axios, { AxiosResponse } from 'axios';
import { Message } from 'discord.js';

let Weather: ICommand;

Expand Down
2 changes: 1 addition & 1 deletion src/commands/xmas.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Message } from 'discord.js';
import ICommand from '@/library/interfaces/iCommand';
import { Message } from 'discord.js';

let Xmas: ICommand;

Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Client } from 'discord.js';
const client = new Client();
const core = new Core(client);

client.on('ready', () => core.ready);
client.on('ready', () => core.ready());

client.on('message', core.message);

Expand Down
3 changes: 2 additions & 1 deletion src/library/interfaces/iCommand.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Client, Message } from "discord.js";
import Commands from "@/commands";
import Commands from "@/library/commands";


/**
* An interface for all commands to extend, representing the API that all
Expand Down
10 changes: 10 additions & 0 deletions src/library/interfaces/iRunner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* An interface for all code runners to extend, representing the API that all
* subclasses should implement.
*
* @class Runner
*/

export default interface IRunner {
execute(code: string): Promise<{success: boolean, output: string}>;
}
Loading

0 comments on commit ecb66e5

Please sign in to comment.