Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7b5a6ec30 | ||
|
|
da9576fee0 | ||
|
|
579df25be4 | ||
|
|
1886c0c9ec | ||
|
|
f48176bebf | ||
|
|
83f64fbdcd | ||
|
|
a7bf5e60f3 | ||
|
|
e0cd041d98 | ||
|
|
4f76e9da60 | ||
|
|
966cc5af92 | ||
|
|
f4998d90e7 | ||
|
|
245496c854 | ||
|
|
d553f6c069 | ||
|
|
afd0694111 | ||
|
|
32db9cdec6 | ||
|
|
ad3cd7e7ac | ||
|
|
e719c68321 | ||
|
|
ce3b4ed43d | ||
|
|
2953c15e5e | ||
|
|
b2b1021207 | ||
|
|
9ddfd58a2b | ||
|
|
fe1476f875 | ||
|
|
067a87a07c | ||
|
|
5133ee713f | ||
|
|
2ac7881cf2 |
12
.github/codeql/codeql-config.yml
vendored
Normal file
12
.github/codeql/codeql-config.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
name: "CodeQL config"
|
||||
queries:
|
||||
- name: Run standard queries
|
||||
uses: security-and-quality
|
||||
- name: Run custom javascript queries
|
||||
uses: ./.github/codeql/queries
|
||||
paths:
|
||||
- ./extensions/ql-vscode
|
||||
paths-ignore:
|
||||
- '**/node_modules'
|
||||
- '**/build'
|
||||
- '**/out'
|
||||
21
.github/codeql/queries/assert-pure.ql
vendored
Normal file
21
.github/codeql/queries/assert-pure.ql
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @name Unwanted dependency on vscode API
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @id vscode-codeql/assert-pure
|
||||
* @description The modules stored under `pure` and tested in the `pure-tests`
|
||||
* are intended to be "pure".
|
||||
*/
|
||||
import javascript
|
||||
|
||||
class VSCodeImport extends ASTNode {
|
||||
VSCodeImport() {
|
||||
this.(Import).getImportedPath().getValue() = "vscode"
|
||||
}
|
||||
}
|
||||
|
||||
from Module m, VSCodeImport v
|
||||
where
|
||||
m.getFile().getRelativePath().regexpMatch(".*src/pure/.*") and
|
||||
m.getAnImportedModule*().getAnImport() = v
|
||||
select m, "This module is not pure: it has a transitive dependency on the vscode API imported $@", v, "here"
|
||||
3
.github/codeql/queries/qlpack.yml
vendored
Normal file
3
.github/codeql/queries/qlpack.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
name: vscode-codeql-custom-queries-javascript
|
||||
version: 0.0.0
|
||||
libraryPathDependencies: codeql-javascript
|
||||
3
.github/workflows/codeql.yml
vendored
3
.github/workflows/codeql.yml
vendored
@@ -17,6 +17,9 @@ jobs:
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: javascript
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
|
||||
18
.github/workflows/release.yml
vendored
18
.github/workflows/release.yml
vendored
@@ -6,20 +6,16 @@
|
||||
|
||||
name: Release
|
||||
on:
|
||||
push:
|
||||
# Path filters are not evaluated for pushes to tags.
|
||||
# (source: https://help.github.com/en/github/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#onpushpull_requestpaths)
|
||||
# So this workflow is triggered in the following events:
|
||||
# - Release event: a SemVer tag, e.g. v1.0.0 or v1.0.0-alpha, is pushed
|
||||
tags:
|
||||
- 'v[0-9]+.[0-9]+.[0-9]+*'
|
||||
# OR
|
||||
# - Test event: this file is modified on a branch in the main repo containing `/actions/` in the name.
|
||||
branches:
|
||||
- '**/actions/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- '**/workflows/release.yml'
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
push:
|
||||
tags:
|
||||
- 'v[0-9]+.[0-9]+.[0-9]+*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Release
|
||||
|
||||
5
.vscode/launch.json
vendored
5
.vscode/launch.json
vendored
@@ -16,8 +16,9 @@
|
||||
"${workspaceRoot}/extensions/ql-vscode/out/**/*.js",
|
||||
],
|
||||
"env": {
|
||||
// uncomment to allow debugging the language server Java process from a remote java debugger
|
||||
// "DEBUG_LANGUAGE_SERVER": "true"
|
||||
// change to 'true' debug the IDE or Query servers
|
||||
"IDE_SERVER_JAVA_DEBUG": "false",
|
||||
"QUERY_SERVER_JAVA_DEBUG": "false",
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -91,15 +91,28 @@ Alternatively, you can run the tests inside of vscode. There are several vscode
|
||||
|
||||
## Releasing (write access required)
|
||||
|
||||
1. Double-check the `CHANGELOG.md` contains all desired change comments
|
||||
and has the version to be released with date at the top.
|
||||
1. Double-check that the extension `package.json` has the version you intend to release.
|
||||
If you are doing a patch release (as opposed to minor or major version) this should already
|
||||
be correct.
|
||||
1. Trigger a release build on Actions by adding a new tag on branch `main` of the format `vxx.xx.xx`
|
||||
1. Double-check the `CHANGELOG.md` contains all desired change comments and has the version to be released with date at the top.
|
||||
* Go through all recent PRs and make sure they are properly accounted for.
|
||||
* Make sure all changelog entries have links back to their PR(s) if appropriate.
|
||||
1. Double-check that the extension `package.json` has the version you intend to release. If you are doing a patch release (as opposed to minor or major version) this should already be correct.
|
||||
1. Create a PR for this release:
|
||||
* This PR will contain any missing bits from steps 1 and 2. Most of the time, this will just be updating `CHANGELOG.md` with today's date.
|
||||
* Create a new branch for the release named after the new version. For example: `v1.3.6`
|
||||
* Create a new commit with a message the same as the branch name.
|
||||
* Create a PR for this branch.
|
||||
* Wait for the PR to be merged into `main`
|
||||
1. Trigger a release build on Actions by adding a new tag on branch `main` named after the release, as above. Note that when you push to upstream, you will need to fully qualify the ref. A command like this will work:
|
||||
|
||||
```bash
|
||||
git push upstream refs/tags/v1.3.6
|
||||
```
|
||||
|
||||
* **IMPORTANT** Make sure you are on the `main` branch and your local checkout is fully updated when you add the tag.
|
||||
* If you accidentally add the tag to the wrong ref, you can just force push it to the right one later.
|
||||
|
||||
1. Monitor the status of the release build in the `Release` workflow in the Actions tab.
|
||||
1. Download the VSIX from the draft GitHub release at the top of [the releases page](https://github.com/github/vscode-codeql/releases) that is created when the release build finishes.
|
||||
1. Optionally unzip the `.vsix` and inspect its `package.json` to make sure the version is what you expect,
|
||||
1. Unzip the `.vsix` and inspect its `package.json` to make sure the version is what you expect,
|
||||
or look at the source if there's any doubt the right code is being shipped.
|
||||
1. Log into the [Visual Studio Marketplace](https://marketplace.visualstudio.com/manage/publishers/github).
|
||||
1. Click the `...` menu in the CodeQL row and click **Update**.
|
||||
|
||||
@@ -1,8 +1,28 @@
|
||||
# CodeQL for Visual Studio Code: Changelog
|
||||
|
||||
## 1.3.7 - 24 November 2020
|
||||
|
||||
- Editors opened by navigating from the results view are no longer opened in _preview mode_. Now they are opened as a persistent editor. [#630](https://github.com/github/vscode-codeql/pull/630)
|
||||
- When comparing the results of a failed QL test run and the `.expected` file does not exist, an empty `.expected` file is created and compared against the `.actual` file. [#669](https://github.com/github/vscode-codeql/pull/669)
|
||||
- Alter structure of the _Test Explorer_ tree. It now follows the structure of the filesystem instead of the QL Packs. [#624](https://github.com/github/vscode-codeql/pull/624)
|
||||
- Alter structure of the _Test Explorer_ tree. It now follows the structure of the filesystem instead of the QL Packs. [#624](https://github.com/github/vscode-codeql/pull/624)
|
||||
- Add more structured output for tests. [#626](https://github.com/github/vscode-codeql/pull/626)
|
||||
- Whenever the extension restarts, orphaned databases will be cleaned up. These are databases whose files are located inside of the extension's storage area, but are not imported into the workspace.
|
||||
- After renaming a database, the database list is re-sorted. [#685](https://github.com/github/vscode-codeql/pull/685)
|
||||
- Add a `codeQl.resultsDisplay.pageSize` setting to configure the number of results displayed in a single results view page. Increase the default page size from 100 to 200. [#686](https://github.com/github/vscode-codeql/pull/686)
|
||||
- Update the AST Viewer to include edge labels (if available) in addition to the target node labels. So far, only C/C++ databases take advantage of this change. [#688](https://github.com/github/vscode-codeql/pull/688)
|
||||
|
||||
## 1.3.6 - 4 November 2020
|
||||
|
||||
- Fix URI encoding for databases that were created with special characters in their paths. [#648](https://github.com/github/vscode-codeql/pull/648)
|
||||
- Disable CodeQL Test commands from the command palette [#667](https://github.com/github/vscode-codeql/pull/667)
|
||||
- Fix display of booleans in results view. [#657](https://github.com/github/vscode-codeql/pull/657)
|
||||
- Avoid recursive selection changes in AST Viewer. [#668](https://github.com/github/vscode-codeql/pull/668)
|
||||
|
||||
## 1.3.5 - 27 October 2020
|
||||
|
||||
- Fix a bug where archived source folders for databases were not showing any contents.
|
||||
- Fix URI encoding for databases that were created with special characters in their paths.
|
||||
|
||||
## 1.3.4 - 22 October 2020
|
||||
|
||||
@@ -19,6 +39,8 @@
|
||||
- Add a `View DIL` command on query history items. This opens a text editor containing the Datalog Intermediary Language representation of the compiled query.
|
||||
- Remove feature flag for the AST Viewer. For more information on how to use the AST Viewer, [see the documentation](https://help.semmle.com/codeql/codeql-for-vscode/procedures/exploring-the-structure-of-your-source-code.html).
|
||||
- The `codeQL.runningTests.numberOfThreads` setting is now used correctly when running tests.
|
||||
- Alter structure of the _Test Explorer_ tree. It now follows the structure of the filesystem instead of the qlpacks.
|
||||
- Ensure output of CodeQL test runs includes compilation error messages and test failure messages.
|
||||
|
||||
## 1.3.3 - 16 September 2020
|
||||
|
||||
|
||||
62
extensions/ql-vscode/package-lock.json
generated
62
extensions/ql-vscode/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vscode-codeql",
|
||||
"version": "1.3.5",
|
||||
"version": "1.3.7",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -217,9 +217,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/fs-extra": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.1.tgz",
|
||||
"integrity": "sha512-TcUlBem321DFQzBNuz8p0CLLKp0VvF/XH9E4KHNmgwyp4E3AfgI5cjiIVZWlbfThBop2qxFIh4+LeY6hVWWZ2w==",
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.3.tgz",
|
||||
"integrity": "sha512-NKdGoXLTFTRED3ENcfCsH8+ekV4gbsysanx2OPbstXVV6fZMgUCqTxubs6I9r7pbOJbFgVq1rpFtLURjKCZWUw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
@@ -310,9 +310,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "12.12.50",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.50.tgz",
|
||||
"integrity": "sha512-5ImO01Fb8YsEOYpV+aeyGYztcYcjGsBvN4D7G5r1ef2cuQOpymjWNQi5V0rKHE6PC2ru3HkoUr/Br2/8GUA84w==",
|
||||
"version": "12.19.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.4.tgz",
|
||||
"integrity": "sha512-o3oj1bETk8kBwzz1WlO6JWL/AfAA3Vm6J1B3C9CsdxHYp7XgPiH7OEXPUbZTndHlRaIElrANkQfe6ZmfJb3H2w==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node-fetch": {
|
||||
@@ -1251,6 +1251,11 @@
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
|
||||
"dev": true
|
||||
},
|
||||
"at-least-node": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
||||
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
|
||||
},
|
||||
"atob": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
||||
@@ -3748,13 +3753,14 @@
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
|
||||
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
|
||||
"integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
|
||||
"requires": {
|
||||
"at-least-node": "^1.0.0",
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^4.0.0",
|
||||
"universalify": "^0.1.0"
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"fs-mkdirp-stream": {
|
||||
@@ -5026,11 +5032,19 @@
|
||||
"dev": true
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
||||
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
"graceful-fs": "^4.1.6",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"universalify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"jsx-ast-utils": {
|
||||
@@ -9001,9 +9015,9 @@
|
||||
}
|
||||
},
|
||||
"universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
|
||||
"integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug=="
|
||||
},
|
||||
"unset-value": {
|
||||
"version": "1.0.0",
|
||||
@@ -10016,6 +10030,16 @@
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "5.0.0-security.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz",
|
||||
"integrity": "sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "^3.0.0",
|
||||
"object.assign": "^4.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"description": "CodeQL for Visual Studio Code",
|
||||
"author": "GitHub",
|
||||
"private": true,
|
||||
"version": "1.3.5",
|
||||
"version": "1.3.7",
|
||||
"publisher": "GitHub",
|
||||
"license": "MIT",
|
||||
"icon": "media/VS-marketplace-CodeQL-icon.png",
|
||||
@@ -157,6 +157,11 @@
|
||||
"default": 20,
|
||||
"description": "Max number of simultaneous queries to run using the 'CodeQL: Run Queries' command."
|
||||
},
|
||||
"codeQL.resultsDisplay.pageSize": {
|
||||
"type": "integer",
|
||||
"default": 200,
|
||||
"description": "Number of queries displayed per page of the results view."
|
||||
},
|
||||
"codeQL.queryHistory.format": {
|
||||
"type": "string",
|
||||
"default": "[%t] %q on %d - %s",
|
||||
@@ -197,6 +202,10 @@
|
||||
"dark": "media/dark/folder-opened-plus.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "codeQLDatabases.removeOrphanedDatabases",
|
||||
"title": "Delete unused databases"
|
||||
},
|
||||
{
|
||||
"command": "codeQLDatabases.chooseDatabaseArchive",
|
||||
"title": "Choose Database from Archive",
|
||||
@@ -355,11 +364,11 @@
|
||||
},
|
||||
{
|
||||
"command": "codeQLTests.showOutputDifferences",
|
||||
"title": "CodeQL: Show Test Output Differences"
|
||||
"title": "Show Test Output Differences"
|
||||
},
|
||||
{
|
||||
"command": "codeQLTests.acceptOutput",
|
||||
"title": "CodeQL: Accept Test Output"
|
||||
"title": "Accept Test Output"
|
||||
},
|
||||
{
|
||||
"command": "codeQLAstViewer.gotoCode",
|
||||
@@ -573,6 +582,10 @@
|
||||
"command": "codeQLDatabases.chooseDatabaseArchive",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "codeQLDatabases.removeOrphanedDatabases",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "codeQLDatabases.chooseDatabaseInternet",
|
||||
"when": "false"
|
||||
@@ -628,6 +641,14 @@
|
||||
{
|
||||
"command": "codeQLAstViewer.clear",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "codeQLTests.acceptOutput",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "codeQLTests.showOutputDifferences",
|
||||
"when": "false"
|
||||
}
|
||||
],
|
||||
"editor/context": [
|
||||
@@ -696,7 +717,7 @@
|
||||
"dependencies": {
|
||||
"child-process-promise": "^2.2.1",
|
||||
"classnames": "~2.2.6",
|
||||
"fs-extra": "^8.1.0",
|
||||
"fs-extra": "^9.0.1",
|
||||
"glob-promise": "^3.4.0",
|
||||
"js-yaml": "^3.14.0",
|
||||
"minimist": "~1.2.5",
|
||||
@@ -719,7 +740,7 @@
|
||||
"@types/chai-as-promised": "~7.1.2",
|
||||
"@types/child-process-promise": "^2.2.1",
|
||||
"@types/classnames": "~2.2.9",
|
||||
"@types/fs-extra": "^8.0.0",
|
||||
"@types/fs-extra": "^9.0.3",
|
||||
"@types/glob": "^7.1.1",
|
||||
"@types/google-protobuf": "^3.2.7",
|
||||
"@types/gulp": "^4.0.6",
|
||||
@@ -727,7 +748,7 @@
|
||||
"@types/js-yaml": "^3.12.5",
|
||||
"@types/jszip": "~3.1.6",
|
||||
"@types/mocha": "~8.0.3",
|
||||
"@types/node": "^12.0.8",
|
||||
"@types/node": "^12.14.1",
|
||||
"@types/node-fetch": "~2.5.2",
|
||||
"@types/proxyquire": "~1.3.28",
|
||||
"@types/react": "^16.8.17",
|
||||
|
||||
@@ -84,7 +84,7 @@ export function encodeSourceArchiveUri(ref: ZipFileReference): vscode.Uri {
|
||||
// This lets us separate the paths, ignoring the leading slash if we added one.
|
||||
const sourceArchiveZipPathEndIndex = sourceArchiveZipPathStartIndex + sourceArchiveZipPath.length;
|
||||
const authority = `${sourceArchiveZipPathStartIndex}-${sourceArchiveZipPathEndIndex}`;
|
||||
return vscode.Uri.parse(zipArchiveScheme + ':/').with({
|
||||
return vscode.Uri.parse(zipArchiveScheme + ':/', true).with({
|
||||
path: encodedPath,
|
||||
authority,
|
||||
});
|
||||
|
||||
@@ -8,15 +8,16 @@ import {
|
||||
TreeItem,
|
||||
TreeView,
|
||||
TextEditorSelectionChangeEvent,
|
||||
TextEditorSelectionChangeKind,
|
||||
Location,
|
||||
Range
|
||||
} from 'vscode';
|
||||
import * as path from 'path';
|
||||
|
||||
import { DatabaseItem } from './databases';
|
||||
import { UrlValue, BqrsId } from './bqrs-cli-types';
|
||||
import { UrlValue, BqrsId } from './pure/bqrs-cli-types';
|
||||
import { showLocation } from './interface-utils';
|
||||
import { isStringLoc, isWholeFileLoc, isLineColumnLoc } from './bqrs-utils';
|
||||
import { isStringLoc, isWholeFileLoc, isLineColumnLoc } from './pure/bqrs-utils';
|
||||
import { commandRunner } from './helpers';
|
||||
import { DisposableObject } from './vscode-utils/disposable-object';
|
||||
|
||||
@@ -33,7 +34,7 @@ export interface ChildAstItem extends AstItem {
|
||||
parent: ChildAstItem | AstItem;
|
||||
}
|
||||
|
||||
class AstViewerDataProvider extends DisposableObject implements TreeDataProvider<AstItem> {
|
||||
class AstViewerDataProvider extends DisposableObject implements TreeDataProvider<AstItem> {
|
||||
|
||||
public roots: AstItem[] = [];
|
||||
public db: DatabaseItem | undefined;
|
||||
@@ -47,9 +48,9 @@ class AstViewerDataProvider extends DisposableObject implements TreeDataProvide
|
||||
super();
|
||||
this.push(
|
||||
commandRunner('codeQLAstViewer.gotoCode',
|
||||
async (item: AstItem) => {
|
||||
await showLocation(item.fileLocation);
|
||||
})
|
||||
async (item: AstItem) => {
|
||||
await showLocation(item.fileLocation);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -160,6 +161,11 @@ export class AstViewer extends DisposableObject {
|
||||
return;
|
||||
}
|
||||
|
||||
// Avoid recursive tree-source code updates.
|
||||
if (e.kind === TextEditorSelectionChangeKind.Command) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
this.treeView.visible &&
|
||||
e.textEditor.document.uri.fsPath === this.currentFile &&
|
||||
|
||||
@@ -11,12 +11,13 @@ import * as tk from 'tree-kill';
|
||||
import { promisify } from 'util';
|
||||
import { CancellationToken, Disposable } from 'vscode';
|
||||
|
||||
import { BQRSInfo, DecodedBqrsChunk } from './bqrs-cli-types';
|
||||
import { BQRSInfo, DecodedBqrsChunk } from './pure/bqrs-cli-types';
|
||||
import { CliConfig } from './config';
|
||||
import { DistributionProvider, FindDistributionResultKind } from './distribution';
|
||||
import { assertNever } from './helpers-pure';
|
||||
import { QueryMetadata, SortDirection } from './interface-types';
|
||||
import { assertNever } from './pure/helpers-pure';
|
||||
import { QueryMetadata, SortDirection } from './pure/interface-types';
|
||||
import { Logger, ProgressReporter } from './logging';
|
||||
import { CompilationMessage } from './pure/messages';
|
||||
|
||||
/**
|
||||
* The version of the SARIF format that we are using.
|
||||
@@ -90,10 +91,11 @@ export interface TestRunOptions {
|
||||
export interface TestCompleted {
|
||||
test: string;
|
||||
pass: boolean;
|
||||
messages: string[];
|
||||
messages: CompilationMessage[];
|
||||
compilationMs: number;
|
||||
evaluationMs: number;
|
||||
expected: string;
|
||||
diff: string[] | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -470,7 +472,11 @@ export class CodeQLCliServer implements Disposable {
|
||||
const subcommandArgs = [
|
||||
testPath
|
||||
];
|
||||
return await this.runJsonCodeQlCliCommand<ResolvedTests>(['resolve', 'tests'], subcommandArgs, 'Resolving tests');
|
||||
return await this.runJsonCodeQlCliCommand<ResolvedTests>(
|
||||
['resolve', 'tests', '--strict-test-discovery'],
|
||||
subcommandArgs,
|
||||
'Resolving tests'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -702,7 +708,7 @@ export class CodeQLCliServer implements Disposable {
|
||||
|
||||
private async refreshVersion() {
|
||||
const distribution = await this.distributionProvider.getDistribution();
|
||||
switch(distribution.kind) {
|
||||
switch (distribution.kind) {
|
||||
case FindDistributionResultKind.CompatibleDistribution:
|
||||
// eslint-disable-next-line no-fallthrough
|
||||
case FindDistributionResultKind.IncompatibleDistribution:
|
||||
@@ -901,3 +907,16 @@ async function logStream(stream: Readable, logger: Logger): Promise<void> {
|
||||
logger.log(line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function shouldDebugIdeServer() {
|
||||
return 'IDE_SERVER_JAVA_DEBUG' in process.env
|
||||
&& process.env.IDE_SERVER_JAVA_DEBUG !== '0'
|
||||
&& process.env.IDE_SERVER_JAVA_DEBUG?.toLocaleLowerCase() !== 'false';
|
||||
}
|
||||
|
||||
export function shouldDebugQueryServer() {
|
||||
return 'QUERY_SERVER_JAVA_DEBUG' in process.env
|
||||
&& process.env.QUERY_SERVER_JAVA_DEBUG !== '0'
|
||||
&& process.env.QUERY_SERVER_JAVA_DEBUG?.toLocaleLowerCase() !== 'false';
|
||||
}
|
||||
|
||||
@@ -14,12 +14,12 @@ import {
|
||||
FromCompareViewMessage,
|
||||
ToCompareViewMessage,
|
||||
QueryCompareResult,
|
||||
} from '../interface-types';
|
||||
} from '../pure/interface-types';
|
||||
import { Logger } from '../logging';
|
||||
import { CodeQLCliServer } from '../cli';
|
||||
import { DatabaseManager } from '../databases';
|
||||
import { getHtmlForWebview, jumpToLocation } from '../interface-utils';
|
||||
import { transformBqrsResultSet, RawResultSet, BQRSInfo } from '../bqrs-cli-types';
|
||||
import { transformBqrsResultSet, RawResultSet, BQRSInfo } from '../pure/bqrs-cli-types';
|
||||
import resultsDiff from './resultsDiff';
|
||||
|
||||
interface ComparePair {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { RawResultSet } from '../bqrs-cli-types';
|
||||
import { QueryCompareResult } from '../interface-types';
|
||||
import { RawResultSet } from '../pure/bqrs-cli-types';
|
||||
import { QueryCompareResult } from '../pure/interface-types';
|
||||
|
||||
/**
|
||||
* Compare the rows of two queries. Use deep equality to determine if
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as Rdom from 'react-dom';
|
||||
import {
|
||||
ToCompareViewMessage,
|
||||
SetComparisonsMessage,
|
||||
} from '../../interface-types';
|
||||
} from '../../pure/interface-types';
|
||||
import CompareSelector from './CompareSelector';
|
||||
import { vscode } from '../../view/vscode-api';
|
||||
import CompareTable from './CompareTable';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { SetComparisonsMessage } from '../../interface-types';
|
||||
import { SetComparisonsMessage } from '../../pure/interface-types';
|
||||
import RawTableHeader from '../../view/RawTableHeader';
|
||||
import { className } from '../../view/result-table-utils';
|
||||
import { ResultRow } from '../../bqrs-cli-types';
|
||||
import { ResultRow } from '../../pure/bqrs-cli-types';
|
||||
import RawTableRow from '../../view/RawTableRow';
|
||||
import { vscode } from '../../view/vscode-api';
|
||||
|
||||
|
||||
@@ -68,10 +68,12 @@ const TIMEOUT_SETTING = new Setting('timeout', RUNNING_QUERIES_SETTING);
|
||||
const MEMORY_SETTING = new Setting('memory', RUNNING_QUERIES_SETTING);
|
||||
const DEBUG_SETTING = new Setting('debug', RUNNING_QUERIES_SETTING);
|
||||
const RUNNING_TESTS_SETTING = new Setting('runningTests', ROOT_SETTING);
|
||||
const RESULTS_DISPLAY_SETTING = new Setting('resultsDisplay', ROOT_SETTING);
|
||||
|
||||
export const NUMBER_OF_TEST_THREADS_SETTING = new Setting('numberOfThreads', RUNNING_TESTS_SETTING);
|
||||
export const MAX_QUERIES = new Setting('maxQueries', RUNNING_QUERIES_SETTING);
|
||||
export const AUTOSAVE_SETTING = new Setting('autoSave', RUNNING_QUERIES_SETTING);
|
||||
export const PAGE_SIZE = new Setting('pageSize', RESULTS_DISPLAY_SETTING);
|
||||
|
||||
/** When these settings change, the running query server should be restarted. */
|
||||
const QUERY_SERVER_RESTARTING_SETTINGS = [NUMBER_OF_THREADS_SETTING, MEMORY_SETTING, DEBUG_SETTING];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { QueryWithResults } from '../run-queries';
|
||||
import { CodeQLCliServer } from '../cli';
|
||||
import { DecodedBqrsChunk, BqrsId, EntityValue } from '../bqrs-cli-types';
|
||||
import { DecodedBqrsChunk, BqrsId, EntityValue } from '../pure/bqrs-cli-types';
|
||||
import { DatabaseItem } from '../databases';
|
||||
import { ChildAstItem, AstItem } from '../astViewer';
|
||||
import fileRangeFromURI from './fileRangeFromURI';
|
||||
@@ -45,17 +45,18 @@ export default class AstBuilder {
|
||||
const parentToChildren = new Map<BqrsId, BqrsId[]>();
|
||||
const childToParent = new Map<BqrsId, BqrsId>();
|
||||
const astOrder = new Map<BqrsId, number>();
|
||||
const edgeLabels = new Map<BqrsId, string>();
|
||||
const roots = [];
|
||||
|
||||
// Build up the parent-child relationships
|
||||
edgeTuples.tuples.forEach(tuple => {
|
||||
const [source, target, tupleType, orderValue] = tuple as [EntityValue, EntityValue, string, string];
|
||||
const [source, target, tupleType, value] = tuple as [EntityValue, EntityValue, string, string];
|
||||
const sourceId = source.id!;
|
||||
const targetId = target.id!;
|
||||
|
||||
switch (tupleType) {
|
||||
case 'semmle.order':
|
||||
astOrder.set(targetId, Number(orderValue));
|
||||
astOrder.set(targetId, Number(value));
|
||||
break;
|
||||
|
||||
case 'semmle.label': {
|
||||
@@ -65,6 +66,11 @@ export default class AstBuilder {
|
||||
parentToChildren.set(sourceId, children = []);
|
||||
}
|
||||
children.push(targetId);
|
||||
|
||||
// ignore values that indicate a numeric order.
|
||||
if (!Number.isFinite(Number(value))) {
|
||||
edgeLabels.set(targetId, value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -75,18 +81,22 @@ export default class AstBuilder {
|
||||
|
||||
// populate parents and children
|
||||
nodeTuples.tuples.forEach(tuple => {
|
||||
const [entity, tupleType, orderValue] = tuple as [EntityValue, string, string];
|
||||
const [entity, tupleType, value] = tuple as [EntityValue, string, string];
|
||||
const id = entity.id!;
|
||||
|
||||
switch (tupleType) {
|
||||
case 'semmle.order':
|
||||
astOrder.set(id, Number(orderValue));
|
||||
astOrder.set(id, Number(value));
|
||||
break;
|
||||
|
||||
case 'semmle.label': {
|
||||
// If an edge label exists, include it and separate from the node label using ':'
|
||||
const nodeLabel = value ?? entity.label;
|
||||
const edgeLabel = edgeLabels.get(id);
|
||||
const label = [edgeLabel, nodeLabel].filter(e => e).join(': ');
|
||||
const item = {
|
||||
id,
|
||||
label: entity.label,
|
||||
label,
|
||||
location: entity.url,
|
||||
fileLocation: fileRangeFromURI(entity.url, this.db),
|
||||
children: [] as ChildAstItem[],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import { UrlValue, LineColumnLocation } from '../bqrs-cli-types';
|
||||
import { isEmptyPath } from '../bqrs-utils';
|
||||
import { UrlValue, LineColumnLocation } from '../pure/bqrs-cli-types';
|
||||
import { isEmptyPath } from '../pure/bqrs-utils';
|
||||
import { DatabaseItem } from '../databases';
|
||||
|
||||
|
||||
@@ -20,9 +20,8 @@ export default function fileRangeFromURI(uri: UrlValue | undefined, db: Database
|
||||
Math.max(0, (loc.endLine || 0) - 1),
|
||||
Math.max(0, (loc.endColumn || 0)));
|
||||
try {
|
||||
const parsed = vscode.Uri.parse(uri.uri, true);
|
||||
if (parsed.scheme === 'file') {
|
||||
return new vscode.Location(db.resolveSourceFile(parsed.fsPath), range);
|
||||
if (uri.uri.startsWith('file:')) {
|
||||
return new vscode.Location(db.resolveSourceFile(uri.uri), range);
|
||||
}
|
||||
return undefined;
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import { decodeSourceArchiveUri, encodeArchiveBasePath } from '../archive-filesystem-provider';
|
||||
import { ColumnKindCode, EntityValue, getResultSetSchema, ResultSetSchema } from '../bqrs-cli-types';
|
||||
import { ColumnKindCode, EntityValue, getResultSetSchema, ResultSetSchema } from '../pure/bqrs-cli-types';
|
||||
import { CodeQLCliServer } from '../cli';
|
||||
import { DatabaseManager, DatabaseItem } from '../databases';
|
||||
import fileRangeFromURI from './fileRangeFromURI';
|
||||
import * as messages from '../messages';
|
||||
import * as messages from '../pure/messages';
|
||||
import { QueryServerClient } from '../queryserver-client';
|
||||
import { QueryWithResults, compileAndRunQueryAgainstDatabase } from '../run-queries';
|
||||
import { ProgressCallback } from '../helpers';
|
||||
@@ -43,7 +43,7 @@ export async function getLocationsForUriString(
|
||||
token: vscode.CancellationToken,
|
||||
filter: (src: string, dest: string) => boolean
|
||||
): Promise<FullLocationLink[]> {
|
||||
const uri = decodeSourceArchiveUri(vscode.Uri.parse(uriString));
|
||||
const uri = decodeSourceArchiveUri(vscode.Uri.parse(uriString, true));
|
||||
const sourceArchiveUri = encodeArchiveBasePath(uri.sourceArchiveZipPath);
|
||||
|
||||
const db = dbm.findDatabaseItemBySourceArchive(sourceArchiveUri);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { decodeSourceArchiveUri, encodeArchiveBasePath, zipArchiveScheme } from
|
||||
import { CodeQLCliServer } from '../cli';
|
||||
import { DatabaseManager } from '../databases';
|
||||
import { CachedOperation, ProgressCallback, withProgress } from '../helpers';
|
||||
import * as messages from '../messages';
|
||||
import * as messages from '../pure/messages';
|
||||
import { QueryServerClient } from '../queryserver-client';
|
||||
import { compileAndRunQueryAgainstDatabase, QueryWithResults } from '../run-queries';
|
||||
import AstBuilder from './astBuilder';
|
||||
@@ -136,7 +136,7 @@ export class TemplatePrintAstProvider {
|
||||
|
||||
return new AstBuilder(
|
||||
queryResults, this.cli,
|
||||
this.dbm.findDatabaseItem(vscode.Uri.parse(queryResults.database.databaseUri!))!,
|
||||
this.dbm.findDatabaseItem(vscode.Uri.parse(queryResults.database.databaseUri!, true))!,
|
||||
document.fileName
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
TreeItem,
|
||||
Uri,
|
||||
window,
|
||||
env
|
||||
env,
|
||||
} from 'vscode';
|
||||
import * as fs from 'fs-extra';
|
||||
|
||||
@@ -18,6 +18,8 @@ import {
|
||||
DatabaseItem,
|
||||
DatabaseManager,
|
||||
getUpgradesDirectories,
|
||||
isLikelyDatabaseRoot,
|
||||
isLikelyDbLanguageFolder,
|
||||
} from './databases';
|
||||
import {
|
||||
commandRunner,
|
||||
@@ -35,7 +37,8 @@ import {
|
||||
promptImportInternetDatabase,
|
||||
promptImportLgtmDatabase,
|
||||
} from './databaseFetcher';
|
||||
import { CancellationToken } from 'vscode-jsonrpc';
|
||||
import { CancellationToken } from 'vscode';
|
||||
import { asyncFilter } from './pure/helpers-pure';
|
||||
|
||||
type ThemableIconPath = { light: string; dark: string } | string;
|
||||
|
||||
@@ -229,7 +232,9 @@ export class DatabaseUI extends DisposableObject {
|
||||
canSelectMany: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
init() {
|
||||
logger.log('Registering database panel commands.');
|
||||
this.push(
|
||||
commandRunnerWithProgress(
|
||||
@@ -340,6 +345,12 @@ export class DatabaseUI extends DisposableObject {
|
||||
this.handleOpenFolder
|
||||
)
|
||||
);
|
||||
this.push(
|
||||
commandRunner(
|
||||
'codeQLDatabases.removeOrphanedDatabases',
|
||||
this.handleRemoveOrphanedDatabases
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private handleMakeCurrentDatabase = async (
|
||||
@@ -360,6 +371,53 @@ export class DatabaseUI extends DisposableObject {
|
||||
}
|
||||
};
|
||||
|
||||
handleRemoveOrphanedDatabases = async (): Promise<void> => {
|
||||
logger.log('Removing orphaned databases from workspace storage.');
|
||||
let dbDirs =
|
||||
// read directory
|
||||
(await fs.readdir(this.storagePath, { withFileTypes: true }))
|
||||
// remove non-directories
|
||||
.filter(dirent => dirent.isDirectory())
|
||||
// get the full path
|
||||
.map(dirent => path.join(this.storagePath, dirent.name))
|
||||
// remove databases still in workspace
|
||||
.filter(dbDir => {
|
||||
const dbUri = Uri.file(dbDir);
|
||||
return this.databaseManager.databaseItems.every(item => item.databaseUri.fsPath !== dbUri.fsPath);
|
||||
});
|
||||
|
||||
// remove non-databases
|
||||
dbDirs = await asyncFilter(dbDirs, isLikelyDatabaseRoot);
|
||||
|
||||
if (!dbDirs.length) {
|
||||
logger.log('No orphaned databases found.');
|
||||
return;
|
||||
}
|
||||
|
||||
// delete
|
||||
const failures = [] as string[];
|
||||
await Promise.all(
|
||||
dbDirs.map(async dbDir => {
|
||||
try {
|
||||
logger.log(`Deleting orphaned database '${dbDir}'.`);
|
||||
await fs.rmdir(dbDir, { recursive: true } as any); // typings doesn't recognize the options argument
|
||||
} catch (e) {
|
||||
failures.push(`${path.basename(dbDir)}`);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if (failures.length) {
|
||||
const dirname = path.dirname(failures[0]);
|
||||
showAndLogErrorMessage(
|
||||
`Failed to delete unused databases:\n ${
|
||||
failures.join('\n ')
|
||||
}\n. To delete unused databases, please remove them manually from the storage folder ${dirname}.`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
handleChooseDatabaseArchive = async (
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken
|
||||
@@ -653,7 +711,7 @@ export class DatabaseUI extends DisposableObject {
|
||||
dbPath = path.dirname(dbPath);
|
||||
}
|
||||
|
||||
if (isLikelyDbFolder(dbPath)) {
|
||||
if (isLikelyDbLanguageFolder(dbPath)) {
|
||||
dbPath = path.dirname(dbPath);
|
||||
}
|
||||
return Uri.file(dbPath);
|
||||
@@ -668,9 +726,3 @@ export class DatabaseUI extends DisposableObject {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Get the list of supported languages from a list that will be auto-updated.
|
||||
const dbRegeEx = /^db-(javascript|go|cpp|java|python|csharp)$/;
|
||||
function isLikelyDbFolder(dbPath: string) {
|
||||
return path.basename(dbPath).match(dbRegeEx);
|
||||
}
|
||||
|
||||
@@ -341,28 +341,29 @@ export class DatabaseItemImpl implements DatabaseItem {
|
||||
}
|
||||
}
|
||||
|
||||
public resolveSourceFile(uri: string | undefined): vscode.Uri {
|
||||
public resolveSourceFile(uriStr: string | undefined): vscode.Uri {
|
||||
const sourceArchive = this.sourceArchive;
|
||||
// Sometimes, we are passed a path, sometimes a file URI.
|
||||
// We need to convert this to a file path that is probably inside of a zip file.
|
||||
const file = uri?.replace(/file:/, '');
|
||||
const uri = uriStr ? vscode.Uri.parse(uriStr, true) : undefined;
|
||||
if (uri && uri.scheme !== 'file') {
|
||||
throw new Error(`Invalid uri scheme in ${uriStr}. Only 'file' is allowed.`);
|
||||
}
|
||||
if (!sourceArchive) {
|
||||
if (file) {
|
||||
// Treat it as an absolute path.
|
||||
return vscode.Uri.file(file);
|
||||
if (uri) {
|
||||
return uri;
|
||||
} else {
|
||||
return this.databaseUri;
|
||||
}
|
||||
}
|
||||
|
||||
if (file) {
|
||||
const absoluteFilePath = file.replace(':', '_');
|
||||
// Strip any leading slashes from the file path, and replace `:` with `_`.
|
||||
const relativeFilePath = absoluteFilePath.replace(/^\/*/, '').replace(':', '_');
|
||||
if (uri) {
|
||||
const relativeFilePath = decodeURI(uri.path).replace(':', '_').replace(/^\/*/, '');
|
||||
if (sourceArchive.scheme === zipArchiveScheme) {
|
||||
const zipRef = decodeSourceArchiveUri(sourceArchive);
|
||||
const pathWithinSourceArchive = zipRef.pathWithinSourceArchive === '/'
|
||||
? relativeFilePath
|
||||
: zipRef.pathWithinSourceArchive + '/' + relativeFilePath;
|
||||
return encodeSourceArchiveUri({
|
||||
pathWithinSourceArchive: zipRef.pathWithinSourceArchive + '/' + absoluteFilePath,
|
||||
pathWithinSourceArchive,
|
||||
sourceArchiveZipPath: zipRef.sourceArchiveZipPath,
|
||||
});
|
||||
|
||||
@@ -396,10 +397,7 @@ export class DatabaseItemImpl implements DatabaseItem {
|
||||
* Holds if the database item refers to an exported snapshot
|
||||
*/
|
||||
public async hasMetadataFile(): Promise<boolean> {
|
||||
return (await Promise.all([
|
||||
fs.pathExists(path.join(this.databaseUri.fsPath, '.dbinfo')),
|
||||
fs.pathExists(path.join(this.databaseUri.fsPath, 'codeql-database.yml'))
|
||||
])).some(x => x);
|
||||
return await isLikelyDatabaseRoot(this.databaseUri.fsPath);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -579,7 +577,7 @@ export class DatabaseManager extends DisposableObject {
|
||||
displayName,
|
||||
dateAdded
|
||||
};
|
||||
const item = new DatabaseItemImpl(vscode.Uri.parse(state.uri), undefined, fullOptions,
|
||||
const item = new DatabaseItemImpl(vscode.Uri.parse(state.uri, true), undefined, fullOptions,
|
||||
(event) => {
|
||||
this._onDidChangeDatabaseItem.fire(event);
|
||||
});
|
||||
@@ -669,7 +667,8 @@ export class DatabaseManager extends DisposableObject {
|
||||
item.name = newName;
|
||||
this.updatePersistedDatabaseList();
|
||||
this._onDidChangeDatabaseItem.fire({
|
||||
item,
|
||||
// pass undefined so that the entire tree is rebuilt in order to re-sort
|
||||
item: undefined,
|
||||
kind: DatabaseEventKind.Rename
|
||||
});
|
||||
}
|
||||
@@ -729,3 +728,23 @@ export function getUpgradesDirectories(scripts: string[]): vscode.Uri[] {
|
||||
const uniqueParentDirs = new Set(parentDirs);
|
||||
return Array.from(uniqueParentDirs).map(filePath => vscode.Uri.file(filePath));
|
||||
}
|
||||
|
||||
|
||||
// TODO: Get the list of supported languages from a list that will be auto-updated.
|
||||
|
||||
export async function isLikelyDatabaseRoot(fsPath: string) {
|
||||
const [a, b, c] = (await Promise.all([
|
||||
// databases can have either .dbinfo or codeql-database.yml.
|
||||
fs.pathExists(path.join(fsPath, '.dbinfo')),
|
||||
fs.pathExists(path.join(fsPath, 'codeql-database.yml')),
|
||||
|
||||
// they *must* have a db-language folder
|
||||
(await fs.readdir(fsPath)).some(isLikelyDbLanguageFolder)
|
||||
]));
|
||||
|
||||
return (a || b) && c;
|
||||
}
|
||||
|
||||
export function isLikelyDbLanguageFolder(dbPath: string) {
|
||||
return !!path.basename(dbPath).startsWith('db-');
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ import {
|
||||
GithubRateLimitedError
|
||||
} from './distribution';
|
||||
import * as helpers from './helpers';
|
||||
import { assertNever } from './helpers-pure';
|
||||
import { assertNever } from './pure/helpers-pure';
|
||||
import { spawnIdeServer } from './ide-server';
|
||||
import { InterfaceManager } from './interface';
|
||||
import { WebviewReveal } from './interface-utils';
|
||||
@@ -58,7 +58,7 @@ import { compileAndRunQueryAgainstDatabase, tmpDirDisposal } from './run-queries
|
||||
import { QLTestAdapterFactory } from './test-adapter';
|
||||
import { TestUIService } from './test-ui';
|
||||
import { CompareInterfaceManager } from './compare/compare-interface';
|
||||
import { gatherQlFiles } from './files';
|
||||
import { gatherQlFiles } from './pure/files';
|
||||
|
||||
/**
|
||||
* extension.ts
|
||||
@@ -349,6 +349,7 @@ async function activateWithInstalledDistribution(
|
||||
getContextStoragePath(ctx),
|
||||
ctx.extensionPath
|
||||
);
|
||||
databaseUI.init();
|
||||
ctx.subscriptions.push(databaseUI);
|
||||
|
||||
logger.log('Initializing query history manager.');
|
||||
@@ -643,6 +644,8 @@ async function activateWithInstalledDistribution(
|
||||
title: 'Calculate AST'
|
||||
}));
|
||||
|
||||
commands.executeCommand('codeQLDatabases.removeOrphanedDatabases');
|
||||
|
||||
logger.log('Successfully finished extension initialization.');
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import { ideServerLogger } from './logging';
|
||||
export async function spawnIdeServer(config: QueryServerConfig): Promise<StreamInfo> {
|
||||
return window.withProgress({ title: 'CodeQL language server', location: ProgressLocation.Window }, async (progressReporter, _) => {
|
||||
const args = ['--check-errors', 'ON_CHANGE'];
|
||||
if (shouldDebug()) {
|
||||
if (cli.shouldDebugIdeServer()) {
|
||||
args.push('-J=-agentlib:jdwp=transport=dt_socket,address=localhost:9009,server=y,suspend=n,quiet=y');
|
||||
}
|
||||
const child = cli.spawnServer(
|
||||
@@ -28,9 +28,3 @@ export async function spawnIdeServer(config: QueryServerConfig): Promise<StreamI
|
||||
return { writer: child.stdin!, reader: child.stdout! };
|
||||
});
|
||||
}
|
||||
|
||||
function shouldDebug() {
|
||||
return 'DEBUG_LANGUAGE_SERVER' in process.env
|
||||
&& process.env.DEBUG_LANGUAGE_SERVER !== '0'
|
||||
&& process.env.DEBUG_LANGUAGE_SERVER?.toLocaleLowerCase() !== 'false';
|
||||
}
|
||||
|
||||
@@ -15,11 +15,16 @@ import {
|
||||
import {
|
||||
tryGetResolvableLocation,
|
||||
isLineColumnLoc
|
||||
} from './bqrs-utils';
|
||||
} from './pure/bqrs-utils';
|
||||
import { DatabaseItem, DatabaseManager } from './databases';
|
||||
import { ViewSourceFileMsg } from './interface-types';
|
||||
import { ViewSourceFileMsg } from './pure/interface-types';
|
||||
import { Logger } from './logging';
|
||||
import { LineColumnLocation, WholeFileLocation, UrlValue, ResolvableLocationValue } from './bqrs-cli-types';
|
||||
import {
|
||||
LineColumnLocation,
|
||||
WholeFileLocation,
|
||||
UrlValue,
|
||||
ResolvableLocationValue
|
||||
} from './pure/bqrs-cli-types';
|
||||
|
||||
/**
|
||||
* This module contains functions and types that are sharedd between
|
||||
@@ -162,7 +167,13 @@ export async function showLocation(location?: Location) {
|
||||
const editor =
|
||||
editorsWithDoc.length > 0
|
||||
? editorsWithDoc[0]
|
||||
: await Window.showTextDocument(doc, ViewColumn.One);
|
||||
: await Window.showTextDocument(
|
||||
doc, {
|
||||
// avoid preview mode so editor is sticky and will be added to navigation and search histories.
|
||||
preview: false,
|
||||
viewColumn: ViewColumn.One,
|
||||
});
|
||||
|
||||
const range = location.range;
|
||||
// When highlighting the range, vscode's occurrence-match and bracket-match highlighting will
|
||||
// trigger based on where we place the cursor/selection, and will compete for the user's attention.
|
||||
|
||||
@@ -15,7 +15,7 @@ import * as cli from './cli';
|
||||
import { CodeQLCliServer } from './cli';
|
||||
import { DatabaseEventKind, DatabaseItem, DatabaseManager } from './databases';
|
||||
import { showAndLogErrorMessage } from './helpers';
|
||||
import { assertNever } from './helpers-pure';
|
||||
import { assertNever } from './pure/helpers-pure';
|
||||
import {
|
||||
FromResultsViewMsg,
|
||||
Interpretation,
|
||||
@@ -26,17 +26,15 @@ import {
|
||||
SortedResultsMap,
|
||||
InterpretedResultsSortState,
|
||||
SortDirection,
|
||||
RAW_RESULTS_PAGE_SIZE,
|
||||
INTERPRETED_RESULTS_PAGE_SIZE,
|
||||
ALERTS_TABLE_NAME,
|
||||
RawResultsSortState,
|
||||
} from './interface-types';
|
||||
} from './pure/interface-types';
|
||||
import { Logger } from './logging';
|
||||
import { commandRunner } from './helpers';
|
||||
import * as messages from './messages';
|
||||
import * as messages from './pure/messages';
|
||||
import { CompletedQuery, interpretResults } from './query-results';
|
||||
import { QueryInfo, tmpDir } from './run-queries';
|
||||
import { parseSarifLocation, parseSarifPlainTextMessage } from './sarif-utils';
|
||||
import { parseSarifLocation, parseSarifPlainTextMessage } from './pure/sarif-utils';
|
||||
import {
|
||||
WebviewReveal,
|
||||
fileUriToWebviewUri,
|
||||
@@ -46,8 +44,9 @@ import {
|
||||
shownLocationLineDecoration,
|
||||
jumpToLocation,
|
||||
} from './interface-utils';
|
||||
import { getDefaultResultSetName, ParsedResultSets } from './interface-types';
|
||||
import { RawResultSet, transformBqrsResultSet, ResultSetSchema } from './bqrs-cli-types';
|
||||
import { getDefaultResultSetName, ParsedResultSets } from './pure/interface-types';
|
||||
import { RawResultSet, transformBqrsResultSet, ResultSetSchema } from './pure/bqrs-cli-types';
|
||||
import { PAGE_SIZE } from './config';
|
||||
|
||||
/**
|
||||
* interface.ts
|
||||
@@ -89,11 +88,11 @@ function sortInterpretedResults(
|
||||
}
|
||||
|
||||
function numPagesOfResultSet(resultSet: RawResultSet): number {
|
||||
return Math.ceil(resultSet.schema.rows / RAW_RESULTS_PAGE_SIZE);
|
||||
return Math.ceil(resultSet.schema.rows / PAGE_SIZE.getValue<number>());
|
||||
}
|
||||
|
||||
function numInterpretedPages(interpretation: Interpretation | undefined): number {
|
||||
return Math.ceil((interpretation?.sarif.runs[0].results?.length || 0) / INTERPRETED_RESULTS_PAGE_SIZE);
|
||||
return Math.ceil((interpretation?.sarif.runs[0].results?.length || 0) / PAGE_SIZE.getValue<number>());
|
||||
}
|
||||
|
||||
export class InterfaceManager extends DisposableObject {
|
||||
@@ -378,7 +377,7 @@ export class InterfaceManager extends DisposableObject {
|
||||
// Use sorted results path if it exists. This may happen if we are
|
||||
// reloading the results view after it has been sorted in the past.
|
||||
const resultsPath = results.getResultsPath(selectedTable);
|
||||
|
||||
const pageSize = PAGE_SIZE.getValue<number>();
|
||||
const chunk = await this.cliServer.bqrsDecode(
|
||||
resultsPath,
|
||||
schema.name,
|
||||
@@ -388,12 +387,13 @@ export class InterfaceManager extends DisposableObject {
|
||||
// if there are interpreted results, but speculatively
|
||||
// send anyway.
|
||||
offset: schema.pagination?.offsets[0],
|
||||
pageSize: RAW_RESULTS_PAGE_SIZE
|
||||
pageSize
|
||||
}
|
||||
);
|
||||
const resultSet = transformBqrsResultSet(schema, chunk);
|
||||
const parsedResultSets: ParsedResultSets = {
|
||||
pageNumber: 0,
|
||||
pageSize,
|
||||
numPages: numPagesOfResultSet(resultSet),
|
||||
numInterpretedPages: numInterpretedPages(this._interpretation),
|
||||
resultSet: { ...resultSet, t: 'RawResultSet' },
|
||||
@@ -442,6 +442,7 @@ export class InterfaceManager extends DisposableObject {
|
||||
metadata: this._displayedQuery.query.metadata,
|
||||
pageNumber,
|
||||
resultSetNames,
|
||||
pageSize: PAGE_SIZE.getValue(),
|
||||
numPages: numInterpretedPages(this._interpretation),
|
||||
});
|
||||
}
|
||||
@@ -450,7 +451,7 @@ export class InterfaceManager extends DisposableObject {
|
||||
const resultsPath = results.getResultsPath(selectedTable);
|
||||
const schemas = await this.cliServer.bqrsInfo(
|
||||
resultsPath,
|
||||
RAW_RESULTS_PAGE_SIZE
|
||||
PAGE_SIZE.getValue()
|
||||
);
|
||||
return schemas['result-sets'];
|
||||
}
|
||||
@@ -483,18 +484,20 @@ export class InterfaceManager extends DisposableObject {
|
||||
if (schema === undefined)
|
||||
throw new Error(`Query result set '${selectedTable}' not found.`);
|
||||
|
||||
const pageSize = PAGE_SIZE.getValue<number>();
|
||||
const chunk = await this.cliServer.bqrsDecode(
|
||||
results.getResultsPath(selectedTable, sorted),
|
||||
schema.name,
|
||||
{
|
||||
offset: schema.pagination?.offsets[pageNumber],
|
||||
pageSize: RAW_RESULTS_PAGE_SIZE
|
||||
pageSize
|
||||
}
|
||||
);
|
||||
const resultSet = transformBqrsResultSet(schema, chunk);
|
||||
|
||||
const parsedResultSets: ParsedResultSets = {
|
||||
pageNumber,
|
||||
pageSize,
|
||||
resultSet: { t: 'RawResultSet', ...resultSet },
|
||||
numPages: numPagesOfResultSet(resultSet),
|
||||
numInterpretedPages: numInterpretedPages(this._interpretation),
|
||||
@@ -559,8 +562,8 @@ export class InterfaceManager extends DisposableObject {
|
||||
function getPageOfRun(run: Sarif.Run): Sarif.Run {
|
||||
return {
|
||||
...run, results: run.results?.slice(
|
||||
INTERPRETED_RESULTS_PAGE_SIZE * pageNumber,
|
||||
INTERPRETED_RESULTS_PAGE_SIZE * (pageNumber + 1)
|
||||
PAGE_SIZE.getValue<number>() * pageNumber,
|
||||
PAGE_SIZE.getValue<number>() * (pageNumber + 1)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -77,10 +77,10 @@ export interface WholeFileLocation {
|
||||
endColumn: never;
|
||||
}
|
||||
|
||||
export type UrlValue = LineColumnLocation | WholeFileLocation | string;
|
||||
|
||||
export type ResolvableLocationValue = WholeFileLocation | LineColumnLocation;
|
||||
|
||||
export type UrlValue = ResolvableLocationValue | string;
|
||||
|
||||
export type ColumnValue = EntityValue | number | string | boolean;
|
||||
|
||||
export type ResultRow = ColumnValue[];
|
||||
@@ -1,4 +1,9 @@
|
||||
import { UrlValue, ResolvableLocationValue, LineColumnLocation, WholeFileLocation } from './bqrs-cli-types';
|
||||
import {
|
||||
UrlValue,
|
||||
ResolvableLocationValue,
|
||||
LineColumnLocation,
|
||||
WholeFileLocation
|
||||
} from './bqrs-cli-types';
|
||||
|
||||
/**
|
||||
* The CodeQL filesystem libraries use this pattern in `getURL()` predicates
|
||||
@@ -21,3 +21,11 @@ class ExhaustivityCheckingError extends Error {
|
||||
export function assertNever(value: never): never {
|
||||
throw new ExhaustivityCheckingError(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to perform array filters where the predicate is asynchronous.
|
||||
*/
|
||||
export const asyncFilter = async function <T>(arr: T[], predicate: (arg0: T) => Promise<boolean>) {
|
||||
const results = await Promise.all(arr.map(predicate));
|
||||
return arr.filter((_, index) => results[index]);
|
||||
};
|
||||
@@ -23,16 +23,6 @@ export type ResultSet = RawTableResultSet | PathTableResultSet;
|
||||
*/
|
||||
export const RAW_RESULTS_LIMIT = 10000;
|
||||
|
||||
/**
|
||||
* Show this many rows in a raw result table at a time.
|
||||
*/
|
||||
export const RAW_RESULTS_PAGE_SIZE = 100;
|
||||
|
||||
/**
|
||||
* Show this many rows in an interpreted results table at a time.
|
||||
*/
|
||||
export const INTERPRETED_RESULTS_PAGE_SIZE = 100;
|
||||
|
||||
export interface DatabaseInfo {
|
||||
name: string;
|
||||
databaseUri: string;
|
||||
@@ -124,6 +114,7 @@ export interface ShowInterpretedPageMsg {
|
||||
metadata?: QueryMetadata;
|
||||
pageNumber: number;
|
||||
numPages: number;
|
||||
pageSize: number;
|
||||
resultSetNames: string[];
|
||||
}
|
||||
|
||||
@@ -352,6 +343,7 @@ export function getDefaultResultSetName(
|
||||
|
||||
export interface ParsedResultSets {
|
||||
pageNumber: number;
|
||||
pageSize: number;
|
||||
numPages: number;
|
||||
numInterpretedPages: number;
|
||||
selectedTable?: string; // when undefined, means 'show default table'
|
||||
@@ -72,10 +72,28 @@ export function getPathRelativeToSourceLocationPrefix(
|
||||
sourceLocationPrefix: string,
|
||||
sarifRelativeUri: string
|
||||
) {
|
||||
const normalizedSourceLocationPrefix = sourceLocationPrefix.replace(/\\/g, '/');
|
||||
return `file:${normalizedSourceLocationPrefix}/${sarifRelativeUri}`;
|
||||
// convert a platform specific path into encoded path uri segments
|
||||
// need to be careful about drive letters and ensure that there
|
||||
// is a starting '/'
|
||||
let prefix = '';
|
||||
if (sourceLocationPrefix[1] === ':') {
|
||||
// assume this is a windows drive separator
|
||||
prefix = sourceLocationPrefix.substring(0, 2);
|
||||
sourceLocationPrefix = sourceLocationPrefix.substring(2);
|
||||
}
|
||||
const normalizedSourceLocationPrefix = prefix + sourceLocationPrefix.replace(/\\/g, '/')
|
||||
.split('/')
|
||||
.map(encodeURIComponent)
|
||||
.join('/');
|
||||
const slashPrefix = normalizedSourceLocationPrefix.startsWith('/') ? '' : '/';
|
||||
return `file:${slashPrefix + normalizedSourceLocationPrefix}/${sarifRelativeUri}`;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param loc specifies the database-relative location of the source location
|
||||
* @param sourceLocationPrefix a file path (usually a full path) to the database containing the source location.
|
||||
*/
|
||||
export function parseSarifLocation(
|
||||
loc: Sarif.Location,
|
||||
sourceLocationPrefix: string
|
||||
@@ -1,58 +0,0 @@
|
||||
import { EventEmitter, Event, Uri, WorkspaceFolder, RelativePattern } from 'vscode';
|
||||
import { MultiFileSystemWatcher } from './vscode-utils/multi-file-system-watcher';
|
||||
import { CodeQLCliServer, QlpacksInfo } from './cli';
|
||||
import { Discovery } from './discovery';
|
||||
|
||||
export interface QLPack {
|
||||
name: string;
|
||||
uri: Uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Service to discover all available QL packs in a workspace folder.
|
||||
*/
|
||||
export class QLPackDiscovery extends Discovery<QlpacksInfo> {
|
||||
private readonly _onDidChangeQLPacks = this.push(new EventEmitter<void>());
|
||||
private readonly watcher = this.push(new MultiFileSystemWatcher());
|
||||
private _qlPacks: readonly QLPack[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly workspaceFolder: WorkspaceFolder,
|
||||
private readonly cliServer: CodeQLCliServer
|
||||
) {
|
||||
super('QL Pack Discovery');
|
||||
|
||||
// Watch for any changes to `qlpack.yml` files in this workspace folder.
|
||||
// TODO: The CLI server should tell us what paths to watch for.
|
||||
this.watcher.addWatch(new RelativePattern(this.workspaceFolder, '**/qlpack.yml'));
|
||||
this.watcher.addWatch(new RelativePattern(this.workspaceFolder, '**/.codeqlmanifest.json'));
|
||||
this.push(this.watcher.onDidChange(this.handleQLPackFileChanged, this));
|
||||
}
|
||||
|
||||
public get onDidChangeQLPacks(): Event<void> { return this._onDidChangeQLPacks.event; }
|
||||
|
||||
public get qlPacks(): readonly QLPack[] { return this._qlPacks; }
|
||||
|
||||
private handleQLPackFileChanged(_uri: Uri): void {
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
protected discover(): Promise<QlpacksInfo> {
|
||||
// Only look for QL packs in this workspace folder.
|
||||
return this.cliServer.resolveQlpacks([this.workspaceFolder.uri.fsPath], []);
|
||||
}
|
||||
|
||||
protected update(results: QlpacksInfo): void {
|
||||
const qlPacks: QLPack[] = [];
|
||||
for (const id in results) {
|
||||
qlPacks.push(...results[id].map(fsPath => {
|
||||
return {
|
||||
name: id,
|
||||
uri: Uri.file(fsPath)
|
||||
};
|
||||
}));
|
||||
}
|
||||
this._qlPacks = qlPacks;
|
||||
this._onDidChangeQLPacks.fire();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import * as path from 'path';
|
||||
import { QLPackDiscovery, QLPack } from './qlpack-discovery';
|
||||
import { Discovery } from './discovery';
|
||||
import { EventEmitter, Event, Uri, RelativePattern, WorkspaceFolder, env, workspace } from 'vscode';
|
||||
import { EventEmitter, Event, Uri, RelativePattern, WorkspaceFolder, env } from 'vscode';
|
||||
import { MultiFileSystemWatcher } from './vscode-utils/multi-file-system-watcher';
|
||||
import { CodeQLCliServer } from './cli';
|
||||
|
||||
@@ -29,9 +28,8 @@ export abstract class QLTestNode {
|
||||
* A directory containing one or more QL tests or other test directories.
|
||||
*/
|
||||
export class QLTestDirectory extends QLTestNode {
|
||||
private _children: QLTestNode[] = [];
|
||||
|
||||
constructor(_path: string, _name: string) {
|
||||
constructor(_path: string, _name: string, private _children: QLTestNode[] = []) {
|
||||
super(_path, _name);
|
||||
}
|
||||
|
||||
@@ -55,10 +53,23 @@ export class QLTestDirectory extends QLTestNode {
|
||||
}
|
||||
|
||||
public finish(): void {
|
||||
// remove empty directories
|
||||
this._children.filter(child =>
|
||||
child instanceof QLTestFile || child.children.length > 0
|
||||
);
|
||||
this._children.sort((a, b) => a.name.localeCompare(b.name, env.language));
|
||||
for (const child of this._children) {
|
||||
this._children.forEach((child, i) => {
|
||||
child.finish();
|
||||
}
|
||||
if (child.children?.length === 1 && child.children[0] instanceof QLTestDirectory) {
|
||||
// collapse children
|
||||
const replacement = new QLTestDirectory(
|
||||
child.children[0].path,
|
||||
child.name + ' / ' + child.children[0].name,
|
||||
Array.from(child.children[0].children)
|
||||
);
|
||||
this._children[i] = replacement;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private createChildDirectory(name: string): QLTestDirectory {
|
||||
@@ -96,14 +107,15 @@ export class QLTestFile extends QLTestNode {
|
||||
*/
|
||||
interface QLTestDiscoveryResults {
|
||||
/**
|
||||
* The root test directory for each QL pack that contains tests.
|
||||
* A directory that contains one or more QL Tests, or other QLTestDirectories.
|
||||
*/
|
||||
testDirectories: QLTestDirectory[];
|
||||
testDirectory: QLTestDirectory | undefined;
|
||||
|
||||
/**
|
||||
* The list of file system paths to watch. If any of these paths changes, the discovery results
|
||||
* may be out of date.
|
||||
* The file system path to a directory to watch. If any ql or qlref file changes in
|
||||
* this directory, then this signifies a change in tests.
|
||||
*/
|
||||
watchPaths: string[];
|
||||
watchPath: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,31 +124,30 @@ interface QLTestDiscoveryResults {
|
||||
export class QLTestDiscovery extends Discovery<QLTestDiscoveryResults> {
|
||||
private readonly _onDidChangeTests = this.push(new EventEmitter<void>());
|
||||
private readonly watcher: MultiFileSystemWatcher = this.push(new MultiFileSystemWatcher());
|
||||
private _testDirectories: QLTestDirectory[] = [];
|
||||
private _testDirectory: QLTestDirectory | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly qlPackDiscovery: QLPackDiscovery,
|
||||
private readonly workspaceFolder: WorkspaceFolder,
|
||||
private readonly cliServer: CodeQLCliServer
|
||||
) {
|
||||
super('QL Test Discovery');
|
||||
|
||||
this.push(this.qlPackDiscovery.onDidChangeQLPacks(this.handleDidChangeQLPacks, this));
|
||||
this.push(this.watcher.onDidChange(this.handleDidChange, this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Event to be fired when the set of discovered tests may have changed.
|
||||
*/
|
||||
public get onDidChangeTests(): Event<void> { return this._onDidChangeTests.event; }
|
||||
public get onDidChangeTests(): Event<void> {
|
||||
return this._onDidChangeTests.event;
|
||||
}
|
||||
|
||||
/**
|
||||
* The root test directory for each QL pack that contains tests.
|
||||
* The root directory. There is at least one test in this directory, or
|
||||
* in a subdirectory of this.
|
||||
*/
|
||||
public get testDirectories(): QLTestDirectory[] { return this._testDirectories; }
|
||||
|
||||
private handleDidChangeQLPacks(): void {
|
||||
this.refresh();
|
||||
public get testDirectory(): QLTestDirectory | undefined {
|
||||
return this._testDirectory;
|
||||
}
|
||||
|
||||
private handleDidChange(uri: Uri): void {
|
||||
@@ -144,72 +155,45 @@ export class QLTestDiscovery extends Discovery<QLTestDiscoveryResults> {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
protected async discover(): Promise<QLTestDiscoveryResults> {
|
||||
const testDirectories: QLTestDirectory[] = [];
|
||||
const watchPaths: string[] = [];
|
||||
const qlPacks = this.qlPackDiscovery.qlPacks;
|
||||
for (const qlPack of qlPacks) {
|
||||
//HACK: Assume that only QL packs whose name ends with '-tests' contain tests.
|
||||
if (this.isRelevantQlPack(qlPack)) {
|
||||
watchPaths.push(qlPack.uri.fsPath);
|
||||
const testPackage = await this.discoverTests(qlPack.uri.fsPath, qlPack.name);
|
||||
if (testPackage !== undefined) {
|
||||
testDirectories.push(testPackage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { testDirectories, watchPaths };
|
||||
const testDirectory = await this.discoverTests();
|
||||
return {
|
||||
testDirectory,
|
||||
watchPath: this.workspaceFolder.uri.fsPath
|
||||
};
|
||||
}
|
||||
|
||||
protected update(results: QLTestDiscoveryResults): void {
|
||||
this._testDirectories = results.testDirectories;
|
||||
this._testDirectory = results.testDirectory;
|
||||
|
||||
// Watch for changes to any `.ql` or `.qlref` file in any of the QL packs that contain tests.
|
||||
this.watcher.clear();
|
||||
results.watchPaths.forEach(watchPath => {
|
||||
this.watcher.addWatch(new RelativePattern(watchPath, '**/*.{ql,qlref}'));
|
||||
});
|
||||
this.watcher.addWatch(new RelativePattern(results.watchPath, '**/*.{ql,qlref}'));
|
||||
this._onDidChangeTests.fire();
|
||||
}
|
||||
|
||||
/**
|
||||
* Only include qlpacks suffixed with '-tests' that are contained
|
||||
* within the provided workspace folder.
|
||||
*/
|
||||
private isRelevantQlPack(qlPack: QLPack): boolean {
|
||||
return qlPack.name.endsWith('-tests')
|
||||
&& workspace.getWorkspaceFolder(qlPack.uri)?.index === this.workspaceFolder.index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover all QL tests in the specified directory and its subdirectories.
|
||||
* @param fullPath The full path of the test directory.
|
||||
* @param name The display name to use for the returned `TestDirectory` object.
|
||||
* @returns A `QLTestDirectory` object describing the contents of the directory, or `undefined` if
|
||||
* no tests were found.
|
||||
*/
|
||||
private async discoverTests(fullPath: string, name: string): Promise<QLTestDirectory | undefined> {
|
||||
private async discoverTests(): Promise<QLTestDirectory> {
|
||||
const fullPath = this.workspaceFolder.uri.fsPath;
|
||||
const name = this.workspaceFolder.name;
|
||||
const resolvedTests = (await this.cliServer.resolveTests(fullPath))
|
||||
.filter((testPath) => !QLTestDiscovery.ignoreTestPath(testPath));
|
||||
|
||||
if (resolvedTests.length === 0) {
|
||||
return undefined;
|
||||
const rootDirectory = new QLTestDirectory(fullPath, name);
|
||||
for (const testPath of resolvedTests) {
|
||||
const relativePath = path.normalize(path.relative(fullPath, testPath));
|
||||
const dirName = path.dirname(relativePath);
|
||||
const parentDirectory = rootDirectory.createDirectory(dirName);
|
||||
parentDirectory.addChild(new QLTestFile(testPath, path.basename(testPath)));
|
||||
}
|
||||
else {
|
||||
const rootDirectory = new QLTestDirectory(fullPath, name);
|
||||
for (const testPath of resolvedTests) {
|
||||
const relativePath = path.normalize(path.relative(fullPath, testPath));
|
||||
const dirName = path.dirname(relativePath);
|
||||
const parentDirectory = rootDirectory.createDirectory(dirName);
|
||||
parentDirectory.addChild(new QLTestFile(testPath, path.basename(testPath)));
|
||||
}
|
||||
|
||||
rootDirectory.finish();
|
||||
rootDirectory.finish();
|
||||
|
||||
return rootDirectory;
|
||||
}
|
||||
return rootDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -453,7 +453,7 @@ export class QueryHistoryManager extends DisposableObject {
|
||||
queryText: encodeURIComponent(await this.getQueryText(singleItem)),
|
||||
});
|
||||
const uri = vscode.Uri.parse(
|
||||
`codeql:${singleItem.query.queryID}-${queryName}?${params.toString()}`
|
||||
`codeql:${singleItem.query.queryID}-${queryName}?${params.toString()}`, true
|
||||
);
|
||||
const doc = await vscode.workspace.openTextDocument(uri);
|
||||
await vscode.window.showTextDocument(doc, { preview: false });
|
||||
@@ -545,9 +545,7 @@ export class QueryHistoryManager extends DisposableObject {
|
||||
private async tryOpenExternalFile(fileLocation: string) {
|
||||
const uri = vscode.Uri.file(fileLocation);
|
||||
try {
|
||||
await vscode.window.showTextDocument(uri, {
|
||||
preview: false
|
||||
});
|
||||
await vscode.window.showTextDocument(uri, { preview: false });
|
||||
} catch (e) {
|
||||
if (
|
||||
e.message.includes(
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { env, TreeItem } from 'vscode';
|
||||
|
||||
import { QueryWithResults, tmpDir, QueryInfo } from './run-queries';
|
||||
import * as messages from './messages';
|
||||
import * as messages from './pure/messages';
|
||||
import * as cli from './cli';
|
||||
import * as sarif from 'sarif';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import { RawResultsSortState, SortedResultSetInfo, DatabaseInfo, QueryMetadata, InterpretedResultsSortState, ResultsPaths } from './interface-types';
|
||||
import { RawResultsSortState, SortedResultSetInfo, DatabaseInfo, QueryMetadata, InterpretedResultsSortState, ResultsPaths } from './pure/interface-types';
|
||||
import { QueryHistoryConfig } from './config';
|
||||
import { QueryHistoryItemOptions } from './query-history';
|
||||
|
||||
@@ -96,8 +96,8 @@ export class CompletedQuery implements QueryWithResults {
|
||||
}
|
||||
|
||||
getLabel(): string {
|
||||
return this.options?.label
|
||||
|| this.config.format;
|
||||
return this.options?.label
|
||||
|| this.config.format;
|
||||
}
|
||||
|
||||
get didRunSuccessfully(): boolean {
|
||||
|
||||
@@ -6,8 +6,8 @@ import { CancellationToken, createMessageConnection, MessageConnection, RequestT
|
||||
import * as cli from './cli';
|
||||
import { QueryServerConfig } from './config';
|
||||
import { Logger, ProgressReporter } from './logging';
|
||||
import { completeQuery, EvaluationResult, progress, ProgressMessage, WithProgressId } from './messages';
|
||||
import * as messages from './messages';
|
||||
import { completeQuery, EvaluationResult, progress, ProgressMessage, WithProgressId } from './pure/messages';
|
||||
import * as messages from './pure/messages';
|
||||
|
||||
type ServerOpts = {
|
||||
logger: Logger;
|
||||
@@ -107,6 +107,11 @@ export class QueryServerClient extends DisposableObject {
|
||||
if (this.config.debug) {
|
||||
args.push('--debug', '--tuple-counting');
|
||||
}
|
||||
|
||||
if (cli.shouldDebugQueryServer()) {
|
||||
args.push('-J=-agentlib:jdwp=transport=dt_socket,address=localhost:9010,server=y,suspend=n,quiet=y');
|
||||
}
|
||||
|
||||
const child = cli.spawnServer(
|
||||
this.config.codeQlPath,
|
||||
'CodeQL query server',
|
||||
|
||||
@@ -16,9 +16,9 @@ import * as cli from './cli';
|
||||
import * as config from './config';
|
||||
import { DatabaseItem, getUpgradesDirectories } from './databases';
|
||||
import * as helpers from './helpers';
|
||||
import { DatabaseInfo, QueryMetadata, ResultsPaths } from './interface-types';
|
||||
import { DatabaseInfo, QueryMetadata, ResultsPaths } from './pure/interface-types';
|
||||
import { logger } from './logging';
|
||||
import * as messages from './messages';
|
||||
import * as messages from './pure/messages';
|
||||
import { QueryHistoryItemOptions } from './query-history';
|
||||
import * as qsClient from './queryserver-client';
|
||||
import { isQuickQueryPath } from './quick-query';
|
||||
|
||||
@@ -16,7 +16,6 @@ import { TestAdapterRegistrar } from 'vscode-test-adapter-util';
|
||||
import { QLTestFile, QLTestNode, QLTestDirectory, QLTestDiscovery } from './qltest-discovery';
|
||||
import { Event, EventEmitter, CancellationTokenSource, CancellationToken } from 'vscode';
|
||||
import { DisposableObject } from './vscode-utils/disposable-object';
|
||||
import { QLPackDiscovery } from './qlpack-discovery';
|
||||
import { CodeQLCliServer } from './cli';
|
||||
import { getOnDiskWorkspaceFolders } from './helpers';
|
||||
import { testLogger } from './logging';
|
||||
@@ -82,7 +81,6 @@ function changeExtension(p: string, ext: string): string {
|
||||
* Test adapter for QL tests.
|
||||
*/
|
||||
export class QLTestAdapter extends DisposableObject implements TestAdapter {
|
||||
private readonly qlPackDiscovery: QLPackDiscovery;
|
||||
private readonly qlTestDiscovery: QLTestDiscovery;
|
||||
private readonly _tests = this.push(
|
||||
new EventEmitter<TestLoadStartedEvent | TestLoadFinishedEvent>());
|
||||
@@ -97,9 +95,7 @@ export class QLTestAdapter extends DisposableObject implements TestAdapter {
|
||||
) {
|
||||
super();
|
||||
|
||||
this.qlPackDiscovery = this.push(new QLPackDiscovery(workspaceFolder, cliServer));
|
||||
this.qlTestDiscovery = this.push(new QLTestDiscovery(this.qlPackDiscovery, workspaceFolder, cliServer));
|
||||
this.qlPackDiscovery.refresh();
|
||||
this.qlTestDiscovery = this.push(new QLTestDiscovery(workspaceFolder, cliServer));
|
||||
this.qlTestDiscovery.refresh();
|
||||
|
||||
this.push(this.qlTestDiscovery.onDidChangeTests(this.discoverTests, this));
|
||||
@@ -160,20 +156,20 @@ export class QLTestAdapter extends DisposableObject implements TestAdapter {
|
||||
private discoverTests(): void {
|
||||
this._tests.fire({ type: 'started' } as TestLoadStartedEvent);
|
||||
|
||||
const testDirectories = this.qlTestDiscovery.testDirectories;
|
||||
const children = testDirectories.map(
|
||||
testDirectory => QLTestAdapter.createTestSuiteInfo(testDirectory, testDirectory.name)
|
||||
);
|
||||
const testSuite: TestSuiteInfo = {
|
||||
type: 'suite',
|
||||
label: 'CodeQL',
|
||||
id: '.',
|
||||
children
|
||||
};
|
||||
|
||||
const testDirectory = this.qlTestDiscovery.testDirectory;
|
||||
let testSuite: TestSuiteInfo | undefined;
|
||||
if (testDirectory?.children.length) {
|
||||
const children = QLTestAdapter.createTestOrSuiteInfos(testDirectory.children);
|
||||
testSuite = {
|
||||
type: 'suite',
|
||||
label: 'CodeQL',
|
||||
id: testDirectory.path,
|
||||
children
|
||||
};
|
||||
}
|
||||
this._tests.fire({
|
||||
type: 'finished',
|
||||
suite: children.length > 0 ? testSuite : undefined
|
||||
suite: testSuite
|
||||
} as TestLoadFinishedEvent);
|
||||
}
|
||||
|
||||
@@ -221,10 +217,26 @@ export class QLTestAdapter extends DisposableObject implements TestAdapter {
|
||||
cancellationToken: cancellationToken,
|
||||
logger: testLogger
|
||||
})) {
|
||||
const state = event.pass
|
||||
? 'passed'
|
||||
: event.messages?.length
|
||||
? 'errored'
|
||||
: 'failed';
|
||||
let message: string | undefined;
|
||||
if (event.diff?.length) {
|
||||
message = ['', `${state}: ${event.test}`, ...event.diff, ''].join('\n');
|
||||
testLogger.log(message);
|
||||
}
|
||||
(event.diff || []).join('\n');
|
||||
this._testStates.fire({
|
||||
type: 'test',
|
||||
state: event.pass ? 'passed' : 'failed',
|
||||
test: event.test
|
||||
state,
|
||||
test: event.test,
|
||||
message,
|
||||
decorations: event.messages?.map(msg => ({
|
||||
line: msg.position.line,
|
||||
message: msg.message
|
||||
}))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
import * as fs from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import { Uri, TextDocumentShowOptions, commands, window } from 'vscode';
|
||||
import {
|
||||
TestHub,
|
||||
TestController,
|
||||
TestAdapter,
|
||||
TestRunStartedEvent,
|
||||
TestRunFinishedEvent,
|
||||
TestEvent,
|
||||
TestSuiteEvent
|
||||
} from 'vscode-test-adapter-api';
|
||||
|
||||
import { showAndLogWarningMessage } from './helpers';
|
||||
import { TestTreeNode } from './test-tree-node';
|
||||
import { DisposableObject } from './vscode-utils/disposable-object';
|
||||
import { UIService } from './vscode-utils/ui-service';
|
||||
import { TestHub, TestController, TestAdapter, TestRunStartedEvent, TestRunFinishedEvent, TestEvent, TestSuiteEvent } from 'vscode-test-adapter-api';
|
||||
import { QLTestAdapter, getExpectedFile, getActualFile } from './test-adapter';
|
||||
import { logger } from './logging';
|
||||
|
||||
@@ -78,12 +88,17 @@ export class TestUIService extends UIService implements TestController {
|
||||
preserveFocus: true,
|
||||
preview: true
|
||||
};
|
||||
|
||||
if (!await fs.pathExists(expectedPath)) {
|
||||
showAndLogWarningMessage(`'${path.basename(expectedPath)}' does not exist. Creating an empty file.`);
|
||||
await fs.createFile(expectedPath);
|
||||
}
|
||||
|
||||
if (await fs.pathExists(actualPath)) {
|
||||
const actualUri = Uri.file(actualPath);
|
||||
await commands.executeCommand<void>('vscode.diff', expectedUri, actualUri,
|
||||
`Expected vs. Actual for ${path.basename(testId)}`, options);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
await window.showTextDocument(expectedUri, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as vscode from 'vscode';
|
||||
import { DatabaseItem } from './databases';
|
||||
import * as helpers from './helpers';
|
||||
import { logger } from './logging';
|
||||
import * as messages from './messages';
|
||||
import * as messages from './pure/messages';
|
||||
import * as qsClient from './queryserver-client';
|
||||
import { upgradesTmpDir } from './run-queries';
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { vscode } from './vscode-api';
|
||||
import { RawResultsSortState, SortDirection } from '../interface-types';
|
||||
import { RawResultsSortState, SortDirection } from '../pure/interface-types';
|
||||
import { nextSortDirection } from './result-table-utils';
|
||||
import { Column } from '../bqrs-cli-types';
|
||||
import { Column } from '../pure/bqrs-cli-types';
|
||||
|
||||
interface Props {
|
||||
readonly columns: readonly Column[];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { ResultRow } from '../bqrs-cli-types';
|
||||
import { ResultRow } from '../pure/bqrs-cli-types';
|
||||
import { zebraStripe } from './result-table-utils';
|
||||
import RawTableValue from './RawTableValue';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { renderLocation } from './result-table-utils';
|
||||
import { ColumnValue } from '../bqrs-cli-types';
|
||||
import { ColumnValue } from '../pure/bqrs-cli-types';
|
||||
|
||||
interface Props {
|
||||
value: ColumnValue;
|
||||
@@ -15,7 +15,7 @@ export default function RawTableValue(props: Props): JSX.Element {
|
||||
|| typeof v === 'number'
|
||||
|| typeof v === 'boolean'
|
||||
) {
|
||||
return <span>{v}</span>;
|
||||
return <span>{v.toString()}</span>;
|
||||
}
|
||||
|
||||
return renderLocation(v.url, v.label, props.databaseUri);
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import * as path from 'path';
|
||||
import * as React from 'react';
|
||||
import * as Sarif from 'sarif';
|
||||
import * as Keys from '../result-keys';
|
||||
import * as Keys from '../pure/result-keys';
|
||||
import * as octicons from './octicons';
|
||||
import { className, renderLocation, ResultTableProps, zebraStripe, selectableZebraStripe, jumpToLocation, nextSortDirection } from './result-table-utils';
|
||||
import { onNavigation, NavigationEvent } from './results';
|
||||
import { PathTableResultSet } from '../interface-types';
|
||||
import { parseSarifPlainTextMessage, parseSarifLocation, isNoLocation } from '../sarif-utils';
|
||||
import { InterpretedResultsSortColumn, SortDirection, InterpretedResultsSortState } from '../interface-types';
|
||||
import { PathTableResultSet } from '../pure/interface-types';
|
||||
import {
|
||||
parseSarifPlainTextMessage,
|
||||
parseSarifLocation,
|
||||
isNoLocation
|
||||
} from '../pure/sarif-utils';
|
||||
import { InterpretedResultsSortColumn, SortDirection, InterpretedResultsSortState } from '../pure/interface-types';
|
||||
import { vscode } from './vscode-api';
|
||||
import { isWholeFileLoc, isLineColumnLoc } from '../bqrs-utils';
|
||||
import { isWholeFileLoc, isLineColumnLoc } from '../pure/bqrs-utils';
|
||||
|
||||
export type PathTableProps = ResultTableProps & { resultSet: PathTableResultSet };
|
||||
export interface PathTableState {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import { ResultTableProps, className } from './result-table-utils';
|
||||
import { RAW_RESULTS_LIMIT, RawResultsSortState } from '../interface-types';
|
||||
import { RawTableResultSet } from '../interface-types';
|
||||
import { RAW_RESULTS_LIMIT, RawResultsSortState } from '../pure/interface-types';
|
||||
import { RawTableResultSet } from '../pure/interface-types';
|
||||
import RawTableHeader from './RawTableHeader';
|
||||
import RawTableRow from './RawTableRow';
|
||||
import { ResultRow } from '../bqrs-cli-types';
|
||||
import { ResultRow } from '../pure/bqrs-cli-types';
|
||||
|
||||
export type RawTableProps = ResultTableProps & {
|
||||
resultSet: RawTableResultSet;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import * as React from 'react';
|
||||
import { UrlValue, ResolvableLocationValue } from '../bqrs-cli-types';
|
||||
import { isStringLoc, tryGetResolvableLocation } from '../bqrs-utils';
|
||||
import { RawResultsSortState, QueryMetadata, SortDirection } from '../interface-types';
|
||||
import { assertNever } from '../helpers-pure';
|
||||
import { ResultSet } from '../interface-types';
|
||||
import { UrlValue, ResolvableLocationValue } from '../pure/bqrs-cli-types';
|
||||
import { isStringLoc, tryGetResolvableLocation } from '../pure/bqrs-utils';
|
||||
import { RawResultsSortState, QueryMetadata, SortDirection } from '../pure/interface-types';
|
||||
import { assertNever } from '../pure/helpers-pure';
|
||||
import { ResultSet } from '../pure/interface-types';
|
||||
import { vscode } from './vscode-api';
|
||||
|
||||
export interface ResultTableProps {
|
||||
|
||||
@@ -6,17 +6,21 @@ import {
|
||||
QueryMetadata,
|
||||
ResultsPaths,
|
||||
InterpretedResultsSortState,
|
||||
RAW_RESULTS_PAGE_SIZE,
|
||||
ResultSet,
|
||||
ALERTS_TABLE_NAME,
|
||||
SELECT_TABLE_NAME,
|
||||
getDefaultResultSetName,
|
||||
ParsedResultSets,
|
||||
IntoResultsViewMsg
|
||||
} from '../interface-types';
|
||||
} from '../pure/interface-types';
|
||||
import { PathTable } from './alert-table';
|
||||
import { RawTable } from './raw-results-table';
|
||||
import { ResultTableProps, tableSelectionHeaderClassName, toggleDiagnosticsClassName, alertExtrasClassName } from './result-table-utils';
|
||||
import {
|
||||
ResultTableProps,
|
||||
tableSelectionHeaderClassName,
|
||||
toggleDiagnosticsClassName,
|
||||
alertExtrasClassName
|
||||
} from './result-table-utils';
|
||||
import { vscode } from './vscode-api';
|
||||
|
||||
|
||||
@@ -95,7 +99,7 @@ export class ResultTables
|
||||
return resultSets;
|
||||
}
|
||||
|
||||
private getResultSetNames(resultSets: ResultSet[]): string[] {
|
||||
private getResultSetNames(): string[] {
|
||||
return this.props.parsedResultSets.resultSetNames.concat([ALERTS_TABLE_NAME]);
|
||||
}
|
||||
|
||||
@@ -164,7 +168,7 @@ export class ResultTables
|
||||
|
||||
getOffset(): number {
|
||||
const { parsedResultSets } = this.props;
|
||||
return parsedResultSets.pageNumber * RAW_RESULTS_PAGE_SIZE;
|
||||
return parsedResultSets.pageNumber * parsedResultSets.pageSize;
|
||||
}
|
||||
|
||||
renderPageButtons(): JSX.Element {
|
||||
@@ -215,6 +219,8 @@ export class ResultTables
|
||||
type="number"
|
||||
size={3}
|
||||
value={this.state.selectedPage}
|
||||
min="1"
|
||||
max={numPages}
|
||||
onChange={onChange}
|
||||
onBlur={e => choosePage(e.target.value)}
|
||||
onKeyDown={e => {
|
||||
@@ -234,7 +240,7 @@ export class ResultTables
|
||||
render(): React.ReactNode {
|
||||
const { selectedTable } = this.state;
|
||||
const resultSets = this.getResultSets();
|
||||
const resultSetNames = this.getResultSetNames(resultSets);
|
||||
const resultSetNames = this.getResultSetNames();
|
||||
|
||||
const resultSet = resultSets.find(resultSet => resultSet.schema.name == selectedTable);
|
||||
const nonemptyRawResults = resultSets.some(resultSet => resultSet.t == 'RawResultSet' && resultSet.rows.length > 0);
|
||||
@@ -279,7 +285,7 @@ export class ResultTables
|
||||
break;
|
||||
|
||||
default:
|
||||
// noop
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import * as Rdom from 'react-dom';
|
||||
import { assertNever } from '../helpers-pure';
|
||||
import { assertNever } from '../pure/helpers-pure';
|
||||
import {
|
||||
DatabaseInfo,
|
||||
Interpretation,
|
||||
@@ -12,10 +12,10 @@ import {
|
||||
ResultsPaths,
|
||||
ALERTS_TABLE_NAME,
|
||||
ParsedResultSets
|
||||
} from '../interface-types';
|
||||
} from '../pure/interface-types';
|
||||
import { EventHandlers as EventHandlerList } from './event-handler-list';
|
||||
import { ResultTables } from './result-tables';
|
||||
import { ResultSet } from '../interface-types';
|
||||
import { ResultSet } from '../pure/interface-types';
|
||||
import { vscode } from './vscode-api';
|
||||
|
||||
/**
|
||||
@@ -105,6 +105,7 @@ class App extends React.Component<{}, ResultsViewState> {
|
||||
resultsPath: '', // FIXME: Not used for interpreted, refactor so this is not needed
|
||||
parsedResultSets: {
|
||||
numPages: msg.numPages,
|
||||
pageSize: msg.pageSize,
|
||||
numInterpretedPages: msg.numPages,
|
||||
resultSetNames: msg.resultSetNames,
|
||||
pageNumber: msg.pageNumber,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FromCompareViewMessage, FromResultsViewMsg } from '../interface-types';
|
||||
import { FromCompareViewMessage, FromResultsViewMsg } from '../pure/interface-types';
|
||||
|
||||
export interface VsCodeApi {
|
||||
/**
|
||||
|
||||
@@ -1,40 +1,60 @@
|
||||
import 'vscode-test';
|
||||
import 'mocha';
|
||||
import * as path from 'path';
|
||||
import { Uri, workspace } from 'vscode';
|
||||
import { Uri, WorkspaceFolder } from 'vscode';
|
||||
import { expect } from 'chai';
|
||||
|
||||
import { QLTestDiscovery } from '../../qltest-discovery';
|
||||
|
||||
describe('qltest-discovery', () => {
|
||||
describe('isRelevantQlPack', () => {
|
||||
it('should check if a qlpack is relevant', () => {
|
||||
const qlTestDiscover: any = new QLTestDiscovery(
|
||||
{ onDidChangeQLPacks: () => ({}) } as any,
|
||||
{ index: 0 } as any,
|
||||
{} as any
|
||||
describe('discoverTests', () => {
|
||||
it('should run discovery', async () => {
|
||||
const baseUri = Uri.parse('file:/a/b');
|
||||
const baseDir = baseUri.fsPath;
|
||||
const cDir = Uri.parse('file:/a/b/c').fsPath;
|
||||
const dFile = Uri.parse('file:/a/b/c/d.ql').fsPath;
|
||||
const eFile = Uri.parse('file:/a/b/c/e.ql').fsPath;
|
||||
const hDir = Uri.parse('file:/a/b/c/f/g/h').fsPath;
|
||||
const iFile = Uri.parse('file:/a/b/c/f/g/h/i.ql').fsPath;
|
||||
const qlTestDiscover = new QLTestDiscovery(
|
||||
{
|
||||
uri: baseUri,
|
||||
name: 'My tests'
|
||||
} as unknown as WorkspaceFolder,
|
||||
{
|
||||
resolveTests() {
|
||||
return [
|
||||
Uri.parse('file:/a/b/c/d.ql').fsPath,
|
||||
Uri.parse('file:/a/b/c/e.ql').fsPath,
|
||||
Uri.parse('file:/a/b/c/f/g/h/i.ql').fsPath
|
||||
];
|
||||
}
|
||||
} as any
|
||||
);
|
||||
|
||||
const uri = workspace.workspaceFolders![0].uri;
|
||||
expect(qlTestDiscover.isRelevantQlPack({
|
||||
name: '-hucairz',
|
||||
uri
|
||||
})).to.be.false;
|
||||
const result = await (qlTestDiscover as any).discover();
|
||||
expect(result.watchPath).to.eq(baseDir);
|
||||
expect(result.testDirectory.path).to.eq(baseDir);
|
||||
expect(result.testDirectory.name).to.eq('My tests');
|
||||
|
||||
expect(qlTestDiscover.isRelevantQlPack({
|
||||
name: '-tests',
|
||||
uri: Uri.file('/a/b/')
|
||||
})).to.be.false;
|
||||
let children = result.testDirectory.children;
|
||||
expect(children[0].path).to.eq(cDir);
|
||||
expect(children[0].name).to.eq('c');
|
||||
expect(children.length).to.eq(1);
|
||||
|
||||
expect(qlTestDiscover.isRelevantQlPack({
|
||||
name: '-tests',
|
||||
uri
|
||||
})).to.be.true;
|
||||
children = children[0].children;
|
||||
expect(children[0].path).to.eq(dFile);
|
||||
expect(children[0].name).to.eq('d.ql');
|
||||
expect(children[1].path).to.eq(eFile);
|
||||
expect(children[1].name).to.eq('e.ql');
|
||||
|
||||
expect(qlTestDiscover.isRelevantQlPack({
|
||||
name: '-tests',
|
||||
uri: Uri.file(path.join(uri.fsPath, 'other'))
|
||||
})).to.be.true;
|
||||
// A merged foler
|
||||
expect(children[2].path).to.eq(hDir);
|
||||
expect(children[2].name).to.eq('f / g / h');
|
||||
expect(children.length).to.eq(3);
|
||||
|
||||
children = children[2].children;
|
||||
expect(children[0].path).to.eq(iFile);
|
||||
expect(children[0].name).to.eq('i.ql');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -65,6 +65,66 @@ describe('AstBuilder', () => {
|
||||
)).to.deep.eq(expectedRoots);
|
||||
});
|
||||
|
||||
it('should build an AST child without edge label', async () => {
|
||||
// just test one of the children to make sure that the structure is right
|
||||
// this label should only come from the node, not the edge
|
||||
const astBuilder = createAstBuilder();
|
||||
const roots = await astBuilder.getRoots();
|
||||
|
||||
expect(roots[0].children[0].parent).to.eq(roots[0]);
|
||||
// break the recursion
|
||||
(roots[0].children[0] as any).parent = undefined;
|
||||
(roots[0].children[0] as any).children = undefined;
|
||||
|
||||
const child = {
|
||||
children: undefined,
|
||||
fileLocation: undefined,
|
||||
id: 26359,
|
||||
label: 'params',
|
||||
location: {
|
||||
endColumn: 22,
|
||||
endLine: 19,
|
||||
startColumn: 5,
|
||||
startLine: 19,
|
||||
uri: 'file:/opt/src/arch/sandbox/lib/interrupts.c'
|
||||
},
|
||||
order: 0,
|
||||
parent: undefined
|
||||
};
|
||||
|
||||
expect(roots[0].children[0]).to.deep.eq(child);
|
||||
});
|
||||
|
||||
it('should build an AST child with edge label', async () => {
|
||||
// just test one of the children to make sure that the structure is right
|
||||
// this label should only come from both the node and the edge
|
||||
const astBuilder = createAstBuilder();
|
||||
const roots = await astBuilder.getRoots();
|
||||
|
||||
expect(roots[0].children[1].parent).to.eq(roots[0]);
|
||||
// break the recursion
|
||||
(roots[0].children[1] as any).parent = undefined;
|
||||
(roots[0].children[1] as any).children = undefined;
|
||||
|
||||
const child = {
|
||||
children: undefined,
|
||||
fileLocation: undefined,
|
||||
id: 26367,
|
||||
label: 'body: [Block] { ... }',
|
||||
location: {
|
||||
endColumn: 1,
|
||||
endLine: 22,
|
||||
startColumn: 1,
|
||||
startLine: 20,
|
||||
uri: 'file:/opt/src/arch/sandbox/lib/interrupts.c'
|
||||
},
|
||||
order: 2,
|
||||
parent: undefined
|
||||
};
|
||||
|
||||
expect(roots[0].children[1]).to.deep.eq(child);
|
||||
});
|
||||
|
||||
it('should fail when graphProperties are not correct', async () => {
|
||||
overrides.graphProperties = {
|
||||
tuples: [
|
||||
|
||||
@@ -5,13 +5,33 @@ import { Uri, Range } from 'vscode';
|
||||
|
||||
import fileRangeFromURI from '../../../contextual/fileRangeFromURI';
|
||||
import { DatabaseItem } from '../../../databases';
|
||||
import { WholeFileLocation, LineColumnLocation } from '../../../bqrs-cli-types';
|
||||
import { WholeFileLocation, LineColumnLocation } from '../../../pure/bqrs-cli-types';
|
||||
|
||||
describe('fileRangeFromURI', () => {
|
||||
it('should return undefined when value is a string', () => {
|
||||
it('should return undefined when value is not a file URI', () => {
|
||||
expect(fileRangeFromURI('hucairz', createMockDatabaseItem())).to.be.undefined;
|
||||
});
|
||||
|
||||
it('should fail to find a location when not a file URI and a full 5 part location', () => {
|
||||
expect(fileRangeFromURI({
|
||||
uri: 'https://yahoo.com',
|
||||
startLine: 1,
|
||||
startColumn: 2,
|
||||
endLine: 3,
|
||||
endColumn: 4,
|
||||
} as LineColumnLocation, createMockDatabaseItem())).to.be.undefined;
|
||||
});
|
||||
|
||||
it('should fail to find a location when there is a silly protocol', () => {
|
||||
expect(fileRangeFromURI({
|
||||
uri: 'filesilly://yahoo.com',
|
||||
startLine: 1,
|
||||
startColumn: 2,
|
||||
endLine: 3,
|
||||
endColumn: 4,
|
||||
} as LineColumnLocation, createMockDatabaseItem())).to.be.undefined;
|
||||
});
|
||||
|
||||
it('should return undefined when value is an empty uri', () => {
|
||||
expect(fileRangeFromURI({
|
||||
uri: 'file:/',
|
||||
@@ -46,7 +66,7 @@ describe('fileRangeFromURI', () => {
|
||||
|
||||
function createMockDatabaseItem(): DatabaseItem {
|
||||
return {
|
||||
resolveSourceFile: (file: string) => Uri.file(file)
|
||||
resolveSourceFile: (file: string) => Uri.parse(file)
|
||||
} as DatabaseItem;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26359,
|
||||
"label": "",
|
||||
"label": "SHOULD NOT USE ",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 19,
|
||||
@@ -28,12 +28,12 @@
|
||||
}
|
||||
},
|
||||
"semmle.label",
|
||||
""
|
||||
"params"
|
||||
],
|
||||
[
|
||||
{
|
||||
"id": 26360,
|
||||
"label": "",
|
||||
"label": "SHOULD NOT USE ",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 15,
|
||||
@@ -48,7 +48,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26361,
|
||||
"label": "",
|
||||
"label": "SHOULD NOT USE ",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 10,
|
||||
@@ -63,7 +63,7 @@
|
||||
[
|
||||
{
|
||||
"id": 0,
|
||||
"label": "[TopLevelFunction] int disable_interrupts()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] int disable_interrupts()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 19,
|
||||
@@ -78,7 +78,7 @@
|
||||
[
|
||||
{
|
||||
"id": 0,
|
||||
"label": "[TopLevelFunction] int disable_interrupts()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] int disable_interrupts()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 19,
|
||||
@@ -93,7 +93,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26363,
|
||||
"label": "[TopLevelFunction] void enable_interrupts()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] void enable_interrupts()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 15,
|
||||
@@ -108,7 +108,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26363,
|
||||
"label": "[TopLevelFunction] void enable_interrupts()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] void enable_interrupts()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 15,
|
||||
@@ -123,7 +123,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26364,
|
||||
"label": "[TopLevelFunction] int interrupt_init()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] int interrupt_init()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 10,
|
||||
@@ -138,7 +138,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26364,
|
||||
"label": "[TopLevelFunction] int interrupt_init()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] int interrupt_init()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 10,
|
||||
@@ -153,7 +153,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26365,
|
||||
"label": "[Literal] 0",
|
||||
"label": "SHOULD NOT USE [Literal] 0",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 21,
|
||||
@@ -168,7 +168,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26365,
|
||||
"label": "[Literal] 0",
|
||||
"label": "SHOULD NOT USE [Literal] 0",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 21,
|
||||
@@ -183,7 +183,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26365,
|
||||
"label": "[Literal] 0",
|
||||
"label": "SHOULD NOT USE [Literal] 0",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 21,
|
||||
@@ -198,7 +198,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26365,
|
||||
"label": "[Literal] 0",
|
||||
"label": "SHOULD NOT USE [Literal] 0",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 21,
|
||||
@@ -213,7 +213,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26366,
|
||||
"label": "[ReturnStmt] return ...",
|
||||
"label": "SHOULD NOT USE [ReturnStmt] return ...",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 21,
|
||||
@@ -228,7 +228,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26367,
|
||||
"label": "[Block] { ... }",
|
||||
"label": "SHOULD NOT USE [Block] { ... }",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 20,
|
||||
@@ -243,7 +243,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26368,
|
||||
"label": "[ReturnStmt] return ...",
|
||||
"label": "SHOULD NOT USE [ReturnStmt] return ...",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 17,
|
||||
@@ -258,7 +258,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26369,
|
||||
"label": "[Block] { ... }",
|
||||
"label": "SHOULD NOT USE [Block] { ... }",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 16,
|
||||
@@ -273,7 +273,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26370,
|
||||
"label": "[Literal] 0",
|
||||
"label": "SHOULD NOT USE [Literal] 0",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 12,
|
||||
@@ -288,7 +288,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26370,
|
||||
"label": "[Literal] 0",
|
||||
"label": "SHOULD NOT USE [Literal] 0",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 12,
|
||||
@@ -303,7 +303,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26370,
|
||||
"label": "[Literal] 0",
|
||||
"label": "SHOULD NOT USE [Literal] 0",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 12,
|
||||
@@ -318,7 +318,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26370,
|
||||
"label": "[Literal] 0",
|
||||
"label": "SHOULD NOT USE [Literal] 0",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 12,
|
||||
@@ -333,7 +333,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26371,
|
||||
"label": "[ReturnStmt] return ...",
|
||||
"label": "SHOULD NOT USE [ReturnStmt] return ...",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 12,
|
||||
@@ -348,7 +348,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26372,
|
||||
"label": "[Block] { ... }",
|
||||
"label": "SHOULD NOT USE [Block] { ... }",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 11,
|
||||
@@ -385,7 +385,7 @@
|
||||
[
|
||||
{
|
||||
"id": 0,
|
||||
"label": "[TopLevelFunction] int disable_interrupts()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] int disable_interrupts()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 19,
|
||||
@@ -396,7 +396,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26359,
|
||||
"label": "",
|
||||
"label": "SHOULD NOT USE ",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 19,
|
||||
@@ -406,12 +406,12 @@
|
||||
}
|
||||
},
|
||||
"semmle.label",
|
||||
"params"
|
||||
"1234"
|
||||
],
|
||||
[
|
||||
{
|
||||
"id": 0,
|
||||
"label": "[TopLevelFunction] int disable_interrupts()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] int disable_interrupts()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 19,
|
||||
@@ -422,7 +422,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26359,
|
||||
"label": "",
|
||||
"label": "SHOULD NOT USE ",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 19,
|
||||
@@ -437,7 +437,7 @@
|
||||
[
|
||||
{
|
||||
"id": 0,
|
||||
"label": "[TopLevelFunction] int disable_interrupts()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] int disable_interrupts()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 19,
|
||||
@@ -448,7 +448,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26367,
|
||||
"label": "[Block] { ... }",
|
||||
"label": "SHOULD NOT USE [Block] { ... }",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 20,
|
||||
@@ -463,7 +463,7 @@
|
||||
[
|
||||
{
|
||||
"id": 0,
|
||||
"label": "[TopLevelFunction] int disable_interrupts()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] int disable_interrupts()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 19,
|
||||
@@ -474,7 +474,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26367,
|
||||
"label": "[Block] { ... }",
|
||||
"label": "SHOULD NOT USE [Block] { ... }",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 20,
|
||||
@@ -489,7 +489,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26363,
|
||||
"label": "[TopLevelFunction] void enable_interrupts()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] void enable_interrupts()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 15,
|
||||
@@ -500,7 +500,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26360,
|
||||
"label": "",
|
||||
"label": "SHOULD NOT USE ",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 15,
|
||||
@@ -515,7 +515,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26363,
|
||||
"label": "[TopLevelFunction] void enable_interrupts()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] void enable_interrupts()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 15,
|
||||
@@ -526,7 +526,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26360,
|
||||
"label": "",
|
||||
"label": "SHOULD NOT USE ",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 15,
|
||||
@@ -541,7 +541,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26363,
|
||||
"label": "[TopLevelFunction] void enable_interrupts()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] void enable_interrupts()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 15,
|
||||
@@ -552,7 +552,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26369,
|
||||
"label": "[Block] { ... }",
|
||||
"label": "SHOULD NOT USE [Block] { ... }",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 16,
|
||||
@@ -567,7 +567,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26363,
|
||||
"label": "[TopLevelFunction] void enable_interrupts()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] void enable_interrupts()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 15,
|
||||
@@ -578,7 +578,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26369,
|
||||
"label": "[Block] { ... }",
|
||||
"label": "SHOULD NOT USE [Block] { ... }",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 16,
|
||||
@@ -593,7 +593,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26364,
|
||||
"label": "[TopLevelFunction] int interrupt_init()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] int interrupt_init()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 10,
|
||||
@@ -604,7 +604,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26361,
|
||||
"label": "",
|
||||
"label": "SHOULD NOT USE ",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 10,
|
||||
@@ -619,7 +619,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26364,
|
||||
"label": "[TopLevelFunction] int interrupt_init()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] int interrupt_init()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 10,
|
||||
@@ -630,7 +630,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26361,
|
||||
"label": "",
|
||||
"label": "SHOULD NOT USE ",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 10,
|
||||
@@ -645,7 +645,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26364,
|
||||
"label": "[TopLevelFunction] int interrupt_init()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] int interrupt_init()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 10,
|
||||
@@ -656,7 +656,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26372,
|
||||
"label": "[Block] { ... }",
|
||||
"label": "SHOULD NOT USE [Block] { ... }",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 11,
|
||||
@@ -671,7 +671,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26364,
|
||||
"label": "[TopLevelFunction] int interrupt_init()",
|
||||
"label": "SHOULD NOT USE [TopLevelFunction] int interrupt_init()",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 10,
|
||||
@@ -682,7 +682,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26372,
|
||||
"label": "[Block] { ... }",
|
||||
"label": "SHOULD NOT USE [Block] { ... }",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 11,
|
||||
@@ -697,7 +697,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26366,
|
||||
"label": "[ReturnStmt] return ...",
|
||||
"label": "SHOULD NOT USE [ReturnStmt] return ...",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 21,
|
||||
@@ -708,7 +708,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26365,
|
||||
"label": "[Literal] 0",
|
||||
"label": "SHOULD NOT USE [Literal] 0",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 21,
|
||||
@@ -723,7 +723,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26366,
|
||||
"label": "[ReturnStmt] return ...",
|
||||
"label": "SHOULD NOT USE [ReturnStmt] return ...",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 21,
|
||||
@@ -734,7 +734,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26365,
|
||||
"label": "[Literal] 0",
|
||||
"label": "SHOULD NOT USE [Literal] 0",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 21,
|
||||
@@ -749,7 +749,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26367,
|
||||
"label": "[Block] { ... }",
|
||||
"label": "SHOULD NOT USE [Block] { ... }",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 20,
|
||||
@@ -760,7 +760,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26366,
|
||||
"label": "[ReturnStmt] return ...",
|
||||
"label": "SHOULD NOT USE [ReturnStmt] return ...",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 21,
|
||||
@@ -775,7 +775,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26367,
|
||||
"label": "[Block] { ... }",
|
||||
"label": "SHOULD NOT USE [Block] { ... }",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 20,
|
||||
@@ -786,7 +786,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26366,
|
||||
"label": "[ReturnStmt] return ...",
|
||||
"label": "SHOULD NOT USE [ReturnStmt] return ...",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 21,
|
||||
@@ -801,7 +801,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26369,
|
||||
"label": "[Block] { ... }",
|
||||
"label": "SHOULD NOT USE [Block] { ... }",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 16,
|
||||
@@ -812,7 +812,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26368,
|
||||
"label": "[ReturnStmt] return ...",
|
||||
"label": "SHOULD NOT USE [ReturnStmt] return ...",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 17,
|
||||
@@ -827,7 +827,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26369,
|
||||
"label": "[Block] { ... }",
|
||||
"label": "SHOULD NOT USE [Block] { ... }",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 16,
|
||||
@@ -838,7 +838,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26368,
|
||||
"label": "[ReturnStmt] return ...",
|
||||
"label": "SHOULD NOT USE [ReturnStmt] return ...",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 17,
|
||||
@@ -853,7 +853,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26371,
|
||||
"label": "[ReturnStmt] return ...",
|
||||
"label": "SHOULD NOT USE [ReturnStmt] return ...",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 12,
|
||||
@@ -864,7 +864,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26370,
|
||||
"label": "[Literal] 0",
|
||||
"label": "SHOULD NOT USE [Literal] 0",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 12,
|
||||
@@ -879,7 +879,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26371,
|
||||
"label": "[ReturnStmt] return ...",
|
||||
"label": "SHOULD NOT USE [ReturnStmt] return ...",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 12,
|
||||
@@ -890,7 +890,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26370,
|
||||
"label": "[Literal] 0",
|
||||
"label": "SHOULD NOT USE [Literal] 0",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 12,
|
||||
@@ -905,7 +905,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26372,
|
||||
"label": "[Block] { ... }",
|
||||
"label": "SHOULD NOT USE [Block] { ... }",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 11,
|
||||
@@ -916,7 +916,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26371,
|
||||
"label": "[ReturnStmt] return ...",
|
||||
"label": "SHOULD NOT USE [ReturnStmt] return ...",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 12,
|
||||
@@ -931,7 +931,7 @@
|
||||
[
|
||||
{
|
||||
"id": 26372,
|
||||
"label": "[Block] { ... }",
|
||||
"label": "SHOULD NOT USE [Block] { ... }",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 11,
|
||||
@@ -942,7 +942,7 @@
|
||||
},
|
||||
{
|
||||
"id": 26371,
|
||||
"label": "[ReturnStmt] return ...",
|
||||
"label": "SHOULD NOT USE [ReturnStmt] return ...",
|
||||
"url": {
|
||||
"uri": "file:/opt/src/arch/sandbox/lib/interrupts.c",
|
||||
"startLine": 12,
|
||||
|
||||
@@ -49,11 +49,59 @@ describe('databases-ui', () => {
|
||||
const parentDir = path.join(dir, 'db-hucairz');
|
||||
const dbDir = path.join(parentDir, 'db-javascript');
|
||||
const file = path.join(dbDir, 'nested');
|
||||
await fs.mkdirs(dbDir);
|
||||
await fs.createFile(file);
|
||||
fs.mkdirsSync(dbDir);
|
||||
fs.createFileSync(file);
|
||||
|
||||
const uri = await fixDbUri(Uri.file(file));
|
||||
expect(uri.toString()).to.eq(Uri.file(parentDir).toString());
|
||||
});
|
||||
});
|
||||
|
||||
it('should delete orphaned databases', async () => {
|
||||
const storageDir = tmp.dirSync().name;
|
||||
const db1 = createDatabase(storageDir, 'db1-imported', 'cpp');
|
||||
const db2 = createDatabase(storageDir, 'db2-notimported', 'cpp');
|
||||
const db3 = createDatabase(storageDir, 'db3-invalidlanguage', 'hucairz');
|
||||
|
||||
// these two should be deleted
|
||||
const db4 = createDatabase(storageDir, 'db2-notimported-with-db-info', 'cpp', '.dbinfo');
|
||||
const db5 = createDatabase(storageDir, 'db2-notimported-with-codeql-database.yml', 'cpp', 'codeql-database.yml');
|
||||
|
||||
const databaseUI = new DatabaseUI(
|
||||
{} as any,
|
||||
{
|
||||
databaseItems: [
|
||||
{ databaseUri: Uri.file(db1) }
|
||||
],
|
||||
onDidChangeDatabaseItem: () => { /**/ },
|
||||
onDidChangeCurrentDatabaseItem: () => { /**/ },
|
||||
} as any,
|
||||
{} as any,
|
||||
storageDir,
|
||||
storageDir
|
||||
);
|
||||
|
||||
await databaseUI.handleRemoveOrphanedDatabases();
|
||||
|
||||
expect(fs.pathExistsSync(db1)).to.be.true;
|
||||
expect(fs.pathExistsSync(db2)).to.be.true;
|
||||
expect(fs.pathExistsSync(db3)).to.be.true;
|
||||
|
||||
expect(fs.pathExistsSync(db4)).to.be.false;
|
||||
expect(fs.pathExistsSync(db5)).to.be.false;
|
||||
|
||||
databaseUI.dispose();
|
||||
});
|
||||
|
||||
function createDatabase(storageDir: string, dbName: string, language: string, extraFile?: string) {
|
||||
const parentDir = path.join(storageDir, dbName);
|
||||
const dbDir = path.join(parentDir, `db-${language}`);
|
||||
fs.mkdirsSync(dbDir);
|
||||
|
||||
if (extraFile) {
|
||||
fs.createFileSync(path.join(parentDir, extraFile));
|
||||
}
|
||||
|
||||
return parentDir;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -9,7 +9,8 @@ import {
|
||||
DatabaseItem,
|
||||
DatabaseManager,
|
||||
DatabaseItemImpl,
|
||||
DatabaseContents
|
||||
DatabaseContents,
|
||||
isLikelyDbLanguageFolder
|
||||
} from '../../databases';
|
||||
import { QueryServerConfig } from '../../config';
|
||||
import { Logger } from '../../logging';
|
||||
@@ -24,8 +25,9 @@ describe('databases', () => {
|
||||
databaseManager = new DatabaseManager(
|
||||
{
|
||||
workspaceState: {
|
||||
update: updateSpy
|
||||
}
|
||||
update: updateSpy,
|
||||
get: sinon.stub()
|
||||
},
|
||||
} as unknown as ExtensionContext,
|
||||
{} as QueryServerConfig,
|
||||
{} as Logger,
|
||||
@@ -81,45 +83,37 @@ describe('databases', () => {
|
||||
expect(mockDbItem.name).to.eq('new name');
|
||||
expect(updateSpy).to.have.been.calledWith('databaseList', ['new name']);
|
||||
expect(spy).to.have.been.calledWith({
|
||||
item: mockDbItem,
|
||||
item: undefined,
|
||||
kind: DatabaseEventKind.Rename
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveSourceFile', () => {
|
||||
describe('unzipped source archive', () => {
|
||||
it('should resolve a source file in an unzipped database', () => {
|
||||
const db = createMockDB();
|
||||
const resolved = db.resolveSourceFile('abc');
|
||||
expect(resolved.toString()).to.eq('file:///sourceArchive-uri/abc');
|
||||
});
|
||||
it('should fail to resolve when not a uri', () => {
|
||||
const db = createMockDB(Uri.parse('file:/sourceArchive-uri/'));
|
||||
(db as any)._contents.sourceArchiveUri = undefined;
|
||||
expect(() => db.resolveSourceFile('abc')).to.throw('Scheme is missing');
|
||||
});
|
||||
|
||||
it('should resolve a source file in an unzipped database with trailing slash', () => {
|
||||
const db = createMockDB(Uri.parse('file:/sourceArchive-uri/'));
|
||||
const resolved = db.resolveSourceFile('abc');
|
||||
expect(resolved.toString()).to.eq('file:///sourceArchive-uri/abc');
|
||||
});
|
||||
|
||||
it('should resolve a source uri in an unzipped database with trailing slash', () => {
|
||||
const db = createMockDB(Uri.parse('file:/sourceArchive-uri/'));
|
||||
const resolved = db.resolveSourceFile('file:/abc');
|
||||
expect(resolved.toString()).to.eq('file:///sourceArchive-uri/abc');
|
||||
});
|
||||
it('should fail to resolve when not a file uri', () => {
|
||||
const db = createMockDB(Uri.parse('file:/sourceArchive-uri/'));
|
||||
(db as any)._contents.sourceArchiveUri = undefined;
|
||||
expect(() => db.resolveSourceFile('http://abc')).to.throw('Invalid uri scheme');
|
||||
});
|
||||
|
||||
describe('no source archive', () => {
|
||||
it('should resolve a file', () => {
|
||||
it('should resolve undefined', () => {
|
||||
const db = createMockDB(Uri.parse('file:/sourceArchive-uri/'));
|
||||
(db as any)._contents.sourceArchiveUri = undefined;
|
||||
const resolved = db.resolveSourceFile('abc');
|
||||
expect(resolved.toString()).to.eq('file:///abc');
|
||||
const resolved = db.resolveSourceFile(undefined);
|
||||
expect(resolved.toString()).to.eq('file:///database-uri');
|
||||
});
|
||||
|
||||
it('should resolve an empty file', () => {
|
||||
const db = createMockDB(Uri.parse('file:/sourceArchive-uri/'));
|
||||
(db as any)._contents.sourceArchiveUri = undefined;
|
||||
const resolved = db.resolveSourceFile('file:');
|
||||
expect(resolved.toString()).to.eq('file:///database-uri');
|
||||
expect(resolved.toString()).to.eq('file:///');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -160,7 +154,7 @@ describe('databases', () => {
|
||||
pathWithinSourceArchive: 'def'
|
||||
}));
|
||||
const resolved = db.resolveSourceFile('file:');
|
||||
expect(resolved.toString()).to.eq('codeql-zip-archive://1-18/sourceArchive-uri/def');
|
||||
expect(resolved.toString()).to.eq('codeql-zip-archive://1-18/sourceArchive-uri/def/');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -186,4 +180,9 @@ describe('databases', () => {
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('should find likely db language folders', () => {
|
||||
expect(isLikelyDbLanguageFolder('db-javascript')).to.be.true;
|
||||
expect(isLikelyDbLanguageFolder('dbnot-a-db')).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
fileUriToWebviewUri,
|
||||
tryResolveLocation,
|
||||
} from '../../interface-utils';
|
||||
import { getDefaultResultSetName } from '../../interface-types';
|
||||
import { getDefaultResultSetName } from '../../pure/interface-types';
|
||||
import { DatabaseItem } from '../../databases';
|
||||
|
||||
describe('interface-utils', () => {
|
||||
|
||||
@@ -8,8 +8,8 @@ import * as chaiAsPromised from 'chai-as-promised';
|
||||
import { CompletedQuery, interpretResults } from '../../query-results';
|
||||
import { QueryInfo, QueryWithResults, tmpDir } from '../../run-queries';
|
||||
import { QueryHistoryConfig } from '../../config';
|
||||
import { EvaluationResult, QueryResultType } from '../../messages';
|
||||
import { SortDirection, SortedResultSetInfo } from '../../interface-types';
|
||||
import { EvaluationResult, QueryResultType } from '../../pure/messages';
|
||||
import { SortDirection, SortedResultSetInfo } from '../../pure/interface-types';
|
||||
import { CodeQLCliServer, SourceInfo } from '../../cli';
|
||||
|
||||
chai.use(chaiAsPromised);
|
||||
@@ -204,7 +204,7 @@ describe('CompletedQuery', () => {
|
||||
});
|
||||
|
||||
function mockCompletedQuery() {
|
||||
return new CompletedQuery(
|
||||
return new CompletedQuery(
|
||||
mockQueryWithResults(),
|
||||
mockQueryHistoryConfig()
|
||||
);
|
||||
|
||||
@@ -5,11 +5,11 @@ import * as path from 'path';
|
||||
import * as tmp from 'tmp';
|
||||
import * as url from 'url';
|
||||
import { CancellationTokenSource } from 'vscode-jsonrpc';
|
||||
import * as messages from '../../messages';
|
||||
import * as messages from '../../pure/messages';
|
||||
import * as qsClient from '../../queryserver-client';
|
||||
import * as cli from '../../cli';
|
||||
import { ProgressReporter, Logger } from '../../logging';
|
||||
import { ColumnValue } from '../../bqrs-cli-types';
|
||||
import { ColumnValue } from '../../pure/bqrs-cli-types';
|
||||
import { FindDistributionResultKind } from '../../distribution';
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as sinon from 'sinon';
|
||||
import * as chaiAsPromised from 'chai-as-promised';
|
||||
|
||||
import { QueryInfo } from '../../run-queries';
|
||||
import { QlProgram, Severity, compileQuery } from '../../messages';
|
||||
import { QlProgram, Severity, compileQuery } from '../../pure/messages';
|
||||
import { DatabaseItem } from '../../databases';
|
||||
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import 'vscode-test';
|
||||
import 'mocha';
|
||||
import * as sinon from 'sinon';
|
||||
import { Uri, WorkspaceFolder } from 'vscode';
|
||||
import { expect } from 'chai';
|
||||
|
||||
import { QLTestAdapter } from '../../test-adapter';
|
||||
import { CodeQLCliServer } from '../../cli';
|
||||
|
||||
describe('test-adapter', () => {
|
||||
let adapter: QLTestAdapter;
|
||||
let runTestsSpy: sinon.SinonStub;
|
||||
let resolveTestsSpy: sinon.SinonStub;
|
||||
let resolveQlpacksSpy: sinon.SinonStub;
|
||||
let sandox: sinon.SinonSandbox;
|
||||
|
||||
beforeEach(() => {
|
||||
sandox = sinon.createSandbox();
|
||||
mockRunTests();
|
||||
resolveQlpacksSpy = sandox.stub().resolves({});
|
||||
resolveTestsSpy = sandox.stub().resolves([]);
|
||||
adapter = new QLTestAdapter({
|
||||
name: 'ABC',
|
||||
uri: Uri.parse('file:/ab/c')
|
||||
} as WorkspaceFolder, {
|
||||
runTests: runTestsSpy,
|
||||
resolveQlpacks: resolveQlpacksSpy,
|
||||
resolveTests: resolveTestsSpy
|
||||
} as unknown as CodeQLCliServer);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandox.restore();
|
||||
});
|
||||
|
||||
it('should run some tests', async () => {
|
||||
|
||||
const listenerSpy = sandox.spy();
|
||||
adapter.testStates(listenerSpy);
|
||||
const testsPath = Uri.parse('file:/ab/c').fsPath;
|
||||
const dPath = Uri.parse('file:/ab/c/d.ql').fsPath;
|
||||
const gPath = Uri.parse('file:/ab/c/e/f/g.ql').fsPath;
|
||||
const hPath = Uri.parse('file:/ab/c/e/f/h.ql').fsPath;
|
||||
|
||||
await adapter.run([testsPath]);
|
||||
|
||||
expect(listenerSpy.getCall(0).args).to.deep.eq([
|
||||
{ type: 'started', tests: [testsPath] }
|
||||
]);
|
||||
expect(listenerSpy.getCall(1).args).to.deep.eq([{
|
||||
type: 'test',
|
||||
state: 'passed',
|
||||
test: dPath,
|
||||
message: undefined,
|
||||
decorations: []
|
||||
}]);
|
||||
expect(listenerSpy.getCall(2).args).to.deep.eq([{
|
||||
type: 'test',
|
||||
state: 'errored',
|
||||
test: gPath,
|
||||
message: `\nerrored: ${gPath}\npqr\nxyz\n`,
|
||||
decorations: [
|
||||
{ line: 1, message: 'abc' }
|
||||
]
|
||||
}]);
|
||||
expect(listenerSpy.getCall(3).args).to.deep.eq([{
|
||||
type: 'test',
|
||||
state: 'failed',
|
||||
test: hPath,
|
||||
message: `\nfailed: ${hPath}\njkh\ntuv\n`,
|
||||
decorations: []
|
||||
}]);
|
||||
expect(listenerSpy.getCall(4).args).to.deep.eq([{ type: 'finished' }]);
|
||||
expect(listenerSpy).to.have.callCount(5);
|
||||
});
|
||||
|
||||
function mockRunTests() {
|
||||
// runTests is an async generator function. This is not directly supported in sinon
|
||||
// However, we can pretend the same thing by just returning an async array.
|
||||
runTestsSpy = sandox.stub();
|
||||
runTestsSpy.returns(
|
||||
(async function*() {
|
||||
yield Promise.resolve({
|
||||
test: Uri.parse('file:/ab/c/d.ql').fsPath,
|
||||
pass: true,
|
||||
messages: []
|
||||
});
|
||||
yield Promise.resolve({
|
||||
test: Uri.parse('file:/ab/c/e/f/g.ql').fsPath,
|
||||
pass: false,
|
||||
diff: ['pqr', 'xyz'],
|
||||
// a compile error
|
||||
messages: [
|
||||
{ position: { line: 1 }, message: 'abc' }
|
||||
]
|
||||
});
|
||||
yield Promise.resolve({
|
||||
test: Uri.parse('file:/ab/c/e/f/h.ql').fsPath,
|
||||
pass: false,
|
||||
diff: ['jkh', 'tuv'],
|
||||
messages: []
|
||||
});
|
||||
})()
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -32,7 +32,6 @@ describe('commands declared in package.json', function() {
|
||||
if (
|
||||
command.match(/^codeQL\./)
|
||||
|| command.match(/^codeQLQueryResults\./)
|
||||
|| command.match(/^codeQLTests\./)
|
||||
) {
|
||||
paletteCmds.add(command);
|
||||
expect(title).not.to.be.undefined;
|
||||
@@ -42,6 +41,7 @@ describe('commands declared in package.json', function() {
|
||||
command.match(/^codeQLDatabases\./)
|
||||
|| command.match(/^codeQLQueryHistory\./)
|
||||
|| command.match(/^codeQLAstViewer\./)
|
||||
|| command.match(/^codeQLTests\./)
|
||||
) {
|
||||
scopedCmds.add(command);
|
||||
expect(title).not.to.be.undefined;
|
||||
@@ -69,8 +69,6 @@ describe('commands declared in package.json', function() {
|
||||
disabledInPalette.add(commandDecl.command);
|
||||
});
|
||||
|
||||
|
||||
|
||||
it('should have commands appropriately prefixed', function() {
|
||||
paletteCmds.forEach(command => {
|
||||
expect(commandTitles[command], `command ${command} should be prefixed with 'CodeQL: ', since it is accessible from the command palette`).to.match(/^CodeQL: /);
|
||||
|
||||
@@ -4,7 +4,7 @@ import * as sinonChai from 'sinon-chai';
|
||||
import 'mocha';
|
||||
import * as path from 'path';
|
||||
|
||||
import { gatherQlFiles } from '../../src/files';
|
||||
import { gatherQlFiles } from '../../src/pure/files';
|
||||
|
||||
chai.use(sinonChai);
|
||||
const expect = chai.expect;
|
||||
@@ -13,9 +13,6 @@ describe('files', () => {
|
||||
const dataDir = path.join(path.dirname(__dirname), 'data');
|
||||
const data2Dir = path.join(path.dirname(__dirname), 'data2');
|
||||
|
||||
it('should pass', () => {
|
||||
expect(true).to.be.eq(true);
|
||||
});
|
||||
it('should find one file', async () => {
|
||||
const singleFile = path.join(dataDir, 'query.ql');
|
||||
const result = await gatherQlFiles([singleFile]);
|
||||
|
||||
22
extensions/ql-vscode/test/pure-tests/helpers-pure.test.ts
Normal file
22
extensions/ql-vscode/test/pure-tests/helpers-pure.test.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { fail } from 'assert';
|
||||
import { expect } from 'chai';
|
||||
import { asyncFilter } from '../../src/pure/helpers-pure';
|
||||
|
||||
describe('helpers-pure', () => {
|
||||
it('should filter asynchronously', async () => {
|
||||
expect(await asyncFilter([1, 2, 3], x => Promise.resolve(x > 2))).to.deep.eq([3]);
|
||||
});
|
||||
|
||||
it('should throw on error when filtering', async () => {
|
||||
const rejects = (x: number) => x === 3
|
||||
? Promise.reject(new Error('opps'))
|
||||
: Promise.resolve(true);
|
||||
|
||||
try {
|
||||
await asyncFilter([1, 2, 3], rejects);
|
||||
fail('Should have thrown');
|
||||
} catch (e) {
|
||||
expect(e.message).to.eq('opps');
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import { expect } from 'chai';
|
||||
import 'mocha';
|
||||
import { tryGetResolvableLocation } from '../../src/bqrs-utils';
|
||||
import { tryGetResolvableLocation } from '../../src/pure/bqrs-utils';
|
||||
|
||||
describe('processing string locations', function() {
|
||||
it('should detect Windows whole-file locations', function() {
|
||||
|
||||
@@ -2,7 +2,12 @@ import 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import * as Sarif from 'sarif';
|
||||
|
||||
import { getPathRelativeToSourceLocationPrefix, parseSarifLocation, parseSarifPlainTextMessage, unescapeSarifText } from '../../src/sarif-utils';
|
||||
import {
|
||||
getPathRelativeToSourceLocationPrefix,
|
||||
parseSarifLocation,
|
||||
parseSarifPlainTextMessage,
|
||||
unescapeSarifText
|
||||
} from '../../src/pure/sarif-utils';
|
||||
|
||||
|
||||
describe('parsing sarif', () => {
|
||||
@@ -46,20 +51,24 @@ describe('parsing sarif', () => {
|
||||
|
||||
it('should normalize source locations', () => {
|
||||
expect(getPathRelativeToSourceLocationPrefix('C:\\a\\b', '?x=test'))
|
||||
.to.eq('file:C:/a/b/?x=test');
|
||||
.to.eq('file:/C:/a/b/?x=test');
|
||||
expect(getPathRelativeToSourceLocationPrefix('C:\\a\\b', '%3Fx%3Dtest'))
|
||||
.to.eq('file:C:/a/b/%3Fx%3Dtest');
|
||||
.to.eq('file:/C:/a/b/%3Fx%3Dtest');
|
||||
expect(getPathRelativeToSourceLocationPrefix('C:\\a =\\b c?', '?x=test'))
|
||||
.to.eq('file:/C:/a%20%3D/b%20c%3F/?x=test');
|
||||
expect(getPathRelativeToSourceLocationPrefix('/a/b/c', '?x=test'))
|
||||
.to.eq('file:/a/b/c/?x=test');
|
||||
});
|
||||
|
||||
describe('parseSarifLocation', () => {
|
||||
it('should parse a sarif location with "no location"', () => {
|
||||
expect(parseSarifLocation({ }, '')).to.deep.equal({
|
||||
expect(parseSarifLocation({}, '')).to.deep.equal({
|
||||
hint: 'no physical location'
|
||||
});
|
||||
expect(parseSarifLocation({ physicalLocation: {} }, '')).to.deep.equal({
|
||||
hint: 'no artifact location'
|
||||
});
|
||||
expect(parseSarifLocation({ physicalLocation: { artifactLocation: { } } }, '')).to.deep.equal({
|
||||
expect(parseSarifLocation({ physicalLocation: { artifactLocation: {} } }, '')).to.deep.equal({
|
||||
hint: 'artifact location has no uri'
|
||||
});
|
||||
});
|
||||
@@ -73,7 +82,7 @@ describe('parsing sarif', () => {
|
||||
}
|
||||
};
|
||||
expect(parseSarifLocation(location, 'prefix')).to.deep.equal({
|
||||
uri: 'file:prefix/abc?x=test',
|
||||
uri: 'file:/prefix/abc?x=test',
|
||||
userVisibleFile: 'abc?x=test'
|
||||
});
|
||||
});
|
||||
@@ -82,13 +91,13 @@ describe('parsing sarif', () => {
|
||||
const location: Sarif.Location = {
|
||||
physicalLocation: {
|
||||
artifactLocation: {
|
||||
uri: 'file:abc%3Fx%3Dtest'
|
||||
uri: 'file:/abc%3Fx%3Dtest'
|
||||
}
|
||||
}
|
||||
};
|
||||
expect(parseSarifLocation(location, 'prefix')).to.deep.equal({
|
||||
uri: 'file:abc%3Fx%3Dtest',
|
||||
userVisibleFile: 'abc?x=test'
|
||||
uri: 'file:/abc%3Fx%3Dtest',
|
||||
userVisibleFile: '/abc?x=test'
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
"module": "commonjs",
|
||||
"target": "es2017",
|
||||
"outDir": "out",
|
||||
"lib": [
|
||||
"es6"
|
||||
],
|
||||
"lib": ["ES2020"],
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"rootDir": "src",
|
||||
@@ -21,12 +19,6 @@
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"test",
|
||||
"**/view"
|
||||
]
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["node_modules", "test", "**/view"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user