local CONFIG_FILE_NAME = '.darklua.json5'
local function concatCommands(...)
return table.concat({...}, ' && ')
end
local function run(...)
local command = concatCommands(...)
local status = os.execute(command)
if status ~= 0 then
return false, ('\n\nAn error status code (%d) was returned after running the command:\n%s\n'):format(status, command)
end
return true
end
local function verify(success, message)
if not success then
error(message, 2)
end
end
local function verifyRun(...)
verify(run(...))
end
local Project = {}
local projectMetatable = {__index = Project}
function Project.new(repo, commit, processFolder, ...)
return setmetatable({
Repository = repo,
RepositoryName = repo:match('([%a%-]+)%.git'),
Commit = commit,
ProcessFolder = processFolder,
Test = concatCommands(...),
}, projectMetatable)
end
function Project:init()
verifyRun(
'git clone ' .. self.Repository,
'cd ' .. self.RepositoryName,
'git checkout ' .. self.Commit,
'git submodule init',
'git submodule update',
'cd ..'
)
end
function Project:clean()
verifyRun('rm -r -f ' .. self.RepositoryName)
end
function Project:test(generatedFolderName)
return run((self.Test:gsub('%$generated', generatedFolderName)))
end
local Json = {}
function Json.fromArray(array)
local content = {}
for i=1, #array do
table.insert(content, Json.from(array[i]))
end
return ('[%s]'):format(table.concat(content, ','))
end
function Json.fromMap(data)
local content = {}
for key, value in pairs(data) do
table.insert(content, ('%s:%s'):format(key, Json.from(value)))
end
return ('{%s}'):format(table.concat(content, ','))
end
function Json.from(data)
local dataType = type(data)
if dataType == 'table' then
if #data ~= 0 then
return Json.fromArray(data)
else
return Json.fromMap(data)
end
elseif dataType == 'string' then
return ('"%s"'):format(data)
end
return tostring(data)
end
local DarkluaTest = {}
local darkluaTestMetatable = {__index = DarkluaTest}
function DarkluaTest.new(name, command, config)
return setmetatable({
Name = name,
Command = command,
ConfigurationFile = config and Json.fromMap(config) or '',
}, darkluaTestMetatable)
end
function DarkluaTest:execute(project)
local generatedName = 'processed-' .. project.RepositoryName
local escapedRepoName = project.RepositoryName:gsub('%-', '%%-')
local output = project.ProcessFolder:gsub(escapedRepoName, generatedName);
local command = self.Command
:gsub('$input', project.ProcessFolder)
:gsub('$output', output)
if self.ConfigurationFile:len() > 0 then
local configFile = io.open(CONFIG_FILE_NAME, 'w+')
configFile:write(self.ConfigurationFile)
configFile:close()
end
verifyRun('cargo run --release -- ' .. command)
verifyRun(('rm -f %s'):format(CONFIG_FILE_NAME))
local success, message = project:test(generatedName)
if not success then
return false, (('\nerror while executing test <%s> on <%s>:\n%s'):format(
self.Name,
project.RepositoryName,
message
))
end
return true, 'success', function() verifyRun('rm -r -f ' .. generatedName) end
end
local projects = {
Project.new(
'https://github.com/Roblox/roact.git',
'd9b7f9661b26ff16db240f2fe8b0f8284303c61d',
'roact/src',
'cp -r roact/bin $generated/bin',
'cp -r roact/modules $generated/modules',
'cd $generated',
'lua bin/spec.lua',
'cd ..'
),
Project.new(
'https://github.com/Roblox/rodux.git',
'45c106f09c58f706a7ea458c6ff17914dd9a22c6',
'rodux/src',
'cp rodux/spec.lua $generated/spec.lua',
'cp -r rodux/modules $generated/modules',
'cd $generated',
'lua spec.lua',
'cd ..'
),
Project.new(
'https://github.com/Roblox/roact-rodux.git',
'7ec071ae3174a88e9054d8a814828ad4f0448a7a',
'roact-rodux/src',
'cp -r roact-rodux/test $generated/test',
'cp -r roact-rodux/modules $generated/modules',
'cd $generated',
'lua test/lemur.lua',
'cd ..'
),
Project.new(
'https://github.com/Roblox/t.git',
'00b91a76847572e32a365dff71ac606798f86609',
't/lib',
'cp t/spec.lua $generated/spec.lua',
'cp -r t/modules $generated/modules',
'cd $generated',
'lua spec.lua',
'cd ..'
),
}
local testSuite = {
DarkluaTest.new('minify', 'minify $input $output'),
DarkluaTest.new('default-process-dense', 'process $input $output --format dense'),
DarkluaTest.new('default-process-readable', 'process $input $output --format readable'),
DarkluaTest.new('default-process-retain-lines', 'process $input $output --format retain-lines'),
DarkluaTest.new('rename-dense', 'process $input $output --format dense', {
process = {{
rule = 'rename_variables',
globals = {'$default', '$roblox'},
}}
}),
DarkluaTest.new('rename-retain-lines', 'process $input $output --format retain-lines', {
process = {{
rule = 'rename_variables',
globals = {'$default', '$roblox'},
}}
}),
DarkluaTest.new('rename-all-retain-lines', 'process $input $output --format retain-lines', {
process = {{
rule = 'rename_variables',
globals = {'$default', '$roblox'},
include_functions = true,
}}
}),
DarkluaTest.new('process-retain-lines', 'process $input $output --format retain-lines', {
process = {
'compute_expression',
'remove_unused_if_branch',
'remove_unused_while',
'remove_empty_do',
{
rule = 'rename_variables',
globals = { '$default', '$roblox' },
},
'remove_function_call_parens',
}
}),
DarkluaTest.new('compress-dense', 'process $input $output --format dense', {
process = {
'compute_expression',
'remove_unused_if_branch',
'remove_unused_while',
'convert_index_to_field',
'remove_method_definition',
'convert_local_function_to_assign',
'group_local_assignment',
'remove_empty_do',
{
rule = 'rename_variables',
globals = {'$default', '$roblox'},
include_functions = true,
},
'remove_function_call_parens',
}
}),
}
local failFast = false
for i=1, select('#', ...) do
local argument = select(i, ...)
if argument == '--fail-fast' or argument == '-f' then
failFast = true
end
end
local results = {}
for _, test in ipairs(testSuite) do
results[test.Name] = {}
end
local allSuccess = true
local longestProjectNameLength = 0
for _, project in ipairs(projects) do
project:init()
longestProjectNameLength = math.max(
longestProjectNameLength,
project.RepositoryName:len()
)
for _, test in ipairs(testSuite) do
local success, message, cleanCallback = test:execute(project)
allSuccess = allSuccess and success
if not success and failFast then
print(message)
os.exit(1)
end
if cleanCallback then
cleanCallback()
end
results[test.Name][project.RepositoryName] = success
end
project:clean()
end
print('')
print('Printing test results')
for testName, projectResults in pairs(results) do
print((':'):rep(80))
print(('Test: %s'):format(testName))
for projectName, success in pairs(projectResults) do
local padding = (' '):rep(longestProjectNameLength - projectName:len())
print((' %s%s -> %s'):format(projectName, padding, success and 'ok' or 'failed !!!'))
end
print('')
end
if not allSuccess then
os.exit(1)
end