Skip to content

Commit

Permalink
autotest (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
myrrc committed Jun 5, 2024
1 parent 6eeb630 commit 5b68d0b
Show file tree
Hide file tree
Showing 22 changed files with 1,818 additions and 187 deletions.
2 changes: 1 addition & 1 deletion .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# These are supported funding model platforms

github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
github: myrrc
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: michaelmuszynski
Expand Down
22 changes: 22 additions & 0 deletions .github/workflows/wf.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: workflow
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: awalsh128/cache-apt-pkgs-action@latest
with: { packages: xdotool, version: 1.0 }
- uses: actions/checkout@v4
- id: cache
uses: actions/cache@v3
with: { path: tests/reaper, key: cache }
- if: steps.cache.outputs.cache-hit != 'true'
run: cd tests; chmod +x prepare; ./prepare
- run: |
export DISPLAY=:99; sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
cd tests; chmod +x copy-configs patch-settings test
./copy-configs
./patch-settings
./test
exit $?
8 changes: 1 addition & 7 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1 @@
internal/saved/data/*
!/internal/saved/data/.gitkeep
internal/gui/feedback/model_data.lua
internal/state_machine/state.lua
Scripts/gen
reaper-keys.ReaperKeyMap

tests/reaper
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
lint:
luacheck internal/ --globals gfx reaper
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,31 @@ internal/definitions/bindings.lua -> add or customise key bindings
internal/definitions/config.lua -> change GUI settings
```

## Reporting performance issues
## Contributing
### Running tests

For running tests locally you'd need some Linux distribution with X11 and `xdotool`.

```sh
cd tests;
chmod +x prepare copy-configs patch-settings test

./prepare # This will create a local Reaper installation
./copy-configs # This will make current instance of reaper-keys testable
./patch-settings # Or change test to true in internal/definitions/config.lua
./test # This will run every test and compare with reference projects
```

If you don't use X11 you can have a look at `.github/workflows/wf.yml` to see how x11 is
emulated with Xvfb.

### Writing tests

Each test is just a sequence of keys you press to achieve some result. One notable exception is
a hotkey or a special key like "Return" (Enter) or "Backspace". In that case, prefix line with
`&` and enter the key combination after, like `&Return`.

### Reporting performance issues

1. Download "Lua profiler" from ReaTeam Scripts and "ReaImGui" from ReaTeam Extensions via
ReaPack.
Expand Down
1 change: 1 addition & 0 deletions internal/definitions/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ local general = {
show_feedback_window = true,
search_for_custom_config = false,
profile = false,
test = false,
-- should operators in visual modes reset the selection or have it persist?
persist_visual_timeline_selection = true,
persist_visual_track_selection = false,
Expand Down
2 changes: 1 addition & 1 deletion internal/gui/feedback/controller.lua
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ function feedback.update()
feedback_view = FeedbackView:new()
feedback_view:open()

if config.show_start_up_message then
if config.show_start_up_message and not config.test then
reaper.ShowMessageBox(startup_msg, "Reaper Keys Open Message", 1)
end

Expand Down
6 changes: 3 additions & 3 deletions internal/state_machine/state_machine.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ local state_interface = require('state_machine.state_interface')
local buildCommand = require('command.builder')
local handleCommand = require('command.handler')
local getPossibleFutureEntries = require('command.completer')
local show_feedback_window = require 'definitions.config'.general.show_feedback_window
local config = require 'definitions.config'.general
local log = require('utils.log')
local format = require('utils.format')
local feedback = require('gui.feedback.controller')
Expand Down Expand Up @@ -127,14 +127,14 @@ local function input()
local hotkey = { context = section_id == 0 and "main" or "midi", key = ctxToState(ctx) }

log.info("Input: " .. format.line(hotkey))
if show_feedback_window then feedback.clear() end
if config.show_feedback_window and not config.test then feedback.clear() end

local state = state_interface.get()
local new_state = step(state, hotkey)
state_interface.set(new_state)

log.info("New state: " .. format.block(new_state))
if not show_feedback_window then return end
if config.test or not config.show_feedback_window then return end

feedback.displayState(new_state)
feedback.update()
Expand Down
108 changes: 54 additions & 54 deletions internal/utils/format.lua
Original file line number Diff line number Diff line change
@@ -1,83 +1,83 @@
local utils = require('command.utils')
local ser = require('serpent')
local string_util = require('string')
local utils = require 'command.utils'
local serpent = require 'serpent'
local string_util = require 'string'
local format = {}

function pairsByKeys(t, f)
local a = {}
for n in pairs(t) do
table.insert(a, n)
end
table.sort(a, f)
local i = 0
local iter = function ()
i = i + 1
if a[i] == nil then
return nil
else
return a[i], t[a[i]]
local function pairsByKeys(t, f)
local a = {}
for n in pairs(t) do
table.insert(a, n)
end
end
return iter
table.sort(a, f)
local i = 0
local iter = function()
i = i + 1
if a[i] == nil then
return nil
else
return a[i], t[a[i]]
end
end
return iter
end

function sortTableAlphabetically(table_to_sort)
local t = {}
for title,value in pairsByKeys(table_to_sort) do
table.insert(t, { title = title, value = value })
end
return t
local t = {}
for title, value in pairsByKeys(table_to_sort) do
table.insert(t, { title = title, value = value })
end
return t
end

function format.line(data)
return ser.line(data, {comment=false})
return serpent.line(data, { comment = false })
end

function format.block(data)
return ser.block(data, {comment=false})
return serpent.block(data, { comment = false })
end

function removeUglyBrackets(key)
local pretty_key = key
if string_util.sub(key, 1, 1) == "<" and string_util.sub(key, #key, #key) == ">" then
pretty_key = string_util.sub(key, 2, #key - 1)
end
local function removeUglyBrackets(key)
local pretty_key = key
if string_util.sub(key, 1, 1) == "<" and string_util.sub(key, #key, #key) == ">" then
pretty_key = string_util.sub(key, 2, #key - 1)
end

return pretty_key
return pretty_key
end

function format.keySequence(key_sequence, spacing)
local rest_of_key_seq = key_sequence
local key_sequence_string = ""
while #rest_of_key_seq ~= 0 do
first_key, rest_of_key_seq = utils.splitFirstKey(rest_of_key_seq)
if tonumber(first_key) or not spacing then
key_sequence_string = key_sequence_string .. first_key
else
key_sequence_string = key_sequence_string .. " " .. removeUglyBrackets(first_key)
local rest_of_key_seq = key_sequence
local key_sequence_string = ""
while #rest_of_key_seq ~= 0 do
first_key, rest_of_key_seq = utils.splitFirstKey(rest_of_key_seq)
if tonumber(first_key) or not spacing then
key_sequence_string = key_sequence_string .. first_key
else
key_sequence_string = key_sequence_string .. " " .. removeUglyBrackets(first_key)
end
end
end

return key_sequence_string
return key_sequence_string
end

---@param command Command
---@return string
function format.commandDescription(command)
local desc = ""
for _, command_part in pairs(command.action_keys) do
if type(command_part) == 'table' then
local name = command_part[1]
desc = desc .. '['
for _,additional_args in pairs(command_part) do
desc = desc .. ' ' .. additional_args
end
desc = desc .. ' ]'
else
desc = desc .. (command_part) .. " "
local desc = ""
for _, command_part in pairs(command.action_keys) do
if type(command_part) == 'table' then
local name = command_part[1]
desc = desc .. '['
for _, additional_args in pairs(command_part) do
desc = desc .. ' ' .. additional_args
end
desc = desc .. ' ]'
else
desc = desc .. (command_part) .. " "
end
end
end
return desc
return desc
end

return format
8 changes: 3 additions & 5 deletions internal/utils/get_action.lua
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
local actions = require("definitions.actions")
local actions = require "definitions.actions"

---@param action_name string
---@param name string
---@return Action | nil
function getAction(action_name)
return actions[action_name]
end
function getAction(name) return actions[name] end

return getAction
71 changes: 26 additions & 45 deletions internal/utils/project_state.lua
Original file line number Diff line number Diff line change
@@ -1,71 +1,52 @@
local log = require('utils.log')
local serpent = require('serpent')

local serpent = require 'serpent'
local project_state = {}

---@param ext string
---@param key string
---@param lua_table table | string
---@param lua_table table | string
function project_state.overwrite(ext, key, lua_table)
local current_project, _ = reaper.EnumProjects(-1, "")
local lua_table_string = serpent.block(lua_table, { comment = false })
reaper.SetProjExtState(current_project, ext, key, lua_table_string)
local current_project, _ = reaper.EnumProjects(-1, "")
local lua_table_string = serpent.block(lua_table, { comment = false })
reaper.SetProjExtState(current_project, ext, key, lua_table_string)
end

---@param ext string
function project_state.getAll(ext)
local keys = {}
local max_keys = 5000
local exists = false
for i=0,max_keys do
ok, key, val = reaper.EnumProjExtState(0, ext, i)
if not ok then
break
end

ok, lua_table = serpent.load(val)
if not ok then
return false, keys
local keys, max_keys, exists = {}, 5000, false
for i = 0, max_keys do
local enum_ok, key, val = reaper.EnumProjExtState(0, ext, i)
if not enum_ok then break end
local serpent_ok, lua_table = serpent.load(val)
if not serpent_ok then return false, keys end

keys[key] = lua_table
exists = true
end

keys[key] = lua_table
exists = true
end

return exists, keys
return exists, keys
end

---@param ext string
---@param key string
function project_state.get(ext, key)
local current_project, _ = reaper.EnumProjects(-1, "")
local exists, value = reaper.GetProjExtState(current_project, ext, key)
if exists and value then
local ok, lua_table = serpent.load(value)
if not ok or not lua_table then
return false, lua_table
end

if lua_table['deleted'] then
return false, lua_table
end

return ok, lua_table
end
local current_project, _ = reaper.EnumProjects(-1, "")
local exists, value = reaper.GetProjExtState(current_project, ext, key)
if not exists or not value then return false, 'Does not exist' end

return false, 'Does not exist'
local ok, table = serpent.load(value)
if not ok or not table or table.deleted then return false, table end
return ok, table
end

---@param ext string
---@param key string
function project_state.delete(ext, key)
-- reaper has the function 'DeleteExtState', but it dosen't work for project
-- state, so I introduce a 'deleted' key to indicate deletion
local ok, val = project_state.get(ext, key)
if ok and not val['deleted'] then
val['deleted'] = true
-- reaper has the function 'DeleteExtState', but it doesn't work for project
-- state, so I introduce a 'deleted' key to indicate deletion
local ok, val = project_state.get(ext, key)
if not ok or val.deleted then return end
val.deleted = true
project_state.overwrite(ext, key, val)
end
end

return project_state
Loading

1 comment on commit 5b68d0b

@molleweide
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is really impressive stuff

Please sign in to comment.