Skip to content

Commit

Permalink
add unit testing, update testing infrastructure (add nyc, add uncache…
Browse files Browse the repository at this point in the history
…d require, remove defaults in test.js), eslint-disable no-console in config.js, refactoring checkChallenge (#287)

* refactor MIBL

* fix

* smaller

* clearer function naming

* tweaked handicap code

* handicap minor changes

* standardize number of handicap stones and number of periods functions

* move handicap to periods, make rank a specific function

this is because number of handicap and number of periods share
many similarities, while rank function is different, among which
"your rank is too low", and arg and notif conversions to displayable
ranks (ex: 5k)

* fix devel's canadian return, and enhance canadian check

no need to multiply arg if we divide notif by number of stones
this way we also get a notif per stone same as fischer and all other
time controls

* minor fixes

* move handicap periods function above main periodtime function

this matches chronological order

* move handicap and periods part 2

* move getBlitzLiveCorr to match chronological order

* simplify isMin code

* rename .minMax to .miniMaxi

* remove familyObject

* much clearer undefined check for number args

* clearer canadian periodtime info

* clearer canadian explanation

* minor

* clearer

* fix old description

* enhanced argNameString check

check argNameString before checking config[argNameString]
so we avoid undefined error while also checking strictly
for undefined for booleanly false number values such as 0

* fix

* replace setting[0] setting[1] setting[2] with [timecontrolName, timecontrolDescr, timecontrolNotif] = timecontrolArr;

* fix canadian periodtime unconverted notification displayed

* rename checkMinMaxCondition to checkNotifIsInMinMaxArgRange

* fix non-byoyomi time controls always rejecting challenge number of periods

* fix display canadian periodtime for all the X stones

* fix .includes

* be non-strict in minmax comparisons

minhandicap 0 maxhandicap 2 should allow
- min => 0 or higher
- max => 2 or lower

0,1, 2

being non-strict would allow only value 1

* fix binary division loss of precision: multiply arg, dont divide notif

for canadian periodtime (for all the X stones)

* clearer comments, check for timecontrol at the earliest

* unfinished

* fix mismatch from devel after auto fix merge conflicts to latest

* add getMinMaxReject, refactor to be more abstract

* use object to access timecontrol info, add sanity check timecontrol notif

* various fixes in connection.js from local testing in checkChallenge.test.js

* rename test/uhmaeat.test.js -> test/checkChallenge.test.js

* add testing for minmaintimeblitz and minperiodtimeblitz

* add maintime and periodtime blitz in byoyomi testing (to debug config)

config is currently not renewed before each "it"

* fix test with a workaround: overwrite old config inputs

this is not clean but works, until we can review and enhance it

* add byoyomi live timesettings testing

* add nested describe for "Bans" and "Byoyomi time settings"

* add tests for byoyomi correspondence time settings

* fix indentation

* fix connection.js based on added rank testing

* add min max rank testing

* add testing for handicap and fakerank

* add missing fakerank test

* add canadian testing

* Updated test infrastructure

* fix merge conflicts

* add .nyc_output to .gitignore, replace let with const in testing

* remove fixed manual need to erase previous config before each test

these spots were marked like this:
      // remove old vars
      // this is not clean but it is a workaround until we review this

* remove allowed families defaults in test.js and fix connection.js

these lines in test.js:

config.allowed_boardsizes[19] = true;
config.allow_all_komis = true;
config.allowed_speeds['live'] = true;
config.allowed_timecontrols['fischer'] = true;

are not needed in test.js, which does not check challenges, so
they should be in checkChallenge.test.js

however removing them showed that our connection.js does not check
for config.boardsizes (for example), which makes sense because we
have defaults so they are assumed always defined

so adding a check in connection.js makes connection.js more solid,
and it also allows to have a cleaner test.js

these removed values should be tested in checkChallenge.test.js
individually, not globally

* add abstraction layers to avoid repetitions in allowed families

* add no numbers of periods check for non-byoyomi time controls

* add semicolon }); in describes in checkChallenge.test.js

* fix maintime and periodtime being checked even if they should not

for example "simple" time control has no main time, so we can skip
the main time check

* add limited time controls tests, ex: "none" has no time settings

so do not check unexisting settings

* add testing for canadian time controls

* add canadian maintime testing

* add testing for ranked unranked precedence rules

* add testing for fischer time settings

* add testing for simple time settings

