Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

test: Add test for "needCheckForUpdates" #82

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ module.exports = {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{ varsIgnorePattern: "_" },
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
},
],
"@typescript-eslint/no-non-null-assertion": "error",
"guard-for-in": "error",
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -989,15 +989,18 @@
},
"devDependencies": {
"@sourcegraph/scip-typescript": "^0.2.9",
"@types/chai": "^4.3.3",
"@types/glob": "^8.0.0",
"@types/mocha": "^9.1.1",
"@types/node": "18.7.14",
"@types/remarkable": "^2.0.3",
"@types/semver": "^7.3.12",
"@types/sinon": "^10.0.13",
"@types/vscode": "1.59.0",
"@typescript-eslint/eslint-plugin": "^5.36.1",
"@typescript-eslint/parser": "^5.36.1",
"@vscode/test-electron": "^2.1.5",
"chai": "^4.3.6",
"eslint": "^8.23.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-mocha": "^10.1.0",
Expand All @@ -1007,6 +1010,7 @@
"ovsx": "0.5.1",
"prettier": "2.7.1",
"rimraf": "^3.0.2",
"sinon": "^14.0.0",
"ts-mocha": "^10.0.0",
"typescript": "4.8.2",
"vsce": "2.11.0"
Expand Down
4 changes: 4 additions & 0 deletions src/ConfigurationTarget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum ConfigurationTarget {
Global,
Workspace,
}
83 changes: 32 additions & 51 deletions src/getServerVersion.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import {
commands,
ConfigurationTarget,
ExtensionContext,
window,
WorkspaceConfiguration,
ConfigurationTarget as VConfigurationTarget,
} from "vscode";
import * as metalsLanguageClient from "metals-languageclient";
import * as workbenchCommands from "./workbenchCommands";
import http from "https";
import { getConfigValue } from "./util";
import { DefaultCheckForUpdateRepo } from "./repository/CheckForUpdateRepo";
import { needCheckForUpdates } from "./service/checkForUpdate";
import { ConfigurationTarget } from "./ConfigurationTarget";

const serverVersionSection = "serverVersion";
const suggestLatestUpgrade = "suggestLatestUpgrade";

const currentVersionKey = "currentVersion";
const lastUpdatedAtKey = "lastUpdatedAt";

export function getServerVersion(
config: WorkspaceConfiguration,
context: ExtensionContext
Expand All @@ -40,12 +40,15 @@ async function validateCurrentVersion(
suggestLatestUpgrade
);

const checkForUpdateRepo = new DefaultCheckForUpdateRepo(context);

const checkForUpdate = async () => {
if (suggestUpgradeSetting?.value) {
return needCheckForUpdates(
serverVersion,
suggestUpgradeSetting.target,
context
todayString(),
fromVSCode(suggestUpgradeSetting.target),
checkForUpdateRepo
);
} else {
return false;
Expand All @@ -68,13 +71,17 @@ async function validateCurrentVersion(
nextVersion,
suggestUpgradeSetting.target
);
saveVersionDate(nextVersion, suggestUpgradeSetting.target, context);
checkForUpdateRepo.saveLastUpdated(
nextVersion,
todayString(),
fromVSCode(suggestUpgradeSetting.target)
);
} else if (result == ignoreChoice) {
// extend the current version expiration date
saveVersionDate(
checkForUpdateRepo.saveLastUpdated(
serverVersion,
suggestUpgradeSetting.target,
context
todayString(),
fromVSCode(suggestUpgradeSetting.target)
);
}
});
Expand All @@ -101,46 +108,6 @@ async function fetchLatest(): Promise<string> {
return sorted[sorted.length - 1];
}

/**
* The logic is the following:
* - if version was set more than a day ago - update is needed
* - if version is seen in a first time (user changed version in config by it self) - the update will be delayed for a day
*/
async function needCheckForUpdates(
currentVersion: string,
target: ConfigurationTarget,
context: ExtensionContext
): Promise<boolean> {
const state =
target === ConfigurationTarget.Global
? context.globalState
: context.workspaceState;
const prevVersion = state.get<string>(currentVersionKey);
const lastUpdated = state.get<string>(lastUpdatedAtKey);

const today = todayString();
if (prevVersion !== currentVersion) {
saveVersionDate(currentVersion, target, context);
return false;
} else {
return lastUpdated !== today;
}
}

function saveVersionDate(
version: string,
target: ConfigurationTarget,
context: ExtensionContext
): void {
const state =
target === ConfigurationTarget.Global
? context.globalState
: context.workspaceState;

state.update(currentVersionKey, version);
state.update(lastUpdatedAtKey, todayString());
}

function warnIfIsOutdated(config: WorkspaceConfiguration): void {
metalsLanguageClient.checkServerVersion({
config,
Expand Down Expand Up @@ -175,10 +142,24 @@ function warnIfIsOutdated(config: WorkspaceConfiguration): void {
});
}

function todayString(): string {
/**
* @returns YYYY-MM-DD in a local date
*/
export function todayString(): string {
const date = new Date();
const year = date.getFullYear().toString();
const month = (date.getMonth() + 1).toString().padStart(2, "0");
const day = date.getDate().toString().padStart(2, "0");
return [year, month, day].join("-");
}

function fromVSCode(target: VConfigurationTarget): ConfigurationTarget {
switch (target) {
case VConfigurationTarget.Global:
return ConfigurationTarget.Global;
case VConfigurationTarget.Workspace:
return ConfigurationTarget.Workspace;
case VConfigurationTarget.WorkspaceFolder:
return ConfigurationTarget.Workspace;
}
}
50 changes: 50 additions & 0 deletions src/repository/CheckForUpdateRepo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { ExtensionContext, Memento } from "vscode";
import { ConfigurationTarget } from "../ConfigurationTarget";

type LastUpdated = {
prevVersion?: string;
lastUpdatedAt?: string;
};

export interface CheckForUpdateRepo {
getLastUpdated(target: ConfigurationTarget): LastUpdated;
saveLastUpdated(
serverVersion: string,
lastUpdatedAt: string,
target: ConfigurationTarget
): void;
}

export class DefaultCheckForUpdateRepo implements CheckForUpdateRepo {
constructor(private context: ExtensionContext) {}

private CurrentVersionKey = "currentVersion";
private LastUpdatedAtKey = "lastUpdatedAt";

getLastUpdated(target: ConfigurationTarget): LastUpdated {
const state = this.storage(target);
const prevVersion = state.get<string>(this.CurrentVersionKey);
const lastUpdatedAt = state.get<string>(this.LastUpdatedAtKey);
return {
prevVersion,
lastUpdatedAt,
};
}

saveLastUpdated(
serverVersion: string,
lastUpdatedAt: string,
target: ConfigurationTarget
): void {
const state = this.storage(target);
state.update(this.CurrentVersionKey, serverVersion);
state.update(this.LastUpdatedAtKey, lastUpdatedAt);
return;
}

private storage(target: ConfigurationTarget): Memento {
return target === ConfigurationTarget.Global
? this.context.globalState
: this.context.workspaceState;
}
}
23 changes: 23 additions & 0 deletions src/service/checkForUpdate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ConfigurationTarget } from "../ConfigurationTarget";
import { CheckForUpdateRepo } from "../repository/CheckForUpdateRepo";

/**
* The logic is the following:
* - if version was set more than a day ago - update is needed
* - if version is seen for the first time (user changed version in config by it self) - the update will be delayed for a day
*/
export async function needCheckForUpdates(
currentVersion: string,
today: string,
target: ConfigurationTarget,
repo: CheckForUpdateRepo
): Promise<boolean> {
const { prevVersion, lastUpdatedAt } = repo.getLastUpdated(target);

if (prevVersion !== currentVersion) {
repo.saveLastUpdated(currentVersion, today, target);
return false;
} else {
return lastUpdatedAt !== today;
}
}
97 changes: 97 additions & 0 deletions src/test/unit/checkForUpdate.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { ConfigurationTarget } from "../../ConfigurationTarget";
import { needCheckForUpdates } from "../../service/checkForUpdate";
import { CheckForUpdateRepo } from "../../repository/CheckForUpdateRepo";
import sinon from "sinon";
import { expect } from "chai";

class MockRepo implements CheckForUpdateRepo {
constructor(private prevVersion?: string, private lastUpdatedAt?: string) {}
getLastUpdated(_target: ConfigurationTarget): {
prevVersion?: string | undefined;
lastUpdatedAt?: string | undefined;
} {
return {
prevVersion: this.prevVersion,
lastUpdatedAt: this.lastUpdatedAt,
};
}
saveLastUpdated(
_serverVersion: string,
_lastUpdatedAt: string,
_target: ConfigurationTarget
): void {
return;
}
}

describe("needCheckForUpdates", () => {
it("should false if nothing has saved / save current versions", async () => {
const currentVersion = "0.11.8";
const today = "2022-01-01";
const repo = new MockRepo(undefined, undefined);
const spy = sinon.spy(repo, "saveLastUpdated");
const actual = await needCheckForUpdates(
currentVersion,
today,
ConfigurationTarget.Global,
repo
);
expect(actual).false;
expect(spy.getCall(0).args).to.eql([
currentVersion,
today,
ConfigurationTarget.Global,
]);
});

it("should false if currentVersion was seen for the first time / save current versions", async () => {
const prevVersion = "0.11.8";
const currentVersion = "0.11.9";
const today = "2022-01-01";
const repo = new MockRepo(prevVersion, today);
const spy = sinon.spy(repo, "saveLastUpdated");
const actual = await needCheckForUpdates(
currentVersion,
today,
ConfigurationTarget.Global,
repo
);
expect(actual).false;
expect(spy.getCall(0).args).to.eql([
currentVersion,
today,
ConfigurationTarget.Global,
]);
});

it("should false if currentVersion is set today", async () => {
const currentVersion = "0.11.8";
const today = "2022-01-01";
const repo = new MockRepo(currentVersion, today);
const spy = sinon.spy(repo, "saveLastUpdated");
const actual = await needCheckForUpdates(
currentVersion,
today,
ConfigurationTarget.Global,
repo
);
expect(actual).false;
expect(spy.notCalled).true;
});

it("should true if currentVersion is set more than a day ago", async () => {
const currentVersion = "0.11.8";
const lastUpdatedAt = "2022-01-01";
const today = "2022-01-02";
const repo = new MockRepo(currentVersion, lastUpdatedAt);
const spy = sinon.spy(repo, "saveLastUpdated");
const actual = await needCheckForUpdates(
currentVersion,
today,
ConfigurationTarget.Global,
repo
);
expect(actual).true;
expect(spy.notCalled).true;
});
});
4 changes: 2 additions & 2 deletions src/test/unit/indentPattern.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import assert from "assert";
import { expect } from "chai";
import { increaseIndentPattern } from "../../indentPattern";

function checkIndent(indentPattern: RegExp, result: boolean) {
return (text: string) => assert(indentPattern.test(text) === result);
return (text: string) => expect(indentPattern.test(text)).to.equal(result);
}

function checkFunctions(indentPattern: RegExp) {
Expand Down
Loading