leetcode-cli
Version:
A cli tool to enjoy leetcode!
658 lines (565 loc) • 20.5 kB
JavaScript
var _ = require('underscore');
var assert = require('chai').assert;
var nock = require('nock');
var rewire = require('rewire');
var config = require('../../lib/config');
var log = require('../../lib/log');
var plugin = rewire('../../lib/plugins/leetcode');
var session = rewire('../../lib/session');
describe('plugin:leetcode', function() {
var USER = {hash: 'abcdef'};
var PROBLEM = {
id: 389,
name: 'Find the Difference',
slug: 'find-the-difference',
link: 'https://leetcode.com/problems/find-the-difference',
locked: false,
file: '/dev/null'
};
var SUBMISSION = {
id: '73790064',
lang: 'cpp',
runtime: '9 ms',
path: '/submissions/detail/73790064/',
state: 'Accepted'
};
before(function() {
log.init();
config.init();
plugin.init();
session.getUser = function() {
return USER;
};
session.saveUser = function() {};
plugin.__set__('session', session);
});
describe('#login', function() {
it('should ok', function(done) {
nock('https://leetcode.com')
.get('/accounts/login/')
.reply(200, '', {
'Set-Cookie': [
'csrftoken=LOGIN_CSRF_TOKEN; Max-Age=31449600; Path=/; secure'
]});
nock('https://leetcode.com')
.post('/accounts/login/')
.reply(302, '', {
'Set-Cookie': [
'csrftoken=SESSION_CSRF_TOKEN; Max-Age=31449600; Path=/; secure',
'LEETCODE_SESSION=SESSION_ID; Max-Age=31449600; Path=/; secure'
]});
nock('https://leetcode.com')
.get('/list/api/questions')
.reply(200, JSON.stringify({
user_name: 'Eric',
favorites: {
private_favorites: [{id_hash: 'abcdef', name: 'Favorite'}]
}
}));
plugin.login({}, function(e, user) {
assert.equal(e, null);
assert.equal(user.loginCSRF, 'LOGIN_CSRF_TOKEN');
assert.equal(user.sessionCSRF, 'SESSION_CSRF_TOKEN');
assert.equal(user.sessionId, 'SESSION_ID');
assert.equal(user.name, 'Eric');
assert.equal(user.hash, 'abcdef');
done();
});
});
it('should fail if http error', function(done) {
nock('https://leetcode.com')
.get('/accounts/login/')
.reply(200, '', {
'Set-Cookie': [
'csrftoken=LOGIN_CSRF_TOKEN; Max-Age=31449600; Path=/; secure'
]});
nock('https://leetcode.com')
.post('/accounts/login/')
.replyWithError('unknown error!');
plugin.login({}, function(e, user) {
assert.equal(e.message, 'unknown error!');
done();
});
});
it('should fail if http error, 2nd', function(done) {
nock('https://leetcode.com')
.get('/accounts/login/')
.replyWithError('unknown error!');
plugin.login({}, function(e, user) {
assert.equal(e.message, 'unknown error!');
done();
});
});
}); // #login
describe('#getProblems', function() {
it('should ok', function(done) {
nock('https://leetcode.com')
.get('/api/problems/algorithms/')
.replyWithFile(200, './test/mock/problems.json.20160911');
nock('https://leetcode.com')
.get('/api/problems/database/')
.replyWithFile(200, './test/mock/problems.json.20160911');
nock('https://leetcode.com')
.get('/api/problems/shell/')
.replyWithFile(200, './test/mock/problems.json.20160911');
plugin.getProblems(function(e, problems) {
assert.equal(e, null);
assert.equal(problems.length, 377 * 3);
done();
});
});
it('should fail if error occurs', function(done) {
nock('https://leetcode.com')
.get('/api/problems/algorithms/')
.replyWithFile(200, './test/mock/problems.json.20160911');
nock('https://leetcode.com')
.get('/api/problems/database/')
.replyWithError('unknown error');
nock('https://leetcode.com')
.get('/api/problems/shell/')
.replyWithFile(200, './test/mock/problems.json.20160911');
plugin.getProblems(function(e, problems) {
assert.equal(e.message, 'unknown error');
done();
});
});
}); // #getProblems
describe('#getCategoryProblems', function() {
it('should ok', function(done) {
nock('https://leetcode.com')
.get('/api/problems/algorithms/')
.replyWithFile(200, './test/mock/problems.json.20160911');
plugin.getCategoryProblems('algorithms', function(e, problems) {
assert.equal(e, null);
assert.equal(problems.length, 377);
done();
});
});
it('should fail if not login', function(done) {
config.autologin.enable = false;
nock('https://leetcode.com')
.get('/api/problems/algorithms/')
.replyWithFile(200, './test/mock/problems.nologin.json.20161015');
plugin.getCategoryProblems('algorithms', function(e, problems) {
assert.deepEqual(e, session.errors.EXPIRED);
done();
});
});
}); // #getCategoryProblems
describe('#getProblem', function() {
beforeEach(function() {
PROBLEM.locked = false;
});
it('should ok', function(done) {
nock('https://leetcode.com')
.post('/graphql')
.replyWithFile(200, './test/mock/find-the-difference.json.20171216');
plugin.getProblem(PROBLEM, function(e, problem) {
assert.equal(e, null);
assert.equal(problem.totalAC, '89.7K');
assert.equal(problem.totalSubmit, '175.7K');
assert.equal(problem.desc,
[
'',
'Given two strings s and t which consist of only lowercase letters.',
'',
'String t is generated by random shuffling string s and then add one more letter at a random position.',
'',
'Find the letter that was added in t.',
'',
'Example:',
'',
'Input:',
's = "abcd"',
't = "abcde"',
'',
'Output:',
'e',
'',
'Explanation:',
"'e' is the letter that was added.",
''
].join('\r\n'));
assert.equal(problem.templates.length, 12);
assert.equal(problem.templates[0].value, 'cpp');
assert.equal(problem.templates[0].text, 'C++');
assert.equal(problem.templates[0].defaultCode,
[
'class Solution {',
'public:',
' char findTheDifference(string s, string t) {',
' ',
' }',
'};'
].join('\r\n'));
assert.equal(problem.templates[1].value, 'java');
assert.equal(problem.templates[1].text, 'Java');
assert.equal(problem.templates[1].defaultCode,
[
'class Solution {',
' public char findTheDifference(String s, String t) {',
' ',
' }',
'}'
].join('\r\n'));
assert.equal(problem.templates[2].value, 'python');
assert.equal(problem.templates[2].text, 'Python');
assert.equal(problem.templates[2].defaultCode,
[
'class Solution(object):',
' def findTheDifference(self, s, t):',
' """',
' :type s: str',
' :type t: str',
' :rtype: str',
' """',
' '
].join('\r\n'));
assert.equal(problem.templates[3].value, 'python3');
assert.equal(problem.templates[3].text, 'Python3');
assert.equal(problem.templates[3].defaultCode,
[
'class Solution:',
' def findTheDifference(self, s, t):',
' """',
' :type s: str',
' :type t: str',
' :rtype: str',
' """',
' '
].join('\r\n'));
assert.equal(problem.templates[4].value, 'c');
assert.equal(problem.templates[4].text, 'C');
assert.equal(problem.templates[4].defaultCode,
[
'char findTheDifference(char* s, char* t) {',
' ',
'}'
].join('\r\n'));
assert.equal(problem.templates[5].value, 'csharp');
assert.equal(problem.templates[5].text, 'C#');
assert.equal(problem.templates[5].defaultCode,
[
'public class Solution {',
' public char FindTheDifference(string s, string t) {',
' ',
' }',
'}'
].join('\r\n'));
assert.equal(problem.templates[6].value, 'javascript');
assert.equal(problem.templates[6].text, 'JavaScript');
assert.equal(problem.templates[6].defaultCode,
[
'/**',
' * @param {string} s',
' * @param {string} t',
' * @return {character}',
' */',
'var findTheDifference = function(s, t) {',
' ',
'};'
].join('\r\n'));
assert.equal(problem.templates[7].value, 'ruby');
assert.equal(problem.templates[7].text, 'Ruby');
assert.equal(problem.templates[7].defaultCode,
[
'# @param {String} s',
'# @param {String} t',
'# @return {Character}',
'def find_the_difference(s, t)',
' ',
'end'
].join('\r\n'));
assert.equal(problem.templates[8].value, 'swift');
assert.equal(problem.templates[8].text, 'Swift');
assert.equal(problem.templates[8].defaultCode,
[
'class Solution {',
' func findTheDifference(_ s: String, _ t: String) -> Character {',
' ',
' }',
'}'
].join('\r\n'));
assert.equal(problem.templates[9].value, 'golang');
assert.equal(problem.templates[9].text, 'Go');
assert.equal(problem.templates[9].defaultCode,
[
'func findTheDifference(s string, t string) byte {',
' ',
'}'
].join('\r\n'));
assert.equal(problem.templates[10].value, 'scala');
assert.equal(problem.templates[10].text, 'Scala');
assert.equal(problem.templates[10].defaultCode,
[
'object Solution {',
' def findTheDifference(s: String, t: String): Char = {',
' ',
' }',
'}'
].join('\n'));
assert.equal(problem.templates[11].value, 'kotlin');
assert.equal(problem.templates[11].text, 'Kotlin');
assert.equal(problem.templates[11].defaultCode,
[
'class Solution {',
' fun findTheDifference(s: String, t: String): Char {',
' ',
' }',
'}'
].join('\n'));
done();
});
});
it('should fail if no permission for locked', function(done) {
PROBLEM.locked = true;
plugin.getProblem(PROBLEM, function(e, problem) {
assert.equal(e, 'failed to load locked problem!');
done();
});
});
it('should fail if session expired', function(done) {
nock('https://leetcode.com').post('/graphql').reply(403);
plugin.getProblem(PROBLEM, function(e, problem) {
assert.equal(e, session.errors.EXPIRED);
done();
});
});
it('should fail if http error', function(done) {
nock('https://leetcode.com').post('/graphql').reply(500);
plugin.getProblem(PROBLEM, function(e, problem) {
assert.deepEqual(e, {msg: 'http error', statusCode: 500});
done();
});
});
it('should fail if unknown error', function(done) {
nock('https://leetcode.com').post('/graphql').replyWithError('unknown error!');
plugin.getProblem(PROBLEM, function(e, problem) {
assert.equal(e.message, 'unknown error!');
done();
});
});
}); // #getProblem
describe('#testProblem', function() {
it('should ok', function(done) {
nock('https://leetcode.com')
.post('/problems/find-the-difference/interpret_solution/')
.reply(200, '{"interpret_expected_id": "id1", "interpret_id": "id2"}');
nock('https://leetcode.com')
.get('/submissions/detail/id1/check/')
.reply(200, '{"state": "SUCCESS", "run_success": true, "status_code": 10}');
nock('https://leetcode.com')
.get('/submissions/detail/id2/check/')
.reply(200, '{"state": "SUCCESS", "run_success": false, "status_code": 15}');
plugin.testProblem(PROBLEM, function(e, results) {
assert.equal(e, null);
assert.equal(results[0].id, 'id2');
assert.equal(results[0].ok, false);
assert.equal(results[1].id, 'id1');
assert.equal(results[1].ok, true);
done();
});
});
it('should fail if http error', function(done) {
nock('https://leetcode.com')
.post('/problems/find-the-difference/interpret_solution/')
.replyWithError('unknown error!');
plugin.testProblem(PROBLEM, function(e, results) {
assert.equal(e.message, 'unknown error!');
done();
});
});
}); // #testProblem
describe('#submitProblem', function() {
it('should ok', function(done) {
nock('https://leetcode.com')
.post('/problems/find-the-difference/submit/')
.reply(200, '{"submission_id": "id1"}');
nock('https://leetcode.com')
.get('/submissions/detail/id1/check/')
.reply(200, '{"state": "SUCCESS", "run_success": true, "status_code": 10}');
plugin.submitProblem(PROBLEM, function(e, results) {
assert.equal(e, null);
assert.equal(results[0].id, 'id1');
assert.equal(results[0].ok, true);
done();
});
});
it('should ok after delay', function(done) {
this.timeout(5000);
nock('https://leetcode.com')
.post('/problems/find-the-difference/submit/')
.reply(200, '{"error": "You run code too soon"}');
nock('https://leetcode.com')
.post('/problems/find-the-difference/submit/')
.reply(200, '{"submission_id": "id1"}');
nock('https://leetcode.com')
.get('/submissions/detail/id1/check/')
.reply(200, '{"state": "STARTED"}');
nock('https://leetcode.com')
.get('/submissions/detail/id1/check/')
.reply(200, '{"state": "SUCCESS", "run_success": true, "status_code": 10}');
plugin.submitProblem(PROBLEM, function(e, results) {
assert.equal(e, null);
assert.equal(results[0].id, 'id1');
assert.equal(results[0].ok, true);
done();
});
});
it('should fail if server error', function(done) {
nock('https://leetcode.com')
.post('/problems/find-the-difference/submit/')
.reply(200, '{"error": "maybe internal error?"}');
plugin.submitProblem(PROBLEM, function(e, results) {
assert.equal(e, 'maybe internal error?');
done();
});
});
it('should fail if server error in check result', function(done) {
nock('https://leetcode.com')
.post('/problems/find-the-difference/submit/')
.reply(200, '{"submission_id": "id1"}');
nock('https://leetcode.com')
.get('/submissions/detail/id1/check/')
.replyWithError('unknown error!');
plugin.submitProblem(PROBLEM, function(e, results) {
assert.equal(e.message, 'unknown error!');
done();
});
});
}); // #submitProblem
describe('#starProblem', function() {
it('should star ok', function(done) {
nock('https://leetcode.com')
.post('/list/api/questions')
.reply(204, '');
plugin.starProblem(PROBLEM, true, function(e, starred) {
assert.equal(e, null);
assert.equal(starred, true);
done();
});
});
it('should unstar ok', function(done) {
nock('https://leetcode.com')
.delete('/list/api/questions/abcdef/389')
.reply(204, '');
plugin.starProblem(PROBLEM, false, function(e, starred) {
assert.equal(e, null);
assert.equal(starred, false);
done();
});
});
it('should star fail if http error', function(done) {
nock('https://leetcode.com')
.post('/list/api/questions')
.replyWithError('unknown error!');
plugin.starProblem(PROBLEM, true, function(e, starred) {
assert.equal(e.message, 'unknown error!');
done();
});
});
}); // #starProblem
describe('#getSubmissions', function() {
it('should ok', function(done) {
var problem = {
id: 1,
name: 'Two Sum',
slug: 'two-sum',
link: 'https://leetcode.com/problems/two-sum',
locked: false
};
nock('https://leetcode.com')
.get('/api/submissions/two-sum')
.replyWithFile(200, './test/mock/two-sum.submissions.json.20170425');
plugin.getSubmissions(problem, function(e, submissions) {
assert.equal(e, null);
assert.equal(submissions.length, 20);
assert.deepEqual(submissions[0], {
id: '95464136',
title: 'Two Sum',
is_pending: false,
lang: 'cpp',
time: '1 month, 3 weeks',
runtime: '12 ms',
url: '/submissions/detail/95464136/',
status_display: 'Accepted'
});
assert.deepEqual(submissions[1], {
id: '78502271',
title: 'Two Sum',
is_pending: false,
lang: 'cpp',
time: '6 months, 1 week',
runtime: '13 ms',
url: '/submissions/detail/78502271/',
status_display: 'Accepted'
});
done();
});
});
it('should fail if http error', function(done) {
nock('https://leetcode.com')
.get('/api/submissions/find-the-difference')
.replyWithError('unknown error!');
plugin.getSubmissions(PROBLEM, function(e, submissions) {
assert.equal(e.message, 'unknown error!');
done();
});
});
}); // #getSubmissions
describe('#getSubmission', function() {
it('should ok', function(done) {
nock('https://leetcode.com')
.get('/submissions/detail/73790064/')
.replyWithFile(200, './test/mock/two-sum.submission.73790064.html.20161006');
plugin.getSubmission(_.clone(SUBMISSION), function(e, submission) {
assert.equal(e, null);
assert.deepEqual(submission.code,
[
'class Solution {',
'public:',
' vector<int> twoSum(vector<int>& nums, int target) {',
' return res;',
' }',
'};',
''
].join('\r\n'));
done();
});
});
it('should fail if http error', function(done) {
nock('https://leetcode.com')
.get('/submissions/detail/73790064/')
.replyWithError('unknown error!');
plugin.getSubmission(_.clone(SUBMISSION), function(e, submission) {
assert.equal(e.message, 'unknown error!');
done();
});
});
it('should fail if no matching submission', function(done) {
nock('https://leetcode.com')
.get('/submissions/detail/73790064/')
.replyWithFile(200, './test/mock/locked.html.20161015');
plugin.getSubmission(_.clone(SUBMISSION), function(e, submission) {
assert.equal(e, null);
assert.equal(submission.code, null);
done();
});
});
}); // #getSubmission
describe('#getFavorites', function() {
it('should ok', function(done) {
nock('https://leetcode.com')
.get('/list/api/questions')
.replyWithFile(200, './test/mock/favorites.json.20170716');
plugin.getFavorites(function(e, favorites) {
assert.equal(e, null);
var my = favorites.favorites.private_favorites;
assert.equal(my.length, 1);
assert.equal(my[0].name, 'Favorite');
assert.equal(my[0].id_hash, 'abcdefg');
done();
});
});
}); // #getFavorites
});