* add absolute time settings testing

* add testing for allowed families, refactor allowed families

* fix boardsizes in connection.js and test against connection.js, not config.js

* replace let with const in checkChallenge.test.js

* minor fixes

* add .vscode to gitignore

* minor various tweaks and fixes

* minor

* various fixes, move some functions to /utils

* fix

* add process exports functions for allowed families and bans

* fixes

* add checkChallengeHandicap, noautohandicap is true if minhandicap > 0

* finished adding all fixed from @Dorus 's review

* refactor booleans ranked unranked checks

* fix

* split checkChallenge Mandatory into User and Bot

* minor fix indentation

* fix config undefined in new instances of Connection

* add getNewConnection()

* clearer noautohandicap description

* follow logical order foreign modules / utils shared / gtp2ogs modules

* remove console import in config.js

if bot admin inputs a wrong set of argv and values, it's a good idea
to stop current run of gtp2ogs with a throw and kill gtp2ogs, rather
than use console.error which also requires process.exit

console.error is better used in other modules where the error
(ex: gamedata change, bot failed to start in one game) is not a
reason to stop our gtp2ogs altogether, so we beautify the line of
error in logging

however throw is simpler and already provides line of error information

* disable no-console ESLint rule in config.js

explanations are in DEV.md

* remove debug line, minor cleanup

* fix order

* add unit testing for rankedonly and unrankedonly

* add speeds sanity check: unknown speeds make time settings uncheckable

unknown speed "turbo" would make --minmaintimeturbo uncheckable
(does not exist)

* unknown speed makes challenge uncheckable, add sanity check

* move sanity Checks on top of checkChallenge, add unit testing

move err method out of class Connection
remove unused ok method

* fix remove duplicate tests

* add link to visual studio code testing extensions in DEV.md

* fix no handicap games

* fixes

* fix formatting in checkChallenge.test.js

Co-authored-by: Dorus <[email protected]>
  • Loading branch information
wonderingabout and Dorus authored Jun 11, 2020
1 parent fc76812 commit 0f29e41
Show file tree
Hide file tree
Showing 15 changed files with 3,842 additions and 578 deletions.
2 changes: 1 addition & 1 deletion bot.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// vim: tw=120 softtabstop=4 shiftwidth=4

const child_process = require('child_process');
const split2 = require('split2');

const { decodeMoves } = require("./utils/decodeMoves");
const { gtpchar2num } = require("./utils/gtpchar2num");
const { move2gtpvertex } = require("./utils/move2gtpvertex");

const child_process = require('child_process');
const console = require('./console').console;
const config = require('./config');
const { Pv } = require('./pv');
Expand Down
260 changes: 130 additions & 130 deletions config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
// vim: tw=120 softtabstop=4 shiftwidth=4

const fs = require('fs')
const console = require('console');
// see: https://github.com/online-go/gtp2ogs/blob/devel/docs/DEV.md#no-console-eslint-rule-in-configjs
/* eslint-disable no-console */

const fs = require('fs');

const { getArgNamesGRU } = require('./utils/getArgNamesGRU');
const { getFamilyName } = require('./utils/getFamilyName');
const { getRankedUnranked } = require('./utils/getRankedUnranked');
const { getRankedUnrankedUnderscored } = require('./utils/getRankedUnrankedUnderscored');

exports.check_rejectnew = function() {};

