diff --git a/.busted b/.busted new file mode 100644 index 00000000000..8135e3dd586 --- /dev/null +++ b/.busted @@ -0,0 +1,12 @@ +return { + _all = { + verbose = true, + helper = 'spec/test_helper.lua', + }, + default = { + ROOT = {"spec"}, + }, + ci = { + ROOT = {"spec"}, + }, +} diff --git a/.github/workflows/luacheck.yml b/.github/workflows/luacheck.yml index 1210c73ea2a..b19d8db35f0 100644 --- a/.github/workflows/luacheck.yml +++ b/.github/workflows/luacheck.yml @@ -1,34 +1,66 @@ -name: Code Style +name: Code Style and Unit Tests on: [pull_request, workflow_dispatch] jobs: - test-lua: + lua-code-style: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - name: Checkout + uses: actions/checkout@master - - uses: leafo/gh-actions-lua@v9 + - name: Setup lua + uses: leafo/gh-actions-lua@v9 with: - luaVersion: "5.1" + luaVersion: '5.1' - - uses: leafo/gh-actions-luarocks@v4 + - name: Setup luarock + uses: leafo/gh-actions-luarocks@v4 - - name: setup + - name: Setup dependencies run: | luarocks install luacheck - - name: test + - name: Run lint run: | luacheck ./ | luacheck ./ --formatter=JUnit > report.xml - - name: junit + - name: Report lint uses: mikepenz/action-junit-report@v3 if: always() with: report_paths: 'report.xml' - check_name: 'junit-report' - annotate_notice: false + check_name: 'Lint Report' + lua-unit-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@master + + - name: Setup lua + uses: leafo/gh-actions-lua@v9 + with: + luaVersion: '5.1' + + - name: Setup luarocks + uses: leafo/gh-actions-luarocks@v4 + + - name: Setup dependencies + run: | + luarocks install busted + + - name: Run test + uses: lunarmodules/busted@v2.2.0 + with: + args: --run=ci --output=junit > busted.xml + + - name: Report test + uses: mikepenz/action-junit-report@v3 + if: always() + with: + report_paths: 'busted.xml' + check_name: 'Test Report' diff --git a/.luarc.json b/.luarc.json index 71693a4f4b0..80bb1138924 100644 --- a/.luarc.json +++ b/.luarc.json @@ -9,5 +9,9 @@ "diagnostics.neededFileStatus": { "codestyle-check": "None", "name-style-check": "None" - } + }, + "workspace.library": [ + "${3rd}/busted/library", + "${3rd}/luassert/library" + ] } diff --git a/definitions/mw.lua b/definitions/mw.lua index de11c59840e..04a39696752 100644 --- a/definitions/mw.lua +++ b/definitions/mw.lua @@ -1,5 +1,6 @@ --- luacheck: ignore ---@meta mw +-- luacheck: ignore +---This file contains definitions and simulations of the MediaWiki enviroment mw = {} ---Adds a warning which is displayed above the preview when previewing an edit. `text` is parsed as wikitext. @@ -34,7 +35,10 @@ function mw.isSubsting() end ---See www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#mw.loadData ---@param module string ---@return table -function mw.loadData(module) end +function mw.loadData(module) + --TODO: add __index that errors + return require(module) +end ---This is the same as mw.loadData(), except it loads data from JSON pages rather than Lua tables. The JSON content must be an array or object. See also mw.text.jsonDecode(). ---@param page string @@ -215,7 +219,9 @@ function mw.language.fetchLanguageNames(inLanguage, include) end ---Returns a new language object for the wiki's default content language. ---@return Language -function mw.language.getContentLanguage() end +function mw.language.getContentLanguage() + return setmetatable(mw.language, {}) +end mw.getContentLanguage = mw.language.getContentLanguage ---Returns a list of MediaWiki's fallback language codes for the specified code. @@ -246,7 +252,9 @@ function mw.language.isValidCode(code) end ---Creates a new language object. Language objects do not have any publicly accessible properties, but they do have several methods, which are documented below. ---@param code string ---@return Language -function mw.language.new(code) end +function mw.language.new(code) + return mw.language.getContentLanguage() +end mw.getLanguage = mw.language.new ---Returns the language code for this language object. @@ -289,8 +297,18 @@ function mw.language:caseFold(str) end ---Formats a number with grouping and decimal separators appropriate for the given language. Given 123456.78, this may produce "123,456.78", "123.456,78", or even something like "١٢٣٬٤٥٦٫٧٨" depending on the language and wiki configuration. ---@param num number ---@param options? {noCommafy: boolean} ----@return number -function mw.language:formatNum(num, options) end +---@return string +function mw.language:formatNum(num, options) + local k + local formatted = tostring(num) + while true do + formatted, k = string.gsub(formatted, '^(-?%d+)(%d%d%d)', '%1,%2') + if (k == 0) then + break + end + end + return formatted +end ---Formats a date according to the given format string. If timestamp is omitted, the default is the current time. The value for local must be a boolean or nil; if true, the time is formatted in the wiki's local time rather than in UTC. ---@param format string @@ -483,7 +501,14 @@ function mw.text.nowiki(s) end ---@param pattern string? ---@param plain boolean? ---@return string[] -function mw.text.split(s, pattern, plain) end +function mw.text.split(s, pattern, plain) + pattern = pattern or "%s" + local t = {} + for str in string.gmatch(s, "([^"..pattern.."]+)") do + table.insert(t, str) + end + return t +end ---Returns an iterator function that will iterate over the substrings that would be returned by the equivalent call to mw.text.split(). ---@param s string @@ -652,6 +677,148 @@ function mw.title:canonicalUrl(query) end ---@return string? function mw.title:getContent() end +---@class ustring +---@field maxPatternLength number The maximum allowed length of a pattern, in bytes. +---@field maxStringLength number The maximum allowed length of a string, in bytes. +mw.ustring = {} + +---Returns individual bytes; identical to string.byte(). +---@see string.byte +---@param s string|number +---@param i? integer +---@param j? integer +---@return integer ... +function mw.ustring.byte(s, i, j) end + +---Returns the byte offset of a character in the string. The default for both l and i is 1. i may be negative, in which case it counts from the end of the string. +---@param s string|number +---@param l? integer +---@param i? integer +---@return integer ... +function mw.ustring.byteoffset(s, l, i) end + +---Much like string.char(), except that the integers are Unicode codepoints rather than byte values. +---@see string.char +---@param ... integer +---@return string +function mw.ustring.char(...) end + +---Much like string.byte(), except that the return values are codepoints and the offsets are characters rather than bytes. +---@see string.byte +---@param s string|number +---@param i? integer +---@param j? integer +---@return integer ... +function mw.ustring.codepoint(s, i, j) end + +---Much like string.find(), except that the pattern is extended as described in Ustring patterns and the init offset is in characters rather than bytes. +---@see string.find +---@param s string|number +---@param pattern string|number +---@param init? integer +---@param plain? boolean +---@return integer|nil start +---@return integer|nil end +---@return any|nil ... captured +function mw.ustring.find(s, pattern, init, plain) end + +---Identical to string.format(). Widths and precisions for strings are expressed in bytes, not codepoints. +---@see string.format +---@param format string|number +---@param ... any +---@return string +function mw.ustring.format(format, ...) end + +---Returns three values for iterating over the codepoints in the string. i defaults to 1, and j to -1. This is intended for use in the iterator form of for: +---@param s string|number +---@param i? integer +---@param j? integer +---@return string +function mw.ustring.gcodepoint(s, i, j) end + +---Much like string.gmatch(), except that the pattern is extended as described in Ustring patterns. +---@see string.gmatch +---@param s string|number +---@param pattern string|number +---@return fun():string, ... +function mw.ustring.gmatch(s, pattern) end + +---Much like string.gmatch(), except that the pattern is extended as described in Ustring patterns. +---@see string.gsub +---@param s string|number +---@param pattern string|number +---@param repl string|number|table|function +---@param n? integer +---@return string +---@return integer count +function mw.ustring.gsub(s, pattern, repl, n) end + +---Returns true if the string is valid UTF-8, false if not. +---@param s string|number +---@return boolean +function mw.ustring.isutf8(s) end + +---Returns the length of the string in codepoints, or nil if the string is not valid UTF-8. +---@see string.len +---@param s string|number +---@return integer +function mw.ustring.len(s) end + +---Much like string.lower(), except that all characters with lowercase to uppercase definitions in Unicode are converted. +---@see string.lower +---@param s string|number +---@return string +function mw.ustring.lower(s) return string.lower(s) end + +---Much like string.match(), except that the pattern is extended as described in Ustring patterns and the init offset is in characters rather than bytes. +---@see string.match +---@param s string|number +---@param pattern string|number +---@param init? integer +---@return any ... +function mw.ustring.match(s, pattern, init) end + +---Identical to string.rep(). +---@see string.rep +---@param s string|number +---@param n integer +---@return string +function mw.ustring.rep(s, n) end + +---Identical to string.sub(). +---@see string.sub +---@param s string|number +---@param i integer +---@param j? integer +---@return string +function mw.ustring.sub(s, i, j) end + +---Converts the string to Normalization Form C (also known as Normalization Form Canonical Composition). Returns nil if the string is not valid UTF-8. +---@param s string|number +---@return string? +function mw.ustring.toNFC(s) return tostring(s) end + +---Converts the string to Normalization Form D (also known as Normalization Form Canonical Decomposition). Returns nil if the string is not valid UTF-8. +---@param s string|number +---@return string? +function mw.ustring.toNFD(s) return tostring(s) end + +---Converts the string to Normalization Form KC (also known as Normalization Form Compatibility Composition). Returns nil if the string is not valid UTF-8. +---@param s string|number +---@return string? +function mw.ustring.toNFKC(s) return tostring(s) end + +---Converts the string to Normalization Form KD (also known as Normalization Form Compatibility Decomposition). Returns nil if the string is not valid UTF-8. +---@param s string|number +---@return string? +function mw.ustring.toNFKD(s) return tostring(s) end + +---Much like string.upper(), except that all characters with uppercase to lowercase definitions in Unicode are converted. +---@see string.upper +---@param s string|number +---@return string +function mw.ustring.upper(s) return string.upper(s) end + mw.ext = {} mw.ext.LiquipediaDB = {} @@ -665,4 +832,63 @@ function mw.ext.LiquipediaDB.lpdb_create_json(obj) end ---Encode an Array to a JSON array. Errors are raised if the passed value cannot be encoded in JSON. function mw.ext.LiquipediaDB.lpdb_create_array(obj) end +mw.ext.VariablesLua = {} +---@alias wikiVaribleKey string|number +---@alias wikiVariableValue string|number|nil + +---Fake storage for enviroment simulation +---@private +mw.ext.VariablesLua.variablesStorage = {} + +---Stores a wiki-variable and returns the empty string +---@param name wikiVaribleKey +---@param value wikiVariableValue +---@return string #always an empty string +function mw.ext.VariablesLua.vardefine(name, value) + mw.ext.VariablesLua.variablesStorage[name] = value + return '' +end + +---Stores a wiki-variable and returns the stored value +---@param name wikiVaribleKey Key of the wiki-variable +---@param value wikiVariableValue Value of the wiki-variable +---@return string +function mw.ext.VariablesLua.vardefineecho(name, value) + mw.ext.VariablesLua.vardefine(name, value) + return mw.ext.VariablesLua.var(name) +end + +---Gets the stored value of a wiki-variable +---@param name wikiVaribleKey Key of the wiki-variable +---@return string +function mw.ext.VariablesLua.var(name) + return mw.ext.VariablesLua.variablesStorage[name] and tostring(mw.ext.VariablesLua.variablesStorage[name]) or '' +end + +---Checks if a wiki-variable is stored +---@param name wikiVaribleKey Key of the wiki-variable +---@return boolean +function mw.ext.VariablesLua.varexist(name) + return mw.ext.VariablesLua.variablesStorage[name] ~= nil +end + +mw.ext.CurrencyExchange = {} + +---@param amount number +---@param fromCurrency string +---@param toCurrency string +---@param date? string +---@return number +function mw.ext.CurrencyExchange.currencyexchange(amount, fromCurrency, toCurrency, date) + -- Fake mock number + return 0.97097276906869 +end + +mw.ext.TeamLiquidIntegration = {} + +---Adds a category to a page +---@param name string +---@param sortName string? +function mw.ext.TeamLiquidIntegration.add_category(name, sortName) end + return mw diff --git a/plugins/sumneko_plugin.lua b/plugins/sumneko_plugin.lua index 00c6de4fada..25e6ac9449e 100644 --- a/plugins/sumneko_plugin.lua +++ b/plugins/sumneko_plugin.lua @@ -7,23 +7,31 @@ local liquipedia = {} local importFunctions = {} importFunctions.functions = {'require', 'mw%.loadData', 'Lua%.import', 'Lua%.requireIfExists'} -importFunctions.prefixModules = {table = 'standard.', math = 'standard.', string = 'standard.'} +importFunctions.prefixModules = {table = 'standard.', math = 'standard.', string = 'standard.', array = 'standard.'} -function importFunctions._row(name) - local normModuleName = - name - :gsub('Module:', '') -- Remove starting Module: - :gsub('^%u', string.lower) -- Lower case first letter - :gsub('%u', '_%0') -- Prefix uppercase letters with an underscore - :gsub('/', '_') -- Change slash to underscore - :gsub('__', '_') -- Never have two underscores in a row - :lower() -- Lowercase everything +---Transforms a MediaWiki module name, e.g. `Module:Array`, into a lua repository name, e.g. `array` +---@param name string +---@return string +function importFunctions.luaifyModuleName(name) + local normModuleName = name + :gsub('Module:', '')-- Remove starting Module: + :gsub('^%u', string.lower)-- Lower case first letter + :gsub('%u', '_%0')-- Prefix uppercase letters with an underscore + :gsub('/', '_')-- Change slash to underscore + :gsub('__', '_')-- Never have two underscores in a row + :lower() -- Lowercase everything if importFunctions.prefixModules[normModuleName] then normModuleName = importFunctions.prefixModules[normModuleName] .. normModuleName end - return ' ---@module \'' .. normModuleName ..'\'' + return normModuleName +end + +function importFunctions._row(name) + local normModuleName = importFunctions.luaifyModuleName(name) + + return ' ---@module \'' .. normModuleName .. '\'' end function importFunctions.annotate(text, funcName, diffs) @@ -57,9 +65,15 @@ function OnSetText(uri, text) return nil end + if text:sub(1, 8) == '---@meta' then + return nil + end + local diffs = {} liquipedia.annotate(text, diffs) return diffs end + +return importFunctions diff --git a/spec/abbreviation_spec.lua b/spec/abbreviation_spec.lua new file mode 100644 index 00000000000..f9ab5dd24f4 --- /dev/null +++ b/spec/abbreviation_spec.lua @@ -0,0 +1,18 @@ +--- Triple Comment to Enable our LLS Plugin +describe('abbreviation', function() + local Abbreviation = require('Module:Abbreviation') + + describe('make abbreviation', function() + it('Empty input returns nil', function() + assert.is_nil(Abbreviation.make()) + assert.is_nil(Abbreviation.make('')) + end) + it('Only one input returns nil', function() + assert.is_nil(Abbreviation.make('Abc', nil)) + assert.is_nil(Abbreviation.make('', 'Def')) + end) + it('Abbreviation works', function() + assert.are_same('Cake', Abbreviation.make('Cake', 'Cookie')) + end) + end) +end) diff --git a/spec/array_spec.lua b/spec/array_spec.lua new file mode 100644 index 00000000000..4f5619f07b2 --- /dev/null +++ b/spec/array_spec.lua @@ -0,0 +1,208 @@ +--- Triple Comment to Enable our LLS Plugin +describe('array', function() + local Array = require('Module:Array') + local Table = require('Module:Table') + + describe('isArray', function() + it('Empty table is array', function() + assert.is_true(Array.isArray{}) + end) + it('Arrays are array', function() + assert.is_true(Array.isArray{5, 2, 3}) + end) + it('Tables are array', function() + assert.is_false(Array.isArray{a = 1, [3] = 2, c = 3}) + assert.is_false(Array.isArray{5, 2, c = 3}) + end) + end) + + describe('Copy', function() + it('check', function() + local a, b, c = {1, 2, 3}, {}, {{5}} + assert.are_same(a, Array.copy(a)) + assert.is_false(Array.copy(b) == b) + assert.is_true(Array.copy(c)[1] == c[1]) + end) + end) + + describe('Sub', function() + it('check', function() + local a = {3, 5, 7, 11} + assert.are_same({5, 7, 11}, Array.sub(a, 2)) + assert.are_same({5, 7}, Array.sub(a, 2, 3)) + assert.are_same({7, 11}, Array.sub(a, -2, -1)) + end) + end) + + describe('Map', function() + it('check', function() + local a = {1, 2, 3} + assert.are_same({2, 4, 6}, Array.map(a, function(x) + return 2 * x + end)) + end) + end) + + describe('Filter', function() + it('check', function() + local a = {1, 2, 3} + assert.are_same({1, 3}, Array.filter(a, function(x) + return x % 2 == 1 + end + )) + end) + end) + + describe('Flatten', function() + it('check', function() + local a = {1, 2, 3, {5, 3}, {6, 4}} + assert.are_same({1, 2, 3, 5, 3, 6, 4}, Array.flatten(a)) + end) + end) + + describe('All', function() + it('check', function() + local a = {1, 2, 3} + assert.is_true(Array.all(a, function(value) + return type(value) == 'number' + end)) + assert.is_false(Array.all(a, function(value) + return value < 3 + end)) + end) + end) + + describe('Any', function() + it('check', function() + local a = {1, 2, 3} + assert.is_false(Array.any(a, function(value) + return type(value) == 'string' + end)) + assert.is_true(Array.any(a, function(value) + return value < 3 + end)) + end) + end) + + describe('Find', function() + it('check', function() + local a = {4, 6, 9} + local b = Array.find(a, function(value, index) + return index == 2 + end) + local c = Array.find(a, function(value, index) + return index == -1 + end) + assert.are_equal(6, b) + assert.are_equal(nil, c) + end) + end) + + describe('Revese', function() + it('check', function() + local a = {4, 6, 9} + assert.are_same({9, 6, 4}, Array.reverse(a)) + end) + end) + + describe('Append', function() + it('check', function() + local a = {2, 3} + assert.are_same({2, 3, 5, 7, 11}, Array.append(a, 5, 7, 11)) + assert.are_same({2, 3}, a) + end) + end) + + describe('AppendWith', function() + it('check', function() + local a = {2, 3} + assert.are_same({2, 3, 5, 7, 11}, Array.appendWith(a, 5, 7, 11)) + assert.are_same({2, 3, 5, 7, 11}, a) + end) + end) + + describe('Extend', function() + it('check', function() + local a, b, c = {2, 3}, {5, 7, 11}, {13} + assert.are_same({2, 3, 5, 7, 11, 13}, Array.extend(a, b, c)) + assert.are_same({2, 3}, a) + end) + end) + + describe('ExtendWith', function() + it('check', function() + local a, b, c = {2, 3}, {5, 7, 11}, {13} + assert.are_same({2, 3, 5, 7, 11, 13}, Array.extendWith(a, b, c)) + assert.are_same({2, 3, 5, 7, 11, 13}, a) + end) + end) + + describe('MapIndexes', function() + it('check', function() + local a = {p1 = 'Abc', p2 = 'cd', p3 = 'cake'} + assert.are_same({'p1Abc', 'p2cd'}, Array.mapIndexes(function(x) + local prefix = 'p' .. x + return a[prefix] ~= 'cake' and (prefix .. a[prefix]) or nil + end)) + end) + end) + + describe('Range', function() + it('check', function() + assert.are_same({1, 2, 3}, Array.range(1, 3)) + assert.are_same({2, 3}, Array.range(2, 3)) + end) + end) + + describe('ForEach', function() + it('check', function() + local a = {} + Array.forEach(Array.range(1, 3), function(x) + table.insert(a, 1, x) + end) + assert.are_same({3, 2, 1}, a) + end) + end) + + describe('Reduce', function() + it('check', function() + local function pow(x, y) return x ^ y end + assert.are_same(32768, Array.reduce({2, 3, 5}, pow)) + assert.are_same(1, Array.reduce({2, 3, 5}, pow, 1)) + end) + end) + + describe('ExtractValues', function() + it('check', function() + local a = {i = 1, j = 2, k = 3, z = 0} + + local customOrder1 = function(_, key1, key2) return key1 > key2 end + local customOrder2 = function(tbl, key1, key2) return tbl[key1] < tbl[key2] end + + assert.are_same({1, 2, 3, 0}, Array.extractValues(a, Table.iter.spairs)) + assert.are_same({0, 3, 2, 1}, Array.extractValues(a, Table.iter.spairs, customOrder1)) + assert.are_same({0, 1, 2, 3}, Array.extractValues(a, Table.iter.spairs, customOrder2)) + + local extractedArray = Array.extractValues(a) + table.sort(extractedArray) + assert.are_same({0, 1, 2, 3}, extractedArray) + end) + end) + + describe('ExtractKeys', function() + it('check', function() + local a = {k = 3, i = 1, z = 0, j = 2} + + local customOrder1 = function(_, key1, key2) return key1 > key2 end + local customOrder2 = function(tbl, key1, key2) return tbl[key1] < tbl[key2] end + + assert.are_same({'i', 'j', 'k', 'z'}, Array.extractKeys(a, Table.iter.spairs)) + assert.are_same({'z', 'k', 'j', 'i'}, Array.extractKeys(a, Table.iter.spairs, customOrder1)) + assert.are_same({'z', 'i', 'j', 'k'}, Array.extractKeys(a, Table.iter.spairs, customOrder2)) + + local extractedKeys = Array.extractKeys(a) + table.sort(extractedKeys) + assert.are_same({'i', 'j', 'k', 'z'}, extractedKeys) + end) + end) +end) diff --git a/spec/currency_spec.lua b/spec/currency_spec.lua new file mode 100644 index 00000000000..5a68718ab96 --- /dev/null +++ b/spec/currency_spec.lua @@ -0,0 +1,71 @@ +--- Triple Comment to Enable our LLS Plugin +describe('currency', function() + local Currency = require('Module:Currency') + local Variables = require('Module:Variables') + + local DASH = '-' + + describe('get exchange rate', function() + it('do it', function() + assert.are_equal(1.45, + Currency.getExchangeRate({currency = 'EUR', currencyRate = '1.45', setVariables = true})) + assert.are_equal(1.45, tonumber(Variables.varDefault('exchangerate_EUR'))) + assert.are_equal(0.97097276906869, Currency.getExchangeRate{date = '2022-10-10', currency = 'EUR'}) + end) + end) + + describe('formatting money', function() + it('do it', function() + assert.are_equal(DASH, Currency.formatMoney('abc')) + assert.are_equal(DASH, Currency.formatMoney(nil)) + assert.are_equal(DASH, Currency.formatMoney('0')) + assert.are_equal(DASH, Currency.formatMoney(0)) + assert.are_equal(0, Currency.formatMoney('abc', nil, nil, false)) + assert.are_equal(0, Currency.formatMoney(nil, nil, nil, false)) + assert.are_equal('12', Currency.formatMoney(12)) + assert.are_equal('1,200', Currency.formatMoney(1200)) + assert.are_equal('1,200.00', Currency.formatMoney(1200, nil, true)) + assert.are_equal('1,200.12', Currency.formatMoney(1200.12345)) + assert.are_equal('1,200.1', Currency.formatMoney(1200.12345, 1)) + assert.are_equal('1,200.1235', Currency.formatMoney(1200.12345, 4)) + end) + end) + + describe('raw', function() + it('validate incorrect input returns nil', function() + assert.is_nil(Currency.raw()) + assert.is_nil(Currency.raw('')) + assert.is_nil(Currency.raw('dummy')) + end) + it('correct data works', function() + assert.are_same({ + code = 'EUR', + name = 'Euro', + symbol = { + hasSpace = false, + isAfter = false, + text = '€', + }, + }, + Currency.raw('EUR') + ) + end) + end) + + describe('display', function() + it('validate incorrect input returns nil', function() + assert.is_nil(Currency.display()) + assert.is_nil(Currency.display('')) + assert.is_nil(Currency.display('dummy')) + end) + it('validate options', function() + assert.are_equal(DASH, Currency.display('dummy', 0, {dashIfZero = true})) + assert.are_equal(DASH, Currency.display('EUR', 0, {dashIfZero = true})) + assert.are_equal('€1,200 EUR', + Currency.display('EUR', 1200, {formatValue = true})) + assert.are_equal('€1200 EUR', Currency.display('EUR', 1200)) + assert.are_equal('€ EUR', Currency.display('EUR')) + assert.are_equal('€ EUR', Currency.display('EUR', nil, {useHtmlStyling = false})) + end) + end) +end) diff --git a/spec/date_ext_spec.lua b/spec/date_ext_spec.lua new file mode 100644 index 00000000000..bcf628de18e --- /dev/null +++ b/spec/date_ext_spec.lua @@ -0,0 +1,67 @@ +--- Triple Comment to Enable our LLS Plugin +describe('Variables', function() + local Variables = require('Module:Variables') + + local DateExt = require('Module:Date/Ext') + + local LanguageMock + + before_each(function() + -- Because of the complex nature of `formatDate`, a lot of the tests are just "check it has been called" + LanguageMock = mock(mw.language, true) + end) + + describe('read timestamp', function() + it('verify', function() + DateExt.readTimestamp('2021-10-17 17:40 EDT') + assert.stub(LanguageMock.formatDate).was.called_with(LanguageMock, 'U', '20211017 17:40 -4:00') + + DateExt.readTimestamp('2021-10-17 21:40') + assert.stub(LanguageMock.formatDate).was.called_with(LanguageMock, 'U', '20211017 21:40') + end) + end) + + describe('format', function() + it('verify', function() + DateExt.formatTimestamp('c', 1634506800) + assert.stub(LanguageMock.formatDate).was.called_with(LanguageMock, 'c', '@' .. 1634506800) + end) + end) + + describe('toYmdInUtc', function() + it('verify', function() + DateExt.toYmdInUtc('November 08, 2021 - 13:00 CET') + assert.stub(LanguageMock.formatDate).was.called_with(LanguageMock, 'Y-m-d', '@') + end) + end) + + describe('getContextualDateOrNow', function() + it('verify', function() + assert.are_equal(os.date('%F'), DateExt.getContextualDateOrNow()) + assert.are_equal(nil, DateExt.getContextualDate()) + + Variables.varDefine('tournament_startdate', '2021-12-24') + assert.are_equal('2021-12-24', DateExt.getContextualDateOrNow()) + assert.are_equal('2021-12-24', DateExt.getContextualDate()) + + Variables.varDefine('tournament_enddate', '2021-12-28') + assert.are_equal('2021-12-28', DateExt.getContextualDateOrNow()) + assert.are_equal('2021-12-28', DateExt.getContextualDate()) + + Variables.varDefine('tournament_startdate') + Variables.varDefine('tournament_enddate') + end) + end) + + describe('parse iso date', function() + it('verify', function() + assert.are_same({year = 2023, month = 7, day = 24}, DateExt.parseIsoDate('2023-07-24')) + assert.are_same({year = 2023, month = 7, day = 24}, + DateExt.parseIsoDate('2023-07-24asdkosdkmoasjoikmakmslkm')) + assert.are_same({year = 2023, month = 7, day = 1}, DateExt.parseIsoDate('2023-07')) + assert.are_same({year = 2023, month = 7, day = 1}, DateExt.parseIsoDate('2023-07sdfsdfdfs')) + assert.are_same({year = 2023, month = 1, day = 1}, DateExt.parseIsoDate('2023')) + assert.is_nil(DateExt.parseIsoDate()) + end) + end) +end) diff --git a/spec/flags_spec.lua b/spec/flags_spec.lua new file mode 100644 index 00000000000..03ca1398096 --- /dev/null +++ b/spec/flags_spec.lua @@ -0,0 +1,89 @@ +--- Triple Comment to Enable our LLS Plugin +describe('flags', function() + local Flags = require('Module:Flags') + local Template = require('Module:Template') + + describe('icon', function() + it('check', function() + local nlOutput = '[[File:nl_hd.png|36x24px|Netherlands|link=]]' + local nlOutputLink = '[[File:nl_hd.png|36x24px|Netherlands|link=Category:Netherlands]]' + + assert.are_equal(nlOutput, Flags.Icon('nl')) + assert.are_equal(nlOutput, Flags.Icon('nld')) + assert.are_equal(nlOutput, Flags.Icon('holland')) + assert.are_equal(nlOutput, Flags.Icon({}, 'nl')) + assert.are_equal(nlOutput, Flags.Icon({}, 'nld')) + assert.are_equal(nlOutput, Flags.Icon({}, 'holland')) + assert.are_equal(nlOutputLink, Flags.Icon({shouldLink = true}, 'nl')) + assert.are_equal(nlOutputLink, Flags.Icon({shouldLink = true}, 'nld')) + assert.are_equal(nlOutputLink, Flags.Icon({shouldLink = true}, 'holland')) + assert.are_equal(nlOutput, Flags.Icon({shouldLink = false}, 'nl')) + assert.are_equal(nlOutput, Flags.Icon({shouldLink = false}, 'nld')) + assert.are_equal(nlOutput, Flags.Icon({shouldLink = false}, 'holland')) + assert.are_equal(nlOutputLink, Flags.Icon{shouldLink = true, flag = 'nl'}) + assert.are_equal(nlOutputLink, Flags.Icon{shouldLink = true, flag = 'nld'}) + assert.are_equal(nlOutputLink, Flags.Icon{shouldLink = true, flag = 'holland'}) + assert.are_equal(nlOutput, Flags.Icon{shouldLink = false, flag = 'nl'}) + assert.are_equal(nlOutput, Flags.Icon{shouldLink = false, flag = 'nld'}) + assert.are_equal(nlOutput, Flags.Icon{shouldLink = false, flag = 'holland'}) + + assert.are_equal('[[File:Space filler flag.png|36x24px|link=]]', + Flags.Icon{flag = 'tbd'}) + + local TemplateMock = stub(Template, "safeExpand") + + Flags.Icon{shouldLink = true, flag = 'dummy'} + assert.stub(TemplateMock).was.called_with(nil, 'Flag/dummy') + + Flags.Icon{shouldLink = false, flag = 'dummy'} + assert.stub(TemplateMock).was.called_with(nil, 'FlagNoLink/dummy') + end) + end) + + describe('localisation', function() + it('check', function() + local nlOutput = 'Dutch' + assert.are_equal(nlOutput, Flags.getLocalisation('nl')) + assert.are_equal(nlOutput, Flags.getLocalisation('Netherlands')) + assert.are_equal(nlOutput, Flags.getLocalisation('netherlands')) + assert.are_equal(nlOutput, Flags.getLocalisation('holland')) + end) + end) + + describe('language icon', function() + it('check', function() + assert.are_equal('[[File:UsGb hd.png|36x24px|English Speaking|link=]]', + Flags.languageIcon('en')) + assert.are_equal('[[File:nl_hd.png|36x24px|Netherlands|link=]]', + Flags.languageIcon('nl')) + end) + end) + + describe('country name', function() + it('check', function() + local nlOutput = 'Netherlands' + assert.are_equal(nlOutput, Flags.CountryName('nl')) + assert.are_equal(nlOutput, Flags.CountryName('Netherlands')) + assert.are_equal(nlOutput, Flags.CountryName('netherlands')) + assert.are_equal(nlOutput, Flags.CountryName('holland')) + end) + end) + + describe('country code', function() + it('check', function() + local nlOutput = 'nl' + assert.are_equal(nlOutput, Flags.CountryCode('nl')) + assert.are_equal(nlOutput, Flags.CountryCode('Netherlands')) + assert.are_equal(nlOutput, Flags.CountryCode('netherlands')) + assert.are_equal(nlOutput, Flags.CountryCode('holland')) + end) + end) + + describe('is valid flag', function() + it('check', function() + assert.is_true(Flags.isValidFlagInput('de')) + assert.is_true(Flags.isValidFlagInput('germany')) + assert.is_false(Flags.isValidFlagInput('aaaaaaa')) + end) + end) +end) diff --git a/spec/locale_spec.lua b/spec/locale_spec.lua new file mode 100644 index 00000000000..f9cd0d974db --- /dev/null +++ b/spec/locale_spec.lua @@ -0,0 +1,30 @@ +--- Triple Comment to Enable our LLS Plugin +describe('Variables', function() + local Locale = require('Module:Locale') + + local NON_BREAKING_SPACE = ' ' + + describe('format location', function() + it('verify', function() + assert.are_equal('', Locale.formatLocation{}) + assert.are_equal('abc,' .. NON_BREAKING_SPACE, Locale.formatLocation{city = 'abc'}) + assert.are_equal('Sweden', Locale.formatLocation{country = 'Sweden'}) + assert.are_equal('abc,' .. NON_BREAKING_SPACE .. 'Sweden', + Locale.formatLocation{city = 'abc', country = 'Sweden'}) + end) + end) + + describe('format locations', function() + it('verify', function() + local test1 = {venue = 'Abc', country1 = 'Sweden', country2 = 'Europe'} + local result1 = {country1 = 'se', region2 = 'Europe', venue1 = 'Abc'} + + local test2 = {venue = 'Abc', country1 = 'Sweden', region1 = 'Europe', venuelink = 'https://lmgtfy.app/'} + local result2 = {country1 = 'se', region1 = 'Europe', venue1 = 'Abc', venuelink1 = 'https://lmgtfy.app/'} + + assert.are_same(result1, Locale.formatLocations(test1)) + assert.are_same(result2, Locale.formatLocations(test2)) + assert.are_same({}, Locale.formatLocations{dummy = true}) + end) + end) +end) diff --git a/spec/logic_spec.lua b/spec/logic_spec.lua new file mode 100644 index 00000000000..97153cfb72d --- /dev/null +++ b/spec/logic_spec.lua @@ -0,0 +1,191 @@ +--- Triple Comment to Enable our LLS Plugin +describe('logic', function() + local Logic = require('Module:Logic') + local Table = require('Module:Table') + + describe('EmptyOr', function() + it('check', function() + assert.are_equal(1, Logic.emptyOr(1, 2, 3)) + assert.are_equal(1, Logic.emptyOr(1, 2)) + assert.are_equal(1, Logic.emptyOr(1, nil, 3)) + assert.are_equal(1, Logic.emptyOr(1, '', 3)) + assert.are_equal(1, Logic.emptyOr(1)) + assert.are_equal(2, Logic.emptyOr(nil, 2, 3)) + assert.are_equal(2, Logic.emptyOr('', 2, 3)) + assert.are_equal(2, Logic.emptyOr(nil, 2)) + assert.are_equal(2, Logic.emptyOr('', 2)) + assert.are_equal(3, Logic.emptyOr(nil, nil, 3)) + assert.are_equal(3, Logic.emptyOr({}, '', 3)) + assert.is_nil(Logic.emptyOr()) + end) + end) + + describe('NilOr', function() + it('check', function() + assert.are_equal(1, Logic.nilOr(1, 2, 3)) + assert.are_equal(1, Logic.nilOr(1, 2)) + assert.are_equal(1, Logic.nilOr(1, nil, 3)) + assert.are_equal(1, Logic.nilOr(1, '', 3)) + assert.are_equal(1, Logic.nilOr(1)) + assert.are_equal(2, Logic.nilOr(nil, 2, 3)) + assert.are_equal('', Logic.nilOr('', 2, 3)) + assert.are_equal(2, Logic.nilOr(nil, 2)) + assert.are_equal('', Logic.nilOr('', 2)) + assert.are_equal(3, Logic.nilOr(nil, nil, 3)) + assert.are_same({}, Logic.nilOr({}, '', 3)) + assert.is_nil(Logic.nilOr()) + assert.are_equal(5, Logic.nilOr(nil, nil, nil, nil, 5)) + end) + end) + + describe('IsEmpty', function() + it('check', function() + assert.is_true(Logic.isEmpty({})) + assert.is_true(Logic.isEmpty()) + assert.is_true(Logic.isEmpty('')) + assert.is_false(Logic.isEmpty({''})) + assert.is_false(Logic.isEmpty({'string'})) + assert.is_false(Logic.isEmpty({{}})) + assert.is_false(Logic.isEmpty(1)) + assert.is_false(Logic.isEmpty('string')) + end) + end) + + describe('IsDeepEmpty', function() + it('check', function() + assert.is_true(Logic.isDeepEmpty({})) + assert.is_true(Logic.isDeepEmpty()) + assert.is_true(Logic.isDeepEmpty('')) + assert.is_true(Logic.isDeepEmpty({''})) + assert.is_false(Logic.isDeepEmpty({'string'})) + assert.is_true(Logic.isDeepEmpty({{}})) + assert.is_false(Logic.isDeepEmpty(1)) + assert.is_false(Logic.isDeepEmpty('string')) + end) + end) + + describe('ReadBool', function() + it('check', function() + assert.is_true(Logic.readBool(1)) + assert.is_true(Logic.readBool('true')) + assert.is_true(Logic.readBool(true)) + assert.is_true(Logic.readBool('t')) + assert.is_true(Logic.readBool('y')) + assert.is_true(Logic.readBool('yes')) + assert.is_true(Logic.readBool('1')) + assert.is_false(Logic.readBool(0)) + assert.is_false(Logic.readBool(false)) + assert.is_false(Logic.readBool('false')) + assert.is_false(Logic.readBool('f')) + assert.is_false(Logic.readBool('0')) + assert.is_false(Logic.readBool('no')) + assert.is_false(Logic.readBool('n')) + assert.is_false(Logic.readBool('someBs')) + assert.is_false(Logic.readBool()) + ---intended bad value + ---@diagnostic disable-next-line: param-type-mismatch + assert.is_false(Logic.readBool{}) + end) + end) + + describe('ReadBoolOrNil', function() + it('check', function() + assert.is_true(Logic.readBoolOrNil(1)) + assert.is_true(Logic.readBoolOrNil('true')) + assert.is_true(Logic.readBoolOrNil(true)) + assert.is_true(Logic.readBoolOrNil('t')) + assert.is_true(Logic.readBoolOrNil('y')) + assert.is_true(Logic.readBoolOrNil('yes')) + assert.is_true(Logic.readBoolOrNil('1')) + assert.is_false(Logic.readBoolOrNil(0)) + assert.is_false(Logic.readBoolOrNil(false)) + assert.is_false(Logic.readBoolOrNil('false')) + assert.is_false(Logic.readBoolOrNil('f')) + assert.is_false(Logic.readBoolOrNil('0')) + assert.is_false(Logic.readBoolOrNil('no')) + assert.is_false(Logic.readBoolOrNil('n')) + assert.is_nil(Logic.readBoolOrNil('someBs')) + assert.is_nil(Logic.readBoolOrNil()) + ---intended bad value + ---@diagnostic disable-next-line: param-type-mismatch + assert.is_nil(Logic.readBoolOrNil{}) + end) + end) + + describe('NilThrows', function() + it('check', function() + assert.are_equal('someVal', Logic.nilThrows('someVal')) + assert.are_equal('', Logic.nilThrows('')) + assert.are_equal(1, Logic.nilThrows(1)) + assert.are_same({'someVal'}, Logic.nilThrows({'someVal'})) + assert.are_same({}, Logic.nilThrows({})) + assert.error(function() return Logic.nilThrows() end) + end) + end) + + describe('TryCatch', function() + it('check', function() + local errorCaught = false + local catch = function(errorMessage) errorCaught = true end + + assert.is_nil(Logic.tryCatch(function() error() end, catch)) + assert.is_true(errorCaught) + errorCaught = false + + assert.is_nil(Logic.tryCatch(function() error('some error') end, catch)) + assert.is_true(errorCaught) + errorCaught = false + + assert.is_nil(Logic.tryCatch(function() assert(false, 'some failed assert') end, catch)) + assert.is_true(errorCaught) + errorCaught = false + + assert.are_equal('someVal', Logic.tryCatch(function() return 'someVal' end, catch)) + assert.is_false(errorCaught) + end) + end) + + describe('IsNumeric', function() + it('check', function() + assert.is_true(Logic.isNumeric(1.5)) + assert.is_true(Logic.isNumeric('1.5')) + assert.is_true(Logic.isNumeric('4.57e-3')) + assert.is_true(Logic.isNumeric(4.57e-3)) + assert.is_true(Logic.isNumeric(0.3e12)) + assert.is_true(Logic.isNumeric('0.3e12')) + assert.is_true(Logic.isNumeric(5e+20)) + assert.is_true(Logic.isNumeric('5e+20')) + assert.is_false(Logic.isNumeric('1+2')) + assert.is_false(Logic.isNumeric()) + assert.is_false(Logic.isNumeric('string')) + ---intended bad value + ---@diagnostic disable-next-line: param-type-mismatch + assert.is_false(Logic.isNumeric{}) + ---intended bad value + ---@diagnostic disable-next-line: param-type-mismatch + assert.is_false(Logic.isNumeric{just = 'a table'}) + end) + end) + + describe('deepEquals', function() + it('check', function() + assert.is_true(Logic.deepEquals(1, 1)) + assert.is_false(Logic.deepEquals(1, 2)) + assert.is_true(Logic.deepEquals('a', 'a')) + assert.is_false(Logic.deepEquals('a', 'b')) + + local tbl1 = {1, 2, {3, 4, {a = 'b'}}} + local tbl2 = {1, 2, {3, 4, {a = 'c'}}} + local tbl3 = {1, 2, {3, 4, {a = 'b'}, 6}} + assert.is_true(Logic.deepEquals(tbl1, tbl1)) + assert.is_true(Logic.deepEquals(tbl1, Table.deepCopy(tbl1))) + assert.is_false(Logic.deepEquals(tbl1, tbl2)) + assert.is_false(Logic.deepEquals(tbl1, tbl3)) + end) + end) + + --currently not testing: + ---try - just uses `Module:ResultOrError` + ---tryOrElseLog - uses `.try` plus `:catch` and `:get` + ---wrapTryOrLog - basically tryOrElseLog +end) diff --git a/spec/page_spec.lua b/spec/page_spec.lua new file mode 100644 index 00000000000..b049a593437 --- /dev/null +++ b/spec/page_spec.lua @@ -0,0 +1,50 @@ +--- Triple Comment to Enable our LLS Plugin +describe('Page', function() + local Page = require('Module:Page') + + local orig = mw.title.new + before_each(function() + mw.title.new = spy.new(function(page) + if page == 'https://google.com' then + return nil + end + return {exists = page == 'Module:Page'} + end) + end) + after_each(function() + mw.title.new = orig + end) + + describe('exists', function() + it('verify', function() + assert.is_false(Page.exists('https://google.com')) + assert.is_false(Page.exists('PageThatDoesntExistPlx')) + assert.is_true(Page.exists('Module:Page')) + end) + end) + + describe('internal link', function() + it('verify', function() + assert.are_equal('[[Module:Page|Module:Page]]', Page.makeInternalLink('Module:Page')) + assert.are_equal('[[Module:Page|DisplayText]]', Page.makeInternalLink('DisplayText', 'Module:Page')) + assert.are_equal('[[Module:Page|DisplayText]]', Page.makeInternalLink({}, 'DisplayText', 'Module:Page')) + assert.is_nil( + Page.makeInternalLink({onlyIfExists = true}, 'DisplayText', 'Module:PageThatDoesntExistPlx') + ) + assert.are_equal( + '[[Module:Page|DisplayText]]', + Page.makeInternalLink({onlyIfExists = true}, 'DisplayText', 'Module:Page') + ) + assert.is_nil(Page.makeInternalLink({})) + end) + end) + + describe('external link', function() + it('verify', function() + assert.is_nil(Page.makeExternalLink('Display', '')) + assert.is_nil(Page.makeExternalLink('', 'https://google.com')) + assert.are_equal('[https://google.com Display Text]', + Page.makeExternalLink('Display Text', 'https://google.com')) + end) + end) +end) diff --git a/spec/test_helper.lua b/spec/test_helper.lua new file mode 100644 index 00000000000..9a3dd00d2a5 --- /dev/null +++ b/spec/test_helper.lua @@ -0,0 +1,66 @@ +-- luacheck: ignore + +-- Copy from standard/lua.lua +local function fileExists(name) + if package.loaded[name] then + return true + else + -- Package.Searchers was renamed from Loaders in lua5.2, have support for both + ---@diagnostic disable-next-line: deprecated + for _, searcher in ipairs(package.searchers or package.loaders) do + local loader = searcher(name) + if type(loader) == 'function' then + package.preload[name] = loader + return true + end + end + return false + end +end + +local function resetMediawiki() + mw.ext.VariablesLua.variablesStorage = {} +end + +local function setupForTesting() + require('definitions.mw') + + package.path = '?.lua;' .. + 'standard/?.lua;' .. -- Load std folder + package.path + + local require_original = require + local Plugin = require_original('plugins.sumneko_plugin') + + function require(module) + local newName = module + if (string.find(module, 'Module:')) then + newName = Plugin.luaifyModuleName(module) + end + + if fileExists(newName) then + return require_original(newName) + end + + if newName == 'info' then + return require_original('info.commons.info') + end + + if newName == 'region' or newName == 'region_data' then + return require('region.commons.' .. newName) + end + + -- Just apply a fake function that returns the first input, as something + local mocked_import = {} + setmetatable(mocked_import, { + __index = function(t, k) + return function(v) return v end + end + }) + + return mocked_import + end +end + +require('busted').subscribe({'suite', 'start'}, setupForTesting) +require('busted').subscribe({'test', 'start'}, resetMediawiki) diff --git a/spec/variables_spec.lua b/spec/variables_spec.lua new file mode 100644 index 00000000000..1f22407ac65 --- /dev/null +++ b/spec/variables_spec.lua @@ -0,0 +1,37 @@ +--- Triple Comment to Enable our LLS Plugin +describe('Variables', function() + local Variables = require('Module:Variables') + + describe('varDefine', function() + it('verify', function() + assert.are_equal('', Variables.varDefine('test', 'foo')) + assert.are_equal('foo', Variables.varDefault('test')) + + assert.are_equal('bar', Variables.varDefineEcho('test', 'bar')) + assert.are_equal('bar', Variables.varDefault('test')) + + assert.are_equal('', Variables.varDefine('test', 3)) + assert.are_equal('3', Variables.varDefault('test')) + + assert.are_equal('', Variables.varDefine('test')) + assert.is_nil(Variables.varDefault('test')) + end) + end) + + describe('varDefault', function() + it('verify', function() + Variables.varDefine('test', 'foo') + assert.are_equal('foo', Variables.varDefault('test')) + assert.is_nil(Variables.varDefault('bar')) + assert.are_equal('baz', Variables.varDefault('bar', 'baz')) + end) + end) + + describe('VarDefaultMulti', function() + it('verify', function() + Variables.varDefine('baz', 'hello world') + assert.are_equal('hello world', Variables.varDefaultMulti('foo', 'bar', 'baz')) + assert.are_equal('banana', Variables.varDefaultMulti('foo', 'bar', 'banana')) + end) + end) +end) diff --git a/standard/currency/currency.lua b/standard/currency.lua similarity index 98% rename from standard/currency/currency.lua rename to standard/currency.lua index ed8284a8196..213831dc679 100644 --- a/standard/currency/currency.lua +++ b/standard/currency.lua @@ -11,7 +11,7 @@ local Arguments = require('Module:Arguments') local CurrencyData = mw.loadData('Module:Currency/Data') local Info = mw.loadData('Module:Info') local Logic = require('Module:Logic') -local Math = require('Module:Math') +local Math = require('Module:MathUtil') local String = require('Module:StringUtils') local Variables = require('Module:Variables') @@ -143,9 +143,11 @@ function Currency.formatMoney(value, precision, forceRoundPrecision, dashIfZero) if not Logic.isNumeric(value) or (tonumber(value) == 0 and not forceRoundPrecision) then return dashIfZero and DASH or 0 end + ---@cast value number + precision = tonumber(precision) or Info.defaultRoundPrecision or DEFAULT_ROUND_PRECISION - local roundedValue = Math.round{value, precision} + local roundedValue = Math.round(value, precision) local integer, decimal = math.modf(roundedValue) if precision <= 0 or decimal == 0 and not forceRoundPrecision then diff --git a/standard/currency/currency_data.lua b/standard/currency_data.lua similarity index 100% rename from standard/currency/currency_data.lua rename to standard/currency_data.lua diff --git a/standard/date_ext.lua b/standard/date_ext.lua index a78689e3e4d..cad2c5445ad 100644 --- a/standard/date_ext.lua +++ b/standard/date_ext.lua @@ -7,7 +7,6 @@ -- local Logic = require('Module:Logic') -local String = require('Module:StringUtils') local Variables = require('Module:Variables') --[[ @@ -104,11 +103,16 @@ function DateExt.parseIsoDate(str) return end local year, month, day = str:match('^(%d%d%d%d)%-?(%d?%d?)%-?(%d?%d?)') + year, month, day = tonumber(year), tonumber(month), tonumber(day) + + if not year then + return + end -- Default month and day to 1 if not set - if String.isEmpty(month) then + if not month then month = 1 end - if String.isEmpty(day) then + if not day then day = 1 end -- create simplified osdate diff --git a/standard/flags.lua b/standard/flags.lua index 7a98d00e548..294dc8c4aab 100644 --- a/standard/flags.lua +++ b/standard/flags.lua @@ -233,14 +233,17 @@ Flags.readKey('Czechoslovakia') -- returns nil ---@return string? function Flags._convertToKey(flagName) -- lowercase all unicode - flagName = mw.ustring.lower(flagName) -- removes all accents and special characters - flagName = string.gsub(mw.ustring.toNFKD(flagName), '[^%l]', '') + local parsedName = mw.ustring.toNFKD(mw.ustring.lower(flagName)) + if not parsedName then + return + end + parsedName = string.gsub(parsedName, '[^%l]', '') - return MasterData.twoLetter[flagName] - or MasterData.threeLetter[flagName] - or MasterData.aliases[flagName] - or (MasterData.data[flagName] and flagName) + return MasterData.twoLetter[parsedName] + or MasterData.threeLetter[parsedName] + or MasterData.aliases[parsedName] + or (MasterData.data[parsedName] and parsedName) end ---@param langName string diff --git a/standard/logic.lua b/standard/logic.lua index 8ce93d3f09d..79911c60cc1 100644 --- a/standard/logic.lua +++ b/standard/logic.lua @@ -6,8 +6,6 @@ -- Please see https://github.com/Liquipedia/Lua-Modules to contribute -- -local Error = require('Module:Error') - local Logic = {} ---Returns `val1` if it isn't empty else returns `val2` if that isn't empty, else returns default @@ -149,7 +147,7 @@ function Logic.tryOrElseLog(f, other, makeError) return Logic.try(f) :catch(function(error) if type(error) == 'string' then - error = Error(error) + error = require('Module:Error')(error) end error.header = 'Error occured while calling a function: (caught by Logic.tryOrElseLog)' diff --git a/standard/math_util.lua b/standard/math_util.lua index 311566ec258..9f7ea4b5bb1 100644 --- a/standard/math_util.lua +++ b/standard/math_util.lua @@ -76,4 +76,13 @@ function MathUtil.dotProduct(xs, ys) return sum end +---Rounds a number to specified precision +---@param value number +---@param precision number? +---@return number +function MathUtil.round(value, precision) + local rescale = math.pow(10, precision or 0); + return math.floor(value * rescale + 0.5) / rescale; +end + return MathUtil diff --git a/standard/test/abbreviation_test.lua b/standard/test/abbreviation_test.lua deleted file mode 100644 index 9d468c519fe..00000000000 --- a/standard/test/abbreviation_test.lua +++ /dev/null @@ -1,22 +0,0 @@ ---- --- @Liquipedia --- wiki=commons --- page=Module:Abbreviation/testcases --- --- Please see https://github.com/Liquipedia/Lua-Modules to contribute --- - -local Lua = require('Module:Lua') -local ScribuntoUnit = require('Module:ScribuntoUnit') - -local Abbreviation = Lua.import('Module:Abbreviation', {requireDevIfEnabled = true}) - -local suite = ScribuntoUnit:new() - -function suite:testMakeAbbr() - self:assertEquals(nil, Abbreviation.make()) - self:assertEquals(nil, Abbreviation.make('')) - self:assertEquals('Cake', Abbreviation.make('Cake', 'Cookie')) -end - -return suite diff --git a/standard/test/array_test.lua b/standard/test/array_test.lua deleted file mode 100644 index 8f317582b4c..00000000000 --- a/standard/test/array_test.lua +++ /dev/null @@ -1,175 +0,0 @@ ---- --- @Liquipedia --- wiki=commons --- page=Module:Array/testcases --- --- Please see https://github.com/Liquipedia/Lua-Modules to contribute --- - -local Lua = require('Module:Lua') -local Table = require('Module:Table') -local ScribuntoUnit = require('Module:ScribuntoUnit') - -local Array = Lua.import('Module:Array', {requireDevIfEnabled = true}) - -local suite = ScribuntoUnit:new() - -function suite:testIsArray() - self:assertTrue(Array.isArray{}) - self:assertTrue(Array.isArray{5, 2, 3}) - self:assertFalse(Array.isArray{a = 1, [3] = 2, c = 3}) - self:assertFalse(Array.isArray{5, 2, c = 3}) -end - -function suite:testCopy() - local a, b, c = {1, 2, 3}, {}, {{5}} - self:assertDeepEquals(a, Array.copy(a)) - self:assertFalse(Array.copy(b) == b) - self:assertTrue(Array.copy(c)[1] == c[1]) -end - -function suite:testSub() - local a = {3, 5, 7, 11} - self:assertDeepEquals({5, 7, 11}, Array.sub(a, 2)) - self:assertDeepEquals({5, 7}, Array.sub(a, 2, 3)) - self:assertDeepEquals({7, 11}, Array.sub(a, -2, -1)) -end - -function suite:testMap() - local a = {1, 2, 3} - self:assertDeepEquals({2, 4, 6}, Array.map(a, function(x) - return 2 * x - end)) -end - -function suite:testFilter() - local a = {1, 2, 3} - self:assertDeepEquals({1, 3}, Array.filter(a, function(x) - return x % 2 == 1 end - )) -end - -function suite:testFlatten() - local a = {1, 2, 3, {5, 3}, {6, 4}} - self:assertDeepEquals({1, 2, 3, 5, 3, 6, 4}, Array.flatten(a)) -end - -function suite:testAll() - local a = {1, 2, 3} - self:assertTrue(Array.all(a, function (value) - return type(value) == 'number' - end)) - self:assertFalse(Array.all(a, function (value) - return value < 3 - end)) -end - -function suite:testAny() - local a = {1, 2, 3} - self:assertFalse(Array.any(a, function (value) - return type(value) == 'string' - end)) - self:assertTrue(Array.any(a, function (value) - return value < 3 - end)) -end - -function suite:testFind() - local a = {4, 6, 9} - local b = Array.find(a, function (value, index) - return index == 2 - end) - local c = Array.find(a, function (value, index) - return index == -1 - end) - self:assertEquals(6, b) - self:assertEquals(nil, c) -end - -function suite:testRevese() - local a = {4, 6, 9} - self:assertDeepEquals({9, 6, 4}, Array.reverse(a)) -end - -function suite:testAppend() - local a = {2, 3} - self:assertDeepEquals({2, 3, 5, 7, 11}, Array.append(a, 5, 7, 11)) - self:assertDeepEquals({2, 3}, a) -end - -function suite:testAppendWith() - local a = {2, 3} - self:assertDeepEquals({2, 3, 5, 7, 11}, Array.appendWith(a, 5, 7, 11)) - self:assertDeepEquals({2, 3, 5, 7, 11}, a) -end - -function suite:testExtend() - local a, b, c = {2, 3}, {5, 7, 11}, {13} - self:assertDeepEquals({2, 3, 5, 7, 11, 13}, Array.extend(a, b, c)) - self:assertDeepEquals({2, 3}, a) -end - -function suite:testExtendWith() - local a, b, c = {2, 3}, {5, 7, 11}, {13} - self:assertDeepEquals({2, 3, 5, 7, 11, 13}, Array.extendWith(a, b, c)) - self:assertDeepEquals({2, 3, 5, 7, 11, 13}, a) -end - -function suite:testMapIndexes() - local a = {p1 = 'Abc', p2 = 'cd', p3 = 'cake'} - self:assertDeepEquals({'p1Abc', 'p2cd'}, Array.mapIndexes(function(x) - local prefix = 'p'.. x - return a[prefix] ~= 'cake' and (prefix .. a[prefix]) or nil - end)) -end - -function suite:testRange() - self:assertDeepEquals({1, 2, 3}, Array.range(1, 3)) - self:assertDeepEquals({2, 3}, Array.range(2, 3)) -end - -function suite:testForEach() - local a = {} - Array.forEach(Array.range(1, 3), function(x) - table.insert(a, 1, x) - end) - self:assertDeepEquals({3, 2, 1}, a) -end - -function suite:testReduce() - local function pow(x, y) return x ^ y end - self:assertDeepEquals(32768, Array.reduce({2, 3, 5}, pow)) - self:assertDeepEquals(1, Array.reduce({2, 3, 5}, pow, 1)) -end - -function suite:testExtractValues() - local a = {i = 1, j = 2, k = 3, z = 0} - - local customOrder1 = function(_, key1, key2) return key1 > key2 end - local customOrder2 = function(tbl, key1, key2) return tbl[key1] < tbl[key2] end - - self:assertDeepEquals({1, 2, 3, 0}, Array.extractValues(a, Table.iter.spairs)) - self:assertDeepEquals({0, 3, 2, 1}, Array.extractValues(a, Table.iter.spairs, customOrder1)) - self:assertDeepEquals({0, 1, 2, 3}, Array.extractValues(a, Table.iter.spairs, customOrder2)) - - local extractedArray = Array.extractValues(a) - table.sort(extractedArray) - self:assertDeepEquals({0, 1, 2, 3}, extractedArray) -end - -function suite:testExtractKeys() - local a = {k = 3, i = 1, z = 0, j = 2} - - local customOrder1 = function(_, key1, key2) return key1 > key2 end - local customOrder2 = function(tbl, key1, key2) return tbl[key1] < tbl[key2] end - - self:assertDeepEquals({'i', 'j', 'k', 'z'}, Array.extractKeys(a, Table.iter.spairs)) - self:assertDeepEquals({'z', 'k', 'j', 'i'}, Array.extractKeys(a, Table.iter.spairs, customOrder1)) - self:assertDeepEquals({'z', 'i', 'j', 'k'}, Array.extractKeys(a, Table.iter.spairs, customOrder2)) - - local extractedKeys = Array.extractKeys(a) - table.sort(extractedKeys) - self:assertDeepEquals({'i', 'j', 'k', 'z'}, extractedKeys) -end - -return suite diff --git a/standard/test/currency_test.lua b/standard/test/currency_test.lua deleted file mode 100644 index 11cd42cdac0..00000000000 --- a/standard/test/currency_test.lua +++ /dev/null @@ -1,69 +0,0 @@ ---- --- @Liquipedia --- wiki=commons --- page=Module:Currency/testcases --- --- Please see https://github.com/Liquipedia/Lua-Modules to contribute --- - -local Lua = require('Module:Lua') -local ScribuntoUnit = require('Module:ScribuntoUnit') - -local Currency = Lua.import('Module:Currency', {requireDevIfEnabled = true}) -local Variables = Lua.import('Module:Variables', {requireDevIfEnabled = true}) - -local suite = ScribuntoUnit:new() - -local DASH = '-' - -function suite:testGetExchangeRate() - self:assertEquals(1.45, Currency.getExchangeRate{currency = 'EUR', currencyRate = '1.45', setVariables = true}) - self:assertEquals(1.45, tonumber(Variables.varDefault('exchangerate_EUR'))) - self:assertEquals(0.97035563534035, Currency.getExchangeRate{date = '2022-10-10', currency = 'EUR'}) -end - -function suite:testFormatMoney() - self:assertEquals(DASH, Currency.formatMoney('abc')) - self:assertEquals(DASH, Currency.formatMoney(nil)) - self:assertEquals(DASH, Currency.formatMoney('0')) - self:assertEquals(DASH, Currency.formatMoney(0)) - self:assertEquals(0, Currency.formatMoney('abc', nil, nil, false)) - self:assertEquals(0, Currency.formatMoney(nil, nil, nil, false)) - self:assertEquals('12', Currency.formatMoney(12)) - self:assertEquals('1,200', Currency.formatMoney(1200)) - self:assertEquals('1,200.00', Currency.formatMoney(1200, nil, true)) - self:assertEquals('1,200.12', Currency.formatMoney(1200.12345)) - self:assertEquals('1,200.1', Currency.formatMoney(1200.12345, 1)) - self:assertEquals('1,200.1235', Currency.formatMoney(1200.12345, 4)) -end - -function suite:testRaw() - self:assertEquals(nil, Currency.raw()) - self:assertEquals(nil, Currency.raw('')) - self:assertEquals(nil, Currency.raw('dummy')) - self:assertDeepEquals({ - code = 'EUR', - name = 'Euro', - symbol = { - hasSpace = false, - isAfter = false, - text = '€', - }, - }, - Currency.raw('EUR') - ) -end - -function suite:testDisplay() - self:assertEquals(nil, Currency.display()) - self:assertEquals(nil, Currency.display('')) - self:assertEquals(nil, Currency.display('dummy')) - self:assertEquals(DASH, Currency.display('dummy', 0, {dashIfZero = true})) - self:assertEquals(DASH, Currency.display('EUR', 0, {dashIfZero = true})) - self:assertEquals('€1,200 EUR', Currency.display('EUR', 1200, {formatValue = true})) - self:assertEquals('€1200 EUR', Currency.display('EUR', 1200)) - self:assertEquals('€ EUR', Currency.display('EUR')) - self:assertEquals('€ EUR', Currency.display('EUR', nil, {useHtmlStyling = false})) -end - -return suite diff --git a/standard/test/date_ext_test.lua b/standard/test/date_ext_test.lua deleted file mode 100644 index 56b0320a143..00000000000 --- a/standard/test/date_ext_test.lua +++ /dev/null @@ -1,57 +0,0 @@ ---- --- @Liquipedia --- wiki=commons --- page=Module:Date/Ext/testcases --- --- Please see https://github.com/Liquipedia/Lua-Modules to contribute --- - -local Lua = require('Module:Lua') -local ScribuntoUnit = require('Module:ScribuntoUnit') -local Variables = require('Module:Variables') - -local DateExt = Lua.import('Module:Date/Ext', {requireDevIfEnabled = true}) - -local suite = ScribuntoUnit:new() - -function suite:testReadTimestamp() - self:assertEquals(1634506800, DateExt.readTimestamp('2021-10-17 17:40 EDT')) - self:assertEquals(1634506800, DateExt.readTimestamp('2021-10-17 21:40')) -end - -function suite:testFormat() - self:assertEquals('2021-10-17T21:40:00+00:00', DateExt.formatTimestamp('c', 1634506800)) -end - -function suite:testToYmdInUtc() - self:assertEquals('2021-11-08', DateExt.toYmdInUtc('November 08, 2021 - 13:00 CET')) - self:assertEquals('2021-11-09', DateExt.toYmdInUtc('2021-11-08 17:00 PST')) -end - -function suite:testGetContextualDateOrNow() - self:assertEquals(os.date('%F'), DateExt.getContextualDateOrNow()) - self:assertEquals(nil, DateExt.getContextualDate()) - - Variables.varDefine('tournament_startdate', '2021-12-24') - self:assertEquals('2021-12-24', DateExt.getContextualDateOrNow()) - self:assertEquals('2021-12-24', DateExt.getContextualDate()) - - Variables.varDefine('tournament_enddate', '2021-12-28') - self:assertEquals('2021-12-28', DateExt.getContextualDateOrNow()) - self:assertEquals('2021-12-28', DateExt.getContextualDate()) - - Variables.varDefine('tournament_startdate') - Variables.varDefine('tournament_enddate') -end - -function suite:parseIsoDate() - self:assertDeepEquals({year = 2023, month = 7, day = 24}, DateExt.parseIsoDate('2023-07-24')) - self:assertDeepEquals({year = 2023, month = 7, day = 24}, DateExt.parseIsoDate('2023-07-24asdkosdkmoasjoikmakmslkm')) - self:assertDeepEquals({year = 2023, month = 7, day = 1}, DateExt.parseIsoDate('2023-07')) - self:assertDeepEquals({year = 2023, month = 7, day = 1}, DateExt.parseIsoDate('2023-07sdfsdfdfs')) - self:assertDeepEquals({year = 2023, month = 1, day = 1}, DateExt.parseIsoDate('2023')) - self:assertDeepEquals({year = 2023, month = 1, day = 1}, DateExt.parseIsoDate('202334rdfg')) - self:assertEquals(nil, DateExt.parseIsoDate()) -end - -return suite diff --git a/standard/test/flags_test.lua b/standard/test/flags_test.lua deleted file mode 100644 index 6df322dba7c..00000000000 --- a/standard/test/flags_test.lua +++ /dev/null @@ -1,81 +0,0 @@ ---- --- @Liquipedia --- wiki=commons --- page=Module:Flags/testcases --- --- Please see https://github.com/Liquipedia/Lua-Modules to contribute --- - -local Lua = require('Module:Lua') -local ScribuntoUnit = require('Module:ScribuntoUnit') - -local Flags = Lua.import('Module:Flags', {requireDevIfEnabled = true}) - -local suite = ScribuntoUnit:new() - -function suite:testIcon() - local nlOutput = '[[File:nl_hd.png|Netherlands|link=]]' - local nlOutputLink = '[[File:nl_hd.png|Netherlands|link=Category:Netherlands]]' - local unknownCat = '[[Category:Pages with unknown flags]]' - - self:assertEquals(nlOutput, Flags.Icon('nl')) - self:assertEquals(nlOutput, Flags.Icon('nld')) - self:assertEquals(nlOutput, Flags.Icon('holland')) - self:assertEquals(nlOutput, Flags.Icon({}, 'nl')) - self:assertEquals(nlOutput, Flags.Icon({}, 'nld')) - self:assertEquals(nlOutput, Flags.Icon({}, 'holland')) - self:assertEquals(nlOutputLink, Flags.Icon({shouldLink = true}, 'nl')) - self:assertEquals(nlOutputLink, Flags.Icon({shouldLink = true}, 'nld')) - self:assertEquals(nlOutputLink, Flags.Icon({shouldLink = true}, 'holland')) - self:assertEquals(nlOutput, Flags.Icon({shouldLink = false}, 'nl')) - self:assertEquals(nlOutput, Flags.Icon({shouldLink = false}, 'nld')) - self:assertEquals(nlOutput, Flags.Icon({shouldLink = false}, 'holland')) - self:assertEquals(nlOutputLink, Flags.Icon{shouldLink = true, flag = 'nl'}) - self:assertEquals(nlOutputLink, Flags.Icon{shouldLink = true, flag = 'nld'}) - self:assertEquals(nlOutputLink, Flags.Icon{shouldLink = true, flag = 'holland'}) - self:assertEquals(nlOutput, Flags.Icon{shouldLink = false, flag = 'nl'}) - self:assertEquals(nlOutput, Flags.Icon{shouldLink = false, flag = 'nld'}) - self:assertEquals(nlOutput, Flags.Icon{shouldLink = false, flag = 'holland'}) - - self:assertEquals('[[File:Space filler flag.png|link=]]', Flags.Icon{flag = 'tbd'}) - - self:assertEquals(('[[Template:Flag/dummy]]' .. unknownCat), Flags.Icon{shouldLink = true, flag = 'dummy'}) - self:assertEquals(('[[Template:FlagNoLink/dummy]]' .. unknownCat), Flags.Icon{shouldLink = false, flag = 'dummy'}) -end - -function suite:testLocalisation() - local nlOutput = 'Dutch' - self:assertEquals(nlOutput, Flags.getLocalisation('nl')) - self:assertEquals(nlOutput, Flags.getLocalisation('Netherlands')) - self:assertEquals(nlOutput, Flags.getLocalisation('netherlands')) - self:assertEquals(nlOutput, Flags.getLocalisation('holland')) -end - -function suite:testLanguageIcon() - self:assertEquals('[[File:UsGb hd.png|English Speaking|link=]]', Flags.languageIcon('en')) - self:assertEquals('[[File:nl_hd.png|Netherlands|link=]]', Flags.languageIcon('nl')) -end - -function suite:testCountryName() - local nlOutput = 'Netherlands' - self:assertEquals(nlOutput, Flags.CountryName('nl')) - self:assertEquals(nlOutput, Flags.CountryName('Netherlands')) - self:assertEquals(nlOutput, Flags.CountryName('netherlands')) - self:assertEquals(nlOutput, Flags.CountryName('holland')) -end - -function suite:testCountryCode() - local nlOutput = 'nl' - self:assertEquals(nlOutput, Flags.CountryCode('nl')) - self:assertEquals(nlOutput, Flags.CountryCode('Netherlands')) - self:assertEquals(nlOutput, Flags.CountryCode('netherlands')) - self:assertEquals(nlOutput, Flags.CountryCode('holland')) -end - -function suite:testIsValidFlagInput() - self:assertEquals(true, Flags.isValidFlagInput('de')) - self:assertEquals(true, Flags.isValidFlagInput('germany')) - self:assertEquals(false, Flags.isValidFlagInput('aaaaaaa')) -end - -return suite diff --git a/standard/test/locale_test.lua b/standard/test/locale_test.lua deleted file mode 100644 index 26652ff4d62..00000000000 --- a/standard/test/locale_test.lua +++ /dev/null @@ -1,37 +0,0 @@ ---- --- @Liquipedia --- wiki=commons --- page=Module:Locale/testcases --- --- Please see https://github.com/Liquipedia/Lua-Modules to contribute --- - -local Lua = require('Module:Lua') -local ScribuntoUnit = require('Module:ScribuntoUnit') - -local Locale = Lua.import('Module:Locale', {requireDevIfEnabled = true}) - -local suite = ScribuntoUnit:new() - -local NON_BREAKING_SPACE = ' ' - -function suite:testFormatLocation() - self:assertEquals('', Locale.formatLocation{}) - self:assertEquals('abc,' .. NON_BREAKING_SPACE, Locale.formatLocation{city = 'abc'}) - self:assertEquals('Sweden', Locale.formatLocation{country = 'Sweden'}) - self:assertEquals('abc,'.. NON_BREAKING_SPACE .. 'Sweden', Locale.formatLocation{city = 'abc', country = 'Sweden'}) -end - -function suite:testLocations() - local test1 = {venue = 'Abc', country1 = 'Sweden', country2='Europe'} - local result1 = {country1 = 'se', region2 = 'Europe', venue1 = 'Abc'} - - local test2 = {venue = 'Abc', country1 = 'Sweden', region1='Europe', venuelink = 'https://lmgtfy.app/'} - local result2 = {country1 = 'se', region1 = 'Europe', venue1 = 'Abc', venuelink1 = 'https://lmgtfy.app/'} - - self:assertDeepEquals(result1, Locale.formatLocations(test1)) - self:assertDeepEquals(result2, Locale.formatLocations(test2)) - self:assertDeepEquals({}, Locale.formatLocations{dummy = true}) -end - -return suite diff --git a/standard/test/logic_test.lua b/standard/test/logic_test.lua deleted file mode 100644 index 62838b0d00e..00000000000 --- a/standard/test/logic_test.lua +++ /dev/null @@ -1,183 +0,0 @@ ---- --- @Liquipedia --- wiki=commons --- page=Module:Logic/testcases --- --- Please see https://github.com/Liquipedia/Lua-Modules to contribute --- - -local Lua = require('Module:Lua') -local ScribuntoUnit = require('Module:ScribuntoUnit') -local Table = require('Module:Table') - -local Logic = Lua.import('Module:Logic', {requireDevIfEnabled = true}) - -local suite = ScribuntoUnit:new() - -function suite:testEmptyOr() - self:assertEquals(1, Logic.emptyOr(1, 2, 3)) - self:assertEquals(1, Logic.emptyOr(1, 2)) - self:assertEquals(1, Logic.emptyOr(1, nil, 3)) - self:assertEquals(1, Logic.emptyOr(1, '', 3)) - self:assertEquals(1, Logic.emptyOr(1)) - self:assertEquals(2, Logic.emptyOr(nil, 2, 3)) - self:assertEquals(2, Logic.emptyOr('', 2, 3)) - self:assertEquals(2, Logic.emptyOr(nil, 2)) - self:assertEquals(2, Logic.emptyOr('', 2)) - self:assertEquals(3, Logic.emptyOr(nil, nil, 3)) - self:assertEquals(3, Logic.emptyOr({}, '', 3)) - self:assertEquals(nil, Logic.emptyOr()) -end - -function suite:testNilOr() - self:assertEquals(1, Logic.nilOr(1, 2, 3)) - self:assertEquals(1, Logic.nilOr(1, 2)) - self:assertEquals(1, Logic.nilOr(1, nil, 3)) - self:assertEquals(1, Logic.nilOr(1, '', 3)) - self:assertEquals(1, Logic.nilOr(1)) - self:assertEquals(2, Logic.nilOr(nil, 2, 3)) - self:assertEquals('', Logic.nilOr('', 2, 3)) - self:assertEquals(2, Logic.nilOr(nil, 2)) - self:assertEquals('', Logic.nilOr('', 2)) - self:assertEquals(3, Logic.nilOr(nil, nil, 3)) - self:assertDeepEquals({}, Logic.nilOr({}, '', 3)) - self:assertEquals(nil, Logic.nilOr()) - self:assertEquals(5, Logic.nilOr(nil, nil, nil, nil, 5)) -end - -function suite:testIsEmpty() - self:assertTrue(Logic.isEmpty({})) - self:assertTrue(Logic.isEmpty()) - self:assertTrue(Logic.isEmpty('')) - self:assertFalse(Logic.isEmpty({''})) - self:assertFalse(Logic.isEmpty({'string'})) - self:assertFalse(Logic.isEmpty({{}})) - self:assertFalse(Logic.isEmpty(1)) - self:assertFalse(Logic.isEmpty('string')) -end - -function suite:testIsDeepEmpty() - self:assertTrue(Logic.isDeepEmpty({})) - self:assertTrue(Logic.isDeepEmpty()) - self:assertTrue(Logic.isDeepEmpty('')) - self:assertTrue(Logic.isDeepEmpty({''})) - self:assertFalse(Logic.isDeepEmpty({'string'})) - self:assertTrue(Logic.isDeepEmpty({{}})) - self:assertFalse(Logic.isDeepEmpty(1)) - self:assertFalse(Logic.isDeepEmpty('string')) -end - -function suite:testReadBool() - self:assertTrue(Logic.readBool(1)) - self:assertTrue(Logic.readBool('true')) - self:assertTrue(Logic.readBool(true)) - self:assertTrue(Logic.readBool('t')) - self:assertTrue(Logic.readBool('y')) - self:assertTrue(Logic.readBool('yes')) - self:assertTrue(Logic.readBool('1')) - self:assertFalse(Logic.readBool(0)) - self:assertFalse(Logic.readBool(false)) - self:assertFalse(Logic.readBool('false')) - self:assertFalse(Logic.readBool('f')) - self:assertFalse(Logic.readBool('0')) - self:assertFalse(Logic.readBool('no')) - self:assertFalse(Logic.readBool('n')) - self:assertFalse(Logic.readBool('someBs')) - self:assertFalse(Logic.readBool()) - ---intended bad value - ---@diagnostic disable-next-line: param-type-mismatch - self:assertFalse(Logic.readBool{}) -end - -function suite:testReadBoolOrNil() - self:assertTrue(Logic.readBoolOrNil(1)) - self:assertTrue(Logic.readBoolOrNil('true')) - self:assertTrue(Logic.readBoolOrNil(true)) - self:assertTrue(Logic.readBoolOrNil('t')) - self:assertTrue(Logic.readBoolOrNil('y')) - self:assertTrue(Logic.readBoolOrNil('yes')) - self:assertTrue(Logic.readBoolOrNil('1')) - self:assertFalse(Logic.readBoolOrNil(0)) - self:assertFalse(Logic.readBoolOrNil(false)) - self:assertFalse(Logic.readBoolOrNil('false')) - self:assertFalse(Logic.readBoolOrNil('f')) - self:assertFalse(Logic.readBoolOrNil('0')) - self:assertFalse(Logic.readBoolOrNil('no')) - self:assertFalse(Logic.readBoolOrNil('n')) - self:assertEquals(nil, Logic.readBoolOrNil('someBs')) - self:assertEquals(nil, Logic.readBoolOrNil()) - ---intended bad value - ---@diagnostic disable-next-line: param-type-mismatch - self:assertEquals(nil, Logic.readBoolOrNil{}) -end - -function suite:testNilThrows() - self:assertEquals('someVal', Logic.nilThrows('someVal')) - self:assertEquals('', Logic.nilThrows('')) - self:assertEquals(1, Logic.nilThrows(1)) - self:assertDeepEquals({'someVal'}, Logic.nilThrows({'someVal'})) - self:assertDeepEquals({}, Logic.nilThrows({})) - self:assertThrows(function() return Logic.nilThrows() end) -end - -function suite:testTryCatch() - local errorCaught = false - local catch = function(errorMessage) errorCaught = true end - - self:assertEquals(nil, Logic.tryCatch(function() error() end, catch)) - self:assertTrue(errorCaught) - errorCaught = false - - self:assertEquals(nil, Logic.tryCatch(function() error('some error') end, catch)) - self:assertTrue(errorCaught) - errorCaught = false - - self:assertEquals(nil, Logic.tryCatch(function() assert(false, 'some failed assert') end, catch)) - self:assertTrue(errorCaught) - errorCaught = false - - self:assertEquals('someVal', Logic.tryCatch(function() return 'someVal' end, catch)) - self:assertFalse(errorCaught) -end - -function suite:testIsNumeric() - self:assertTrue(Logic.isNumeric(1.5)) - self:assertTrue(Logic.isNumeric('1.5')) - self:assertTrue(Logic.isNumeric('4.57e-3')) - self:assertTrue(Logic.isNumeric(4.57e-3)) - self:assertTrue(Logic.isNumeric(0.3e12)) - self:assertTrue(Logic.isNumeric('0.3e12')) - self:assertTrue(Logic.isNumeric(5e+20)) - self:assertTrue(Logic.isNumeric('5e+20')) - self:assertFalse(Logic.isNumeric('1+2')) - self:assertFalse(Logic.isNumeric()) - self:assertFalse(Logic.isNumeric('string')) - ---intended bad value - ---@diagnostic disable-next-line: param-type-mismatch - self:assertFalse(Logic.isNumeric{}) - ---intended bad value - ---@diagnostic disable-next-line: param-type-mismatch - self:assertFalse(Logic.isNumeric{just = 'a table'}) -end - -function suite:testDeepEquals() - self:assertTrue(Logic.deepEquals(1, 1)) - self:assertFalse(Logic.deepEquals(1, 2)) - self:assertTrue(Logic.deepEquals('a', 'a')) - self:assertFalse(Logic.deepEquals('a', 'b')) - - local tbl1 = {1, 2, {3, 4, {a = 'b'}}} - local tbl2 = {1, 2, {3, 4, {a = 'c'}}} - local tbl3 = {1, 2, {3, 4, {a = 'b'}, 6}} - self:assertTrue(Logic.deepEquals(tbl1, tbl1)) - self:assertTrue(Logic.deepEquals(tbl1, Table.deepCopy(tbl1))) - self:assertFalse(Logic.deepEquals(tbl1, tbl2)) - self:assertFalse(Logic.deepEquals(tbl1, tbl3)) -end - ---currently not testing: ----try - just uses `Module:ResultOrError` ----tryOrElseLog - uses `.try` plus `:catch` and `:get` ----wrapTryOrLog - basically tryOrElseLog - -return suite diff --git a/standard/test/page_test.lua b/standard/test/page_test.lua deleted file mode 100644 index 8ca0520ecf6..00000000000 --- a/standard/test/page_test.lua +++ /dev/null @@ -1,43 +0,0 @@ ---- --- @Liquipedia --- wiki=commons --- page=Module:Page/testcases --- --- Please see https://github.com/Liquipedia/Lua-Modules to contribute --- - -local Lua = require('Module:Lua') -local ScribuntoUnit = require('Module:ScribuntoUnit') - -local Page = Lua.import('Module:Page', {requireDevIfEnabled = true}) - -local suite = ScribuntoUnit:new() - -function suite:testExists() - self:assertFalse(Page.exists('https://google.com')) - self:assertFalse(Page.exists('PageThatDoesntExistPlx')) - self:assertTrue(Page.exists('Module:Page')) -end - -function suite:testInternalLink() - self:assertEquals('[[Module:Page|Module:Page]]', Page.makeInternalLink('Module:Page')) - self:assertEquals('[[Module:Page|DisplayText]]', Page.makeInternalLink('DisplayText', 'Module:Page')) - self:assertEquals('[[Module:Page|DisplayText]]', Page.makeInternalLink({}, 'DisplayText', 'Module:Page')) - self:assertEquals( - nil, - Page.makeInternalLink({onlyIfExists = true}, 'DisplayText', 'Module:PageThatDoesntExistPlx') - ) - self:assertEquals( - '[[Module:Page|DisplayText]]', - Page.makeInternalLink({onlyIfExists = true}, 'DisplayText', 'Module:Page') - ) - self:assertEquals(nil, Page.makeInternalLink({})) -end - -function suite:testExternalLink() - self:assertEquals(nil, Page.makeExternalLink('Display', '')) - self:assertEquals(nil, Page.makeExternalLink('', 'https://google.com')) - self:assertEquals('[https://google.com Display Text]', Page.makeExternalLink('Display Text', 'https://google.com')) -end - -return suite diff --git a/standard/test/variables_test.lua b/standard/test/variables_test.lua deleted file mode 100644 index b044fa4211e..00000000000 --- a/standard/test/variables_test.lua +++ /dev/null @@ -1,43 +0,0 @@ ---- --- @Liquipedia --- wiki=commons --- page=Module:Variables/testcases --- --- Please see https://github.com/Liquipedia/Lua-Modules to contribute --- - -local Lua = require('Module:Lua') -local ScribuntoUnit = require('Module:ScribuntoUnit') - -local Variables = Lua.import('Module:Variables', {requireDevIfEnabled = true}) - -local suite = ScribuntoUnit:new() - -function suite:testVarDefine() - self:assertEquals('', Variables.varDefine('test', 'foo')) - self:assertEquals('foo', Variables.varDefault('test')) - - self:assertEquals('bar', Variables.varDefineEcho('test', 'bar')) - self:assertEquals('bar', Variables.varDefault('test')) - - self:assertEquals('', Variables.varDefine('test', 3)) - self:assertEquals('3', Variables.varDefault('test')) - - self:assertEquals('', Variables.varDefine('test')) - self:assertEquals(nil, Variables.varDefault('test')) -end - -function suite:testVarDefault() - Variables.varDefine('test', 'foo') - self:assertEquals('foo', Variables.varDefault('test')) - self:assertEquals(nil, Variables.varDefault('bar')) - self:assertEquals('baz', Variables.varDefault('bar', 'baz')) -end - -function suite:testVarDefaultMulti() - Variables.varDefine('baz', 'hello world') - self:assertEquals('hello world', Variables.varDefaultMulti('foo', 'bar', 'baz')) - self:assertEquals('banana', Variables.varDefaultMulti('foo', 'bar', 'banana')) -end - -return suite diff --git a/standard/variables.lua b/standard/variables.lua index 1e6cbc9c2b7..2b82d258d93 100644 --- a/standard/variables.lua +++ b/standard/variables.lua @@ -10,9 +10,6 @@ local Class = require('Module:Class') local Variables = {} ----@alias wikiVaribleKey string|number ----@alias wikiVariableValue string|number|nil - ---Stores a wiki-variable and returns the empty string ---@param name wikiVaribleKey Key of the wiki-variable ---@param value wikiVariableValue Value of the wiki-variable