Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finish existing tests [Phase 1] #12

Open
wants to merge 42 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
090605e
Update variable names in tests
Aug 15, 2017
dfa7314
Remove unnecessary variable assignments
Aug 15, 2017
5289005
Replace Windows-incompatible random string generation method
Aug 15, 2017
a5e228c
Bypass SSL validation in clone tests
Aug 15, 2017
cca19d1
Finish 'Apply clean' spec
Aug 15, 2017
5228532
Finish 'Apply smudge' spec
Aug 15, 2017
b608209
Refactor 'Amend Check/Smudge' tests
Aug 15, 2017
5aa57ad
Refactor out test constants
Aug 16, 2017
82c4cac
Finish `check` callback tests
Aug 16, 2017
bb7482a
Finish `initialize` callback tests
Aug 16, 2017
582544f
Finish `execHelper` tests
Aug 17, 2017
f1f8ba0
Bump `sinon` to 3.2.1
Aug 18, 2017
4c099e5
Stop swallowing Promise rejections in specs
Aug 21, 2017
9a333dd
Finish `spawnHelper` tests
Aug 21, 2017
3dba914
Finish helper tests
Aug 21, 2017
eb68183
Add object rest spread Babel plugin and fix devDependencies issue
Aug 21, 2017
afd6154
Don't redefine `NodeGitLFS` in tests
Aug 21, 2017
0cd12af
Finish `unregister` tests
Aug 21, 2017
9a7ed04
Remove unnecessary `regexResult` helper
Aug 21, 2017
e0fcf43
Add tests for project-wide helpers
Aug 21, 2017
e501cad
Finish 'clone' tests
Aug 22, 2017
5285d8d
Remove trailing commas
Aug 23, 2017
068f206
Add machinery to simulate a remote locally
Aug 24, 2017
fea3c93
Require `nodegit` 0.20.1
Aug 24, 2017
3d0da1b
Automatically register and unregister the LFS filters before and afte…
Aug 24, 2017
7338e57
Fix clone specs to use new simulated remote machinery
Aug 24, 2017
5ed34e5
Remove trailing commas (post-rebase)
Aug 24, 2017
2652ae1
Remove unnecessary variable assignments (post-rebase)
Aug 24, 2017
d375041
Allow `spawnHelper` to have the created process' `env` overwritten
Aug 25, 2017
b7d61ce
The `spawn` helper should reject if a non-0 exit code is returned
Aug 25, 2017
bb30f6f
Use pre-defined `*RepoPath` constants in tests
Aug 25, 2017
178fb61
Fix segfaults and such (and broken tests)
Aug 25, 2017
68e9f11
Add spec stubs [WIP]
Aug 29, 2017
465d6e4
Standardize test style
Aug 30, 2017
b89bdd0
Standardize error-handling logic
Aug 31, 2017
db59e7a
Kill LFS test server on unhandled Promise rejection in specs
Aug 31, 2017
f132bd7
Adjust for rebase-caused changes
Aug 31, 2017
8a70b3d
Remove unnecessary `branchName` option from the `pull` command
Sep 1, 2017
8152101
Add `errorCatchHandler` spec stubs
Sep 5, 2017
1aff4e5
Update spec stubs (post-rebase)
Sep 5, 2017
deedc94
Remove unnecessary `nodegit` imports
Sep 5, 2017
2536e2b
Fix `spawnHelper` tests (post-rebase)
Sep 5, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"plugins": ["transform-object-rest-spread"],
"presets": ["es2015"]
}
}
10 changes: 3 additions & 7 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,13 @@
],
"rules": {
"chai-friendly/no-unused-expressions": 2,
"comma-dangle": 0,
"comma-dangle": ["error", "never"],
"consistent-return": 0,
"func-names": 0,
"import/prefer-default-export": 0,
"linebreak-style": 0,
"no-bitwise": 0,
"no-param-reassign": 0,
"no-unnamed-functions": 0,
"no-unused-expressions": 0,

// this is for the tests, don't worrry about it for now
"import/no-unresolved": 1,
"import/extensions": 1
"no-unused-expressions": 0
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,7 @@ node_modules
# Generated test files
test/repos
test/server/lfs-test-server
test/server/local-repo
test/server/local-repo-cached

\.DS_Store
145 changes: 144 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,147 @@ Once cloned:
```
cd nodegit-lfs
yarn
```
```

## Tests

**Tests are still a Work In Progress.**
The tests rely on `mocha`, `chai`, `sinon`, and `sinon-chai`, and are currently a mix of system and unit tests.

### Naming

**TODO:** Split out system tests from unit tests and then revise the below guidlines.

These guidelines are inspired by [Better Specs { rspec guidelines with ruby }](https://www.betterspecs.org). Given that these guidelines are, by necessity, quite subjective, consider them as beneficial for the consistency rather than the "correctness" that they provide.

The linter should catch basic stylistic errors (e.g. prefer arrow functions unless `this` is needed).

---

When naming individual `it` blocks, the resulting test name should read like a sentence. For example: `it('returns false if the repo has no filters')`.

Directly describe what the test should do. Use verbs like `returns`, `errors`, `responds`, `reads`, etc. rather than prefixing tests with `should`, suffixing them with `correctly`, etc.. For example:

``` javascript
/* Bad */
it('should read globs from `.gitattributes` correctly', function () {
// ...
});

/* Good */
it('reads globs from `.gitattributes`', function () {
// ...
});
```

---

If you have the temptation to start a test with `can`, try to restructure the test to use a nested `describe` instead (whose message starts with `when`). For example:

``` javascript
/* Bad */
it('can initialize a non-LFS repo', function () {
// ...
});

/* Good */
describe('when provided a non-LFS repo', () => {
it('initializes the repo', function () {
// ...
});
});
```

---

For tests whose behavior varies cross-platform, surround the tests with a `process.platform` test. Be sure to add tests for all platforms where behavior could vary, even if you cannot run them locally. Because CI will run on Windows, macOS, and Linux, this should not be an obstacle to thorough test coverage. For example:

``` javascript
/* Bad */
describe('when on Windows', () => {
beforeEach(() => {
sinon.stub(process, 'platform').returns('win32');
});

it('runs the provided command', function () {
// ...
});
});

describe('when on macOS', () => {
beforeEach(() => {
sinon.stub(process, 'platform').returns('darwin');
});

it('runs the provided command', function () {
// ...
});
});

describe('when on Linux', () => {
beforeEach(() => {
sinon.stub(process, 'platform').returns('linux');
});

it('runs the provided command', function () {
// ...
});
});

/* Good */
switch (process.platform) {
case 'win32':
it('runs the provided command', function () {
// ...
});
break;
case 'macOS':
it('runs the provided command', function () {
// ...
});
break;
case 'linux':
it('runs the provided command', function () {
// ...
});
break;
}
```

---

When referring to parameters, use `provided` rather than `passed-in`, `given`, etc. For example:

``` javascript
/* Bad */
it('runs the passed-in command', function () {
// ...
});

/* Good */
it('runs the provided command', function () {
// ...
});
```

---

Each implementation file should correspond to a similarly-named `<file name>.spec.js` test file in the same relative location. For example, `src/callbacks/check.js` should have a test file located in `test/tests/callbacks/check.spec.js`.

The top-level `describe` should be named after the file. `describe`s for each function should be named after the function itself. On a related note, each function should have its own `describe` block, even if there is only `it` block inside it. In the case that a function does not have a pre-defined name (e.g. it's an anonymous function exported as the default), refer to it as `the default export`. For example:

``` javascript
/* For named exports: */
describe('helpers', () => { // Named after the file name, `helpers.spec.js`
describe('hasLfsFilters', () => { // Named after the exported function name, `hasLfsFilters`
// ...
});
});

/* For default exports: */
describe('check', () => {
describe('the default export', () => {
// ...
});
});
```
13 changes: 8 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "nodegit-lfs",
"version": "0.0.11",
"description": "A wrapper for NodeGit to facilitate LFS Support",
"description": "A wrapper for NodeGit to facilitate LFS support",
"main": "build/src/index.js",
"scripts": {
"build": "yarn eslint && yarn compile",
Expand Down Expand Up @@ -36,9 +36,6 @@
"nodegit": ">=0.20.1"
},
"devDependencies": {
"babel-cli": "^6.24.1",
"babel-core": "^6.25.0",
"babel-preset-es2015": "^6.24.1",
"chai": "^4.0.2",
"eslint": "^3.19.0",
"eslint-config-airbnb-base": "^11.2.0",
Expand All @@ -48,9 +45,15 @@
"jsdoc-to-markdown": "^3.0.0",
"mocha": "^3.4.2",
"nyc": "^11.0.3",
"prompt": "^1.0.0"
"prompt": "^1.0.0",
"sinon": "^3.2.1",
"sinon-chai": "^2.13.0"
},
"dependencies": {
"babel-cli": "^6.24.1",
"babel-core": "^6.25.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"default-shell": "^1.0.1",
"fs-extra": "^3.0.1",
"ignore": "^3.3.3",
Expand Down
10 changes: 4 additions & 6 deletions src/callbacks/check.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ export default src => loadGitattributeFiltersFromRepo(src.repo())
const file = src.path();
const filterIgnore = ignore().add(filters);

// these ignore rules are the closest to the .gitignore rules I have found
if (filterIgnore.ignores(file)) {
return Error.CODE.OK;
}

return Error.CODE.PASSTHROUGH;
// The rules for `.gitignore` are close enough to those for `.gitattributes`
return filterIgnore.ignores(file)
? Error.CODE.OK
: Error.CODE.PASSTHROUGH;
})
.catch(() => Error.CODE.PASSTHROUGH);
19 changes: 8 additions & 11 deletions src/commands/checkout.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ import { core } from './lfsCommands';
import {
regex,
BAD_CORE_RESPONSE,
BAD_REGEX_PARSE_RESULT,
BAD_REGEX_PARSE_RESULT
} from '../constants';

import generateResponse from '../utils/generateResponse';
import {
regexResult,
verifyOutput,
errorCatchHandler
} from '../helpers';
Expand All @@ -22,7 +21,7 @@ const generateCheckoutStats = (raw) => {
const filteredLines = R.filter(isValidLine, outputLines);
const statLine = filteredLines.pop();

const byteResults = regexResult(statLine, regex.TOTAL_BYTES);
const byteResults = statLine.match(regex.TOTAL_BYTES);

stats.total_bytes_checked_out =
byteResults !== null ?
Expand All @@ -32,19 +31,19 @@ const generateCheckoutStats = (raw) => {
byteResults !== null ?
byteResults[1].trim() : BAD_REGEX_PARSE_RESULT;

const fileResults = regexResult(statLine, regex.TOTAL_FILES);
const fileResults = statLine.match(regex.TOTAL_FILES);

stats.total_files_checked_out =
fileResults !== null ?
fileResults[0].trim() : BAD_REGEX_PARSE_RESULT;

const skippedByteResults = regexResult(statLine, regex.SKIPPED_BYTES);
const skippedByteResults = statLine.match(regex.SKIPPED_BYTES);

stats.total_bytes_skipped =
skippedByteResults !== null ?
skippedByteResults[0].trim() : BAD_REGEX_PARSE_RESULT;

const skippedFileResults = regexResult(statLine, regex.SKIPPED_FILES);
const skippedFileResults = statLine.match(regex.SKIPPED_FILES);

stats.total_files_skipped =
skippedFileResults !== null ?
Expand All @@ -62,11 +61,9 @@ const generateCheckoutStats = (raw) => {
};

function checkout(repo, callback) {
const response = generateResponse();
const repoPath = repo.workdir();

return core.checkout('', { cwd: repoPath }, callback)
return core.checkout('', { cwd: repo.workdir() }, callback)
.then(({ stdout }) => {
const response = generateResponse();
response.raw = stdout;
response.checkout = generateCheckoutStats(stdout);

Expand All @@ -77,7 +74,7 @@ function checkout(repo, callback) {
}

return response;
}, errorCatchHandler(response));
}, errorCatchHandler);
}

export default checkout;
28 changes: 14 additions & 14 deletions src/commands/clone.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import R from 'ramda';
import { core } from './lfsCommands';
import {
regex,
BAD_REGEX_PARSE_RESULT,
BAD_REGEX_PARSE_RESULT
} from '../constants';
import generateResponse from '../utils/generateResponse';
import {
regexResult,
errorCatchHandler,
verifyOutput } from '../helpers';
verifyOutput
} from '../helpers';

const isValidLine = str => str !== '';

Expand All @@ -19,7 +19,7 @@ const generateCloneStats = (raw) => {
const filteredLines = R.filter(isValidLine, outputLines);
const statLine = filteredLines.pop();

const byteResults = regexResult(statLine, regex.TOTAL_BYTES);
const byteResults = statLine.match(regex.TOTAL_BYTES);

stats.total_bytes_cloned =
byteResults !== null ?
Expand All @@ -29,19 +29,19 @@ const generateCloneStats = (raw) => {
byteResults !== null ?
byteResults[1].trim() : BAD_REGEX_PARSE_RESULT;

const fileResults = regexResult(statLine, regex.TOTAL_FILES);
const fileResults = statLine.match(regex.TOTAL_FILES);

stats.total_files_cloned =
fileResults !== null ?
fileResults[0].trim() : BAD_REGEX_PARSE_RESULT;

const skippedByteResults = regexResult(statLine, regex.SKIPPED_BYTES);
const skippedByteResults = statLine.match(regex.SKIPPED_BYTES);

stats.total_bytes_skipped =
skippedByteResults !== null ?
skippedByteResults[0].trim() : BAD_REGEX_PARSE_RESULT;

const skippedFileResults = regexResult(statLine, regex.SKIPPED_FILES);
const skippedFileResults = statLine.match(regex.SKIPPED_FILES);

stats.total_files_skipped =
skippedFileResults !== null ?
Expand All @@ -66,16 +66,16 @@ function clone(url, cwd, options) {
const {
branch,
callback,
env = {}
} = (options || {});
const args = branch ? `-b ${branch}` : '';

const response = generateResponse();
return core.clone(`${url} ${args}`, { cwd }, callback)
.then(({ stdout }) => {
response.raw = stdout;
response.clone = generateCloneStats(stdout);
return response;
}, errorCatchHandler(response));
return core.clone(`${url} ${args}`, { cwd, env }, callback)
.then(({ stdout }) => ({
...generateResponse(),
raw: stdout,
clone: generateCloneStats(stdout)
}), errorCatchHandler);
}

export default clone;
Loading