exports.banned_users = {};
exports.banned_users_ranked = {};
exports.banned_users_unranked = {};
Expand Down Expand Up @@ -252,6 +260,9 @@ exports.updateFromArgv = function() {
if (argv.logfile && typeof argv.logfile === "boolean") {
exports.logfile = `gtp2ogs_logfile_${new Date().toISOString()}`;
}
if (argv.rankedonly && argv.unrankedonly) {
throw `Please choose either --rankedonly or --unrankedonly, not both.`;
}
for (const k of ["timeout", "startupbuffer"]) {
if (argv[k]) {
// Convert some times to microseconds once here so
Expand All @@ -262,9 +273,31 @@ exports.updateFromArgv = function() {
if (argv.beta) {
exports.host = 'beta.online-go.com';
}

// Setting minimum handicap higher than -1 has the consequence of disabling
// automatic handicap (notification.handicap === -1).
//
// Except if --fakerank is used: then we leave that choice to bot admin:
// - either he wants to accept automatic handicap (-1) and use fakerank to
// calculate automatic handicap stones based on rank difference between
// bot's fakerank and user's ranking.
// - or as was done previously bot admin can use the noautohandicap options
// to reject automatic handicap challenges
//
if (argv.fakerank) {
exports.fakerank = parseRank(argv.fakerank);
} else {
if (argv.minhandicap > -1) {
exports.noautohandicap = true;
}
if (argv.minhandicapranked > -1) {
exports.noautohandicapranked = true;
}
if (argv.noautohandicapunranked > -1) {
exports.noautohandicapunranked = true;
}
}

if (argv.ogspv) {
exports.ogspv = argv.ogspv.toUpperCase();
}
Expand All @@ -281,134 +314,33 @@ exports.updateFromArgv = function() {
exports.bot_command = argv._;

/* 2) specifc r_u cases :*/
if (argv.minrank && !argv.minrankranked && !argv.minrankunranked) {
exports.minrank = parseRank(argv.minrank);
}
if (argv.minrankranked) {
exports.minrankranked = parseRank(argv.minrankranked);
}
if (argv.minrankunranked) {
exports.minrankunranked = parseRank(argv.minrankunranked);
}
if (argv.maxrank && !argv.maxrankranked && !argv.maxrankunranked) {
exports.maxrank = parseRank(argv.maxrank);
}
if (argv.maxrankranked) {
exports.maxrankranked = parseRank(argv.maxrankranked);
}
if (argv.maxrankunranked) {
exports.maxrankunranked = parseRank(argv.maxrankunranked);
}
processRankExport("minrank", argv);
processRankExport("minrankranked", argv);
processRankExport("minrankunranked", argv);

if (argv.bans) {
for (const user of argv.bans.split(',')) {
exports.banned_users[user] = true;
}
}
if (argv.bansranked) {
for (const user of argv.bansranked.split(',')) {
exports.banned_users_ranked[user] = true;
}
}
if (argv.bansunranked) {
for (const user of argv.bansunranked.split(',')) {
exports.banned_users_unranked[user] = true;
}
}
processRankExport("maxrank", argv);
processRankExport("maxrankranked", argv);
processRankExport("maxrankunranked", argv);

if (argv.boardsizes) {
for (const boardsize of argv.boardsizes.split(',')) {
if (boardsize === "all") {
exports.allow_all_boardsizes = true;
} else {
exports.allowed_boardsizes[boardsize] = true;
}
}
}
if (argv.boardsizesranked) {
for (const boardsizeranked of argv.boardsizesranked.split(',')) {
if (boardsizeranked === "all") {
exports.allow_all_boardsizes_ranked = true;
} else {
exports.allowed_boardsizes_ranked[boardsizeranked] = true;
}
}
}
if (argv.boardsizesunranked) {
for (const boardsizeunranked of argv.boardsizesunranked.split(',')) {
if (boardsizeunranked === "all") {
exports.allow_all_boardsizes_unranked = true;
} else {
exports.allowed_boardsizes_unranked[boardsizeunranked] = true;
}
}
}
processBansExport("bans", argv);
processBansExport("bansranked", argv);
processBansExport("bansunranked", argv);

if (argv.komis) {
for (const komi of argv.komis.split(',')) {
if (komi === "all") {
exports.allow_all_komis = true;
} else if (komi === "automatic") {
exports.allowed_komis[null] = true;
} else {
exports.allowed_komis[komi] = true;
}
}
}
if (argv.komisranked) {
for (const komiranked of argv.komisranked.split(',')) {
if (komiranked === "all") {
exports.allow_all_komis_ranked = true;
} else if (komiranked === "automatic") {
exports.allowed_komis_ranked[null] = true;
} else {
exports.allowed_komis_ranked[komiranked] = true;
}
}
}
if (argv.komisunranked) {
for (const komiunranked of argv.komisunranked.split(',')) {
if (komiunranked === "all") {
exports.allow_all_komis_unranked = true;
} else if (komiunranked === "automatic") {
exports.allowed_komis_unranked[null] = true;
} else {
exports.allowed_komis_unranked[komiunranked] = true;
}
}
}
processBoardsizesExport("boardsizes", argv);
processBoardsizesExport("boardsizesranked", argv);
processBoardsizesExport("boardsizesunranked", argv);

if (argv.speeds) {
for (const e of argv.speeds.split(',')) {
exports.allowed_speeds[e] = true;
}
}
if (argv.speedsranked) {
for (const e of argv.speedsranked.split(',')) {
exports.allowed_speeds_ranked[e] = true;
}
}
if (argv.speedsunranked) {
for (const e of argv.speedsunranked.split(',')) {
exports.allowed_speeds_unranked[e] = true;
}
}
processKomisExport("komis", argv);
processKomisExport("komisranked", argv);
processKomisExport("komisunranked", argv);

if (argv.timecontrols) {
for (const e of argv.timecontrols.split(',')) {
exports.allowed_timecontrols[e] = true;
}
}
if (argv.timecontrolsranked) {
for (const e of argv.timecontrolsranked.split(',')) {
exports.allowed_timecontrols_ranked[e] = true;
}
}
if (argv.timecontrolsunranked) {
for (const e of argv.timecontrolsunranked.split(',')) {
exports.allowed_timecontrols_unranked[e] = true;
}
}
processAllowedFamilyExport("speeds", argv);
processAllowedFamilyExport("speedsranked", argv);
processAllowedFamilyExport("speedsunranked", argv);

processAllowedFamilyExport("timecontrols", argv);
processAllowedFamilyExport("timecontrolsranked", argv);
processAllowedFamilyExport("timecontrolsunranked", argv);

// console messages
// C - test exports warnings
Expand Down Expand Up @@ -500,11 +432,6 @@ function ensureSupportedOgspvAI(ogspv, ogsPvAIs) {
}
}

// argv.arg(general/ranked/unranked) to exports.(r_u).arg
function getArgNamesGRU(familyName) {
return ["", "ranked", "unranked"].map( e => `${familyName}${e}` );
}

function parseRank(arg) {
if (arg) {
const re = /(\d+)([kdp])/;
Expand All @@ -524,6 +451,79 @@ function parseRank(arg) {
}
}

function processRankExport(argName, argv) {
const arg = argv[argName];
if (arg) {
exports[argName] = parseRank(arg);
}
}

function processBansExport(argName, argv) {
const arg = argv[argName];
const rankedUnrankedUnderscored = getRankedUnrankedUnderscored(argName);

if (arg) {
const bans = arg.split(',');
for (const bannedUser of bans) {
exports[`banned_users${rankedUnrankedUnderscored}`][bannedUser] = true;
}
}
}

function processBoardsizesExport(argName, argv) {
const arg = argv[argName];

if (arg) {
const rankedUnranked = getRankedUnranked(argName);
const rankedUnrankedUnderscored = getRankedUnrankedUnderscored(rankedUnranked);
const boardsizes = arg.split(',');
for (const boardsize of boardsizes) {
if (boardsize === "all") {
exports[`allow_all_boardsizes${rankedUnrankedUnderscored}`] = true;
} else {
exports[`allowed_boardsizes${rankedUnrankedUnderscored}`][boardsize] = true;
}
}
}
}

function processKomisExport(argName, argv) {
const arg = argv[argName];

if (arg) {
const rankedUnranked = getRankedUnranked(argName);
const rankedUnrankedUnderscored = getRankedUnrankedUnderscored(rankedUnranked);
const komis = arg.split(',');
for (const komi of komis) {
if (komi === "all") {
exports[`allow_all_komis${rankedUnrankedUnderscored}`] = true;
} else if (komi === "automatic") {
exports[`allowed_komis${rankedUnrankedUnderscored}`][null] = true;
} else {
exports[`allowed_komis${rankedUnrankedUnderscored}`][komi] = true;
}
}
}
}

function processAllowedFamilyExport(argName, argv) {
const arg = argv[argName];

if (arg) {
const familyName = getFamilyName(argName);
const rankedUnranked = getRankedUnranked(argName);
const rankedUnrankedUnderscored = getRankedUnrankedUnderscored(rankedUnranked);
const allowedValues = arg.split(',');
for (const allowedValue of allowedValues) {
if (allowedValue === "all") {
exports[`allow_all_${familyName}${rankedUnrankedUnderscored}`] = true;
} else {
exports[`allowed_${familyName}${rankedUnrankedUnderscored}`][allowedValue] = true;
}
}
}
}

function testExportsWarnings() {
console.log("TESTING WARNINGS:\n-------------------------------------------------------");
let isWarning = false;
Expand Down
Loading

0 comments on commit 0f29e41

Please sign in to comment.