summaryrefslogtreecommitdiff
path: root/Data
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2021-10-26 11:32:46 +0800
committerchai <chaifix@163.com>2021-10-26 11:32:46 +0800
commit0549b1e5a8a3132005e275d6026db8003cb067d2 (patch)
treef0d7751ec32ecf5c4d23997fa0ffd3450a5a755a /Data
parent32345800737b668011a87328cd3dcce59ec2934c (diff)
*rename folder
Diffstat (limited to 'Data')
-rw-r--r--Data/.vscode/KillEditor.bat1
-rw-r--r--Data/.vscode/LaunchEditor.bat1
-rw-r--r--Data/.vscode/launch.json37
-rw-r--r--Data/.vscode/settings.json3
-rw-r--r--Data/.vscode/tasks.json19
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Class.lua38
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Animation/Animation.lua0
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Animation/init.lua6
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Core/Camera.lua5
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Core/Component.lua11
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Core/Game.lua14
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Core/GameObject.lua7
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Core/Sprite.lua21
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/GL/init.lua20
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Math/Math.lua21
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix33.lua7
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix44.lua73
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Math/Quaternion.lua14
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector2.lua5
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector3.lua5
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector4.lua45
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Math/init.lua16
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color.lua36
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color32.lua36
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Rendering/init.lua13
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Utils/EventCenter.lua23
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Utils/StateMachine.lua0
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/Utils/Util.lua0
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Engine/init.lua5
-rw-r--r--Data/DefaultContent/Libraries/GameLab/Enum.lua9
-rw-r--r--Data/DefaultContent/Libraries/GameLab/InternalClass.lua12
-rw-r--r--Data/DefaultContent/Libraries/GameLab/init.lua41
-rw-r--r--Data/DefaultContent/Libraries/LiteJson/LICENSE20
-rw-r--r--Data/DefaultContent/Libraries/LiteJson/README.md46
-rw-r--r--Data/DefaultContent/Libraries/LiteJson/bench/bench_all.lua6
-rw-r--r--Data/DefaultContent/Libraries/LiteJson/bench/bench_decode.lua75
-rw-r--r--Data/DefaultContent/Libraries/LiteJson/bench/bench_encode.lua63
-rw-r--r--Data/DefaultContent/Libraries/LiteJson/bench/get_json_libs.sh15
-rw-r--r--Data/DefaultContent/Libraries/LiteJson/bench/util/bench.lua62
-rw-r--r--Data/DefaultContent/Libraries/LiteJson/json.lua388
-rw-r--r--Data/DefaultContent/Libraries/LiteJson/test/test.lua245
-rw-r--r--Data/DefaultContent/Libraries/containers/README.md202
-rw-r--r--Data/DefaultContent/Libraries/containers/list.lua199
-rw-r--r--Data/DefaultContent/Libraries/containers/queue.lua111
-rw-r--r--Data/DefaultContent/Libraries/containers/stack.lua67
-rw-r--r--Data/DefaultContent/Libraries/containers/tuple.lua60
-rw-r--r--Data/DefaultContent/Libraries/containers/vector.lua122
-rw-r--r--Data/DefaultContent/Libraries/inspect/.travis.yml36
-rw-r--r--Data/DefaultContent/Libraries/inspect/CHANGELOG.md39
-rw-r--r--Data/DefaultContent/Libraries/inspect/MIT-LICENSE.txt20
-rw-r--r--Data/DefaultContent/Libraries/inspect/README.md253
-rw-r--r--Data/DefaultContent/Libraries/inspect/inspect.lua334
-rw-r--r--Data/DefaultContent/Libraries/inspect/rockspecs/inspect-1.2-2.rockspec23
-rw-r--r--Data/DefaultContent/Libraries/inspect/rockspecs/inspect-2.0-1.rockspec23
-rw-r--r--Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-1.rockspec23
-rw-r--r--Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-2.rockspec23
-rw-r--r--Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-3.rockspec23
-rw-r--r--Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-4.rockspec23
-rw-r--r--Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.1.1-0.rockspec23
-rw-r--r--Data/DefaultContent/Libraries/inspect/spec/inspect_spec.lua460
-rw-r--r--Data/DefaultContent/Libraries/inspect/spec/unindent.lua39
-rw-r--r--Data/DefaultContent/Libraries/json4lua/README.md52
-rw-r--r--Data/DefaultContent/Libraries/json4lua/doc/INSTALL.txt4
-rw-r--r--Data/DefaultContent/Libraries/json4lua/doc/LICENCE.txt21
-rw-r--r--Data/DefaultContent/Libraries/json4lua/doc/README.txt5
-rw-r--r--Data/DefaultContent/Libraries/json4lua/doc/VERSION.txt4
-rw-r--r--Data/DefaultContent/Libraries/json4lua/doc/cgilua_patch.html187
-rw-r--r--Data/DefaultContent/Libraries/json4lua/doc/index.html394
-rw-r--r--Data/DefaultContent/Libraries/json4lua/doc/pics/json4lua.gifbin0 -> 5023 bytes
-rw-r--r--Data/DefaultContent/Libraries/json4lua/doc/pics/lunartone.gifbin0 -> 312 bytes
-rw-r--r--Data/DefaultContent/Libraries/json4lua/examples/example.lua23
-rw-r--r--Data/DefaultContent/Libraries/json4lua/examples/jsonrpc.lua21
-rw-r--r--Data/DefaultContent/Libraries/json4lua/examples/tests.lua223
-rw-r--r--Data/DefaultContent/Libraries/json4lua/examples/timetrials.lua46
-rw-r--r--Data/DefaultContent/Libraries/json4lua/json/json.lua427
-rw-r--r--Data/DefaultContent/Libraries/json4lua/json/rpc.lua107
-rw-r--r--Data/DefaultContent/Libraries/json4lua/json/rpcserver.lua78
-rw-r--r--Data/DefaultContent/Libraries/json4lua/json4lua-1.0.0-1.rockspec32
-rw-r--r--Data/DefaultContent/Libraries/lbase64/.gitignore3
-rw-r--r--Data/DefaultContent/Libraries/lbase64/.travis.yml25
-rw-r--r--Data/DefaultContent/Libraries/lbase64/README.md48
-rw-r--r--Data/DefaultContent/Libraries/lbase64/base64.lua201
-rw-r--r--Data/DefaultContent/Libraries/lbase64/bench.lua76
-rw-r--r--Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-1.rockspec20
-rw-r--r--Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-2.rockspec20
-rw-r--r--Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-3.rockspec20
-rw-r--r--Data/DefaultContent/Libraries/lbase64/test.lua47
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/.gitignore2
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/AUTHORS2
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/LICENSE22
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/README.md93
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/lua/config.ld4
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/lua/csv.lua557
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/lua/test.lua102
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/makefile14
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-1-1.rockspec24
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-scm-1.rockspec23
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/test-data/BOM.csv3
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/test-data/bars.txt7
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/test-data/blank-line.csv2
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/test-data/embedded-newlines.csv8
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/test-data/embedded-quotes.csv2
-rw-r--r--Data/DefaultContent/Libraries/lua-csv/test-data/header.csv3
-rw-r--r--Data/DefaultContent/Libraries/luafun/.gitignore4
-rw-r--r--Data/DefaultContent/Libraries/luafun/.travis.yml74
-rw-r--r--Data/DefaultContent/Libraries/luafun/CONTRIBUTING.md20
-rw-r--r--Data/DefaultContent/Libraries/luafun/COPYING.md27
-rw-r--r--Data/DefaultContent/Libraries/luafun/README.md107
-rw-r--r--Data/DefaultContent/Libraries/luafun/debian/.gitignore8
-rw-r--r--Data/DefaultContent/Libraries/luafun/debian/changelog5
-rw-r--r--Data/DefaultContent/Libraries/luafun/debian/compat1
-rw-r--r--Data/DefaultContent/Libraries/luafun/debian/control20
-rw-r--r--Data/DefaultContent/Libraries/luafun/debian/copyright31
-rw-r--r--Data/DefaultContent/Libraries/luafun/debian/lua-fun.docs1
-rw-r--r--Data/DefaultContent/Libraries/luafun/debian/lua5.1.dh-lua.conf4
-rw-r--r--Data/DefaultContent/Libraries/luafun/debian/lua5.2.dh-lua.conf1
-rw-r--r--Data/DefaultContent/Libraries/luafun/debian/lua5.3.dh-lua.conf1
-rw-r--r--Data/DefaultContent/Libraries/luafun/debian/patches/series0
-rw-r--r--Data/DefaultContent/Libraries/luafun/debian/rules12
-rw-r--r--Data/DefaultContent/Libraries/luafun/debian/source/format1
-rw-r--r--Data/DefaultContent/Libraries/luafun/debian/watch6
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/.gitignore1
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/Makefile153
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/_static/.keep0
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/_templates/layout.html14
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/about.rst42
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/basic.rst141
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/compositions.rst140
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/conf.py247
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/filtering.rst121
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/generators.rst233
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/getting_started.rst254
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/index.rst29
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/indexing.rst74
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/intro.rst69
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/logo.pngbin0 -> 14370 bytes
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/logo.svg758
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/make.bat190
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/operators.rst203
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/reducing.rst323
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/reference.rst14
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/slicing.rst246
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/transformations.rst87
-rw-r--r--Data/DefaultContent/Libraries/luafun/doc/under_the_hood.rst154
-rw-r--r--Data/DefaultContent/Libraries/luafun/fun-scm-1.rockspec34
-rw-r--r--Data/DefaultContent/Libraries/luafun/fun.lua1058
-rw-r--r--Data/DefaultContent/Libraries/luafun/rpm/lua-fun.spec76
-rw-r--r--Data/DefaultContent/Libraries/luafun/tests/.gitignore1
-rw-r--r--Data/DefaultContent/Libraries/luafun/tests/basic.lua332
-rw-r--r--Data/DefaultContent/Libraries/luafun/tests/compositions.lua170
-rw-r--r--Data/DefaultContent/Libraries/luafun/tests/filtering.lua102
-rw-r--r--Data/DefaultContent/Libraries/luafun/tests/generators.lua287
-rw-r--r--Data/DefaultContent/Libraries/luafun/tests/indexing.lua83
-rw-r--r--Data/DefaultContent/Libraries/luafun/tests/operators.lua322
-rw-r--r--Data/DefaultContent/Libraries/luafun/tests/reducing.lua289
-rw-r--r--Data/DefaultContent/Libraries/luafun/tests/runtest114
-rw-r--r--Data/DefaultContent/Libraries/luafun/tests/slicing.lua339
-rw-r--r--Data/DefaultContent/Libraries/luafun/tests/transformations.lua107
-rw-r--r--Data/DefaultContent/Libraries/md5.lua/.travis.yml34
-rw-r--r--Data/DefaultContent/Libraries/md5.lua/CHANGELOG.md5
-rw-r--r--Data/DefaultContent/Libraries/md5.lua/MIT-LICENSE.txt20
-rw-r--r--Data/DefaultContent/Libraries/md5.lua/README.md62
-rw-r--r--Data/DefaultContent/Libraries/md5.lua/md5.lua396
-rw-r--r--Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-0.rockspec21
-rw-r--r--Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-1.rockspec21
-rw-r--r--Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-2.rockspec21
-rw-r--r--Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.1-0.rockspec21
-rw-r--r--Data/DefaultContent/Libraries/md5.lua/spec/md5_spec.lua40
-rw-r--r--Data/DefaultContent/Libraries/middleclass/.travis.yml36
-rw-r--r--Data/DefaultContent/Libraries/middleclass/CHANGELOG.md55
-rw-r--r--Data/DefaultContent/Libraries/middleclass/MIT-LICENSE.txt20
-rw-r--r--Data/DefaultContent/Libraries/middleclass/README.md80
-rw-r--r--Data/DefaultContent/Libraries/middleclass/UPDATING.md69
-rw-r--r--Data/DefaultContent/Libraries/middleclass/middleclass.lua183
-rw-r--r--Data/DefaultContent/Libraries/middleclass/performance/run.lua43
-rw-r--r--Data/DefaultContent/Libraries/middleclass/performance/time.lua13
-rw-r--r--Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.0-0.rockspec21
-rw-r--r--Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.1-0.rockspec21
-rw-r--r--Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.2-0.rockspec21
-rw-r--r--Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.0-0.rockspec21
-rw-r--r--Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1-0.rockspec21
-rw-r--r--Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1.1-0.rockspec21
-rw-r--r--Data/DefaultContent/Libraries/middleclass/spec/class_spec.lua28
-rw-r--r--Data/DefaultContent/Libraries/middleclass/spec/classes_spec.lua138
-rw-r--r--Data/DefaultContent/Libraries/middleclass/spec/default_methods_spec.lua236
-rw-r--r--Data/DefaultContent/Libraries/middleclass/spec/instances_spec.lua65
-rw-r--r--Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_2.lua85
-rw-r--r--Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_3.lua106
-rw-r--r--Data/DefaultContent/Libraries/middleclass/spec/metamethods_spec.lua317
-rw-r--r--Data/DefaultContent/Libraries/middleclass/spec/mixins_spec.lua53
-rw-r--r--Data/DefaultContent/Libraries/socket/README.txt1
-rw-r--r--Data/DefaultContent/Libraries/socket/core.dllbin0 -> 104448 bytes
-rw-r--r--Data/DefaultContent/Textures/blank.pngbin0 -> 188 bytes
-rw-r--r--Data/DefaultContent/readme.txt6
-rw-r--r--Data/Libraries/GameLab/Editor/Animation/init.lua0
-rw-r--r--Data/Libraries/GameLab/Editor/AssetManager.lua8
-rw-r--r--Data/Libraries/GameLab/Editor/GUI/EditorWindow.lua23
-rw-r--r--Data/Libraries/GameLab/Editor/GUI/Functions.lua0
-rw-r--r--Data/Libraries/GameLab/Editor/GUI/init.lua10
-rw-r--r--Data/Libraries/GameLab/Editor/Resource/init.lua1
-rw-r--r--Data/Libraries/GameLab/Editor/init.lua2
-rw-r--r--Data/Libraries/LuaPanda/LuaPanda.lua3606
-rw-r--r--Data/Libraries/LuaPanda/README.txt1
-rw-r--r--Data/Libraries/luaunit/.appveyor/install-lua.cmd133
-rw-r--r--Data/Libraries/luaunit/.appveyor/install-luajit.cmd25
-rw-r--r--Data/Libraries/luaunit/.gitignore65
-rw-r--r--Data/Libraries/luaunit/.luacheckrc26
-rw-r--r--Data/Libraries/luaunit/.travis.yml47
-rw-r--r--Data/Libraries/luaunit/.travis/emulate_travis.sh16
-rw-r--r--Data/Libraries/luaunit/.travis/setup_lua.sh231
-rw-r--r--Data/Libraries/luaunit/LICENSE.txt12
-rw-r--r--Data/Libraries/luaunit/README.md267
-rw-r--r--Data/Libraries/luaunit/TODO.txt223
-rw-r--r--Data/Libraries/luaunit/appveyor.yml42
-rw-r--r--Data/Libraries/luaunit/doc/Makefile177
-rw-r--r--Data/Libraries/luaunit/doc/conf.py259
-rw-r--r--Data/Libraries/luaunit/doc/index.rst2644
-rw-r--r--Data/Libraries/luaunit/doc/make.bat241
-rw-r--r--Data/Libraries/luaunit/doc/my_test_suite.lua127
-rw-r--r--Data/Libraries/luaunit/doit.py237
-rw-r--r--Data/Libraries/luaunit/example_with_luaunit.lua150
-rw-r--r--Data/Libraries/luaunit/junitxml/Makefile17
-rw-r--r--Data/Libraries/luaunit/junitxml/XMLJUnitResultFormatter.java.txt301
-rw-r--r--Data/Libraries/luaunit/junitxml/example-apache-ant.xml31
-rw-r--r--Data/Libraries/luaunit/junitxml/example-bamboo-1.xml70
-rw-r--r--Data/Libraries/luaunit/junitxml/example-bamboo-2.xml56
-rw-r--r--Data/Libraries/luaunit/junitxml/example-jenkins.xml29
-rw-r--r--Data/Libraries/luaunit/junitxml/junit-apache-ant.xsd206
-rw-r--r--Data/Libraries/luaunit/junitxml/junit-jenkins.xsd91
-rw-r--r--Data/Libraries/luaunit/junitxml/notes-junit-compatibility.txt34
-rw-r--r--Data/Libraries/luaunit/luaunit-3.4-1.rockspec48
-rw-r--r--Data/Libraries/luaunit/luaunit.lua3453
-rw-r--r--Data/Libraries/luaunit/run_functional_tests.lua820
-rw-r--r--Data/Libraries/luaunit/run_unit_tests.lua30
-rw-r--r--Data/Libraries/luaunit/test/check_lua_calc_error.lua23
-rw-r--r--Data/Libraries/luaunit/test/compat_luaunit_v2x.lua175
-rw-r--r--Data/Libraries/luaunit/test/legacy_example_with_luaunit.lua140
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassNilDefault-failures.txt0
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassNilDefault-success.txt0
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassNilDefault.txt0
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTapDefault-failures.txt20
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTapDefault-success.txt10
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTapDefault.txt30
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTapQuiet-failures.txt15
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTapQuiet-success.txt10
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTapQuiet.txt20
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTapVerbose-failures.txt30
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTapVerbose-success.txt10
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTapVerbose.txt50
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTextDefault-failures.txt29
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTextDefault-success.txt3
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTextDefault.txt56
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTextQuiet-failures.txt29
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTextQuiet-success.txt3
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTextQuiet.txt56
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-1.txt3
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-2.txt25
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-3.txt13
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-4.txt13
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTextVerbose-failures.txt45
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTextVerbose-success.txt9
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassTextVerbose.txt82
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-failures.txt20
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-failures.xml46
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-success.txt10
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-success.xml21
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlDefault.txt30
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlDefault.xml71
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-failures.txt20
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-failures.xml46
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-success.txt10
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-success.xml21
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet.txt30
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet.xml71
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-failures.txt20
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-failures.xml46
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-success.txt10
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-success.xml21
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose.txt30
-rw-r--r--Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose.xml71
-rw-r--r--Data/Libraries/luaunit/test/ref/errPassFailTapQuiet.txt20
-rw-r--r--Data/Libraries/luaunit/test/ref/exampleNilDefault.txt0
-rw-r--r--Data/Libraries/luaunit/test/ref/exampleTapDefault.txt36
-rw-r--r--Data/Libraries/luaunit/test/ref/exampleTapQuiet.txt21
-rw-r--r--Data/Libraries/luaunit/test/ref/exampleTapVerbose.txt63
-rw-r--r--Data/Libraries/luaunit/test/ref/exampleTextDefault.txt72
-rw-r--r--Data/Libraries/luaunit/test/ref/exampleTextQuiet.txt72
-rw-r--r--Data/Libraries/luaunit/test/ref/exampleTextVerbose.txt105
-rw-r--r--Data/Libraries/luaunit/test/ref/exampleXmlDefault.txt36
-rw-r--r--Data/Libraries/luaunit/test/ref/exampleXmlDefault.xml86
-rw-r--r--Data/Libraries/luaunit/test/ref/exampleXmlQuiet.txt36
-rw-r--r--Data/Libraries/luaunit/test/ref/exampleXmlQuiet.xml86
-rw-r--r--Data/Libraries/luaunit/test/ref/exampleXmlVerbose.txt36
-rw-r--r--Data/Libraries/luaunit/test/ref/exampleXmlVerbose.xml86
-rw-r--r--Data/Libraries/luaunit/test/ref/some_lists_comparisons.txt844
-rw-r--r--Data/Libraries/luaunit/test/ref/testWithXmlDefault.txt11
-rw-r--r--Data/Libraries/luaunit/test/ref/testWithXmlDefault.xml25
-rw-r--r--Data/Libraries/luaunit/test/ref/testWithXmlQuiet.txt11
-rw-r--r--Data/Libraries/luaunit/test/ref/testWithXmlQuiet.xml25
-rw-r--r--Data/Libraries/luaunit/test/ref/testWithXmlVerbose.txt11
-rw-r--r--Data/Libraries/luaunit/test/ref/testWithXmlVerbose.xml25
-rw-r--r--Data/Libraries/luaunit/test/some_lists_comparisons.lua147
-rw-r--r--Data/Libraries/luaunit/test/test_luaunit.lua4413
-rw-r--r--Data/Libraries/luaunit/test/test_with_err_fail_pass.lua71
-rw-r--r--Data/Libraries/luaunit/test/test_with_xml.lua23
-rw-r--r--Data/Resources/Icon/GameLab.icobin0 -> 32870 bytes
-rw-r--r--Data/Resources/Images/UI.csv2
-rw-r--r--Data/Resources/Images/UI.xlsxbin0 -> 6625 bytes
-rw-r--r--Data/Resources/Shaders/UI.glsl12
-rw-r--r--Data/Scripts/Editor/AssetBrowser.lua28
-rw-r--r--Data/Scripts/Editor/Properties.lua4
-rw-r--r--Data/Scripts/EditorApplication.lua71
-rw-r--r--Data/Scripts/EditorGUI/EditorImages.lua2
-rw-r--r--Data/Scripts/EditorGUI/EditorWindowManager.lua5
-rw-r--r--Data/Scripts/Utils/Utils.lua4
-rw-r--r--Data/boot.lua33
-rw-r--r--Data/macro.lua3
-rw-r--r--Data/readme.txt7
318 files changed, 37734 insertions, 0 deletions
diff --git a/Data/.vscode/KillEditor.bat b/Data/.vscode/KillEditor.bat
new file mode 100644
index 0000000..8ba7d7a
--- /dev/null
+++ b/Data/.vscode/KillEditor.bat
@@ -0,0 +1 @@
+taskkill /f /im Editor.exe \ No newline at end of file
diff --git a/Data/.vscode/LaunchEditor.bat b/Data/.vscode/LaunchEditor.bat
new file mode 100644
index 0000000..bb9661c
--- /dev/null
+++ b/Data/.vscode/LaunchEditor.bat
@@ -0,0 +1 @@
+start "GameLabEditor" cmd /c "timeout 3 & ..\Build\Editor.exe" \ No newline at end of file
diff --git a/Data/.vscode/launch.json b/Data/.vscode/launch.json
new file mode 100644
index 0000000..94088ea
--- /dev/null
+++ b/Data/.vscode/launch.json
@@ -0,0 +1,37 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "lua",
+ "request": "launch",
+ "tag": "normal",
+ "name": "LuaPanda",
+ "description": "通用模式,通常调试项目请选择此模式 | launchVer:3.2.0",
+ "cwd": "${workspaceFolder}",
+ "luaFileExtension": "",
+ "connectionPort": 8818,
+ "stopOnEntry": false,
+ "useCHook": true,
+ "autoPathMode": true,
+ // 自动启动编辑器
+ "program": "${workspaceFolder}/../Build/Editor.exe", "postDebugTask": "KillEditor"
+ //"preLaunchTask": "LaunchEditor", "postDebugTask": "KillEditor"
+ },
+ {
+ "type": "lua",
+ "request": "launch",
+ "tag": "independent_file",
+ "name": "LuaPanda-IndependentFile",
+ "description": "独立文件调试模式,使用前请参考文档",
+ "luaPath": "",
+ "packagePath": [],
+ "luaFileExtension": "",
+ "connectionPort": 8820,
+ "stopOnEntry": false,
+ "useCHook": true
+ }
+ ]
+} \ No newline at end of file
diff --git a/Data/.vscode/settings.json b/Data/.vscode/settings.json
new file mode 100644
index 0000000..55d72f8
--- /dev/null
+++ b/Data/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "lua_analyzer.codeLinting.ignoreErrorCode": "611;612;613;614;542;631"
+} \ No newline at end of file
diff --git a/Data/.vscode/tasks.json b/Data/.vscode/tasks.json
new file mode 100644
index 0000000..6409b18
--- /dev/null
+++ b/Data/.vscode/tasks.json
@@ -0,0 +1,19 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "LaunchEditor",
+ "type": "shell",
+ "command": "${workspaceFolder}/.vscode/LaunchEditor.bat"
+ },
+ {
+ "label": "KillEditor",
+ "type": "shell",
+ "command": "${workspaceFolder}/.vscode/KillEditor.bat",
+ "isBackground": true,
+ "presentation": {
+ "reveal": "never" // 在终端里隐藏
+ },
+ }
+ ]
+} \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Class.lua b/Data/DefaultContent/Libraries/GameLab/Class.lua
new file mode 100644
index 0000000..62369e1
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Class.lua
@@ -0,0 +1,38 @@
+-- Declare class
+
+local _class = function (className)
+ local class = {}
+ local pkgName = (type(className) == "string") and string.match(className, "^(.+)%.%w+$") or ""
+ local shortName = (type(className) == "string") and string.match(className, "%.*(%w+)$") or ""
+ class._type = { -- 类型元数据,GameLab的类型都会包含这些
+ mode = "lua",
+ name = shortName or "",
+ package = pkgName or "",
+ fullName = className
+ }
+ class.__index = class
+ class.New = function(...)
+ local instance = {}
+ setmetatable(instance, class)
+ instance:Ctor(...)
+ return instance
+ end
+ return class
+end
+
+-- 提供ClassName和PkgName作为类型的元数据,可以留空,但是最好提供,会作为类型判断的依据
+local Class = function(className)
+ local cls = _class(className)
+ cls.Extend = function(childName)
+ local child = _class(childName)
+ if cls then
+ setmetatable(child, cls)
+ child.base = cls
+ end
+ return child
+ end
+ return cls
+end
+
+GameLab.Class = Class
+return Class \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Animation/Animation.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Animation/Animation.lua
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Animation/Animation.lua
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Animation/init.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Animation/init.lua
new file mode 100644
index 0000000..032f42d
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Animation/init.lua
@@ -0,0 +1,6 @@
+GameLab.Animation = GameLab.Animation or {}
+local m = GameLab.Animation
+
+
+
+return m \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Core/Camera.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Camera.lua
new file mode 100644
index 0000000..5fcfbe7
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Camera.lua
@@ -0,0 +1,5 @@
+local Camera = {}
+
+
+
+return Camera \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Core/Component.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Component.lua
new file mode 100644
index 0000000..00bf2ca
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Component.lua
@@ -0,0 +1,11 @@
+local Component = {}
+
+Component.New = function()
+
+end
+
+Component.GetGameObject = function()
+
+end
+
+Jin.Component = Component \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Core/Game.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Game.lua
new file mode 100644
index 0000000..51ce25f
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Game.lua
@@ -0,0 +1,14 @@
+
+-- Game entry
+
+local Game = {}
+
+Game.OnEvent = function(e)
+
+end
+
+Game.MainLoop = function()
+
+end
+
+return Game \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Core/GameObject.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Core/GameObject.lua
new file mode 100644
index 0000000..ee0d143
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Core/GameObject.lua
@@ -0,0 +1,7 @@
+local GameObject = {}
+
+GameObject.AddComponent = function(self, comp)
+
+end
+
+Jin.GameObject = GameObject
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Core/Sprite.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Sprite.lua
new file mode 100644
index 0000000..47cb50d
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Core/Sprite.lua
@@ -0,0 +1,21 @@
+-- Quadķװʺ2DϷ
+local Sprite = {}
+
+Sprite.New = function(quad)
+ local spr = {}
+ spr.quad = Jin.Quad.New(quad)
+ spr.pivot = Jin.Vector2.New(0.5, 0)
+ spr.transform = Jin.Transform.New()
+ spr.depth = 0
+ return spr
+end
+
+Sprite.SetDepth = function(self, depth)
+ spr.depth = depth
+end
+
+Sprite.SetTexture = function(self, tex, reset_quad)
+
+end
+
+Jin.Sprite = Sprite \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/GL/init.lua b/Data/DefaultContent/Libraries/GameLab/Engine/GL/init.lua
new file mode 100644
index 0000000..f69d1f6
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/GL/init.lua
@@ -0,0 +1,20 @@
+local GL = GameLab.Engine.GL or {}
+GameLab.Engine.GL = GL
+
+local Matrix44 = GameLab.find("GameLab.Engine.Math.Matrix44")
+
+GL.LoadPixelMatrix = function(l, r, b, t)
+ local ortho = Matrix44.New()
+ ortho:SetOrtho(l, r, b, t, 0.1, 10)
+ GL.MatrixMode(GL.EMatrixMode.Projection)
+ GL.LoadIdentity()
+ GL.LoadMatrix(ortho)
+ GL.MatrixMode(GL.EMatrixMode.ModelView)
+ GL.LoadIdentity()
+end
+
+GL.LoadPixelMatrixTL = function (l, r, b, t)
+
+end
+
+return GL \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/Math.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Math.lua
new file mode 100644
index 0000000..0bbe7f0
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Math.lua
@@ -0,0 +1,21 @@
+-- 数学函数
+local m = GameLab.Engine.Math or {}
+GameLab.Engine.Math = m
+
+m.Abs = function(n)
+
+end
+
+m.Lerp = function (a, b, t)
+
+end
+
+m.Round = function (n)
+
+end
+
+m.Sign = function(n)
+
+end
+
+return m \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix33.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix33.lua
new file mode 100644
index 0000000..8cb7e72
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix33.lua
@@ -0,0 +1,7 @@
+local Matrix33 = GameLab.Class("GameLab.Engine.Math.Matrix33")
+
+Matrix33.Ctor = function(self)
+
+end
+
+return Matrix33 \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix44.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix44.lua
new file mode 100644
index 0000000..2347207
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Matrix44.lua
@@ -0,0 +1,73 @@
+local Matrix44 = GameLab.Class("GameLab.Engine.Math.Matrix44")
+
+Matrix44.Ctor = function(self)
+ for r = 0, 3 do
+ for c = 0, 3 do
+ self["m"..r..c] = 0
+ end
+ end
+end
+
+Matrix44.Clear = function(self)
+ for r = 0, 3 do
+ for c = 0, 3 do
+ self["m"..r..c] = 0
+ end
+ end
+end
+
+Matrix44.SetRow = function(self, row, value)
+
+end
+
+Matrix44.SetColum = function(self, colum, value)
+
+end
+
+Matrix44.Set = function(self, row, colum ,value)
+
+end
+
+Matrix44.GetColum = function(self, colum)
+
+end
+
+Matrix44.GetRow = function(self, row)
+
+end
+
+-- note: n>0, f>0
+Matrix44.SetOrtho = function(self, l, r, b, t, n, f)
+ self:Clear()
+ self.m00 = 2 / (r - l)
+ self.m03 = (r + l) / (l - r)
+ self.m11 = 2 / (t - b)
+ self.m13 = (t + b) / (b - t)
+ self.m22 = 2 / (n - f)
+ self.m23 = (f + n) / (n - f)
+ self.m33 = 1
+end
+
+-- note: n>0, f>0
+Matrix44.SetFrustum = function(self, l, r, b, t, n, f)
+ self:Clear()
+ self.m00 = 2 * n / (r - l)
+ self.m02 = (r + l) / (r - l)
+ self.m11 = 2 * n / (t - b)
+ self.m12 = (t + b) / (t - b)
+ self.m22 = (f + n) / (n - f)
+ self.m23 = 2 * f * n / (n - f)
+ self.m32 = -1
+end
+
+-- note: n>0, f>0
+Matrix44.SetPerspective = function(self, fov, aspect, near, far)
+ self:Clear()
+ self.m00 = 1 / (aspect * math.tan(fov/2))
+ self.m11 = 1 / math.tan(fov/2)
+ self.m22 = (far + near) / (near - far)
+ self.m23 = 2 * far * near / (near - far)
+ self.m32 = -1
+end
+
+return Matrix44 \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/Quaternion.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Quaternion.lua
new file mode 100644
index 0000000..4d690e3
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Quaternion.lua
@@ -0,0 +1,14 @@
+local Quaternion = {}
+
+Quaternion.Ctor = function(self)
+ self.x = 0
+ self.y = 0
+ self.z = 0
+ self.w = 0
+end
+
+Quaternion.Euler = function(euler)
+
+end
+
+return Quaternion \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector2.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector2.lua
new file mode 100644
index 0000000..5697797
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector2.lua
@@ -0,0 +1,5 @@
+local Vector2 = GameLab.Class("GameLab.Engine.Math.Vector2")
+
+
+
+return Vector2 \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector3.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector3.lua
new file mode 100644
index 0000000..caa28a4
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector3.lua
@@ -0,0 +1,5 @@
+local Vector3 = GameLab.Class("GameLab.Engine.Math.Vector3")
+
+
+
+return Vector3 \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector4.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector4.lua
new file mode 100644
index 0000000..e232c93
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/Vector4.lua
@@ -0,0 +1,45 @@
+local Vector4 = GameLab.Class("GameLab.Engine.Math.Vector4")
+
+Vector4.Ctor = function (self, x, y, z, w)
+ self.x = x or 0
+ self.y = y or 0
+ self.z = z or 0
+ self.w = w or 0
+end
+
+Vector4.Magnitude = function (self)
+
+end
+
+Vector4.Normalized = function (self)
+
+end
+
+Vector4.SqrMagnitude = function (self)
+
+end
+
+Vector4.Distance = function (self, to)
+
+end
+
+Vector4.Dot = function(self, v)
+
+end
+
+Vector4.Lerp = function(self, v, t)
+
+end
+
+Vector4.Project = function (self, v)
+
+end
+
+Vector4.Scale = function(self, scale)
+
+end
+
+Vector4.one = Vector4.New(1,1,1,1)
+Vector4.zero = Vector4.New(0,0,0,0)
+
+return Vector4 \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Math/init.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Math/init.lua
new file mode 100644
index 0000000..eb75db7
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Math/init.lua
@@ -0,0 +1,16 @@
+local m = GameLab.Engine.Math or {}
+GameLab.Engine.Math = m
+
+local import = GameLab.import(...)
+
+import("Math")
+m.Vector2 = import("Vector2")
+m.Vector3 = import("Vector3")
+m.Vector4 = import("Vector4")
+m.Matrix44 = import("Matrix44")
+m.Matrix33 = import("Matrix33")
+m.Quaternion = import("Quaternion")
+
+GameLab.Debug.Log("GameLab.Engine.Math loaded")
+
+return m \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color.lua
new file mode 100644
index 0000000..bf908a4
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color.lua
@@ -0,0 +1,36 @@
+local Color = GameLab.Class("GameLab.Engine.Rendering.Color")
+
+Color.Ctor = function(self, r, g, b, a)
+ self.r = r
+ self.g = g
+ self.b = b
+ self.a = a
+end
+
+Color.ToColor32 = function(self)
+ local Color32 = GameLab.find("GameLab.Engine.Rendering.Color32")
+ local c32 = Color32.New()
+ c32.r = self.r * 255
+ c32.g = self.g * 255
+ c32.b = self.b * 255
+ c32.a = self.a * 255
+ return c32
+end
+
+Color.Clear = function(self)
+ self.r = 0
+ self.g = 0
+ self.b = 0
+ self.a = 0
+end
+
+Color.red = Color.New(1,0,0,1)
+Color.green = Color.New(0,1,0,1)
+Color.blue = Color.New(0,0,1,1)
+Color.magenta = Color.New(1,0,1,1)
+Color.red = Color.New(1,0,0,1)
+Color.yellow = Color.New(1,1,0,1)
+Color.black = Color.New(0,0,0,1)
+Color.white = Color.New(1,1,1,1)
+
+return Color \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color32.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color32.lua
new file mode 100644
index 0000000..d108dfb
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/Color32.lua
@@ -0,0 +1,36 @@
+local Color32 = GameLab.Class("GameLab.Engine.Rendering.Color32")
+
+Color32.Ctor = function(self, r, g, b, a)
+ self.r = r
+ self.g = g
+ self.b = b
+ self.a = a
+end
+
+Color32.ToColor = function(self)
+ local Color = GameLab.find("GameLab.Engine.Rendering.Color")
+ local c = Color.New()
+ c.r = self.r / 255
+ c.g = self.g / 255
+ c.b = self.b / 255
+ c.a = self.a / 255
+ return c
+end
+
+Color32.Clear = function(self)
+ self.r = 0
+ self.g = 0
+ self.b = 0
+ self.a = 0
+end
+
+Color32.red = Color32.New(255,0,0,255)
+Color32.green = Color32.New(0,255,0,255)
+Color32.blue = Color32.New(0,0,255,255)
+Color32.magenta = Color32.New(255,0,255,255)
+Color32.red = Color32.New(255,0,0,255)
+Color32.yellow = Color32.New(255,255,0,255)
+Color32.black = Color32.New(0,0,0,255)
+Color32.white = Color32.New(255,255,255,255)
+
+return Color32 \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/init.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/init.lua
new file mode 100644
index 0000000..d9b4e3e
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Rendering/init.lua
@@ -0,0 +1,13 @@
+local m = GameLab.Engine.Rendering or {}
+GameLab.Engine.Rendering = m
+
+local import = GameLab.import(...)
+
+m.Color = import("Color")
+m.Color32 = import("Color32")
+
+m.LoadTexture = function(path)
+
+end
+
+return m \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Utils/EventCenter.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Utils/EventCenter.lua
new file mode 100644
index 0000000..664ecba
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Utils/EventCenter.lua
@@ -0,0 +1,23 @@
+local EventCenter = {}
+
+EventCenter.Subscribe = function(event, callback)
+
+end
+
+EventCenter.Unsubscribe = function(event, callback)
+
+end
+
+EventCenter.UnsubscribeAll = function(event)
+
+end
+
+EventCenter.Publish = function(event, ...)
+
+end
+
+EventCenter.Clear = function()
+
+end
+
+Jin.EventCenter = EventCenter \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Utils/StateMachine.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Utils/StateMachine.lua
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Utils/StateMachine.lua
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/Utils/Util.lua b/Data/DefaultContent/Libraries/GameLab/Engine/Utils/Util.lua
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/Utils/Util.lua
diff --git a/Data/DefaultContent/Libraries/GameLab/Engine/init.lua b/Data/DefaultContent/Libraries/GameLab/Engine/init.lua
new file mode 100644
index 0000000..f6f46a4
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Engine/init.lua
@@ -0,0 +1,5 @@
+GameLab.Engine = GameLab.Engine or {}
+
+local import = GameLab.import(...)
+
+return GameLab.Engine \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/Enum.lua b/Data/DefaultContent/Libraries/GameLab/Enum.lua
new file mode 100644
index 0000000..d1a1ae0
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/Enum.lua
@@ -0,0 +1,9 @@
+-- Declare enum
+
+
+local Enum = function()
+
+end
+
+
+GameLab.Enum = Enum \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/InternalClass.lua b/Data/DefaultContent/Libraries/GameLab/InternalClass.lua
new file mode 100644
index 0000000..36ad568
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/InternalClass.lua
@@ -0,0 +1,12 @@
+local Class = GameLab.Class or require("GameLab.Class")
+
+-- 声明类的同时添加到G表
+local InternalClass = function(className)
+ local cls = Class(className)
+ _G[className] = className
+ return cls
+end
+
+GameLab.InternalClass = InternalClass
+
+return InternalClass \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/GameLab/init.lua b/Data/DefaultContent/Libraries/GameLab/init.lua
new file mode 100644
index 0000000..c87ace3
--- /dev/null
+++ b/Data/DefaultContent/Libraries/GameLab/init.lua
@@ -0,0 +1,41 @@
+GameLab = GameLab or {}
+
+-- methods
+-- 用于模块的init.lua中加载模块内的脚本
+GameLab.import = function(packageName)
+ local _import = function(path)
+ local name = packageName .. "." .. path
+ local m = require(name)
+ --package.loaded[name] = m
+ return m
+ end
+ return _import
+end
+
+-- 用于相对路径包含
+-- GameLab.require = function(className)
+-- local packageName = (type(className) == "string") and string.match(className, "^(.+)%.%w+$") or ""
+-- local _require = function(path)
+-- local name = packageName .. "." .. path
+-- local m = require(name)
+-- return m
+-- end
+-- return _require
+-- end
+
+GameLab.find = function(fullName)
+ if _G[fullName] ~= nil then
+ return _G[fullName]
+ end
+ if package.loaded[fullName] ~= nil then
+ return package.loaded[fullName]
+ end
+ return require(fullName)
+end
+
+-- classes
+GameLab.Class = require("GameLab.Class")
+
+GameLab.InternalClass = require("GameLab.InternalClass")
+
+return GameLab \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/LiteJson/LICENSE b/Data/DefaultContent/Libraries/LiteJson/LICENSE
new file mode 100644
index 0000000..9eb37b1
--- /dev/null
+++ b/Data/DefaultContent/Libraries/LiteJson/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2020 rxi
+
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Data/DefaultContent/Libraries/LiteJson/README.md b/Data/DefaultContent/Libraries/LiteJson/README.md
new file mode 100644
index 0000000..96b9b66
--- /dev/null
+++ b/Data/DefaultContent/Libraries/LiteJson/README.md
@@ -0,0 +1,46 @@
+# ![json.lua](https://cloud.githubusercontent.com/assets/3920290/9281532/99e5e0cc-42bd-11e5-8fce-eaff2f7fc681.png)
+A lightweight JSON library for Lua
+
+
+## Features
+* Implemented in pure Lua: works with 5.1, 5.2, 5.3 and JIT
+* Fast: generally outperforms other pure Lua JSON implementations
+ ([benchmark scripts](bench/))
+* Tiny: around 280sloc, 9kb
+* Proper error messages, *eg:* `expected '}' or ',' at line 203 col 30`
+
+
+## Usage
+The [json.lua](json.lua?raw=1) file should be dropped into an existing project
+and required by it:
+```lua
+json = require "json"
+```
+The library provides the following functions:
+
+#### json.encode(value)
+Returns a string representing `value` encoded in JSON.
+```lua
+json.encode({ 1, 2, 3, { x = 10 } }) -- Returns '[1,2,3,{"x":10}]'
+```
+
+#### json.decode(str)
+Returns a value representing the decoded JSON string.
+```lua
+json.decode('[1,2,3,{"x":10}]') -- Returns { 1, 2, 3, { x = 10 } }
+```
+
+## Notes
+* Trying to encode values which are unrepresentable in JSON will never result
+ in type conversion or other magic: sparse arrays, tables with mixed key types
+ or invalid numbers (NaN, -inf, inf) will raise an error
+* `null` values contained within an array or object are converted to `nil` and
+ are therefore lost upon decoding
+* *Pretty* encoding is not supported, `json.encode()` only encodes to a compact
+ format
+
+
+## License
+This library is free software; you can redistribute it and/or modify it under
+the terms of the MIT license. See [LICENSE](LICENSE) for details.
+
diff --git a/Data/DefaultContent/Libraries/LiteJson/bench/bench_all.lua b/Data/DefaultContent/Libraries/LiteJson/bench/bench_all.lua
new file mode 100644
index 0000000..3f99e99
--- /dev/null
+++ b/Data/DefaultContent/Libraries/LiteJson/bench/bench_all.lua
@@ -0,0 +1,6 @@
+
+print("[decode]")
+loadfile("bench_decode.lua")()
+print()
+print("[encode]")
+loadfile("bench_encode.lua")()
diff --git a/Data/DefaultContent/Libraries/LiteJson/bench/bench_decode.lua b/Data/DefaultContent/Libraries/LiteJson/bench/bench_decode.lua
new file mode 100644
index 0000000..6c2e93a
--- /dev/null
+++ b/Data/DefaultContent/Libraries/LiteJson/bench/bench_decode.lua
@@ -0,0 +1,75 @@
+local bench = require "util.bench"
+
+
+local libs = {
+ "../json.lua", -- https://github.com/rxi/json.lua
+ "dkjson.lua", -- https://github.com/LuaDist/dkjson
+ "jfjson.lua", -- http://regex.info/blog/lua/json
+ --"json4lua.lua", -- https://github.com/craigmj/json4lua
+}
+
+
+-- JSON string: wikipedia example stored 1000 times in an array
+local text = "[" .. string.rep([[{
+ "firstName": "John",
+ "lastName": "Smith",
+ "isAlive": true,
+ "age": 25,
+ "address": {
+ "streetAddress": "21 2nd Street",
+ "city": "New York",
+ "state": "NY",
+ "postalCode": "10021-3100"
+ },
+ "phoneNumbers": [
+ {
+ "type": "home",
+ "number": "212 555-1234"
+ },
+ {
+ "type": "office",
+ "number": "646 555-4567"
+ }
+ ],
+ "children": [],
+ "spouse": null
+}, ]], 1000):sub(1, -3) .. "]"
+
+
+-- As this is meant to be a pure Lua benchmark, we remove the ability to
+-- require 'lpeg' so dkjson doesn't use it for parsing. (Incidentally json.lua
+-- seems to outperform libraries which use lpeg when both are using LuaJIT)
+local _require = require
+require = function(modname)
+ if modname == "lpeg" then error() end
+ return _require(modname)
+end
+
+-- Run benchmarks, store results
+local results = {}
+
+for i, name in ipairs(libs) do
+ local f = loadfile(name)
+ if not f then
+ error( "failed to load '" .. name .. "'; run './get_json_libs.sh'" )
+ end
+ local json = f()
+
+ -- Remap functions to work for jfjson.lua
+ if name == "jfjson.lua" then
+ local _encode, _decode = json.encode, json.decode
+ json.encode = function(...) return _encode(json, ...) end
+ json.decode = function(...) return _decode(json, ...) end
+ end
+
+ -- Warmup (for LuaJIT)
+ bench.run(name, 1, function() json.decode(text) end)
+
+ -- Run and push results
+ local res = bench.run(name, 10, function() json.decode(text) end)
+ table.insert(results, res)
+end
+
+
+bench.print_system_info()
+bench.print_results(results)
diff --git a/Data/DefaultContent/Libraries/LiteJson/bench/bench_encode.lua b/Data/DefaultContent/Libraries/LiteJson/bench/bench_encode.lua
new file mode 100644
index 0000000..426f7c8
--- /dev/null
+++ b/Data/DefaultContent/Libraries/LiteJson/bench/bench_encode.lua
@@ -0,0 +1,63 @@
+local bench = require "util.bench"
+
+
+local libs = {
+ "../json.lua", -- https://github.com/rxi/json.lua
+ "dkjson.lua", -- https://github.com/LuaDist/dkjson
+ "jfjson.lua", -- http://regex.info/blog/lua/json
+ "json4lua.lua", -- https://github.com/craigmj/json4lua
+}
+
+
+-- Build table which will be encoded: wikipedia example stored 1000 times
+local data = {}
+for i = 1, 1000 do
+ table.insert(data, {
+ firstName = "John",
+ lastName = "Smith",
+ isAlive = true,
+ age = 25,
+ address = {
+ streetAddress = "21 2nd Street",
+ city = "New York",
+ state = "NY",
+ postalCode = "10021-3100"
+ },
+ phoneNumbers = {
+ { type = "home", number = "212 555-1234" },
+ { type = "office", number = "646 555-4567" }
+ },
+ children = {},
+ spouse = nil
+ })
+end
+
+
+-- Run benchmarks
+local results = {}
+
+for i, name in ipairs(libs) do
+ local f = loadfile(name)
+ if not f then
+ error( "failed to load '" .. name .. "'; run './get_json_libs.sh'" )
+ end
+ local json = f()
+
+ -- Handle special cases
+ if name == "jfjson.lua" then
+ local _encode, _decode = json.encode, json.decode
+ json.encode = function(...) return _encode(json, ...) end
+ json.decode = function(...) return _decode(json, ...) end
+ end
+
+ -- Warmup (for LuaJIT)
+ bench.run(name, 1, function() json.encode(data) end)
+
+ -- Run and push results
+ local res = bench.run(name, 10, function() json.encode(data) end)
+ table.insert(results, res)
+end
+
+
+bench.print_system_info()
+bench.print_results(results)
diff --git a/Data/DefaultContent/Libraries/LiteJson/bench/get_json_libs.sh b/Data/DefaultContent/Libraries/LiteJson/bench/get_json_libs.sh
new file mode 100644
index 0000000..ecb4525
--- /dev/null
+++ b/Data/DefaultContent/Libraries/LiteJson/bench/get_json_libs.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Downloads other JSON libraries for use in the benchmark scripts
+
+# Remove libraries
+rm dkjson.lua 2>/dev/null
+rm jfjson.lua 2>/dev/null
+rm json4lua.lua 2>/dev/null
+
+# Get libraries
+echo "Downloading json libs..."
+curl -sS -o dkjson.lua "https://raw.githubusercontent.com/LuaDist/dkjson/master/dkjson.lua"
+curl -sS -o json4lua.lua "https://raw.githubusercontent.com/craigmj/json4lua/master/json/json.lua"
+curl -sS -o jfjson.lua "http://regex.info/code/JSON.lua"
+
+echo "Done"
diff --git a/Data/DefaultContent/Libraries/LiteJson/bench/util/bench.lua b/Data/DefaultContent/Libraries/LiteJson/bench/util/bench.lua
new file mode 100644
index 0000000..9f02738
--- /dev/null
+++ b/Data/DefaultContent/Libraries/LiteJson/bench/util/bench.lua
@@ -0,0 +1,62 @@
+local bench = {}
+
+local unpack = unpack or table.unpack
+local fmt = string.format
+
+
+function bench.run(name, count, func)
+ -- Run bench
+ local res = {}
+ for i = 1, count do
+ local start_time = os.clock()
+ func()
+ table.insert(res, (os.clock() - start_time))
+ end
+ -- Calculate average
+ local avg = 0
+ for i, v in ipairs(res) do
+ avg = avg + v
+ end
+ avg = avg / #res
+ -- Build and return result table
+ return {
+ name = name,
+ avg = avg,
+ min = math.min(unpack(res)),
+ max = math.max(unpack(res)),
+ all = res,
+ }
+end
+
+
+function bench.get_cpu_name()
+ local fp = io.open("/proc/cpuinfo", "rb")
+ if not fp then
+ return "unknown"
+ end
+ local text = fp:read("*a")
+ return text:match("model name%s*:%s*(.-)\n")
+end
+
+
+function bench.print_system_info()
+ print( fmt("Lua version : %s", jit and jit.version or _VERSION) )
+ print( fmt("CPU name : %s", bench.get_cpu_name()) )
+end
+
+
+function bench.print_results(results)
+ -- Find best average
+ local best = math.huge
+ for i, v in ipairs(results) do
+ best = math.min(best, v.avg)
+ end
+ -- Print results
+ for i, v in ipairs(results) do
+ print( fmt("%-13s : %.03gs [x%1.3g] (min: %.03gs, max %.03gs)",
+ v.name, v.avg, v.avg / best, v.min, v.max) )
+ end
+end
+
+
+return bench
diff --git a/Data/DefaultContent/Libraries/LiteJson/json.lua b/Data/DefaultContent/Libraries/LiteJson/json.lua
new file mode 100644
index 0000000..711ef78
--- /dev/null
+++ b/Data/DefaultContent/Libraries/LiteJson/json.lua
@@ -0,0 +1,388 @@
+--
+-- json.lua
+--
+-- Copyright (c) 2020 rxi
+--
+-- Permission is hereby granted, free of charge, to any person obtaining a copy of
+-- this software and associated documentation files (the "Software"), to deal in
+-- the Software without restriction, including without limitation the rights to
+-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+-- of the Software, and to permit persons to whom the Software is furnished to do
+-- so, subject to the following conditions:
+--
+-- The above copyright notice and this permission notice shall be included in all
+-- copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+-- SOFTWARE.
+--
+
+local json = { _version = "0.1.2" }
+
+-------------------------------------------------------------------------------
+-- Encode
+-------------------------------------------------------------------------------
+
+local encode
+
+local escape_char_map = {
+ [ "\\" ] = "\\",
+ [ "\"" ] = "\"",
+ [ "\b" ] = "b",
+ [ "\f" ] = "f",
+ [ "\n" ] = "n",
+ [ "\r" ] = "r",
+ [ "\t" ] = "t",
+}
+
+local escape_char_map_inv = { [ "/" ] = "/" }
+for k, v in pairs(escape_char_map) do
+ escape_char_map_inv[v] = k
+end
+
+
+local function escape_char(c)
+ return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
+end
+
+
+local function encode_nil(val)
+ return "null"
+end
+
+
+local function encode_table(val, stack)
+ local res = {}
+ stack = stack or {}
+
+ -- Circular reference?
+ if stack[val] then error("circular reference") end
+
+ stack[val] = true
+
+ if rawget(val, 1) ~= nil or next(val) == nil then
+ -- Treat as array -- check keys are valid and it is not sparse
+ local n = 0
+ for k in pairs(val) do
+ if type(k) ~= "number" then
+ error("invalid table: mixed or invalid key types")
+ end
+ n = n + 1
+ end
+ if n ~= #val then
+ error("invalid table: sparse array")
+ end
+ -- Encode
+ for i, v in ipairs(val) do
+ table.insert(res, encode(v, stack))
+ end
+ stack[val] = nil
+ return "[" .. table.concat(res, ",") .. "]"
+
+ else
+ -- Treat as an object
+ for k, v in pairs(val) do
+ if type(k) ~= "string" then
+ error("invalid table: mixed or invalid key types")
+ end
+ table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
+ end
+ stack[val] = nil
+ return "{" .. table.concat(res, ",") .. "}"
+ end
+end
+
+
+local function encode_string(val)
+ return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
+end
+
+
+local function encode_number(val)
+ -- Check for NaN, -inf and inf
+ if val ~= val or val <= -math.huge or val >= math.huge then
+ error("unexpected number value '" .. tostring(val) .. "'")
+ end
+ return string.format("%.14g", val)
+end
+
+
+local type_func_map = {
+ [ "nil" ] = encode_nil,
+ [ "table" ] = encode_table,
+ [ "string" ] = encode_string,
+ [ "number" ] = encode_number,
+ [ "boolean" ] = tostring,
+}
+
+
+encode = function(val, stack)
+ local t = type(val)
+ local f = type_func_map[t]
+ if f then
+ return f(val, stack)
+ end
+ error("unexpected type '" .. t .. "'")
+end
+
+
+function json.encode(val)
+ return ( encode(val) )
+end
+
+
+-------------------------------------------------------------------------------
+-- Decode
+-------------------------------------------------------------------------------
+
+local parse
+
+local function create_set(...)
+ local res = {}
+ for i = 1, select("#", ...) do
+ res[ select(i, ...) ] = true
+ end
+ return res
+end
+
+local space_chars = create_set(" ", "\t", "\r", "\n")
+local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
+local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
+local literals = create_set("true", "false", "null")
+
+local literal_map = {
+ [ "true" ] = true,
+ [ "false" ] = false,
+ [ "null" ] = nil,
+}
+
+
+local function next_char(str, idx, set, negate)
+ for i = idx, #str do
+ if set[str:sub(i, i)] ~= negate then
+ return i
+ end
+ end
+ return #str + 1
+end
+
+
+local function decode_error(str, idx, msg)
+ local line_count = 1
+ local col_count = 1
+ for i = 1, idx - 1 do
+ col_count = col_count + 1
+ if str:sub(i, i) == "\n" then
+ line_count = line_count + 1
+ col_count = 1
+ end
+ end
+ error( string.format("%s at line %d col %d", msg, line_count, col_count) )
+end
+
+
+local function codepoint_to_utf8(n)
+ -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
+ local f = math.floor
+ if n <= 0x7f then
+ return string.char(n)
+ elseif n <= 0x7ff then
+ return string.char(f(n / 64) + 192, n % 64 + 128)
+ elseif n <= 0xffff then
+ return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
+ elseif n <= 0x10ffff then
+ return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
+ f(n % 4096 / 64) + 128, n % 64 + 128)
+ end
+ error( string.format("invalid unicode codepoint '%x'", n) )
+end
+
+
+local function parse_unicode_escape(s)
+ local n1 = tonumber( s:sub(1, 4), 16 )
+ local n2 = tonumber( s:sub(7, 10), 16 )
+ -- Surrogate pair?
+ if n2 then
+ return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
+ else
+ return codepoint_to_utf8(n1)
+ end
+end
+
+
+local function parse_string(str, i)
+ local res = ""
+ local j = i + 1
+ local k = j
+
+ while j <= #str do
+ local x = str:byte(j)
+
+ if x < 32 then
+ decode_error(str, j, "control character in string")
+
+ elseif x == 92 then -- `\`: Escape
+ res = res .. str:sub(k, j - 1)
+ j = j + 1
+ local c = str:sub(j, j)
+ if c == "u" then
+ local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
+ or str:match("^%x%x%x%x", j + 1)
+ or decode_error(str, j - 1, "invalid unicode escape in string")
+ res = res .. parse_unicode_escape(hex)
+ j = j + #hex
+ else
+ if not escape_chars[c] then
+ decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
+ end
+ res = res .. escape_char_map_inv[c]
+ end
+ k = j + 1
+
+ elseif x == 34 then -- `"`: End of string
+ res = res .. str:sub(k, j - 1)
+ return res, j + 1
+ end
+
+ j = j + 1
+ end
+
+ decode_error(str, i, "expected closing quote for string")
+end
+
+
+local function parse_number(str, i)
+ local x = next_char(str, i, delim_chars)
+ local s = str:sub(i, x - 1)
+ local n = tonumber(s)
+ if not n then
+ decode_error(str, i, "invalid number '" .. s .. "'")
+ end
+ return n, x
+end
+
+
+local function parse_literal(str, i)
+ local x = next_char(str, i, delim_chars)
+ local word = str:sub(i, x - 1)
+ if not literals[word] then
+ decode_error(str, i, "invalid literal '" .. word .. "'")
+ end
+ return literal_map[word], x
+end
+
+
+local function parse_array(str, i)
+ local res = {}
+ local n = 1
+ i = i + 1
+ while 1 do
+ local x
+ i = next_char(str, i, space_chars, true)
+ -- Empty / end of array?
+ if str:sub(i, i) == "]" then
+ i = i + 1
+ break
+ end
+ -- Read token
+ x, i = parse(str, i)
+ res[n] = x
+ n = n + 1
+ -- Next token
+ i = next_char(str, i, space_chars, true)
+ local chr = str:sub(i, i)
+ i = i + 1
+ if chr == "]" then break end
+ if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
+ end
+ return res, i
+end
+
+
+local function parse_object(str, i)
+ local res = {}
+ i = i + 1
+ while 1 do
+ local key, val
+ i = next_char(str, i, space_chars, true)
+ -- Empty / end of object?
+ if str:sub(i, i) == "}" then
+ i = i + 1
+ break
+ end
+ -- Read key
+ if str:sub(i, i) ~= '"' then
+ decode_error(str, i, "expected string for key")
+ end
+ key, i = parse(str, i)
+ -- Read ':' delimiter
+ i = next_char(str, i, space_chars, true)
+ if str:sub(i, i) ~= ":" then
+ decode_error(str, i, "expected ':' after key")
+ end
+ i = next_char(str, i + 1, space_chars, true)
+ -- Read value
+ val, i = parse(str, i)
+ -- Set
+ res[key] = val
+ -- Next token
+ i = next_char(str, i, space_chars, true)
+ local chr = str:sub(i, i)
+ i = i + 1
+ if chr == "}" then break end
+ if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
+ end
+ return res, i
+end
+
+
+local char_func_map = {
+ [ '"' ] = parse_string,
+ [ "0" ] = parse_number,
+ [ "1" ] = parse_number,
+ [ "2" ] = parse_number,
+ [ "3" ] = parse_number,
+ [ "4" ] = parse_number,
+ [ "5" ] = parse_number,
+ [ "6" ] = parse_number,
+ [ "7" ] = parse_number,
+ [ "8" ] = parse_number,
+ [ "9" ] = parse_number,
+ [ "-" ] = parse_number,
+ [ "t" ] = parse_literal,
+ [ "f" ] = parse_literal,
+ [ "n" ] = parse_literal,
+ [ "[" ] = parse_array,
+ [ "{" ] = parse_object,
+}
+
+
+parse = function(str, idx)
+ local chr = str:sub(idx, idx)
+ local f = char_func_map[chr]
+ if f then
+ return f(str, idx)
+ end
+ decode_error(str, idx, "unexpected character '" .. chr .. "'")
+end
+
+
+function json.decode(str)
+ if type(str) ~= "string" then
+ error("expected argument of type string, got " .. type(str))
+ end
+ local res, idx = parse(str, next_char(str, 1, space_chars, true))
+ idx = next_char(str, idx, space_chars, true)
+ if idx <= #str then
+ decode_error(str, idx, "trailing garbage")
+ end
+ return res
+end
+
+
+return json
diff --git a/Data/DefaultContent/Libraries/LiteJson/test/test.lua b/Data/DefaultContent/Libraries/LiteJson/test/test.lua
new file mode 100644
index 0000000..74470b2
--- /dev/null
+++ b/Data/DefaultContent/Libraries/LiteJson/test/test.lua
@@ -0,0 +1,245 @@
+
+local json = loadfile("../json.lua")()
+
+
+local fmt = string.format
+
+local function test(name, func)
+ xpcall(function()
+ func()
+ print( fmt("[pass] %s", name) )
+ end, function(err)
+ print( fmt("[fail] %s : %s", name, err) )
+ end)
+end
+
+
+local function equal(a, b)
+ -- Handle table
+ if type(a) == "table" and type(b) == "table" then
+ for k in pairs(a) do
+ if not equal(a[k], b[k]) then
+ return false
+ end
+ end
+ for k in pairs(b) do
+ if not equal(b[k], a[k]) then
+ return false
+ end
+ end
+ return true
+ end
+ -- Handle scalar
+ return a == b
+end
+
+
+test("numbers", function()
+ local t = {
+ [ "123.456" ] = 123.456,
+ [ "-123" ] = -123,
+ [ "-567.765" ] = -567.765,
+ [ "12.3" ] = 12.3,
+ [ "0" ] = 0,
+ [ "0.10000000012" ] = 0.10000000012,
+ }
+ for k, v in pairs(t) do
+ local res = json.decode(k)
+ assert( res == v, fmt("expected '%s', got '%s'", k, res) )
+ local res = json.encode(v)
+ assert( res == k, fmt("expected '%s', got '%s'", v, res) )
+ end
+ assert( json.decode("13e2") == 13e2 )
+ assert( json.decode("13E+2") == 13e2 )
+ assert( json.decode("13e-2") == 13e-2 )
+end)
+
+
+test("literals", function()
+ assert( json.decode("true") == true )
+ assert( json.encode(true) == "true" )
+ assert( json.decode("false") == false )
+ assert( json.encode(false) == "false" )
+ assert( json.decode("null") == nil )
+ assert( json.encode(nil) == "null")
+end)
+
+
+test("strings", function()
+ local s = ""
+ assert( s == json.decode( json.encode(s) ) )
+ local s = "\\"
+ assert( s == json.decode( json.encode(s) ) )
+ local s = "Hello world"
+ assert( s == json.decode( json.encode(s) ) )
+ local s = "\0 \13 \27"
+ assert( s == json.decode( json.encode(s) ) )
+ local s = "\0\r\n\8"
+ assert( s == json.decode( json.encode(s) ) )
+end)
+
+
+test("unicode", function()
+ local s = "こんにちは世界"
+ assert( s == json.decode( json.encode(s) ) )
+end)
+
+
+test("arrays", function()
+ local t = { "cat", "dog", "owl" }
+ assert( equal( t, json.decode( json.encode(t) ) ) )
+end)
+
+
+test("objects", function()
+ local t = { x = 10, y = 20, z = 30 }
+ assert( equal( t, json.decode( json.encode(t) ) ) )
+end)
+
+
+--test("strict decode", function()
+-- local t = {
+-- '{x : 1}',
+-- '{x : hello}',
+-- "{'x' : 1}",
+-- '{"x" : nil}',
+-- '{"x" : 0x10}',
+-- '{"x" : 001}',
+-- '{"x" : .1}',
+-- '{"x" : 1, }',
+-- '[1, 2, 3, ]',
+-- }
+-- for i, v in ipairs(t) do
+-- local status = pcall(json.decode, v)
+-- assert( not status, fmt("'%s' was parsed without error", v) )
+-- end
+--end)
+
+
+test("decode invalid", function()
+ local t = {
+ '',
+ ' ',
+ '{',
+ '[',
+ '{"x" : ',
+ '{"x" : 1',
+ '{"x" : z }',
+ '{"x" : 123z }',
+ '{x : 123 }',
+ '{10 : 123 }',
+ '{]',
+ '[}',
+ '"a',
+ '10 xx',
+ '{}123'
+ }
+ for i, v in ipairs(t) do
+ local status = pcall(json.decode, v)
+ assert( not status, fmt("'%s' was parsed without error", v) )
+ end
+end)
+
+
+test("decode invalid string", function()
+ local t = {
+ [["\z"]],
+ [["\1"]],
+ [["\u000z"]],
+ [["\ud83d\ude0q"]],
+ '"x\ny"',
+ '"x\0y"',
+ }
+ for i, v in ipairs(t) do
+ local status, err = pcall(json.decode, v)
+ assert( not status, fmt("'%s' was parsed without error", v) )
+ end
+end)
+
+
+test("decode escape", function()
+ local t = {
+ [ [["\u263a"]] ] = '☺',
+ [ [["\ud83d\ude02"]] ] = '😂',
+ [ [["\r\n\t\\\""]] ] = '\r\n\t\\"',
+ [ [["\\"]] ] = '\\',
+ [ [["\\\\"]] ] = '\\\\',
+ [ [["\/"]] ] = '/',
+ [ [["\\u \u263a"]] ] = [[\u ☺]],
+ }
+ for k, v in pairs(t) do
+ local res = json.decode(k)
+ assert( res == v, fmt("expected '%s', got '%s'", v, res) )
+ end
+end)
+
+
+test("decode empty", function()
+ local t = {
+ [ '[]' ] = {},
+ [ '{}' ] = {},
+ [ '""' ] = "",
+ }
+ for k, v in pairs(t) do
+ local res = json.decode(k)
+ assert( equal(res, v), fmt("'%s' did not equal expected", k) )
+ end
+end)
+
+
+test("decode collection", function()
+ local t = {
+ [ '[1, 2, 3, 4, 5, 6]' ] = {1, 2, 3, 4, 5, 6},
+ [ '[1, 2, 3, "hello"]' ] = {1, 2, 3, "hello"},
+ [ '{ "name": "test", "id": 231 }' ] = {name = "test", id = 231},
+ [ '{"x":1,"y":2,"z":[1,2,3]}' ] = {x = 1, y = 2, z = {1, 2, 3}},
+ }
+ for k, v in pairs(t) do
+ local res = json.decode(k)
+ assert( equal(res, v), fmt("'%s' did not equal expected", k) )
+ end
+end)
+
+
+test("encode invalid", function()
+ local t = {
+ { [1000] = "b" },
+ { [ function() end ] = 12 },
+ { nil, 2, 3, 4 },
+ { x = 10, [1] = 2 },
+ { [1] = "a", [3] = "b" },
+ { x = 10, [4] = 5 },
+ }
+ for i, v in ipairs(t) do
+ local status, res = pcall(json.encode, v)
+ assert( not status, fmt("encoding idx %d did not result in an error", i) )
+ end
+end)
+
+
+test("encode invalid number", function()
+ local t = {
+ math.huge, -- inf
+ -math.huge, -- -inf
+ math.huge * 0, -- NaN
+ }
+ for i, v in ipairs(t) do
+ local status, res = pcall(json.encode, v)
+ assert( not status, fmt("encoding '%s' did not result in an error", v) )
+ end
+end)
+
+
+test("encode escape", function()
+ local t = {
+ [ '"x"' ] = [["\"x\""]],
+ [ 'x\ny' ] = [["x\ny"]],
+ [ 'x\0y' ] = [["x\u0000y"]],
+ [ 'x\27y' ] = [["x\u001by"]],
+ [ '\r\n\t\\"' ] = [["\r\n\t\\\""]],
+ }
+ for k, v in pairs(t) do
+ local res = json.encode(k)
+ assert( res == v, fmt("'%s' was not escaped properly", k) )
+ end
+end)
diff --git a/Data/DefaultContent/Libraries/containers/README.md b/Data/DefaultContent/Libraries/containers/README.md
new file mode 100644
index 0000000..cba8776
--- /dev/null
+++ b/Data/DefaultContent/Libraries/containers/README.md
@@ -0,0 +1,202 @@
+# Lua-ADT(5.1分支和5.2分支)
+封装的lua数据结构, 元组(tuple)、动态数组(vector)、双向链表(list)、队列(queue)、栈(stack)。
+纯lua方法封装,没有使用oop,延续lua的简洁的风格。封装的数据结构能安全使用,在语言层面过滤掉非法操作,使其使用更加简单高效。
+
+所有的类型都支持#获取长度.
+> eg.
+```lua
+ local tuple = require("tuple")
+ local v = tuple.create({2,3,6})
+ print(#v)
+ ---3
+```
+
+### 元组(tuple)
+需要用table的动态数组初始化(不支持hashtable),只对外公开遍历,修改关闭。
+
+遍历:
+```lua
+ local tuple = require("tuple")
+ local v = tuple.create({2,3,6})
+
+ for i,v in ipairs(v) do --只支持ipairs遍历,抛弃了pairs(因为原则上我们是数组,不存在key)
+ print(i,v)
+ end
+ ---1 2
+ ---2 3
+ ---3 6
+
+ print(v) --重写了__tostring,方便快速浏览数据
+ ---2,3,6
+
+ v[2] = 9 --因为对修改关闭了所以这地方修改会抛出错误
+ ---lua: .\tuple.lua:33: >> Dee: Limited access
+ ---stack traceback:
+ ---[C]: in function 'error'
+```
+
+### 动态数组(vector)
+实现高效的遍历和修改,但是新增和删除都不是线性时间复杂度。基本上就是lua table的数组,但是lua的table我们会一不小心就搞成不连续的。比如:
+```lua
+ local t = {2,4}
+ t[4] = 9
+
+ print(#t) -- 2
+```
+#### 方法:
+ * add --尾添加(高效的操作)
+ * insert --插入(会有内存整理)
+ * addRange --尾添加一个表,
+ * removeAt
+ * remove
+ * contains
+ * indexOf
+ * sort
+ * find
+
+#### eg.
+```lua
+ local vector = require("vector")
+ local v = vector.create()
+
+ v:add(4)
+ v:add(5)
+ v:add(6)
+ v:add(7)
+
+ for i,v in ipairs(v) do
+ print(i,v)
+ end
+ ---1 4
+ ---2 5
+ ---3 6
+ ---4 7
+
+ print(v)
+ ---4,5,6,7
+
+ v[4] = 9 --修改值
+
+ print(v)
+ ---4,5,6,9
+
+ v[7] = 9
+ ---lua: .\vector.lua:101: outrange of vector
+ ---stack traceback:
+ --- [C]: in function 'assert'
+```
+
+### 双向链表(list)
+弥补动态数组增删的不足,提供增删效率,但是遍历和修改效率比较低
+
+#### 方法:
+ * addFirst --头添加
+ * addLast --尾添加
+ * addBefore --node前添加
+ * addAfter --node后添加
+ * removeNode --删除node
+ * remove --根据值移除
+ * find --查找node
+#### eg.
+```lua
+ local vector = require("list")
+ local v = list.create()
+
+ v.addFirst(1)
+ v.addLast(2)
+ print(v)
+ ---1,2
+
+ local node = v.find(1)
+ node.value = 9
+ print(v)
+ ---9,2
+
+ v.removeNode(node)
+ print(v)
+ ---2
+
+ v.addLast(10)
+ v.addLast(20)
+ v.addLast(30)
+ print(v)
+ ---2,10,20,30
+
+ for _,i,v in ipairs(v) do --第一个参数是node, i: index, v: value
+ print(i,v)
+ end
+ ---1 2
+ ---2 10
+ ---3 20
+ ---4 30
+```
+### 栈(stack)
+FILO先进后出, 对修改关闭,关闭遍历,只能通过方法修改数据
+#### 方法:
+ * push --添加
+ * pop --移除
+ * peek --返回栈顶数据
+ * clear --清空
+#### eg.
+```lua
+ local stack = require("stack")
+ local v = stack.create()
+
+ v.push(1)
+ v.push(2)
+ v.push(5)
+
+ print(v)
+ ---5,2,1
+ print(v.len)
+ ---3
+ v.pop()
+ print(v)
+ ---2,1
+ v.clear()
+ print(v.len)
+ ---0
+```
+### 队列(queue)
+FIFO,先进先出,因为是队首删除所以不能使用table.remove
+#### 方法:
+ * enqueue --添加
+ * dequeue --移除
+ * peek --返回栈顶数据
+ * clear --清空
+ * #queue --获取长度
+#### eg.
+```lua
+local queue = require("queue")
+-- lua table
+local cnt = 10000 * 1
+
+local t = {}
+for i=1,cnt do
+t[i] = i
+end
+
+local time = os.clock()
+while #t > 0 do
+-- table.remove(t)
+ table.remove(t, 1)
+end
+print(os.clock() - time)
+---1.037s
+
+local v = queue.create()
+
+for i=1,cnt do
+ v.enqueue(i)
+end
+
+
+local time1 = os.clock()
+while v.len > 10 do
+ v.dequeue()
+end
+print(os.clock() - time1)
+---0.005s
+```
+1w条数据,lua table直接删除表头的耗时1.037s,queue耗时0.005s,而且queue整理内存的步长可以调整,耗时可以进步一提高.
+
diff --git a/Data/DefaultContent/Libraries/containers/list.lua b/Data/DefaultContent/Libraries/containers/list.lua
new file mode 100644
index 0000000..59233b9
--- /dev/null
+++ b/Data/DefaultContent/Libraries/containers/list.lua
@@ -0,0 +1,199 @@
+---
+--- Generated by EmmyLua(https://github.com/EmmyLua)
+--- Created by Dee.
+--- DateTime: 2019/3/7 14:00
+--- 高效增删有序表,低效遍历
+---
+
+--[[
+遍历:
+ for _,idx, value in ipairs(l) do .. end
+ for _, value in pairs(l) do ... end
+]]
+
+list = list or {}
+
+function list.create()
+ local lenght = 0
+ -- 类似stl的方式,头尾只是作为指针使用
+ local first = {front = nil, next = nil, value = nil}
+ local last = {front = nil, next = nil, value = nil}
+ first.next = last
+ last.front = first
+
+
+ ---查找值
+ ---@param value
+ ---@return node
+ local find = function(value)
+ local ret = nil
+ local nextNode = first
+ while nextNode do
+ nextNode = nextNode.next
+ if nextNode.value == value then
+ ret = nextNode
+ break
+ end
+ end
+
+ return ret
+ end
+
+ ---查找(根据下标查找)
+ ---@param idx 下标
+ ---@return node
+ local findByIdx = function(idx)
+ local i = 0
+ local ret
+ local nextNode = first
+ while nextNode and i < lenght do
+ i = i+1
+ nextNode = nextNode.next
+ if i == idx then
+ ret = nextNode
+ break
+ end
+ end
+
+ return ret
+ end
+
+ ---在node前添加
+ ---@param node
+ ---@param v
+ local addBefore = function(node, v)
+ assert(node)
+
+ local frontNode = node.front
+ local newNode = {}
+ newNode.front = frontNode
+ newNode.next = node
+ newNode.value = v
+ node.front = newNode
+ frontNode.next = newNode
+
+ lenght = lenght+1
+ end
+
+ ---在node后添加
+ ---@param node
+ ---@param v
+ local addAfter = function(node, v)
+ assert(node)
+ local nextNode = node.next
+ local newNode = {}
+ newNode.front = node
+ newNode.next = nextNode
+ newNode.value = v
+ node.next = newNode
+ nextNode.front = newNode
+
+ lenght = lenght+1
+ end
+
+ ---在队首添加
+ ---@param v
+ local addFirst = function(v)
+ addAfter(first, v)
+ end
+
+ ---在队尾添加
+ ---@param v
+ local addLast = function(v)
+ addBefore(last, v)
+ end
+
+ ---删除节点
+ ---@param node
+ local removeNode = function(node)
+ assert(node)
+
+ local frontNode = node.front
+ local nextNode = node.next
+
+ if frontNode == nil then
+ first = nextNode
+ else
+ frontNode.next = nextNode
+ end
+
+ if nextNode ~= nil then
+ nextNode.front = frontNode
+ end
+ lenght = lenght - 1
+ end
+
+ ---删除节点
+ ---@param v
+ local remove = function(v)
+ local node = find(v)
+ if node then
+ removeNode(node)
+ end
+ end
+
+ local t = {
+ addFirst = addFirst,
+ addLast = addLast,
+ addBefore = addBefore,
+ addAfter = addAfter,
+ removeNode = removeNode,
+ remove = remove,
+ find = find,
+ findByIdx = findByIdx
+ }
+
+ local mt = {
+ __index = function(i_t, key)
+ return findByIdx(key)
+ end,
+ __newindex = function(i_t,k,v)
+ local node = findByIdx(k)
+ if not node then
+ error("out range: "..k)
+ else
+ node.value = v
+ end
+ end,
+ __tostring = function()
+ local ret = {}
+ local next = first.next
+ while next and next ~= last do
+ ret[#ret+1] = next.value
+ next = next.next
+ end
+
+ return table.concat(ret, ',')
+ end,
+ __len = function(v)
+ return lenght
+ end,
+ --迭代器返回node-value
+ __ipairs = function(i_t)
+ local idx = 0
+ local function iter(i_t, node)
+ idx = idx + 1
+ if node and node.next ~= last then
+ return node.next, idx, node.next.value
+ end
+ end
+
+ return iter, t, first
+ end,
+ __pairs = function(i_t)
+ local function iter(i_t, node)
+ if node and node.next ~= last then
+ return node.next, node.next.value
+ end
+ end
+
+ return iter, t, first
+ end
+ }
+
+ setmetatable(t, mt)
+
+ return t
+end
+
+return list \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/containers/queue.lua b/Data/DefaultContent/Libraries/containers/queue.lua
new file mode 100644
index 0000000..126daa8
--- /dev/null
+++ b/Data/DefaultContent/Libraries/containers/queue.lua
@@ -0,0 +1,111 @@
+---
+--- Generated by EmmyLua(https://github.com/EmmyLua)
+--- Created by Dee.
+--- DateTime: 2019/3/7 11:27
+--- FIFO
+---
+
+queue = queue or {}
+
+---@return Queue
+function queue.create()
+ ---数据容器
+ local data = {}
+ ---数据长度
+ local lenght = 0
+ ---队首索引
+ local first = 1
+
+ ---获取队首值
+ local peek = function()
+ return data[first]
+ end
+
+ ---压入数据
+ local enqueue = function(v)
+ assert(v ~= nil, "nil value")
+ first = lenght == 0 and 1 or first
+ lenght = lenght + 1
+ table.insert(data, first+lenght-1, v)
+ end
+
+ ---弹出数据
+ local dequeue = function()
+ assert(lenght > 0, "nill queue")
+
+ local ret = peek()
+ data[first] = nil
+ first = first+1
+ lenght = lenght - 1
+ first = lenght == 0 and 1 or first
+
+ if math.fmod(first, 4) == 0 then
+ local tmp = {}
+ table.move(data, first, first + lenght, 1, tmp)
+
+ first = 1
+ data = nil
+ data = tmp
+ end
+
+ return ret
+ end
+
+ local clear = function()
+ data = {}
+ first = 1
+ lenght = 0
+ end
+
+ local __tostring = function()
+ local tmp = {}
+ for i=1,lenght do
+ tmp[i] = data[i + first - 1]
+ end
+ return table.concat(tmp, ",")
+ end
+
+ local __len = function()
+ return lenght
+ end
+
+ local __index = function(i_t, key)
+ error(">> Dee: Limited access")
+ end
+
+ local __newindex = function(i_t, key, v)
+ error(">> Dee: Limited access")
+ end
+
+ local __ipairs = function(i_t)
+ local idx = 0
+ local function iter(i_t)
+ idx = idx + 1
+ if idx <= lenght then
+ return idx, data[first + idx - 1]
+ end
+ end
+
+ return iter
+ end
+
+ local __pairs = function(i_t)
+ error(">> Dee: Limited access")
+ end
+
+ local mt = {__tostring = __tostring, __index = __index, __newindex = __newindex, __ipairs = __ipairs, __pairs = __pairs, __len = __len}
+
+ ---@class Queue
+ local t = {
+ enqueue = enqueue,
+ dequeue = dequeue,
+ peek = peek,
+ clear = clear
+ }
+
+ setmetatable(t, mt)
+
+ return t
+end
+
+return queue
diff --git a/Data/DefaultContent/Libraries/containers/stack.lua b/Data/DefaultContent/Libraries/containers/stack.lua
new file mode 100644
index 0000000..d828c81
--- /dev/null
+++ b/Data/DefaultContent/Libraries/containers/stack.lua
@@ -0,0 +1,67 @@
+--堆栈实现
+stack = stack or {}
+
+function stack.create()
+ local data = {}
+
+ local function push(v)
+ assert(v)
+ table.insert(data, v)
+ end
+
+ local function pop()
+ assert(#data > 0)
+ table.remove(data)
+ end
+
+ local function peek()
+ return #data > 0 and data[#data] or nil
+ end
+
+ local function clear()
+ for i=1,#data do
+ data[i] = nil
+ end
+ end
+
+
+
+ local __tostring = function()
+ local tmp = {}
+ for i,v in ipairs(data) do
+ tmp[#data+1 - i] = v
+ end
+ return table.concat(tmp, ",")
+ end
+
+ local __index = function(i_t, key)
+ error(">> Dee: Limited access")
+ end
+
+ local __len = function()
+ return #data
+ end
+
+ local __newindex = function(i_t, key, v)
+ error(">> Dee: Limited access")
+ end
+
+ local __ipairs = function()
+ error(">> Dee: Limited access")
+ end
+
+ local mt = {__tostring = __tostring, __index = __index, __newindex = __newindex, __ipairs = __ipairs, __pairs = __ipairs, __len = __len}
+
+ local t = {
+ push = push,
+ pop = pop,
+ peek = peek,
+ clear = clear
+ }
+
+ setmetatable(t, mt)
+
+ return t
+end
+
+return stack \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/containers/tuple.lua b/Data/DefaultContent/Libraries/containers/tuple.lua
new file mode 100644
index 0000000..0646d5a
--- /dev/null
+++ b/Data/DefaultContent/Libraries/containers/tuple.lua
@@ -0,0 +1,60 @@
+---
+--- Generated by EmmyLua(https://github.com/EmmyLua)
+--- Created by Dee.
+--- DateTime: 2019/3/7 14:00
+--- 元組,對修改關閉
+---
+
+tuple = tuple or {}
+
+function tuple.create(i_data)
+ assert(type(i_data) == "table", ">> Dee: shoudle create with table")
+
+ local data = {}
+ for k,v in pairs(i_data) do
+ data[#data+1] = v
+ end
+
+ local t = {}
+
+ local __tostring = function()
+ return table.concat(data, ",")
+ end
+
+ local __index = function(i_t, key)
+ return data[key]
+ end
+
+ local __newindex = function(i_t, key, v)
+ error(">> Dee: Limited access")
+ end
+
+ local __pairs = function()
+ error(">> Dee: Limited access")
+ end
+
+ local __ipairs = function(i_t)
+ local idx = 0
+ local function iter(i_t)
+ idx = idx + 1
+ if idx <= #data then
+ return idx, data[idx]
+ end
+ end
+
+ return iter
+ end
+
+ local __len = function(v)
+ return #data
+ end
+
+ local mt = {__tostring = __tostring, __index = __index, __newindex = __newindex, __pairs =__pairs, __ipairs = __ipairs, __len = __len}
+
+ setmetatable(t, mt)
+
+ return t
+ end
+
+
+return tuple \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/containers/vector.lua b/Data/DefaultContent/Libraries/containers/vector.lua
new file mode 100644
index 0000000..0b349ce
--- /dev/null
+++ b/Data/DefaultContent/Libraries/containers/vector.lua
@@ -0,0 +1,122 @@
+---
+--- Generated by EmmyLua(https://github.com/EmmyLua)
+--- Created by Dee.
+--- DateTime: 2019/3/7 14:00
+--- 快速遍历修改,低效的增删
+---
+
+vector = vector or {}
+
+function vector.create()
+ local t = {}
+
+
+ ---尾添加元素(高效)
+ function t:add(v)
+ rawset(self, #self + 1, v)
+ end
+
+ ---插入(低效)
+ ---@param k 位置
+ ---@param v 值
+ function t:insert(k, v)
+ assert(k > 0 and k <= #self, "outrange of vector")
+
+ local cnt = #self
+ for i = cnt, k, -1 do
+ rawset(self, i+1, self[i])
+ end
+
+ rawset(self, k, v)
+ end
+
+ ---值的索引
+ ---@return -1不存在
+ function t:indexOf(i_v)
+ assert(type(self) == 'table')
+
+ local ret = -1
+ local cnt = #self
+ for i = 1, #self do
+ if self[i] == i_v then
+ ret = i
+ end
+ end
+
+ return ret
+ end
+
+ ---是否存在某元素
+ function t:contains(v)
+ assert(type(self) == 'table')
+ return self:indexOf(v) ~= -1
+ end
+
+ ---根据下标索引移除元素(低效)
+ function t:removeAt(idx)
+ assert(idx <= #self)
+ table.remove(self, idx)
+ end
+
+ ---删除值(非贪婪)
+ ---@return 删除位置 -1未删除
+ function t:remove(v)
+ local ret = self:indexOf(v)
+ if ret ~= -1 then
+ self:removeAt(ret)
+ end
+
+ return ret
+ end
+
+ ---删除所有值
+ function t:removeAll(v)
+ assert(type(self) == 'table')
+ error(">>Dee: wait ...")
+ end
+
+ ---排序
+ function t:sort(comparer)
+ assert(type(self) == 'table')
+ table.sort(self, comparer)
+ end
+
+ ---匹配
+ ---@param 匹配函数
+ ---@return idx,value
+ function t:find(matcher)
+ assert(type(self) == 'table')
+
+ local _idx, _value = -1, nil
+ local cnt = #self
+ for i = 1, cnt do
+ if matcher(i, self[i]) then
+ _value = self[i]
+ _idx = i
+ break
+ end
+ end
+
+ return _idx, _value
+ end
+
+ --------------------------------metatable---------------------------------------
+ t.__newindex = function(i_t,k,v)
+ error(">> Dee: [], replace with add()")
+ end
+
+ t.__tostring = function(i_t)
+ return table.concat(i_t, ',')
+ end
+
+ t.__pairs = function(...)
+ error(">> Dee: Limited access")
+ end
+
+ setmetatable(t, t)
+ -----------------------------------------------------------------------
+
+ return t
+end
+
+return vector \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/inspect/.travis.yml b/Data/DefaultContent/Libraries/inspect/.travis.yml
new file mode 100644
index 0000000..91f7f93
--- /dev/null
+++ b/Data/DefaultContent/Libraries/inspect/.travis.yml
@@ -0,0 +1,36 @@
+language: python
+sudo: false
+
+env:
+ - LUA="lua=5.1"
+ - LUA="lua=5.2"
+ - LUA="lua=5.3"
+ - LUA="luajit=2.0"
+ - LUA="luajit=2.1"
+
+before_install:
+ - pip install hererocks
+ - hererocks lua_install -r^ --$LUA
+ - export PATH=$PATH:$PWD/lua_install/bin # Add directory with all installed binaries to PATH
+
+install:
+ - luarocks install luacheck
+ - luarocks install busted
+ - luarocks install luacov
+ - luarocks install luacov-coveralls
+
+script:
+ - luacheck --std max+busted *.lua spec
+ - busted --verbose --coverage
+
+after_success:
+ - luacov-coveralls --exclude $TRAVIS_BUILD_DIR/lua_install
+
+branches:
+ except:
+ - gh-pages
+
+notifications:
+ email:
+ on_success: change
+ on_failure: always
diff --git a/Data/DefaultContent/Libraries/inspect/CHANGELOG.md b/Data/DefaultContent/Libraries/inspect/CHANGELOG.md
new file mode 100644
index 0000000..bc2311b
--- /dev/null
+++ b/Data/DefaultContent/Libraries/inspect/CHANGELOG.md
@@ -0,0 +1,39 @@
+## v3.1.1
+
+* Better handling of LuaJIT's `ctype` and `cdata` values (#34, thanks @akopytov)
+
+## v3.1.0
+
+* Fixes bug: all control codes are escaped correctly (instead of only the named ones such as \n).
+ Example: \1 becomes \\1 (or \\001 when followed by a digit)
+* Fixes bug when using the `process` option in recursive tables
+* Overriding global `tostring` with inspect no longer results in an error.
+* Simplifies id generation, using less tables and metatables.
+
+## v3.0.3
+* Fixes a bug which sometimes displayed struct-like parts of tables as sequence-like due
+ to the way rawlen/the # operator are implemented.
+
+## v3.0.2
+* Fixes a bug when a table was garbage-collected while inspect was trying to render it
+
+## v3.0.1
+* Fixes a bug when dealing with tables which have a __len metamethod in Lua >= 5.2
+
+## v3.0.0
+
+The basic functionality remains as before, but there's one backwards-incompatible change if you used `options.filter`.
+
+* **Removed** `options.filter`
+* **Added** `options.process`, which can be used to do the same as `options.filter`, and more.
+* **Added** two new constants, `inspect.METATABLE` and `inspect.KEY`
+* **Added** `options.indent` & `options.newline`.
+
+
+## v2.0.0
+
+* Ability to deal with LuaJit's custom types
+* License change from BSD to MIT
+* Moved second parameter (depth) to options (options.depth)
+* Added a new parameter, options.filter.
+* Reimplemented some parts of the system without object orientation
diff --git a/Data/DefaultContent/Libraries/inspect/MIT-LICENSE.txt b/Data/DefaultContent/Libraries/inspect/MIT-LICENSE.txt
new file mode 100644
index 0000000..555835c
--- /dev/null
+++ b/Data/DefaultContent/Libraries/inspect/MIT-LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2013 Enrique García Cota
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Data/DefaultContent/Libraries/inspect/README.md b/Data/DefaultContent/Libraries/inspect/README.md
new file mode 100644
index 0000000..e9c6f86
--- /dev/null
+++ b/Data/DefaultContent/Libraries/inspect/README.md
@@ -0,0 +1,253 @@
+inspect.lua
+===========
+
+[![Build Status](https://travis-ci.org/kikito/inspect.lua.png?branch=master)](https://travis-ci.org/kikito/inspect.lua)
+[![Coverage Status](https://coveralls.io/repos/github/kikito/inspect.lua/badge.svg?branch=master)](https://coveralls.io/github/kikito/inspect.lua?branch=master)
+
+
+This library transforms any Lua value into a human-readable representation. It is especially useful for debugging errors in tables.
+
+The objective here is human understanding (i.e. for debugging), not serialization or compactness.
+
+Examples of use
+===============
+
+`inspect` has the following declaration: `local str = inspect(value, <options>)`.
+
+`value` can be any Lua value.
+
+`inspect` transforms simple types (like strings or numbers) into strings.
+
+```lua
+assert(inspect(1) == "1")
+assert(inspect("Hello") == '"Hello"')
+```
+
+Tables, on the other hand, are rendered in a way a human can read easily.
+
+"Array-like" tables are rendered horizontally:
+
+```lua
+assert(inspect({1,2,3,4}) == "{ 1, 2, 3, 4 }")
+```
+
+"Dictionary-like" tables are rendered with one element per line:
+
+```lua
+assert(inspect({a=1,b=2}) == [[{
+ a = 1,
+ b = 2
+}]])
+```
+
+The keys will be sorted alphanumerically when possible.
+
+"Hybrid" tables will have the array part on the first line, and the dictionary part just below them:
+
+```lua
+assert(inspect({1,2,3,b=2,a=1}) == [[{ 1, 2, 3,
+ a = 1,
+ b = 2
+}]])
+```
+
+Subtables are indented with two spaces per level.
+
+```lua
+assert(inspect({a={b=2}}) == [[{
+ a = {
+ b = 2
+ }
+}]])
+```
+
+Functions, userdata and any other custom types from Luajit are simply as `<function x>`, `<userdata x>`, etc.:
+
+```lua
+assert(inspect({ f = print, ud = some_user_data, thread = a_thread} ) == [[{
+ f = <function 1>,
+ u = <userdata 1>,
+ thread = <thread 1>
+}]])
+```
+
+If the table has a metatable, inspect will include it at the end, in a special field called `<metatable>`:
+
+```lua
+assert(inspect(setmetatable({a=1}, {b=2}) == [[{
+ a = 1
+ <metatable> = {
+ b = 2
+ }
+}]]))
+```
+
+`inspect` can handle tables with loops inside them. It will print `<id>` right before the table is printed out the first time, and replace the whole table with `<table id>` from then on, preventing infinite loops.
+
+```lua
+local a = {1, 2}
+local b = {3, 4, a}
+a[3] = b -- a references b, and b references a
+assert(inspect(a) == "<1>{ 1, 2, { 3, 4, <table 1> } }")
+```
+
+Notice that since both `a` appears more than once in the expression, it is prefixed by `<1>` and replaced by `<table 1>` every time it appears later on.
+
+### options
+
+`inspect` has a second parameter, called `options`. It is not mandatory, but when it is provided, it must be a table.
+
+#### options.depth
+
+`options.depth` sets the maximum depth that will be printed out.
+When the max depth is reached, `inspect` will stop parsing tables and just return `{...}`:
+
+```lua
+
+local t5 = {a = {b = {c = {d = {e = 5}}}}}
+
+assert(inspect(t5, {depth = 4}) == [[{
+ a = {
+ b = {
+ c = {
+ d = {...}
+ }
+ }
+ }
+}]])
+
+assert(inspect(t5, {depth = 2}) == [[{
+ a = {
+ b = {...}
+ }
+}]])
+
+```
+
+`options.depth` defaults to infinite (`math.huge`).
+
+#### options.newline & options.indent
+
+These are the strings used by `inspect` to respectively add a newline and indent each level of a table.
+
+By default, `options.newline` is `"\n"` and `options.indent` is `" "` (two spaces).
+
+``` lua
+local t = {a={b=1}}
+
+assert(inspect(t) == [[{
+ a = {
+ b = 1
+ }
+}]])
+
+assert(inspect(t, {newline='@', indent="++"}), "{@++a = {@++++b = 1@++}@}"
+```
+
+#### options.process
+
+`options.process` is a function which allow altering the passed object before transforming it into a string.
+A typical way to use it would be to remove certain values so that they don't appear at all.
+
+`options.process` has the following signature:
+
+``` lua
+local processed_item = function(item, path)
+```
+
+* `item` is either a key or a value on the table, or any of its subtables
+* `path` is an array-like table built with all the keys that have been used to reach `item`, from the root.
+ * For values, it is just a regular list of keys. For example, to reach the 1 in `{a = {b = 1}}`, the `path`
+ will be `{'a', 'b'}`
+ * For keys, the special value `inspect.KEY` is inserted. For example, to reach the `c` in `{a = {b = {c = 1}}}`,
+ the path will be `{'a', 'b', 'c', inspect.KEY }`
+ * For metatables, the special value `inspect.METATABLE` is inserted. For `{a = {b = 1}}}`, the path
+ `{'a', {b = 1}, inspect.METATABLE}` means "the metatable of the table `{b = 1}`".
+* `processed_item` is the value returned by `options.process`. If it is equal to `item`, then the inspected
+ table will look unchanged. If it is different, then the table will look different; most notably, if it's `nil`,
+ the item will dissapear on the inspected table.
+
+#### Examples
+
+Remove a particular metatable from the result:
+
+``` lua
+local t = {1,2,3}
+local mt = {b = 2}
+setmetatable(t, mt)
+
+local remove_mt = function(item)
+ if item ~= mt then return item end
+end
+
+-- mt does not appear
+assert(inspect(t, {process = remove_mt}) == "{ 1, 2, 3 }")
+```
+
+The previous exaple only works for a particular metatable. If you want to make *all* metatables, you can use the `path` parameter to check
+wether the last element is `inspect.METATABLE`, and return `nil` instead of the item:
+
+``` lua
+local t, mt = ... -- (defined as before)
+
+local remove_all_metatables = function(item, path)
+ if path[#path] ~= inspect.METATABLE then return item end
+end
+
+assert(inspect(t, {process = remove_all_metatables}) == "{ 1, 2, 3 }")
+```
+
+Filter a value:
+
+```lua
+local anonymize_password = function(item, path)
+ if path[#path] == 'password' then return "XXXX" end
+ return item
+end
+
+local info = {user = 'peter', password = 'secret'}
+
+assert(inspect(info, {process = anonymize_password}) == [[{
+ password = "XXXX",
+ user = "peter"
+}]])
+```
+
+Gotchas / Warnings
+==================
+
+This method is *not* appropriate for saving/restoring tables. It is meant to be used by the programmer mainly while debugging a program.
+
+Installation
+============
+
+If you are using luarocks, just run
+
+ luarocks install inspect
+
+Otherwise, you can just copy the inspect.lua file somewhere in your projects (maybe inside a /lib/ folder) and require it accordingly.
+
+Remember to store the value returned by require somewhere! (I suggest a local variable named inspect, although others might like table.inspect)
+
+ local inspect = require 'inspect'
+ -- or --
+ local inspect = require 'lib.inspect'
+
+Also, make sure to read the license; the text of that license file must appear somewhere in your projects' files. For your convenience, it's included at the begining of inspect.lua.
+
+Specs
+=====
+
+This project uses [busted](http://olivinelabs.com/busted/) for its specs. If you want to run the specs, you will have to install busted first. Then just execute the following from the root inspect folder:
+
+ busted
+
+Change log
+==========
+
+Read it on the CHANGELOG.md file
+
+
+
+
+
diff --git a/Data/DefaultContent/Libraries/inspect/inspect.lua b/Data/DefaultContent/Libraries/inspect/inspect.lua
new file mode 100644
index 0000000..e2e3806
--- /dev/null
+++ b/Data/DefaultContent/Libraries/inspect/inspect.lua
@@ -0,0 +1,334 @@
+local inspect ={
+ _VERSION = 'inspect.lua 3.1.0',
+ _URL = 'http://github.com/kikito/inspect.lua',
+ _DESCRIPTION = 'human-readable representations of tables',
+ _LICENSE = [[
+ MIT LICENSE
+
+ Copyright (c) 2013 Enrique García Cota
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ ]]
+}
+
+local tostring = tostring
+
+inspect.KEY = setmetatable({}, {__tostring = function() return 'inspect.KEY' end})
+inspect.METATABLE = setmetatable({}, {__tostring = function() return 'inspect.METATABLE' end})
+
+local function rawpairs(t)
+ return next, t, nil
+end
+
+-- Apostrophizes the string if it has quotes, but not aphostrophes
+-- Otherwise, it returns a regular quoted string
+local function smartQuote(str)
+ if str:match('"') and not str:match("'") then
+ return "'" .. str .. "'"
+ end
+ return '"' .. str:gsub('"', '\\"') .. '"'
+end
+
+-- \a => '\\a', \0 => '\\0', 31 => '\31'
+local shortControlCharEscapes = {
+ ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n",
+ ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v"
+}
+local longControlCharEscapes = {} -- \a => nil, \0 => \000, 31 => \031
+for i=0, 31 do
+ local ch = string.char(i)
+ if not shortControlCharEscapes[ch] then
+ shortControlCharEscapes[ch] = "\\"..i
+ longControlCharEscapes[ch] = string.format("\\%03d", i)
+ end
+end
+
+local function escape(str)
+ return (str:gsub("\\", "\\\\")
+ :gsub("(%c)%f[0-9]", longControlCharEscapes)
+ :gsub("%c", shortControlCharEscapes))
+end
+
+local function isIdentifier(str)
+ return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" )
+end
+
+local function isSequenceKey(k, sequenceLength)
+ return type(k) == 'number'
+ and 1 <= k
+ and k <= sequenceLength
+ and math.floor(k) == k
+end
+
+local defaultTypeOrders = {
+ ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4,
+ ['function'] = 5, ['userdata'] = 6, ['thread'] = 7
+}
+
+local function sortKeys(a, b)
+ local ta, tb = type(a), type(b)
+
+ -- strings and numbers are sorted numerically/alphabetically
+ if ta == tb and (ta == 'string' or ta == 'number') then return a < b end
+
+ local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb]
+ -- Two default types are compared according to the defaultTypeOrders table
+ if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb]
+ elseif dta then return true -- default types before custom ones
+ elseif dtb then return false -- custom types after default ones
+ end
+
+ -- custom types are sorted out alphabetically
+ return ta < tb
+end
+
+-- For implementation reasons, the behavior of rawlen & # is "undefined" when
+-- tables aren't pure sequences. So we implement our own # operator.
+local function getSequenceLength(t)
+ local len = 1
+ local v = rawget(t,len)
+ while v ~= nil do
+ len = len + 1
+ v = rawget(t,len)
+ end
+ return len - 1
+end
+
+local function getNonSequentialKeys(t)
+ local keys, keysLength = {}, 0
+ local sequenceLength = getSequenceLength(t)
+ for k,_ in rawpairs(t) do
+ if not isSequenceKey(k, sequenceLength) then
+ keysLength = keysLength + 1
+ keys[keysLength] = k
+ end
+ end
+ table.sort(keys, sortKeys)
+ return keys, keysLength, sequenceLength
+end
+
+local function countTableAppearances(t, tableAppearances)
+ tableAppearances = tableAppearances or {}
+
+ if type(t) == 'table' then
+ if not tableAppearances[t] then
+ tableAppearances[t] = 1
+ for k,v in rawpairs(t) do
+ countTableAppearances(k, tableAppearances)
+ countTableAppearances(v, tableAppearances)
+ end
+ countTableAppearances(getmetatable(t), tableAppearances)
+ else
+ tableAppearances[t] = tableAppearances[t] + 1
+ end
+ end
+
+ return tableAppearances
+end
+
+local copySequence = function(s)
+ local copy, len = {}, #s
+ for i=1, len do copy[i] = s[i] end
+ return copy, len
+end
+
+local function makePath(path, ...)
+ local keys = {...}
+ local newPath, len = copySequence(path)
+ for i=1, #keys do
+ newPath[len + i] = keys[i]
+ end
+ return newPath
+end
+
+local function processRecursive(process, item, path, visited)
+ if item == nil then return nil end
+ if visited[item] then return visited[item] end
+
+ local processed = process(item, path)
+ if type(processed) == 'table' then
+ local processedCopy = {}
+ visited[item] = processedCopy
+ local processedKey
+
+ for k,v in rawpairs(processed) do
+ processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited)
+ if processedKey ~= nil then
+ processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited)
+ end
+ end
+
+ local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited)
+ if type(mt) ~= 'table' then mt = nil end -- ignore not nil/table __metatable field
+ setmetatable(processedCopy, mt)
+ processed = processedCopy
+ end
+ return processed
+end
+
+
+
+-------------------------------------------------------------------
+
+local Inspector = {}
+local Inspector_mt = {__index = Inspector}
+
+function Inspector:puts(...)
+ local args = {...}
+ local buffer = self.buffer
+ local len = #buffer
+ for i=1, #args do
+ len = len + 1
+ buffer[len] = args[i]
+ end
+end
+
+function Inspector:down(f)
+ self.level = self.level + 1
+ f()
+ self.level = self.level - 1
+end
+
+function Inspector:tabify()
+ self:puts(self.newline, string.rep(self.indent, self.level))
+end
+
+function Inspector:alreadyVisited(v)
+ return self.ids[v] ~= nil
+end
+
+function Inspector:getId(v)
+ local id = self.ids[v]
+ if not id then
+ local tv = type(v)
+ id = (self.maxIds[tv] or 0) + 1
+ self.maxIds[tv] = id
+ self.ids[v] = id
+ end
+ return tostring(id)
+end
+
+function Inspector:putKey(k)
+ if isIdentifier(k) then return self:puts(k) end
+ self:puts("[")
+ self:putValue(k)
+ self:puts("]")
+end
+
+function Inspector:putTable(t)
+ if t == inspect.KEY or t == inspect.METATABLE then
+ self:puts(tostring(t))
+ elseif self:alreadyVisited(t) then
+ self:puts('<table ', self:getId(t), '>')
+ elseif self.level >= self.depth then
+ self:puts('{...}')
+ else
+ if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end
+
+ local nonSequentialKeys, nonSequentialKeysLength, sequenceLength = getNonSequentialKeys(t)
+ local mt = getmetatable(t)
+
+ self:puts('{')
+ self:down(function()
+ local count = 0
+ for i=1, sequenceLength do
+ if count > 0 then self:puts(',') end
+ self:puts(' ')
+ self:putValue(t[i])
+ count = count + 1
+ end
+
+ for i=1, nonSequentialKeysLength do
+ local k = nonSequentialKeys[i]
+ if count > 0 then self:puts(',') end
+ self:tabify()
+ self:putKey(k)
+ self:puts(' = ')
+ self:putValue(t[k])
+ count = count + 1
+ end
+
+ if type(mt) == 'table' then
+ if count > 0 then self:puts(',') end
+ self:tabify()
+ self:puts('<metatable> = ')
+ self:putValue(mt)
+ end
+ end)
+
+ if nonSequentialKeysLength > 0 or type(mt) == 'table' then -- result is multi-lined. Justify closing }
+ self:tabify()
+ elseif sequenceLength > 0 then -- array tables have one extra space before closing }
+ self:puts(' ')
+ end
+
+ self:puts('}')
+ end
+end
+
+function Inspector:putValue(v)
+ local tv = type(v)
+
+ if tv == 'string' then
+ self:puts(smartQuote(escape(v)))
+ elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
+ tv == 'cdata' or tv == 'ctype' then
+ self:puts(tostring(v))
+ elseif tv == 'table' then
+ self:putTable(v)
+ else
+ self:puts('<', tv, ' ', self:getId(v), '>')
+ end
+end
+
+-------------------------------------------------------------------
+
+function inspect.inspect(root, options)
+ options = options or {}
+
+ local depth = options.depth or math.huge
+ local newline = options.newline or '\n'
+ local indent = options.indent or ' '
+ local process = options.process
+
+ if process then
+ root = processRecursive(process, root, {}, {})
+ end
+
+ local inspector = setmetatable({
+ depth = depth,
+ level = 0,
+ buffer = {},
+ ids = {},
+ maxIds = {},
+ newline = newline,
+ indent = indent,
+ tableAppearances = countTableAppearances(root)
+ }, Inspector_mt)
+
+ inspector:putValue(root)
+
+ return table.concat(inspector.buffer)
+end
+
+setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end })
+
+return inspect
+
diff --git a/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-1.2-2.rockspec b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-1.2-2.rockspec
new file mode 100644
index 0000000..b683143
--- /dev/null
+++ b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-1.2-2.rockspec
@@ -0,0 +1,23 @@
+package = "inspect"
+version = "1.2-2"
+source = {
+ url = "https://github.com/kikito/inspect.lua/archive/v1.2.0.tar.gz",
+ dir = "inspect.lua-1.2.0"
+}
+description = {
+ summary = "Lua table visualizer, ideal for debugging",
+ detailed = [[
+ inspect will print out your lua tables nicely so you can debug your programs quickly. It sorts keys by type and name, handles data recursion
+ ]],
+ homepage = "https://github.com/kikito/inspect.lua",
+ license = "MIT <http://opensource.org/licenses/MIT>"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ inspect = "inspect.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-2.0-1.rockspec b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-2.0-1.rockspec
new file mode 100644
index 0000000..286bbd5
--- /dev/null
+++ b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-2.0-1.rockspec
@@ -0,0 +1,23 @@
+package = "inspect"
+version = "2.0-1"
+source = {
+ url = "https://github.com/kikito/inspect.lua/archive/v2.0.0.tar.gz",
+ dir = "inspect.lua-2.0.0"
+}
+description = {
+ summary = "Lua table visualizer, ideal for debugging",
+ detailed = [[
+ inspect will print out your lua tables nicely so you can debug your programs quickly. It sorts keys by type and name, handles data recursion
+ ]],
+ homepage = "https://github.com/kikito/inspect.lua",
+ license = "MIT <http://opensource.org/licenses/MIT>"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ inspect = "inspect.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-1.rockspec b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-1.rockspec
new file mode 100644
index 0000000..387d450
--- /dev/null
+++ b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-1.rockspec
@@ -0,0 +1,23 @@
+package = "inspect"
+version = "3.0-1"
+source = {
+ url = "https://github.com/kikito/inspect.lua/archive/v3.0.0.tar.gz",
+ dir = "inspect.lua-3.0.0"
+}
+description = {
+ summary = "Lua table visualizer, ideal for debugging",
+ detailed = [[
+ inspect will print out your lua tables nicely so you can debug your programs quickly. It sorts keys by type and name and handles recursive tables properly.
+ ]],
+ homepage = "https://github.com/kikito/inspect.lua",
+ license = "MIT <http://opensource.org/licenses/MIT>"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ inspect = "inspect.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-2.rockspec b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-2.rockspec
new file mode 100644
index 0000000..b22ec9c
--- /dev/null
+++ b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-2.rockspec
@@ -0,0 +1,23 @@
+package = "inspect"
+version = "3.0-2"
+source = {
+ url = "https://github.com/kikito/inspect.lua/archive/v3.0.1.tar.gz",
+ dir = "inspect.lua-3.0.1"
+}
+description = {
+ summary = "Lua table visualizer, ideal for debugging",
+ detailed = [[
+ inspect will print out your lua tables nicely so you can debug your programs quickly. It sorts keys by type and name and handles recursive tables properly.
+ ]],
+ homepage = "https://github.com/kikito/inspect.lua",
+ license = "MIT <http://opensource.org/licenses/MIT>"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ inspect = "inspect.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-3.rockspec b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-3.rockspec
new file mode 100644
index 0000000..9e07b01
--- /dev/null
+++ b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-3.rockspec
@@ -0,0 +1,23 @@
+package = "inspect"
+version = "3.0-3"
+source = {
+ url = "https://github.com/kikito/inspect.lua/archive/v3.0.2.tar.gz",
+ dir = "inspect.lua-3.0.2"
+}
+description = {
+ summary = "Lua table visualizer, ideal for debugging",
+ detailed = [[
+ inspect will print out your lua tables nicely so you can debug your programs quickly. It sorts keys by type and name and handles recursive tables properly.
+ ]],
+ homepage = "https://github.com/kikito/inspect.lua",
+ license = "MIT <http://opensource.org/licenses/MIT>"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ inspect = "inspect.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-4.rockspec b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-4.rockspec
new file mode 100644
index 0000000..56f3d48
--- /dev/null
+++ b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.0-4.rockspec
@@ -0,0 +1,23 @@
+package = "inspect"
+version = "3.0-4"
+source = {
+ url = "https://github.com/kikito/inspect.lua/archive/v3.0.3.tar.gz",
+ dir = "inspect.lua-3.0.3"
+}
+description = {
+ summary = "Lua table visualizer, ideal for debugging",
+ detailed = [[
+ inspect will print out your lua tables nicely so you can debug your programs quickly. It sorts keys by type and name and handles recursive tables properly.
+ ]],
+ homepage = "https://github.com/kikito/inspect.lua",
+ license = "MIT <http://opensource.org/licenses/MIT>"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ inspect = "inspect.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.1.1-0.rockspec b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.1.1-0.rockspec
new file mode 100644
index 0000000..740b644
--- /dev/null
+++ b/Data/DefaultContent/Libraries/inspect/rockspecs/inspect-3.1.1-0.rockspec
@@ -0,0 +1,23 @@
+package = "inspect"
+version = "3.1.1-0"
+source = {
+ url = "https://github.com/kikito/inspect.lua/archive/v3.1.1.tar.gz",
+ dir = "inspect.lua-3.1.1"
+}
+description = {
+ summary = "Lua table visualizer, ideal for debugging",
+ detailed = [[
+ inspect will print out your lua tables nicely so you can debug your programs quickly. It sorts keys by type and name and handles recursive tables properly.
+ ]],
+ homepage = "https://github.com/kikito/inspect.lua",
+ license = "MIT <http://opensource.org/licenses/MIT>"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ inspect = "inspect.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/inspect/spec/inspect_spec.lua b/Data/DefaultContent/Libraries/inspect/spec/inspect_spec.lua
new file mode 100644
index 0000000..edea720
--- /dev/null
+++ b/Data/DefaultContent/Libraries/inspect/spec/inspect_spec.lua
@@ -0,0 +1,460 @@
+local inspect = require 'inspect'
+local unindent = require 'spec.unindent'
+local is_luajit, ffi = pcall(require, 'ffi')
+local has_rawlen = type(_G.rawlen) == 'function'
+
+describe( 'inspect', function()
+
+ describe('numbers', function()
+ it('works', function()
+ assert.equals("1", inspect(1))
+ assert.equals("1.5", inspect(1.5))
+ assert.equals("-3.14", inspect(-3.14))
+ end)
+ end)
+
+ describe('strings', function()
+ it('puts quotes around regular strings', function()
+ assert.equals('"hello"', inspect("hello"))
+ end)
+
+ it('puts apostrophes around strings with quotes', function()
+ assert.equals("'I have \"quotes\"'", inspect('I have "quotes"'))
+ end)
+
+ it('uses regular quotes if the string has both quotes and apostrophes', function()
+ assert.equals('"I have \\"quotes\\" and \'apostrophes\'"', inspect("I have \"quotes\" and 'apostrophes'"))
+ end)
+
+ it('escapes newlines properly', function()
+ assert.equals('"I have \\n new \\n lines"', inspect('I have \n new \n lines'))
+ end)
+
+ it('escapes tabs properly', function()
+ assert.equals('"I have \\t a tab character"', inspect('I have \t a tab character'))
+ end)
+
+ it('escapes backspaces properly', function()
+ assert.equals('"I have \\b a back space"', inspect('I have \b a back space'))
+ end)
+
+ it('escapes unnamed control characters with 1 or 2 digits', function()
+ assert.equals('"Here are some control characters: \\0 \\1 \\6 \\17 \\27 \\31"',
+ inspect('Here are some control characters: \0 \1 \6 \17 \27 \31'))
+ end)
+
+ it('escapes unnamed control characters with 3 digits when they are followed by numbers', function()
+ assert.equals('"Control chars followed by digits \\0001 \\0011 \\0061 \\0171 \\0271 \\0311"',
+ inspect('Control chars followed by digits \0001 \0011 \0061 \0171 \0271 \0311'))
+ end)
+
+ it('backslashes its backslashes', function()
+ assert.equals('"I have \\\\ a backslash"', inspect('I have \\ a backslash'))
+ assert.equals('"I have \\\\\\\\ two backslashes"', inspect('I have \\\\ two backslashes'))
+ assert.equals('"I have \\\\\\n a backslash followed by a newline"',
+ inspect('I have \\\n a backslash followed by a newline'))
+ end)
+
+ end)
+
+ it('works with nil', function()
+ assert.equals('nil', inspect(nil))
+ end)
+
+ it('works with functions', function()
+ assert.equals('{ <function 1>, <function 2>, <function 1> }', inspect({ print, type, print }))
+ end)
+
+ it('works with booleans', function()
+ assert.equals('true', inspect(true))
+ assert.equals('false', inspect(false))
+ end)
+
+ if is_luajit then
+ it('works with luajit cdata', function()
+ assert.equals('{ cdata<int>: PTR, ctype<int>, cdata<int>: PTR }',
+ inspect({ ffi.new("int", 1), ffi.typeof("int"), ffi.typeof("int")(1) }):gsub('(0x%x+)','PTR'))
+ end)
+ end
+
+ describe('tables', function()
+
+ it('works with simple array-like tables', function()
+ assert.equals("{ 1, 2, 3 }", inspect({1,2,3}))
+ end)
+
+ it('works with nested arrays', function()
+ assert.equals('{ "a", "b", "c", { "d", "e" }, "f" }', inspect({'a','b','c', {'d','e'}, 'f'}))
+ end)
+
+ if has_rawlen then
+ it('handles arrays with a __len metatable correctly (ignoring the __len metatable and using rawlen)', function()
+ local arr = setmetatable({1,2,3}, {__len = function() return nil end})
+ assert.equals("{ 1, 2, 3,\n <metatable> = {\n __len = <function 1>\n }\n}", inspect(arr))
+ end)
+
+ it('handles tables with a __pairs metamethod (ignoring the __pairs metamethod and using next)', function()
+ local t = setmetatable({ {}, name = "yeah" }, { __pairs = function() end })
+ assert.equals(
+ unindent([[{ {},
+ name = "yeah",
+ <metatable> = {
+ __pairs = <function 1>
+ }
+ }]]),
+ inspect(t))
+ end)
+ end
+
+ it('works with simple dictionary tables', function()
+ assert.equals("{\n a = 1,\n b = 2\n}", inspect({a = 1, b = 2}))
+ end)
+
+ it('identifies tables with no number 1 as struct-like', function()
+ assert.equals(unindent([[{
+ [2] = 1,
+ [25] = 1,
+ id = 1
+ }
+ ]]), inspect({[2]=1,[25]=1,id=1}))
+ end)
+
+ it('identifies numeric non-array keys as dictionary keys', function()
+ assert.equals("{ 1, 2,\n [-1] = true\n}", inspect({1, 2, [-1] = true}))
+ assert.equals("{ 1, 2,\n [1.5] = true\n}", inspect({1, 2, [1.5] = true}))
+ end)
+
+ it('sorts keys in dictionary tables', function()
+ local t = { 1,2,3,
+ [print] = 1, ["buy more"] = 1, a = 1,
+ [coroutine.create(function() end)] = 1,
+ [14] = 1, [{c=2}] = 1, [true]= 1
+ }
+ assert.equals(unindent([[
+ { 1, 2, 3,
+ [14] = 1,
+ [true] = 1,
+ a = 1,
+ ["buy more"] = 1,
+ [{
+ c = 2
+ }] = 1,
+ [<function 1>] = 1,
+ [<thread 1>] = 1
+ }
+ ]]), inspect(t))
+ end)
+
+ it('works with nested dictionary tables', function()
+ assert.equals(unindent([[{
+ a = 1,
+ b = {
+ c = 2
+ },
+ d = 3
+ }]]), inspect( {d=3, b={c=2}, a=1} ))
+ end)
+
+ it('works with hybrid tables', function()
+ assert.equals(unindent([[
+ { "a", {
+ b = 1
+ }, 2,
+ ["ahoy you"] = 4,
+ c = 3
+ }
+ ]]), inspect({ 'a', {b = 1}, 2, c = 3, ['ahoy you'] = 4 }))
+
+
+ end)
+
+ it('displays <table x> instead of repeating an already existing table', function()
+ local a = { 1, 2, 3 }
+ local b = { 'a', 'b', 'c', a }
+ a[4] = b
+ a[5] = a
+ a[6] = b
+ assert.equals('<1>{ 1, 2, 3, <2>{ "a", "b", "c", <table 1> }, <table 1>, <table 2> }', inspect(a))
+ end)
+
+ describe('The depth parameter', function()
+ local level5 = { 1,2,3, a = { b = { c = { d = { e = 5 } } } } }
+ local keys = { [level5] = true }
+
+ it('has infinite depth by default', function()
+ assert.equals(unindent([[
+ { 1, 2, 3,
+ a = {
+ b = {
+ c = {
+ d = {
+ e = 5
+ }
+ }
+ }
+ }
+ }
+ ]]), inspect(level5))
+ end)
+ it('is modifiable by the user', function()
+ assert.equals(unindent([[
+ { 1, 2, 3,
+ a = {
+ b = {...}
+ }
+ }
+ ]]), inspect(level5, {depth = 2}))
+
+ assert.equals(unindent([[
+ { 1, 2, 3,
+ a = {...}
+ }
+ ]]), inspect(level5, {depth = 1}))
+
+ assert.equals(unindent([[
+ { 1, 2, 3,
+ a = {
+ b = {
+ c = {
+ d = {...}
+ }
+ }
+ }
+ }
+ ]]), inspect(level5, {depth = 4}))
+
+ assert.equals("{...}", inspect(level5, {depth = 0}))
+ end)
+
+ it('respects depth on keys', function()
+ assert.equals(unindent([[
+ {
+ [{ 1, 2, 3,
+ a = {
+ b = {
+ c = {...}
+ }
+ }
+ }] = true
+ }
+ ]]), inspect(keys, {depth = 4}))
+ end)
+ end)
+
+ describe('the newline option', function()
+ it('changes the substring used for newlines', function()
+ local t = {a={b=1}}
+
+ assert.equal("{@ a = {@ b = 1@ }@}", inspect(t, {newline='@'}))
+ end)
+ end)
+
+ describe('the indent option', function()
+ it('changes the substring used for indenting', function()
+ local t = {a={b=1}}
+
+ assert.equal("{\n>>>a = {\n>>>>>>b = 1\n>>>}\n}", inspect(t, {indent='>>>'}))
+ end)
+ end)
+
+ describe('the process option', function()
+
+ it('removes one element', function()
+ local names = {'Andrew', 'Peter', 'Ann' }
+ local removeAnn = function(item) if item ~= 'Ann' then return item end end
+ assert.equals('{ "Andrew", "Peter" }', inspect(names, {process = removeAnn}))
+ end)
+
+ it('uses the path', function()
+ local names = {'Andrew', 'Peter', 'Ann' }
+ local removeThird = function(item, path) if path[1] ~= 3 then return item end end
+ assert.equals('{ "Andrew", "Peter" }', inspect(names, {process = removeThird}))
+ end)
+
+ it('replaces items', function()
+ local names = {'Andrew', 'Peter', 'Ann' }
+ local filterAnn = function(item) return item == 'Ann' and '<filtered>' or item end
+ assert.equals('{ "Andrew", "Peter", "<filtered>" }', inspect(names, {process = filterAnn}))
+ end)
+
+ it('nullifies metatables', function()
+ local mt = {'world'}
+ local t = setmetatable({'hello'}, mt)
+ local removeMt = function(item) if item ~= mt then return item end end
+ assert.equals('{ "hello" }', inspect(t, {process = removeMt}))
+ end)
+
+ it('nullifies metatables using their paths', function()
+ local mt = {'world'}
+ local t = setmetatable({'hello'}, mt)
+ local removeMt = function(item, path) if path[#path] ~= inspect.METATABLE then return item end end
+ assert.equals('{ "hello" }', inspect(t, {process = removeMt}))
+ end)
+
+ it('nullifies the root object', function()
+ local names = {'Andrew', 'Peter', 'Ann' }
+ local removeNames = function(item) if item ~= names then return item end end
+ assert.equals('nil', inspect(names, {process = removeNames}))
+ end)
+
+ it('changes keys', function()
+ local dict = {a = 1}
+ local changeKey = function(item) return item == 'a' and 'x' or item end
+ assert.equals('{\n x = 1\n}', inspect(dict, {process = changeKey}))
+ end)
+
+ it('nullifies keys', function()
+ local dict = {a = 1, b = 2}
+ local removeA = function(item) return item ~= 'a' and item or nil end
+ assert.equals('{\n b = 2\n}', inspect(dict, {process = removeA}))
+ end)
+
+ it('prints inspect.KEY & inspect.METATABLE', function()
+ local t = {inspect.KEY, inspect.METATABLE}
+ assert.equals("{ inspect.KEY, inspect.METATABLE }", inspect(t))
+ end)
+
+ it('marks key paths with inspect.KEY and metatables with inspect.METATABLE', function()
+ local t = { [{a=1}] = setmetatable({b=2}, {c=3}) }
+
+ local items = {}
+ local addItem = function(item, path)
+ items[#items + 1] = {item = item, path = path}
+ return item
+ end
+
+ inspect(t, {process = addItem})
+
+ assert.same({
+ {item = t, path = {}},
+ {item = {a=1}, path = {{a=1}, inspect.KEY}},
+ {item = 'a', path = {{a=1}, inspect.KEY, 'a', inspect.KEY}},
+ {item = 1, path = {{a=1}, inspect.KEY, 'a'}},
+ {item = setmetatable({b=2}, {c=3}), path = {{a=1}}},
+ {item = 'b', path = {{a=1}, 'b', inspect.KEY}},
+ {item = 2, path = {{a=1}, 'b'}},
+ {item = {c=3}, path = {{a=1}, inspect.METATABLE}},
+ {item = 'c', path = {{a=1}, inspect.METATABLE, 'c', inspect.KEY}},
+ {item = 3, path = {{a=1}, inspect.METATABLE, 'c'}}
+ }, items)
+
+ end)
+
+ it('handles recursive tables correctly', function()
+ local tbl = { 1,2,3}
+ tbl.loop = tbl
+ inspect(tbl, { process=function(x) return x end})
+ end)
+ end)
+
+ describe('metatables', function()
+
+ it('includes the metatable as an extra hash attribute', function()
+ local foo = { foo = 1, __mode = 'v' }
+ local bar = setmetatable({a = 1}, foo)
+ assert.equals(unindent([[
+ {
+ a = 1,
+ <metatable> = {
+ __mode = "v",
+ foo = 1
+ }
+ }
+ ]]), inspect(bar))
+ end)
+
+ it('can be used on the __tostring metamethod of a table without errors', function()
+ local f = function(x) return inspect(x) end
+ local tbl = setmetatable({ x = 1 }, { __tostring = f })
+ assert.equals(unindent([[
+ {
+ x = 1,
+ <metatable> = {
+ __tostring = <function 1>
+ }
+ }
+ ]]), tostring(tbl))
+ end)
+
+ it('does not allow collecting weak tables while they are being inspected', function()
+ collectgarbage('stop')
+ finally(function() collectgarbage('restart') end)
+ local shimMetatable = {
+ __mode = 'v',
+ __index = function() return {} end,
+ }
+ local function shim() return setmetatable({}, shimMetatable) end
+ local t = shim()
+ t.key = shim()
+ assert.equals(unindent([[
+ {
+ key = {
+ <metatable> = <1>{
+ __index = <function 1>,
+ __mode = "v"
+ }
+ },
+ <metatable> = <table 1>
+ }
+ ]]), inspect(t))
+ end)
+
+ it('ignores metatables with __metatable field set to non-nil and non-table type', function()
+ local function process(item) return item end
+ local function inspector(data) return inspect(data, {process=process}) end
+
+ local foo = setmetatable({}, {__metatable=false})
+ local bar = setmetatable({}, {__metatable=true})
+ local baz = setmetatable({}, {__metatable=10})
+ local spam = setmetatable({}, {__metatable=nil})
+ local eggs = setmetatable({}, {__metatable={}})
+ assert.equals(unindent('{}'), inspector(foo))
+ assert.equals(unindent('{}'), inspector(bar))
+ assert.equals(unindent('{}'), inspector(baz))
+ assert.equals(unindent([[
+ {
+ <metatable> = {}
+ }
+ ]]), inspector(spam))
+ assert.equals(unindent([[
+ {
+ <metatable> = {}
+ }
+ ]]), inspector(eggs))
+ end)
+
+ describe('When a table is its own metatable', function()
+ it('accepts a table that is its own metatable without stack overflowing', function()
+ local x = {}
+ setmetatable(x,x)
+ assert.equals(unindent([[
+ <1>{
+ <metatable> = <table 1>
+ }
+ ]]), inspect(x))
+ end)
+
+ it('can invoke the __tostring method without stack overflowing', function()
+ local t = {}
+ t.__index = t
+ setmetatable(t,t)
+ assert.equals(unindent([[
+ <1>{
+ __index = <table 1>,
+ <metatable> = <table 1>
+ }
+ ]]), inspect(t))
+ end)
+ end)
+ end)
+ end)
+
+ it('allows changing the global tostring', function()
+ local save = _G.tostring
+ _G.tostring = inspect
+ local s = tostring({1, 2, 3})
+ _G.tostring = save
+ assert.equals("{ 1, 2, 3 }", s)
+ end)
+
+end)
diff --git a/Data/DefaultContent/Libraries/inspect/spec/unindent.lua b/Data/DefaultContent/Libraries/inspect/spec/unindent.lua
new file mode 100644
index 0000000..02324a1
--- /dev/null
+++ b/Data/DefaultContent/Libraries/inspect/spec/unindent.lua
@@ -0,0 +1,39 @@
+-- Unindenting transforms a string like this:
+-- [[
+-- {
+-- foo = 1,
+-- bar = 2
+-- }
+-- ]]
+--
+-- Into the same one without indentation, nor start/end newlines
+--
+-- [[{
+-- foo = 1,
+-- bar = 2
+-- }]]
+--
+-- This makes the strings look and read better in the tests
+--
+
+local getIndentPreffix = function(str)
+ local level = math.huge
+ local minPreffix = ""
+ local len
+ for preffix in str:gmatch("\n( +)") do
+ len = #preffix
+ if len < level then
+ level = len
+ minPreffix = preffix
+ end
+ end
+ return minPreffix
+end
+
+local unindent = function(str)
+ str = str:gsub(" +$", ""):gsub("^ +", "") -- remove spaces at start and end
+ local preffix = getIndentPreffix(str)
+ return (str:gsub("\n" .. preffix, "\n"):gsub("\n$", ""))
+end
+
+return unindent
diff --git a/Data/DefaultContent/Libraries/json4lua/README.md b/Data/DefaultContent/Libraries/json4lua/README.md
new file mode 100644
index 0000000..b4f8015
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/README.md
@@ -0,0 +1,52 @@
+# json4lua
+JSON and JSONRPC for Lua
+
+# Installation #
+```
+luarocks install --server=http://rocks.moonscript.org/manifests/amrhassan --local json4Lua
+```
+
+# JSON Usage #
+
+## Encoding ##
+
+```lua
+json = require('json')
+print(json.encode({ 1, 2, 'fred', {first='mars',second='venus',third='earth'} }))
+```
+```json
+[1,2,"fred", {"first":"mars","second":"venus","third":"earth"}]
+```
+
+## Decoding ##
+
+```lua
+json = require("json")
+testString = [[ { "one":1 , "two":2, "primes":[2,3,5,7] } ]]
+decoded = json.decode(testString)
+table.foreach(decoded, print)
+print ("Primes are:")
+table.foreach(decoded.primes,print)
+```
+```
+one 1
+two 2
+primes table: 0032B928
+Primes are:
+1 2
+2 3
+3 5
+4 7
+```
+
+# JSONRPC Usage #
+```lua
+json = require('json')
+require("json.rpc")
+server = json.rpc.proxy("http://jsolait.net/testj.py")
+result, error = server.echo('Test echo!')
+print(result)
+```
+```
+Test echo!
+```
diff --git a/Data/DefaultContent/Libraries/json4lua/doc/INSTALL.txt b/Data/DefaultContent/Libraries/json4lua/doc/INSTALL.txt
new file mode 100644
index 0000000..3e7cad3
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/doc/INSTALL.txt
@@ -0,0 +1,4 @@
+INSTALLATION
+============
+
+See INSTALLATION section in doc/index.html \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/json4lua/doc/LICENCE.txt b/Data/DefaultContent/Libraries/json4lua/doc/LICENCE.txt
new file mode 100644
index 0000000..48f61e7
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/doc/LICENCE.txt
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2009 Craig Mason-Jones
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/json4lua/doc/README.txt b/Data/DefaultContent/Libraries/json4lua/doc/README.txt
new file mode 100644
index 0000000..59e5b7b
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/doc/README.txt
@@ -0,0 +1,5 @@
+===================================================================================================================
+== README.txt
+===================================================================================================================
+
+Please see doc/index.html
diff --git a/Data/DefaultContent/Libraries/json4lua/doc/VERSION.txt b/Data/DefaultContent/Libraries/json4lua/doc/VERSION.txt
new file mode 100644
index 0000000..deae881
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/doc/VERSION.txt
@@ -0,0 +1,4 @@
+JSON4Lua and JSONRPC4Lua
+Version 1.0.0
+4 March 2015
+http://github.com/craigmj/json4lua/ \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/json4lua/doc/cgilua_patch.html b/Data/DefaultContent/Libraries/json4lua/doc/cgilua_patch.html
new file mode 100644
index 0000000..1b4d6b3
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/doc/cgilua_patch.html
@@ -0,0 +1,187 @@
+<html>
+<head>
+<title>JSON4Lua and JSONRPC4Lua</title>
+<style type="text/css">
+body {
+ font-family: Arial, Helvetica, Geneva;
+ font-size: 10pt;
+}
+
+.copyright {
+ color: #999999;
+ font-size: 8pt;
+ text-align:center;
+}
+
+.navBar {
+ border-left: 1px solid lightgray;
+ border-right: 1px solid lightgray;
+ border-bottom: 1px solid lightgray;
+ margin-top:5px;
+ margin-bottom: 5px;
+}
+.navBar h1 {
+ background-image: url('pics/lunartone.gif');
+ background-color: #e0c088;
+ color: white;
+ font-size: 9pt;
+ margin: 0px;
+ padding: 4px;
+}
+
+.navBar .navItem a {
+ color: #999999;
+ font-size: 8pt;
+ padding: 2px 2px 2px 10px;
+ text-decoration:none;
+}
+
+.navBar .navItem a:hover {
+ color: #ff9900;
+ text-decoration: underline;
+}
+
+.titleBar {
+ border-bottom: 2px dotted gray;
+ font-size: 20pt;
+ font-weight: bold;
+ margin-bottom: 15px;
+ width: 100%;
+}
+
+.workArea {
+ border: 1px none lightgray;
+ font-family: Times New Roman;
+ padding: 8px;
+ padding-left: 15px;
+}
+
+.workArea a {
+ font-weight: bold;
+ text-decoration: none;
+}
+
+.workArea a:hover {
+ color: #ff9900;
+ text-decoration: underline;
+}
+
+.workArea .downloadTable {
+ border: 1px solid lightgray;
+ padding: 0px;
+ margin: 0px;
+}
+
+.workArea .downloadTable * th {
+ background-color: #e0c088;
+ background-image: url('pics/lunartone.gif');
+ color: white;
+}
+
+.workArea .downloadTable * tr {
+ border: 1px solid lightgray;
+}
+
+.workArea .downloadTable * td {
+ vertical-align: top;
+}
+
+.workArea * dt {
+ font-size: 12pt;
+ margin-top: 10px;
+}
+
+.workArea * .example {
+ background-color: #ffffcc;
+ border: 1px dashed lightgray;
+ padding: 10px;
+}
+
+.workArea h1 {
+ font-size: 16pt;
+ font-weight: bold;
+}
+
+.workArea h2 {
+ font-size: 14pt;
+ font-weight: normal;
+ color: gray;
+}
+
+</style>
+<body>
+<table border="0">
+ <tr>
+ <td valign="top">
+ <img src="pics/json4lua.gif"><p/>
+ <!-- NAVIGATION BARS -->
+
+ <div class="navBar">
+ <h1>Home Page</h1>
+ <div class="navItem"><a href="index.html#news">Latest News</a></div>
+ <div class="navItem"><a href="index.html#introduction">Introduction</a></div>
+ <div class="navItem"><a href="index.html#licence">Licence</a></div>
+ <div class="navItem"><a href="index.html#requirements">Requirements</a></div>
+ <div class="navItem"><a href="index.html#download">Download</a></div>
+ <div class="navItem"><a href="index.html#installation">Installation</a></div>
+ <div class="navItem"><a href="index.html#usage">Usage &amp; Reference</a></div>
+ <div class="navItem"><a href="index.html#roadmap">History &amp; Roadmap</a></div>
+ </div> <!-- end of navigation bar: This Site -->
+
+ <div class="navBar">
+ <h1>json.luaforge</h1>
+ <div class="navItem"><a href="http://luaforge.net/projects/json/">Summary</a></div>
+ <div class="navItem"><a href="http://luaforge.net/forum/?group_id=143">Forums</a></div>
+ <div class="navItem"><a href="http://luaforge.net/tracker/?group_id=143">Tracker</a></div>
+ <div class="navItem"><a href="http://luaforge.net/news/?group_id=143">News</a></div>
+ <!--<div class="navItem"><a href="http://luaforge.net/scm/?group_id=143">CVS</a></div>-->
+ <div class="navItem"><a href="http://luaforge.net/frs/?group_id=143">Files</a></div>
+ </div> <!-- end of navigation bar: json.luaforge -->
+
+ <div class="navBar">
+ <h1>Lua</h1>
+ <div class="navItem"><a href="http://www.lua.org/">Lua</a></div>
+ <div class="navItem"><a href="http://www.luaforge.net/">Lua Forge</a></div>
+ <div class="navItem"><a href="http://www.keplerproject.org/cgilua/">CGI Lua</a></div>
+ <div class="navItem"><a href="http://www.keplerproject.org/compat/">Lua compat-5.1</a></div>
+ <div class="navItem"><a href="http://www.cs.princeton.edu/~diego/professional/luasocket/">Lua Socket 2.0</a></div>
+ <div class="navItem"><a href="http://www.keplerproject.org/xavante/">Xavante</a></div>
+ </div> <!-- end of navigation bar: Lua Resources -->
+
+ <div class="navBar">
+ <h1>JSON</h1>
+ <div class="navItem"><a href="http://www.json.org/">json.org</a></div>
+ <div class="navItem"><a href="http://www.json-rpc.org/">json-rpc.org</a></div>
+ </div> <!-- end of navigation bar: Lua Resources -->
+
+ </td>
+ <!-- MAIN WORK AREA -->
+ <td valign="top" class="workArea">
+ <div class="titleBar">Patching CGILua to handle <code>text/plain</code></div>
+
+ <!-- cgilua_patch.html -->
+JSON RPC (both the JSONRPC4Lua implementation and the <a href="http://www.jsolait.net/">jsolait Javascript</a> implementation) send the http request with a Content-Type of <code>text/plain</code>.<p/>
+
+CGILua 5.0 does not accept <code>text/plain</code> content, and will generate an error of 'Unsupported Media Type: text/plain'.<p/>
+
+This is easily patched in CGILua 5.0 by making the following change to <code>cgilua/post.lua</code>, line 286:<p/>
+Change:<pre>
+ elseif strfind (contenttype, "text/xml") then
+</pre>
+to
+<pre>
+ elseif strfind (contenttype, "text/xml") or strfind (contenttype, "text/plain") then
+</pre>
+This makes CGILua handle <code>text/plain</code> as it does <code>text/xml</code>, without parsing the incoming POST data.<p/>
+
+<b>Please note:</b> I have requested the maintainers of CGILua to make this change to CGILua, whereafter this patch will no longer be required.
+
+
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" class="copyright">&copy; 2005 Craig Mason-Jones</td>
+ </tr>
+</table>
+</body>
+</html> \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/json4lua/doc/index.html b/Data/DefaultContent/Libraries/json4lua/doc/index.html
new file mode 100644
index 0000000..12ec6c7
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/doc/index.html
@@ -0,0 +1,394 @@
+<html>
+<head>
+<title>JSON4Lua and JSONRPC4Lua</title>
+<style type="text/css">
+body {
+ font-family: Arial, Helvetica, Geneva;
+ font-size: 10pt;
+}
+
+.copyright {
+ color: #999999;
+ font-size: 8pt;
+ text-align:center;
+}
+
+.navBar {
+ border-left: 1px solid lightgray;
+ border-right: 1px solid lightgray;
+ border-bottom: 1px solid lightgray;
+ margin-top:5px;
+ margin-bottom: 5px;
+}
+.navBar h1 {
+ background-image: url('pics/lunartone.gif');
+ background-color: #e0c088;
+ color: white;
+ font-size: 9pt;
+ margin: 0px;
+ padding: 4px;
+}
+
+.navBar .navItem a {
+ color: #999999;
+ font-size: 8pt;
+ padding: 2px 2px 2px 10px;
+ text-decoration:none;
+}
+
+.navBar .navItem a:hover {
+ color: #ff9900;
+ text-decoration: underline;
+}
+
+.titleBar {
+ border-bottom: 2px dotted gray;
+ font-size: 20pt;
+ font-weight: bold;
+ margin-bottom: 15px;
+ width: 100%;
+}
+
+.workArea {
+ border: 1px none lightgray;
+ font-family: Times New Roman;
+ padding: 8px;
+ padding-left: 15px;
+}
+
+.workArea a {
+ font-weight: bold;
+ text-decoration: none;
+}
+
+.workArea a:hover {
+ color: #ff9900;
+ text-decoration: underline;
+}
+
+.workArea .downloadTable {
+ border: 1px solid lightgray;
+ padding: 0px;
+ margin: 0px;
+}
+
+.workArea .downloadTable * th {
+ background-color: #e0c088;
+ background-image: url('pics/lunartone.gif');
+ color: white;
+}
+
+.workArea .downloadTable * tr {
+ border: 1px solid lightgray;
+}
+
+.workArea .downloadTable * td {
+ vertical-align: top;
+}
+
+.workArea * dt {
+ font-size: 12pt;
+ margin-top: 10px;
+}
+
+.workArea * .example {
+ background-color: #ffffcc;
+ border: 1px dashed lightgray;
+ padding: 10px;
+}
+
+.workArea h1 {
+ font-size: 16pt;
+ font-weight: bold;
+}
+
+.workArea h2 {
+ font-size: 14pt;
+ font-weight: normal;
+ color: gray;
+}
+
+</style>
+<body>
+<table border="0">
+ <tr>
+ <td valign="top">
+ <img src="pics/json4lua.gif"><p/>
+ <!-- NAVIGATION BARS -->
+
+ <div class="navBar">
+ <h1>This Page</h1>
+ <div class="navItem"><a href="#news">Latest News</a></div>
+ <div class="navItem"><a href="#introduction">Introduction</a></div>
+ <div class="navItem"><a href="#licence">Licence</a></div>
+ <div class="navItem"><a href="#requirements">Requirements</a></div>
+ <div class="navItem"><a href="#download">Download</a></div>
+ <div class="navItem"><a href="#installation">Installation</a></div>
+ <div class="navItem"><a href="#usage">Usage &amp; Reference</a>
+ <div class="navItem" style="margin-left: 4px"><a href="#json_decode">decode</a></div>
+ <div class="navItem" style="margin-left: 4px"><a href="#json_encode">encode</a></div>
+ <div class="navItem" style="margin-left: 4px"><a href="#json_null">null</a></div>
+ <div class="navItem" style="margin-left: 4px"><a href="#json_rpc_call">rpc.call</a></div>
+ <div class="navItem" style="margin-left: 4px"><a href="#json_rpc_proxy">rpc.proxy</a></div>
+ <div class="navItem" style="margin-left: 4px"><a href="#json_rpcserver_serve">rpcserver.serve</a></div>
+
+ </div>
+ <div class="navItem"><a href="#roadmap">History &amp; Roadmap</a></div>
+ </div> <!-- end of navigation bar: This Site -->
+
+ <div class="navBar">
+ <h1>json.luaforge</h1>
+ <div class="navItem"><a href="http://luaforge.net/projects/json/">Summary</a></div>
+ <div class="navItem"><a href="http://luaforge.net/forum/?group_id=143">Forums</a></div>
+ <div class="navItem"><a href="http://luaforge.net/tracker/?group_id=143">Tracker</a></div>
+ <div class="navItem"><a href="http://luaforge.net/news/?group_id=143">News</a></div>
+ <!--<div class="navItem"><a href="http://luaforge.net/scm/?group_id=143">CVS</a></div>-->
+ <div class="navItem"><a href="http://luaforge.net/frs/?group_id=143">Files</a></div>
+ </div> <!-- end of navigation bar: json.luaforge -->
+
+ <div class="navBar">
+ <h1>Lua</h1>
+ <div class="navItem"><a href="http://www.lua.org/">Lua</a></div>
+ <div class="navItem"><a href="http://www.luaforge.net/">Lua Forge</a></div>
+ <div class="navItem"><a href="http://www.keplerproject.org/cgilua/">CGI Lua</a></div>
+ <div class="navItem"><a href="http://www.keplerproject.org/compat/">Lua compat-5.1</a></div>
+ <div class="navItem"><a href="http://www.cs.princeton.edu/~diego/professional/luasocket/">Lua Socket 2.0</a></div>
+ <div class="navItem"><a href="http://www.keplerproject.org/xavante/">Xavante</a></div>
+ </div> <!-- end of navigation bar: Lua Resources -->
+
+ <div class="navBar">
+ <h1>JSON</h1>
+ <div class="navItem"><a href="http://www.json.org/">json.org</a></div>
+ <div class="navItem"><a href="http://www.json-rpc.org/">json-rpc.org</a></div>
+ </div> <!-- end of navigation bar: Lua Resources -->
+
+ </td>
+ <!-- MAIN WORK AREA -->
+ <td valign="top" class="workArea">
+ <div class="titleBar">JSON4Lua and JSONRPC4Lua</div>
+ <!-- ***************** LATEST NEWS ***************** -->
+ <h1><a name="news"></a>Latest News</h1>
+ <p><small>(2009-08-06)</small> We've changed the JSON4Lua and JSONRPC4Lua licence from the GPL to the MIT licence, like Lua itself.</p>
+ <p>
+ The 0.9.20 release fixes a bug in Lua 5.1 operation, introduces a <a href="#json_null"><code>json.null</code></a> value to force null values in JSON encodings, improves performance (over 50% faster on some tests), and permits <code>/* comments */</code> in the JSON string being decoded.
+ </p>
+
+ <!-- ***************** INTRODUCTION ***************** -->
+ <h1><a name="introduction"></a>Introduction</h1>
+ JSON4Lua and JSONRPC4Lua implement <a href="http://www.json.org">JSON (JavaScript Object Notation)</a> encoding and decoding and a <a href="http://www.json-rpc.org/">JSON-RPC-over-http</a> client for <a href="http://www.lua.org/">Lua</a>.<p/>
+
+JSON is JavaScript Object Notation, a simple encoding of Javascript-like objects that is ideal for lightweight transmission of relatively weakly-typed data.
+A sub-package of JSON4Lua is JSONRPC4Lua, which provides a simple JSON-RPC-over-http client and server (in a CGILua environment) for Lua. Please seen the documentation below for JSONRPC4Lua.
+
+ <!-- ***************** LICENCE ***************** -->
+ <h1><a name="licence"></a>Licence</h1>
+ JSON4Lua is licensed under the MIT Consortium licence like Lua itself. Please see <a href="LICENCE.txt">LICENCE.txt</a> for details.<p/>
+
+ <!-- ***************** REQUIREMENTS ***************** -->
+ <a name="requirements"></a><h1>Requirements</h1>
+ JSON4Lua is a pure-Lua module that is Lua 5.0 compatible (if you have <a href="http://www.keplerproject.org/compat/">compat-5.1</a> for Lua 5.0). JSON4Lua also works (perfectly, I hope) under Lua 5.1, which is where I largely use it nowadays. Since Lua is platform independent, so is JSON4Lua.<p/>
+
+ The JSON4RPC sub-module requires <a href="http://www.cs.princeton.edu/~diego/professional/luasocket/">Lua Socket 2.0</a>. It uses <code>socket.http</code> for for the RPC over http connection. Socket 2.0 includes <code>ltn12</code>, which is also used by JSON4RPC.<p />
+
+ To use <code>json.rpcserver</code> you need a <a href="http://www.keplerproject.org/cgilua/">CGILua</a> enabled webserver. However, a quick <a href="cgilua_patch.html">patch</a> is required in CGILua 5.0 to support JSON-RPC.
+
+ <!-- ***************** START OF DOWNLOAD SECTION ***************** -->
+ <h1><a name="download"></a>Download</h1>
+ JSON4Lua is hosted on <a href="http://www.luaforge.net">LuaForge</a>.
+ <table cols="2" class="downloadTable">
+ <tr><th>Version</th><th>Date</th><th>Notes</th></tr>
+ <tr><td><a href="http://luaforge.net/frs/?group_id=143">0.9.30</a></td><td>6 August 2009</td><td>
+ Changed to MIT Licence.
+ </td></tr>
+ <tr><td><a href="http://luaforge.net/frs/?group_id=143">0.9.20</a></td><td>4 January 2006</td><td>
+ Introduction of local Lua functions for private functions (removed _ function prefix). <br />
+ Fixed Lua 5.1 compatibility issues.<br />
+ Introduced <code>json.null</code> to have null values in associative arrays.<br />
+ Performance improvement (more than 50% on some tests) through <code>table.concat</code> rather than <code>..</code> operator.<br/>
+ <code>json.decode</code> now ignores <code>/* */</code> comments in the JSON string.<br />
+ </td></tr>
+ <tr><td><a href="http://luaforge.net/frs/?group_id=143">0.9.10</a></td><td>20 December 2005</td><td>
+ Fixes bug with array representation when nil / null values occur in the array.<br />
+ Adds content-type header of <code>text/plain</code> to JSON RPC http requests.<br />
+ Introduces <code>json.rpcserver</code> module with simple JSON RPC enablement for Lua objects.<br />
+ Moved the <code>json.lua</code> file into the <code>json</code> directory. Ensure, therefore, that your <code>LUA_PATH</code> contains a module-finding form like <code>LUA_PATH = c:\proj\lua\?\?.lua;?.lua</code>.<br/>
+ </td></tr>
+ <tr>
+ <td><a href="http://luaforge.net/frs/?group_id=143">0.9.01</a></td>
+ <td>19 December 2005</td>
+ <td>Minor corrections to documentation.</td>
+ </tr>
+ <tr>
+ <td><a href="http://luaforge.net/frs/?group_id=143">0.9.00</a></td>
+ <td>19 December 2005</td>
+ <td>First release</td>
+ </tr>
+ </table>
+ <!-- END OF DOWNLOAD SECTION -->
+
+ <!-- ***************** START OF INSTALLATION SECTION ***************** -->
+ <h1><a name="installation"></a>Installation</h1>
+ As of version 0.9.10, all the JSON4Lua files are contained in the <code>json</code> subdirectory in the distribution zip.<p />
+ Simply copy the <code>json</code> subdirectory so that it is in your Lua path.<p />
+ Ensure that your <code>LUA_PATH</code> variable permits module resolution of the form <code>?/?.lua</code>.<p />
+ <b>Example</b>
+ <div class="example">
+ </div>
+ <h2>Using Windows</h2>
+ Under Windows, set your Lua path as (my Lua installation is in <code>c:\proj\lua\</code>): <p/>
+ <code>
+ set LUA_PATH=c:\proj\lua\?.lua;c:\proj\lua\?\?.lua;?.lua
+ </code><p/>
+ For compat-5.1.lua to start when Lua starts (if you're using Lua 5.0), you also need:<p/>
+ <code>
+ set LUA_INIT=@c:\proj\lua\compat-5.1.lua
+ </code><p />
+ You probably also want to set your library path:<p/>
+ <code>set LUA_CPATH=c:\proj\lua\lib\?.dll;?.dll</code>
+
+ <!------------------------ USAGE AND REFERENCE -------------------->
+ <h1><a name="usage"></a>Usage &amp; Reference</h1>
+ The following functions in <b>JSON4Lua</b> and <b>JSONRPC4Lua</b> are of interest:<p />
+ <dl>
+ <dt><a name="json_encode"></a><code>string <b>json.encode</b>( lua_object )</code></dt>
+ <dd>Returns the Lua object JSON encoded into a string.<p/>
+ <b>Example</b>
+ <div class="example">
+ <code>
+ json = require("json")<br/>
+ print (json.encode( { 1, 2, 'fred', {first='mars',second='venus',third='earth'} } ))
+ </code><p/>
+ prints<p/><code> [1,2,"fred", {"first":"mars","second":"venus","third","earth"}]</code>
+ </div>
+
+ </dd>
+ <dt><a name="json_decode"></a><code>lua_object <b>json.decode</b>( json_string )</code></dt>
+ <dd>Decodes the JSON encoded data structure, and returns a Lua object with the appropriate data.<p/>
+ <b>Example</b>
+
+ <div class="example">
+ <code>
+ json = require("json")<br/>
+
+ testString = [[ { "one":1 , "two":2, "primes":[2,3,5,7] } ]]<br/>
+ o = json.decode(testString)<br/>
+ table.foreach(o,print)<br />
+ print ("Primes are:")<br />
+ table.foreach(o.primes,print)
+ </code><p/>
+ prints:<p/>
+ <pre>
+one 1
+two 2
+primes table: 0032B928
+Primes are:
+1 2
+2 3
+3 5
+4 7</pre>
+ </div></dd>
+
+ <dt><a name="json_null"></a><code><b>json.null</b></code></dt>
+ <dd>Returns a unique value that will be encoded as a <code>null</code> in a JSON encoding.
+ <p>This is necessary in one situation. In Lua, if a key in a table has a <code>nil</code> value, the key is simply discarded (since any non-existent key has a nil value). The encoding of arrays has been built to manage this nil-values in arrays, but associative arrays provide a problem. Consider:
+ <div class="example"><pre>t = { user="test", password=nil }</pre></div>
+ Since Lua simply discards the <code>password</code> key, JSON4Lua encodes this as the JSON string
+ <div class="example"><pre>{"user":"test"}</pre></div>
+ If, for some reason, your JSON RPC Server requires a defined <code>null</code> value, use the following code:
+ <div class="example"><pre>t = { user="test", password=json.null }</pre></div>
+ This will now correctly encode to:
+ <div class="example"><pre>{"user":"test","password":null}</pre></div>
+ Incidentally, <code>json.null</code> is simply a function that returns itself, so that you can use either <code>json.null</code> or <code>json.null()</code> as you fancy.
+ </dd>
+
+
+ <dt><a name="json_rpc_call"></a><code>result, error <b>json.rpc.call</b> ( url, method, ...)</code></dt>
+ <dd>Calls the named method on the given url with the arg parameters. Returns the result and the error. If <code>error</code> is <code>nil</code>, no error occurred.<p/>
+ <b>Example</b>
+ <div class="example">
+ <pre>require ("json.rpc")
+result, error = json.rpc.call("http://jsolait.net/testj.py","echo","Test echo!")
+print(result)</pre>
+ <p />prints<p />
+ <pre>Test echo!</pre>
+ </div>
+ </dd>
+ <dt><a name="json_rpc_proxy"></a><code>proxyServer = <b>json.rpc.proxy</b> (url)</code></dt>
+ <dd>Creates a proxy server object on which JSON-RPC calls can be made. Each call will return the <code>result, error</code>. If <code>error</code> is <code>nil</code>, no error occurred.<p/>
+ <b>Example</b>
+ <div class="example">
+ <pre>
+require ("json.rpc")
+server = json.rpc.proxy("http://jsolait.net/testj.py")
+result, error = server.echo('Test echo!')
+print(result)</pre>
+ <p />prints<p />
+ <pre>Test echo!</pre>
+ </div>
+ </dd>
+
+ <dt><a name="json_rpcserver_serve"></a><code><b>json.rpcserver.serve</b>(object[, packReturn])</code></dt>
+ <dd>
+ Handles an incoming CGILua request as a JSON RPC request and serves the request from
+ the given object.
+ <p />The optional <code>packReturn</code> parameter, if set <code>true</code>, will, if the requested
+ method returns more than one value, pack these returned values into an array. If only a single value
+ is returned, it is not packed into an array. If <code>packReturn</code> is <code>false</code> (or not set), only the first
+ return value from the requested method will be returned. This is necessitated since the JSON protocol does not permit a method call to return more than a single value.
+ <p/>
+
+ <code>serve</code> returns nothing.<p/>
+
+ <b>Example</b>
+ <div class="example">
+ <pre>
+--
+-- jsonrpc.lua
+-- Installed in a CGILua webserver environment (with necessary CGI Lua 5.0 patch)
+--
+require ('json.rpcserver')
+
+-- The Lua class that is to serve JSON RPC requests
+local myServer = {
+ echo = function (msg) return msg end,
+ average = function(...)
+ local total=0
+ local count=0
+ for i=1, table.getn(arg) do
+ total = total + arg[i]
+ count = count + 1
+ end
+ return { average= total/count, sum = total, n=count }
+ end
+}
+
+json.rpcserver.serve(myServer)
+</pre>
+An example of using this JSON RPC server from a Lua file:
+<pre>
+require ('json.rpc')
+local server = json.rpc.proxy('http://www.myserver.com/jsonrpc.lua')
+table.foreach(server.average(10,15,23), print)
+</pre>
+Prints:
+<pre>
+average 16
+sum 48
+n 3
+</pre>
+ </div>
+
+ </dd>
+ </dl>
+
+ <!-- ***************** HISTORY AND ROADMAP ***************** -->
+ <h1><a name="roadmap"></a>History &amp; Roadmap</h1>
+ The downloads sections details the versions and their related histories. I will wait for Lua 5.1 to be final (expected late January) before making the JSON4Lua module beta. If no serious bugs or objections are encountered, I will make the module 1.0 on 1 April 2006 (to coincide with April Fool's day!)
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" class="copyright">&copy; 2005, 2006 Craig Mason-Jones</td>
+ </tr>
+</table>
+</body>
+</html> \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/json4lua/doc/pics/json4lua.gif b/Data/DefaultContent/Libraries/json4lua/doc/pics/json4lua.gif
new file mode 100644
index 0000000..938bcb9
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/doc/pics/json4lua.gif
Binary files differ
diff --git a/Data/DefaultContent/Libraries/json4lua/doc/pics/lunartone.gif b/Data/DefaultContent/Libraries/json4lua/doc/pics/lunartone.gif
new file mode 100644
index 0000000..e914a8f
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/doc/pics/lunartone.gif
Binary files differ
diff --git a/Data/DefaultContent/Libraries/json4lua/examples/example.lua b/Data/DefaultContent/Libraries/json4lua/examples/example.lua
new file mode 100644
index 0000000..36497da
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/examples/example.lua
@@ -0,0 +1,23 @@
+--[[
+JSON4Lua example script.
+Demonstrates the simple functionality of the json module.
+]]--
+json = require('json')
+
+
+-- Object to JSON encode
+test = {
+ one='first',two='second',three={2,3,5}
+}
+
+jsonTest = json.encode(test)
+
+print('JSON encoded test is: ' .. jsonTest)
+
+-- Now JSON decode the json string
+result = json.decode(jsonTest)
+
+print ("The decoded table result:")
+table.foreach(result,print)
+print ("The decoded table result.three")
+table.foreach(result.three, print)
diff --git a/Data/DefaultContent/Libraries/json4lua/examples/jsonrpc.lua b/Data/DefaultContent/Libraries/json4lua/examples/jsonrpc.lua
new file mode 100644
index 0000000..f265b8a
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/examples/jsonrpc.lua
@@ -0,0 +1,21 @@
+--
+-- jsonrpc.lua
+-- Installed in a CGILua webserver environment (with necessary CGI Lua 5.0 patch)
+--
+require ('json.rpcserver')
+
+-- The Lua class that is to serve JSON RPC requests
+local myServer = {
+ echo = function (msg) return msg end,
+ average = function(...)
+ local total=0
+ local count=0
+ for i=1, table.getn(arg) do
+ total = total + arg[i]
+ count = count + 1
+ end
+ return { average= total/count, sum = total, n=count }
+ end
+}
+
+json.rpcserver.serve(myServer) \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/json4lua/examples/tests.lua b/Data/DefaultContent/Libraries/json4lua/examples/tests.lua
new file mode 100644
index 0000000..2e58b6e
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/examples/tests.lua
@@ -0,0 +1,223 @@
+--[[
+Some basic tests for JSON4Lua.
+]]--
+
+--- Compares two tables for being data-identical.
+function compareData(a,b)
+ if (type(a)=='string' or type(a)=='number' or type(a)=='boolean' or type(a)=='nil') then return a==b end
+ -- After basic data types, we're only interested in tables
+ if (type(a)~='table') then return true end
+ -- Check that a has everything b has
+ for k,v in pairs(b) do
+ if (not compareData( a[k], v ) ) then return false end
+ end
+ for k,v in pairs(a) do
+ if (not compareData( v, b[k] ) ) then return false end
+ end
+ return true
+end
+
+---
+-- Checks that our compareData function works properly
+function testCompareData()
+ s = "name"
+ r = "name"
+ assert(compareData(s,r))
+ assert(not compareData('fred',s))
+ assert(not compareData(nil, s))
+ assert(not compareData("123",123))
+ assert(not compareData(false, nil))
+ assert(compareData(true, true))
+ assert(compareData({1,2,3},{1,2,3}))
+ assert(compareData({'one',2,'three'},{'one',2,'three'}))
+ assert(not compareData({'one',2,4},{4,2,'one'}))
+ assert(compareData({one='ichi',two='nichi',three='san'}, {three='san',two='nichi',one='ichi'}))
+ s = { one={1,2,3}, two={one='hitotsu',two='futatsu',three='mitsu'} }
+ assert(compareData(s,s))
+ t = { one={1,2,3}, two={one='een',two='twee',three='drie'} }
+ assert(not compareData(s,t))
+end
+
+testCompareData()
+
+--
+--
+-- Performs some perfunctory tests on JSON module
+function testJSON4Lua()
+ json = require('json')
+
+ if nil then
+ -- Test encodeString
+ s = [["\"
+]]
+ r = json._encodeString(s)
+ assert(r=='\\"\\\\\\"\\n')
+ s = [["""\\\"]]
+ r = json._encodeString(s)
+ assert(r==[[\"\"\"\\\\\\\"]])
+
+ end
+
+ -- Test encode for basic strings (complicated strings)
+ s = [[Hello, Lua!]]
+ r = json.encode(s)
+ assert(r=='"Hello, Lua!"')
+ s = [["\"
+]]
+ r = json.encode(s)
+ assert(r=='\"\\"\\\\\\"\\n\"')
+ s = [["""\\\"]]
+ r = json.encode(s)
+ assert(r==[["\"\"\"\\\\\\\""]])
+
+ -- Test encode for numeric values
+ s = 23
+ r = json.encode(s)
+ assert(r=='23')
+ s=48.123
+ r = json.encode(s)
+ assert(r=='48.123')
+
+ -- Test encode for boolean values
+ assert(json.encode(true)=='true')
+ assert(json.encode(false)=='false')
+ assert(json.encode(nil)=='null')
+
+ -- Test encode for arrays
+ s = {1,2,3}
+ r = json.encode(s)
+ assert(r=="[1,2,3]")
+ s = {9,9,9}
+ r = json.encode(s)
+ assert(r=="[9,9,9]")
+
+ -- Complex array test
+ s = { 2, 'joe', false, nil, 'hi' }
+ r = json.encode(s)
+ assert(r=='[2,"joe",false,null,"hi"]')
+
+ -- Test encode for tables
+ s = {Name='Craig',email='craig@lateral.co.za',age=35}
+ r = json.encode(s)
+ -- NB: This test can fail because of order: need to test further once
+ -- decoding is supported.
+ -- assert(r==[[{"age":35,"Name":"Craig","email":"craig@lateral.co.za"}]])
+
+ -- Test encoding tables with numeric (string) indexes
+ s = {}
+ s['1']='One'
+ r = json.encode(s)
+ -- print("r = ", r)
+ assert(r=='{"1":"One"}')
+
+ s['2']= {One='Uno'}
+ r = json.encode(s)
+ assert(compareData(json.decode(r), s))
+
+ -- Test decode_scanWhitespace
+ if nil then
+ s = " \n \r \t "
+ e = json._decode_scanWhitespace(s,1)
+ assert(e==string.len(s)+1)
+ s = " \n\r\t4"
+ assert(json._decode_scanWhitespace(s,1)==5)
+
+ -- Test decode_scanString
+ s = [["Test"]]
+ r,e = json._decode_scanString(s,1)
+ assert(r=='Test' and e==7)
+ s = [["This\nis a \"test"]]
+ r = json._decode_scanString(s,1)
+ assert(r=="This\nis a \"test")
+
+ s = [["Test\u00A7\\"]]
+ r,e = json._decode_scanString(s,1)
+ assert(r=="Test\xC2\xA7\\" and e==9)
+
+ -- Test decode_scanNumber
+ s = [[354]]
+ r,e = json._decode_scanNumber(s,1)
+ assert(r==354 and e==4)
+ s = [[ 4565.23 AND OTHER THINGS ]]
+ r,e = json._decode_scanNumber(s,2)
+ assert(r==4565.23 and e==9)
+ s = [[ -23.22 and ]]
+ r,e = json._decode_scanNumber(s,2)
+ assert(r==-23.22 and e==8)
+
+ -- Test decode_scanConstant
+ s = "true"
+ r,e = json._decode_scanConstant(s,1)
+ assert(r==true and e==5)
+ s = " false "
+ r,e = json._decode_scanConstant(s,3)
+ assert(r==false and e==8)
+ s = "1null6"
+ r,e = json._decode_scanConstant(s,2)
+ assert(r==nil and e==6)
+
+ -- Test decode_scanArray
+ s = "[1,2,3]"
+ r,e = json._decode_scanArray(s,1)
+ assert(compareData(r,{1,2,3}))
+ s = [[[ 1 , 3 ,5 , "Fred" , true, false, null, -23 ] ]]
+ r,e = json._decode_scanArray(s,1)
+ assert(compareData(r, {1,3,5,'Fred',true,false,nil,-23} ) )
+ s = "[3,5,null,7,9]"
+ r,e = json._decode_scanArray(s,1)
+ assert(compareData(r, {3,5,nil,7,9}))
+ s = "[3,5,null,7,9,null,null]"
+ r,e = json._decode_scanArray(s,1)
+ assert(compareData(r, {3,5,nil,7,9,nil,nil}))
+
+ end
+
+ s = [["Test\u00A7\\\""]]
+ r,e = json.decode(s)
+ assert(r=="Test\xC2\xA7\\\"", r)
+
+ -- Test decode_scanObject
+ s = [[ {"one":1, "two":2, "three":"three", "four":true} ]]
+ r,e = json.decode(s)
+ -- for x,y in pairs(r) do
+ -- print(x,y)
+ -- end
+ assert(compareData(r,{one=1,two=2,three='three',four=true}))
+ s = [[ { "one" : { "first":1,"second":2,"third":3}, "two":2, "three":false } ]]
+ r,e = json.decode(s)
+ assert(compareData(r, {one={first=1,second=2,third=3},two=2,three=false}))
+ s = [[ { "primes" : [2,3,5,7,9], "user":{"name":"craig","age":35,"programs_lua":true},
+ "lua_is_great":true } ]]
+ r,e = json.decode(s)
+ assert(compareData(r, {primes={2,3,5,7,9},user={name='craig',age=35,programs_lua=true},lua_is_great=true}))
+
+ -- Test json.null management
+ t = { 1,2,json.null,4 }
+ assert( json.encode(t)=="[1,2,null,4]" )
+ t = {x=json.null }
+ r = json.encode(t)
+ assert( json.encode(t) == '{"x":null}' )
+
+ -- Test comment decoding
+ s = [[ /* A comment
+ that spans
+ a few lines
+ */
+ "test"
+ ]]
+ r,e = json.decode(s)
+ assert(r=='test',"Comment decoding failed")
+
+ -- Per error reported by M.Hund, with incorrect decoding of string-numbered tables
+ s = {}
+ subt = {a="a",b="b",c="c"}
+ s['1'] = subt
+ s['2'] = subt
+ s['3'] = subt
+ r = json.decode('{"1":{"a":"a","b":"b","c":"c"},"2":{"a":"a","b":"b","c":"c"},"3":{"a":"a","b":"b","c":"c"}}')
+ assert(compareData(s, r))
+end
+
+testJSON4Lua()
+
+print("JSON4Lua tests completed successfully")
diff --git a/Data/DefaultContent/Libraries/json4lua/examples/timetrials.lua b/Data/DefaultContent/Libraries/json4lua/examples/timetrials.lua
new file mode 100644
index 0000000..cbda514
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/examples/timetrials.lua
@@ -0,0 +1,46 @@
+--[[
+ Some Time Trails for the JSON4Lua package
+]]--
+
+
+require('json')
+require('os')
+require('table')
+
+local t1 = os.clock()
+local jstr
+local v
+for i=1,100 do
+ local t = {}
+ for j=1,500 do
+ table.insert(t,j)
+ end
+ for j=1,500 do
+ table.insert(t,"VALUE")
+ end
+ jstr = json.encode(t)
+ v = json.decode(jstr)
+ --print(json.encode(t))
+end
+
+for i = 1,100 do
+ local t = {}
+ for j=1,500 do
+ local m= math.mod(j,3)
+ if (m==0) then
+ t['a'..j] = true
+ elseif m==1 then
+ t['a'..j] = json.null
+ else
+ t['a'..j] = j
+ end
+ end
+ jstr = json.encode(t)
+ v = json.decode(jstr)
+end
+
+print (jstr)
+--print(type(t1))
+local t2 = os.clock()
+
+print ("Elapsed time=" .. os.difftime(t2,t1) .. "s") \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/json4lua/json/json.lua b/Data/DefaultContent/Libraries/json4lua/json/json.lua
new file mode 100644
index 0000000..79761b6
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/json/json.lua
@@ -0,0 +1,427 @@
+-----------------------------------------------------------------------------
+-- JSON4Lua: JSON encoding / decoding support for the Lua language.
+-- json Module.
+-- Author: Craig Mason-Jones
+-- Homepage: http://github.com/craigmj/json4lua/
+-- Version: 1.0.0
+-- This module is released under the MIT License (MIT).
+-- Please see LICENCE.txt for details.
+--
+-- USAGE:
+-- This module exposes two functions:
+-- json.encode(o)
+-- Returns the table / string / boolean / number / nil / json.null value as a JSON-encoded string.
+-- json.decode(json_string)
+-- Returns a Lua object populated with the data encoded in the JSON string json_string.
+--
+-- REQUIREMENTS:
+-- compat-5.1 if using Lua 5.0
+--
+-- CHANGELOG
+-- 0.9.20 Introduction of local Lua functions for private functions (removed _ function prefix).
+-- Fixed Lua 5.1 compatibility issues.
+-- Introduced json.null to have null values in associative arrays.
+-- json.encode() performance improvement (more than 50%) through table.concat rather than ..
+-- Introduced decode ability to ignore /**/ comments in the JSON string.
+-- 0.9.10 Fix to array encoding / decoding to correctly manage nil/null values in arrays.
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Imports and dependencies
+-----------------------------------------------------------------------------
+local math = require('math')
+local string = require("string")
+local table = require("table")
+
+-----------------------------------------------------------------------------
+-- Module declaration
+-----------------------------------------------------------------------------
+local json = {} -- Public namespace
+local json_private = {} -- Private namespace
+
+-- Public constants
+json.EMPTY_ARRAY={}
+json.EMPTY_OBJECT={}
+
+-- Public functions
+
+-- Private functions
+local decode_scanArray
+local decode_scanComment
+local decode_scanConstant
+local decode_scanNumber
+local decode_scanObject
+local decode_scanString
+local decode_scanWhitespace
+local encodeString
+local isArray
+local isEncodable
+
+-----------------------------------------------------------------------------
+-- PUBLIC FUNCTIONS
+-----------------------------------------------------------------------------
+--- Encodes an arbitrary Lua object / variable.
+-- @param v The Lua object / variable to be JSON encoded.
+-- @return String containing the JSON encoding in internal Lua string format (i.e. not unicode)
+function json.encode (v)
+ -- Handle nil values
+ if v==nil then
+ return "null"
+ end
+
+ local vtype = type(v)
+
+ -- Handle strings
+ if vtype=='string' then
+ return '"' .. json_private.encodeString(v) .. '"' -- Need to handle encoding in string
+ end
+
+ -- Handle booleans
+ if vtype=='number' or vtype=='boolean' then
+ return tostring(v)
+ end
+
+ -- Handle tables
+ if vtype=='table' then
+ local rval = {}
+ -- Consider arrays separately
+ local bArray, maxCount = isArray(v)
+ if bArray then
+ for i = 1,maxCount do
+ table.insert(rval, json.encode(v[i]))
+ end
+ else -- An object, not an array
+ for i,j in pairs(v) do
+ if isEncodable(i) and isEncodable(j) then
+ table.insert(rval, '"' .. json_private.encodeString(i) .. '":' .. json.encode(j))
+ end
+ end
+ end
+ if bArray then
+ return '[' .. table.concat(rval,',') ..']'
+ else
+ return '{' .. table.concat(rval,',') .. '}'
+ end
+ end
+
+ -- Handle null values
+ if vtype=='function' and v==json.null then
+ return 'null'
+ end
+
+ assert(false,'encode attempt to encode unsupported type ' .. vtype .. ':' .. tostring(v))
+end
+
+
+--- Decodes a JSON string and returns the decoded value as a Lua data structure / value.
+-- @param s The string to scan.
+-- @param [startPos] Optional starting position where the JSON string is located. Defaults to 1.
+-- @param Lua object, number The object that was scanned, as a Lua table / string / number / boolean or nil,
+-- and the position of the first character after
+-- the scanned JSON object.
+function json.decode(s, startPos)
+ startPos = startPos and startPos or 1
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=string.len(s), 'Unterminated JSON encoded object found at position in [' .. s .. ']')
+ local curChar = string.sub(s,startPos,startPos)
+ -- Object
+ if curChar=='{' then
+ return decode_scanObject(s,startPos)
+ end
+ -- Array
+ if curChar=='[' then
+ return decode_scanArray(s,startPos)
+ end
+ -- Number
+ if string.find("+-0123456789.e", curChar, 1, true) then
+ return decode_scanNumber(s,startPos)
+ end
+ -- String
+ if curChar==[["]] or curChar==[[']] then
+ return decode_scanString(s,startPos)
+ end
+ if string.sub(s,startPos,startPos+1)=='/*' then
+ return json.decode(s, decode_scanComment(s,startPos))
+ end
+ -- Otherwise, it must be a constant
+ return decode_scanConstant(s,startPos)
+end
+
+--- The null function allows one to specify a null value in an associative array (which is otherwise
+-- discarded if you set the value with 'nil' in Lua. Simply set t = { first=json.null }
+function json.null()
+ return json.null -- so json.null() will also return null ;-)
+end
+-----------------------------------------------------------------------------
+-- Internal, PRIVATE functions.
+-- Following a Python-like convention, I have prefixed all these 'PRIVATE'
+-- functions with an underscore.
+-----------------------------------------------------------------------------
+
+--- Scans an array from JSON into a Lua object
+-- startPos begins at the start of the array.
+-- Returns the array and the next starting position
+-- @param s The string being scanned.
+-- @param startPos The starting position for the scan.
+-- @return table, int The scanned array as a table, and the position of the next character to scan.
+function decode_scanArray(s,startPos)
+ local array = {} -- The return value
+ local stringLen = string.len(s)
+ assert(string.sub(s,startPos,startPos)=='[','decode_scanArray called but array does not start at position ' .. startPos .. ' in string:\n'..s )
+ startPos = startPos + 1
+ -- Infinite loop for array elements
+ local index = 1
+ repeat
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=stringLen,'JSON String ended unexpectedly scanning array.')
+ local curChar = string.sub(s,startPos,startPos)
+ if (curChar==']') then
+ return array, startPos+1
+ end
+ if (curChar==',') then
+ startPos = decode_scanWhitespace(s,startPos+1)
+ end
+ assert(startPos<=stringLen, 'JSON String ended unexpectedly scanning array.')
+ object, startPos = json.decode(s,startPos)
+ array[index] = object
+ index = index + 1
+ until false
+end
+
+--- Scans a comment and discards the comment.
+-- Returns the position of the next character following the comment.
+-- @param string s The JSON string to scan.
+-- @param int startPos The starting position of the comment
+function decode_scanComment(s, startPos)
+ assert( string.sub(s,startPos,startPos+1)=='/*', "decode_scanComment called but comment does not start at position " .. startPos)
+ local endPos = string.find(s,'*/',startPos+2)
+ assert(endPos~=nil, "Unterminated comment in string at " .. startPos)
+ return endPos+2
+end
+
+--- Scans for given constants: true, false or null
+-- Returns the appropriate Lua type, and the position of the next character to read.
+-- @param s The string being scanned.
+-- @param startPos The position in the string at which to start scanning.
+-- @return object, int The object (true, false or nil) and the position at which the next character should be
+-- scanned.
+function decode_scanConstant(s, startPos)
+ local consts = { ["true"] = true, ["false"] = false, ["null"] = nil }
+ local constNames = {"true","false","null"}
+
+ for i,k in pairs(constNames) do
+ if string.sub(s,startPos, startPos + string.len(k) -1 )==k then
+ return consts[k], startPos + string.len(k)
+ end
+ end
+ assert(nil, 'Failed to scan constant from string ' .. s .. ' at starting position ' .. startPos)
+end
+
+--- Scans a number from the JSON encoded string.
+-- (in fact, also is able to scan numeric +- eqns, which is not
+-- in the JSON spec.)
+-- Returns the number, and the position of the next character
+-- after the number.
+-- @param s The string being scanned.
+-- @param startPos The position at which to start scanning.
+-- @return number, int The extracted number and the position of the next character to scan.
+function decode_scanNumber(s,startPos)
+ local endPos = startPos+1
+ local stringLen = string.len(s)
+ local acceptableChars = "+-0123456789.e"
+ while (string.find(acceptableChars, string.sub(s,endPos,endPos), 1, true)
+ and endPos<=stringLen
+ ) do
+ endPos = endPos + 1
+ end
+ local stringValue = 'return ' .. string.sub(s,startPos, endPos-1)
+ local stringEval = load(stringValue)
+ assert(stringEval, 'Failed to scan number [ ' .. stringValue .. '] in JSON string at position ' .. startPos .. ' : ' .. endPos)
+ return stringEval(), endPos
+end
+
+--- Scans a JSON object into a Lua object.
+-- startPos begins at the start of the object.
+-- Returns the object and the next starting position.
+-- @param s The string being scanned.
+-- @param startPos The starting position of the scan.
+-- @return table, int The scanned object as a table and the position of the next character to scan.
+function decode_scanObject(s,startPos)
+ local object = {}
+ local stringLen = string.len(s)
+ local key, value
+ assert(string.sub(s,startPos,startPos)=='{','decode_scanObject called but object does not start at position ' .. startPos .. ' in string:\n' .. s)
+ startPos = startPos + 1
+ repeat
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly while scanning object.')
+ local curChar = string.sub(s,startPos,startPos)
+ if (curChar=='}') then
+ return object,startPos+1
+ end
+ if (curChar==',') then
+ startPos = decode_scanWhitespace(s,startPos+1)
+ end
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly scanning object.')
+ -- Scan the key
+ key, startPos = json.decode(s,startPos)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
+ assert(string.sub(s,startPos,startPos)==':','JSON object key-value assignment mal-formed at ' .. startPos)
+ startPos = decode_scanWhitespace(s,startPos+1)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
+ value, startPos = json.decode(s,startPos)
+ object[key]=value
+ until false -- infinite loop while key-value pairs are found
+end
+
+-- START SoniEx2
+-- Initialize some things used by decode_scanString
+-- You know, for efficiency
+local escapeSequences = {
+ ["\\t"] = "\t",
+ ["\\f"] = "\f",
+ ["\\r"] = "\r",
+ ["\\n"] = "\n",
+ ["\\b"] = "\b"
+}
+setmetatable(escapeSequences, {__index = function(t,k)
+ -- skip "\" aka strip escape
+ return string.sub(k,2)
+end})
+-- END SoniEx2
+
+--- Scans a JSON string from the opening inverted comma or single quote to the
+-- end of the string.
+-- Returns the string extracted as a Lua string,
+-- and the position of the next non-string character
+-- (after the closing inverted comma or single quote).
+-- @param s The string being scanned.
+-- @param startPos The starting position of the scan.
+-- @return string, int The extracted string as a Lua string, and the next character to parse.
+function decode_scanString(s,startPos)
+ assert(startPos, 'decode_scanString(..) called without start position')
+ local startChar = string.sub(s,startPos,startPos)
+ -- START SoniEx2
+ -- PS: I don't think single quotes are valid JSON
+ assert(startChar == [["]] or startChar == [[']],'decode_scanString called for a non-string')
+ --assert(startPos, "String decoding failed: missing closing " .. startChar .. " for string at position " .. oldStart)
+ local t = {}
+ local i,j = startPos,startPos
+ while string.find(s, startChar, j+1) ~= j+1 do
+ local oldj = j
+ i,j = string.find(s, "\\.", j+1)
+ local x,y = string.find(s, startChar, oldj+1)
+ if not i or x < i then
+ i,j = x,y-1
+ end
+ table.insert(t, string.sub(s, oldj+1, i-1))
+ if string.sub(s, i, j) == "\\u" then
+ local a = string.sub(s,j+1,j+4)
+ j = j + 4
+ local n = tonumber(a, 16)
+ assert(n, "String decoding failed: bad Unicode escape " .. a .. " at position " .. i .. " : " .. j)
+ -- math.floor(x/2^y) == lazy right shift
+ -- a % 2^b == bitwise_and(a, (2^b)-1)
+ -- 64 = 2^6
+ -- 4096 = 2^12 (or 2^6 * 2^6)
+ local x
+ if n < 0x80 then
+ x = string.char(n % 0x80)
+ elseif n < 0x800 then
+ -- [110x xxxx] [10xx xxxx]
+ x = string.char(0xC0 + (math.floor(n/64) % 0x20), 0x80 + (n % 0x40))
+ else
+ -- [1110 xxxx] [10xx xxxx] [10xx xxxx]
+ x = string.char(0xE0 + (math.floor(n/4096) % 0x10), 0x80 + (math.floor(n/64) % 0x40), 0x80 + (n % 0x40))
+ end
+ table.insert(t, x)
+ else
+ table.insert(t, escapeSequences[string.sub(s, i, j)])
+ end
+ end
+ table.insert(t,string.sub(j, j+1))
+ assert(string.find(s, startChar, j+1), "String decoding failed: missing closing " .. startChar .. " at position " .. j .. "(for string at position " .. startPos .. ")")
+ return table.concat(t,""), j+2
+ -- END SoniEx2
+end
+
+--- Scans a JSON string skipping all whitespace from the current start position.
+-- Returns the position of the first non-whitespace character, or nil if the whole end of string is reached.
+-- @param s The string being scanned
+-- @param startPos The starting position where we should begin removing whitespace.
+-- @return int The first position where non-whitespace was encountered, or string.len(s)+1 if the end of string
+-- was reached.
+function decode_scanWhitespace(s,startPos)
+ local whitespace=" \n\r\t"
+ local stringLen = string.len(s)
+ while ( string.find(whitespace, string.sub(s,startPos,startPos), 1, true) and startPos <= stringLen) do
+ startPos = startPos + 1
+ end
+ return startPos
+end
+
+--- Encodes a string to be JSON-compatible.
+-- This just involves back-quoting inverted commas, back-quotes and newlines, I think ;-)
+-- @param s The string to return as a JSON encoded (i.e. backquoted string)
+-- @return The string appropriately escaped.
+
+local escapeList = {
+ ['"'] = '\\"',
+ ['\\'] = '\\\\',
+ ['/'] = '\\/',
+ ['\b'] = '\\b',
+ ['\f'] = '\\f',
+ ['\n'] = '\\n',
+ ['\r'] = '\\r',
+ ['\t'] = '\\t'
+}
+
+function json_private.encodeString(s)
+ local s = tostring(s)
+ return s:gsub(".", function(c) return escapeList[c] end) -- SoniEx2: 5.0 compat
+end
+
+-- Determines whether the given Lua type is an array or a table / dictionary.
+-- We consider any table an array if it has indexes 1..n for its n items, and no
+-- other data in the table.
+-- I think this method is currently a little 'flaky', but can't think of a good way around it yet...
+-- @param t The table to evaluate as an array
+-- @return boolean, number True if the table can be represented as an array, false otherwise. If true,
+-- the second returned value is the maximum
+-- number of indexed elements in the array.
+function isArray(t)
+ -- Next we count all the elements, ensuring that any non-indexed elements are not-encodable
+ -- (with the possible exception of 'n')
+ if (t == json.EMPTY_ARRAY) then return true, 0 end
+ if (t == json.EMPTY_OBJECT) then return false end
+
+ local maxIndex = 0
+ for k,v in pairs(t) do
+ if (type(k)=='number' and math.floor(k)==k and 1<=k) then -- k,v is an indexed pair
+ if (not isEncodable(v)) then return false end -- All array elements must be encodable
+ maxIndex = math.max(maxIndex,k)
+ else
+ if (k=='n') then
+ if v ~= (t.n or #t) then return false end -- False if n does not hold the number of elements
+ else -- Else of (k=='n')
+ if isEncodable(v) then return false end
+ end -- End of (k~='n')
+ end -- End of k,v not an indexed pair
+ end -- End of loop across all pairs
+ return true, maxIndex
+end
+
+--- Determines whether the given Lua object / table / variable can be JSON encoded. The only
+-- types that are JSON encodable are: string, boolean, number, nil, table and json.null.
+-- In this implementation, all other types are ignored.
+-- @param o The object to examine.
+-- @return boolean True if the object should be JSON encoded, false if it should be ignored.
+function isEncodable(o)
+ local t = type(o)
+ return (t=='string' or t=='boolean' or t=='number' or t=='nil' or t=='table') or
+ (t=='function' and o==json.null)
+end
+
+return json
diff --git a/Data/DefaultContent/Libraries/json4lua/json/rpc.lua b/Data/DefaultContent/Libraries/json4lua/json/rpc.lua
new file mode 100644
index 0000000..952c5b5
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/json/rpc.lua
@@ -0,0 +1,107 @@
+-----------------------------------------------------------------------------
+-- JSONRPC4Lua: JSON RPC client calls over http for the Lua language.
+-- json.rpc Module.
+-- Author: Craig Mason-Jones
+-- Homepage: http://github.com/craigmj/json4lua/
+-- Version: 1.0.0
+-- This module is released under the MIT License (MIT).
+-- Please see LICENCE.txt for details.
+--
+-- USAGE:
+-- This module exposes two functions:
+-- proxy( 'url')
+-- Returns a proxy object for calling the JSON RPC Service at the given url.
+-- call ( 'url', 'method', ...)
+-- Calls the JSON RPC server at the given url, invokes the appropriate method, and
+-- passes the remaining parameters. Returns the result and the error. If the result is nil, an error
+-- should be there (or the system returned a null). If an error is there, the result should be nil.
+--
+-- REQUIREMENTS:
+-- Lua socket 2.0 (http://www.cs.princeton.edu/~diego/professional/luasocket/)
+-- json (The JSON4Lua package with which it is bundled)
+-- compat-5.1 if using Lua 5.0.
+-----------------------------------------------------------------------------
+
+local json = require('json')
+json.rpc = {} -- Module public namespace
+
+-----------------------------------------------------------------------------
+-- Imports and dependencies
+-----------------------------------------------------------------------------
+local json = require('json')
+local http = require("socket.http")
+
+-----------------------------------------------------------------------------
+-- PUBLIC functions
+-----------------------------------------------------------------------------
+
+--- Creates an RPC Proxy object for the given Url of a JSON-RPC server.
+-- @param url The URL for the JSON RPC Server.
+-- @return Object on which JSON-RPC remote methods can be called.
+-- EXAMPLE Usage:
+-- local jsolait = json.rpc.proxy('http://jsolait.net/testj.py')
+-- print(jsolait.echo('This is a test of the echo method!'))
+-- print(jsolait.args2String('first','second','third'))
+-- table.foreachi( jsolait.args2Array(5,4,3,2,1), print)
+function json.rpc.proxy(url)
+ local serverProxy = {}
+ local proxyMeta = {
+ __index = function(self, key)
+ return function(...)
+ return json.rpc.call(url, key, ...)
+ end
+ end
+ }
+ setmetatable(serverProxy, proxyMeta)
+ return serverProxy
+end
+
+--- Calls a JSON RPC method on a remote server.
+-- Returns a boolean true if the call succeeded, false otherwise.
+-- On success, the second returned parameter is the decoded
+-- JSON object from the server.
+-- On http failure, returns nil and an error message.
+-- On success, returns the result and nil.
+-- @param url The url of the JSON RPC server.
+-- @param method The method being called.
+-- @param ... Parameters to pass to the method.
+-- @return result, error The JSON RPC result and error. One or the other should be nil. If both
+-- are nil, this means that the result of the RPC call was nil.
+-- EXAMPLE Usage:
+-- print(json.rpc.call('http://jsolait.net/testj.py','echo','This string will be returned'))
+function json.rpc.call(url, method, ...)
+ local JSONRequestArray = {
+ id=tostring(math.random()),
+ ["method"]=method,
+ ["jsonrpc"]="2.0",
+ params = ...
+ }
+ local httpResponse, result , code
+ local jsonRequest = json.encode(JSONRequestArray)
+ -- We use the sophisticated http.request form (with ltn12 sources and sinks) so that
+ -- we can set the content-type to text/plain. While this shouldn't strictly-speaking be true,
+ -- it seems a good idea (Xavante won't work w/out a content-type header, although a patch
+ -- is needed to Xavante to make it work with text/plain)
+ local ltn12 = require('ltn12')
+ local resultChunks = {}
+ httpResponse, code = http.request(
+ { ['url'] = url,
+ sink = ltn12.sink.table(resultChunks),
+ method = 'POST',
+ headers = { ['content-type']='application/json-rpc', ['content-length']=string.len(jsonRequest) },
+ source = ltn12.source.string(jsonRequest)
+ }
+ )
+ httpResponse = table.concat(resultChunks)
+ -- Check the http response code
+ if (code~=200) then
+ return nil, "HTTP ERROR: " .. code
+ end
+ -- And decode the httpResponse and check the JSON RPC result code
+ result = json.decode( httpResponse )
+ if result.result then
+ return result.result, nil
+ else
+ return nil, result.error
+ end
+end
diff --git a/Data/DefaultContent/Libraries/json4lua/json/rpcserver.lua b/Data/DefaultContent/Libraries/json4lua/json/rpcserver.lua
new file mode 100644
index 0000000..e01f1f8
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/json/rpcserver.lua
@@ -0,0 +1,78 @@
+-----------------------------------------------------------------------------
+-- JSONRPC4Lua: JSON RPC server for exposing Lua objects as JSON RPC callable
+-- objects via http.
+-- json.rpcserver Module.
+-- Author: Craig Mason-Jones
+-- Homepage: http://github.com/craigmj/json4lua/
+-- Version: 1.0.0
+-- This module is released under the MIT License (MIT).
+-- Please see LICENCE.txt for details.
+--
+-- USAGE:
+-- This module exposes one function:
+-- server(luaClass, packReturn)
+-- Manages incoming JSON RPC request forwarding the method call to the given
+-- object. If packReturn is true, multiple return values are packed into an
+-- array on return.
+--
+-- IMPORTANT NOTES:
+-- 1. This version ought really not be 0.9.10, since this particular part of the
+-- JSONRPC4Lua package is very first-draft. However, the JSON4Lua package with which
+-- it comes is quite solid, so there you have it :-)
+-- 2. This has only been tested with Xavante webserver, with which it works
+-- if you patch CGILua to accept 'text/plain' content type. See doc\cgilua_patch.html
+-- for details.
+----------------------------------------------------------------------------
+
+module ('json.rpcserver')
+
+---
+-- Implements a JSON RPC Server wrapping for luaClass, exposing each of luaClass's
+-- methods as JSON RPC callable methods.
+-- @param luaClass The JSON RPC class to expose.
+-- @param packReturn If true, the server will automatically wrap any
+-- multiple-value returns into an array. Single returns remain single returns. If
+-- false, when a function returns multiple values, only the first of these values will
+-- be returned.
+--
+function serve(luaClass, packReturn)
+ cgilua.contentheader('text','plain')
+ require('cgilua')
+ require ('json')
+ local postData = ""
+
+ if not cgilua.servervariable('CONTENT_LENGTH') then
+ cgilua.put("Please access JSON Request using HTTP POST Request")
+ return 0
+ else
+ postData = cgi[1] -- SAPI.Request.getpostdata() --[[{ "id":1, "method":"echo","params":["Hi there"]}]] --
+ end
+ -- @TODO Catch an error condition on decoding the data
+ local jsonRequest = json.decode(postData)
+ local jsonResponse = {}
+ jsonResponse.id = jsonRequest.id
+ local method = luaClass[ jsonRequest.method ]
+
+ if not method then
+ jsonResponse.error = 'Method ' .. jsonRequest.method .. ' does not exist at this server.'
+ else
+ local callResult = { pcall( method, unpack( jsonRequest.params ) ) }
+ if callResult[1] then -- Function call successfull
+ table.remove(callResult,1)
+ if packReturn and table.getn(callResult)>1 then
+ jsonResponse.result = callResult
+ else
+ jsonResponse.result = unpack(callResult) -- NB: Does not support multiple argument returns
+ end
+ else
+ jsonResponse.error = callResult[2]
+ end
+ end
+
+ -- Output the result
+ -- TODO: How to be sure that the result and error tags are there even when they are nil in Lua?
+ -- Can force them by hand... ?
+ cgilua.contentheader('text','plain')
+ cgilua.put( json.encode( jsonResponse ) )
+end
+
diff --git a/Data/DefaultContent/Libraries/json4lua/json4lua-1.0.0-1.rockspec b/Data/DefaultContent/Libraries/json4lua/json4lua-1.0.0-1.rockspec
new file mode 100644
index 0000000..b3b737a
--- /dev/null
+++ b/Data/DefaultContent/Libraries/json4lua/json4lua-1.0.0-1.rockspec
@@ -0,0 +1,32 @@
+package="JSON4Lua"
+version="1.0.0"
+source = {
+ url = "git://github.com/craigmj/json4lua.git",
+ tag = "1.0.0"
+}
+description = {
+ summary = "JSON4Lua and JSONRPC4Lua implement JSON (JavaScript Object Notation) encoding and decoding and a JSON-RPC-over-http client for Lua.",
+ detailed = [[
+ JSON4Lua and JSONRPC4Lua implement JSON (JavaScript Object Notation)
+ encoding and decoding and a JSON-RPC-over-http client for Lua.
+ JSON is JavaScript Object Notation, a simple encoding of
+ Javascript-like objects that is ideal for lightweight transmission
+ of relatively weakly-typed data. A sub-package of JSON4Lua is
+ JSONRPC4Lua, which provides a simple JSON-RPC-over-http client and server
+ (in a CGILua environment) for Lua.
+ ]],
+ homepage = "http://github.com/craigmj/json4lua/",
+ license = "GPL"
+}
+dependencies = {
+ "lua >= 5.2",
+ "luasocket",
+}
+
+build = {
+ type = "builtin",
+ modules = {
+ ["json"] = "json/json.lua",
+ ["json.rpc"] = "json/rpc.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/lbase64/.gitignore b/Data/DefaultContent/Libraries/lbase64/.gitignore
new file mode 100644
index 0000000..a70719a
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lbase64/.gitignore
@@ -0,0 +1,3 @@
+*.out
+*.swp
+*.swo
diff --git a/Data/DefaultContent/Libraries/lbase64/.travis.yml b/Data/DefaultContent/Libraries/lbase64/.travis.yml
new file mode 100644
index 0000000..7bca356
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lbase64/.travis.yml
@@ -0,0 +1,25 @@
+language: python
+sudo: false
+
+env:
+ - LUA="lua 5.1"
+ - LUA="lua 5.2"
+ - LUA="lua 5.3"
+ - LUA="lua 5.4"
+ - LUA="luajit 2.0"
+ - LUA="luajit 2.1"
+
+before_install:
+ - pip install hererocks
+ - hererocks env --$LUA -rlatest # Use latest LuaRocks, install into 'env' directory.
+ - source env/bin/activate # Add directory with all installed binaries to PATH.notifications:
+
+notifications:
+ email: false
+
+install:
+ - luarocks install luacheck
+
+script:
+ - luacheck --no-unused-args *.lua
+ - lua test.lua
diff --git a/Data/DefaultContent/Libraries/lbase64/README.md b/Data/DefaultContent/Libraries/lbase64/README.md
new file mode 100644
index 0000000..1b5b0ee
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lbase64/README.md
@@ -0,0 +1,48 @@
+[![Build Status](https://travis-ci.org/iskolbin/lbase64.svg?branch=master)](https://travis-ci.org/iskolbin/lbase64)
+[![license](https://img.shields.io/badge/license-public%20domain-blue.svg)]()
+[![MIT Licence](https://badges.frapsoft.com/os/mit/mit.svg?v=103)](https://opensource.org/licenses/mit-license.php)
+
+Lua base64 encoder/decoder
+==========================
+
+Pure Lua [base64](https://en.wikipedia.org/wiki/Base64) encoder/decoder. Works with
+Lua 5.1+ and LuaJIT. Fallbacks to pure Lua bit operations if bit/bit32/native bit
+operators are not available.
+
+```lua
+local base64 = require'base64'
+local str = 'Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.'
+local b64str = 'TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4='
+local encoded = base64.encode( str )
+local decoded = base64.decode( b64str )
+assert( str == decoded )
+assert( b64str == encoded )
+```
+
+base64.encode( str, encoder = DEFAULT, usecache = false )
+---------------------------------------------------------
+Encodes `str` string using `encoder` table. By default uses table with `+` as
+char for 62, `/` as char for 63 and `=` as padding char. You can specify custom
+encoder. For this you could use `base64.makeencoder`. If you are encoding large
+chunks of text (or another highly redundant data) it's possible to highly
+increase performace (for text approx. x2 gain) by using `usecache = true`. For
+binary data like images using cache decreasing performance.
+
+base64.decode( str, decoder = DEFAULT, usecache = false )
+---------------------------------------------------------
+Decodes `str` string using `decoder` table. Default decoder uses same chars as
+default encoder.
+
+base64.makeencoder( s62 = '+', s63 = '/', spad = '=' )
+------------------------------------------------------
+Make custom encoding table
+
+base64.makedecoder( s62 = '+', s63 = '/', spad = '=' )
+------------------------------------------------------
+Make custom decoding table
+
+Install
+-------
+```bash
+luarocks install base64
+```
diff --git a/Data/DefaultContent/Libraries/lbase64/base64.lua b/Data/DefaultContent/Libraries/lbase64/base64.lua
new file mode 100644
index 0000000..32de332
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lbase64/base64.lua
@@ -0,0 +1,201 @@
+--[[
+
+ base64 -- v1.5.3 public domain Lua base64 encoder/decoder
+ no warranty implied; use at your own risk
+
+ Needs bit32.extract function. If not present it's implemented using BitOp
+ or Lua 5.3 native bit operators. For Lua 5.1 fallbacks to pure Lua
+ implementation inspired by Rici Lake's post:
+ http://ricilake.blogspot.co.uk/2007/10/iterating-bits-in-lua.html
+
+ author: Ilya Kolbin (iskolbin@gmail.com)
+ url: github.com/iskolbin/lbase64
+
+ COMPATIBILITY
+
+ Lua 5.1+, LuaJIT
+
+ LICENSE
+
+ See end of file for license information.
+
+--]]
+
+
+local base64 = {}
+
+local extract = _G.bit32 and _G.bit32.extract -- Lua 5.2/Lua 5.3 in compatibility mode
+if not extract then
+ if _G.bit then -- LuaJIT
+ local shl, shr, band = _G.bit.lshift, _G.bit.rshift, _G.bit.band
+ extract = function( v, from, width )
+ return band( shr( v, from ), shl( 1, width ) - 1 )
+ end
+ elseif _G._VERSION == "Lua 5.1" then
+ extract = function( v, from, width )
+ local w = 0
+ local flag = 2^from
+ for i = 0, width-1 do
+ local flag2 = flag + flag
+ if v % flag2 >= flag then
+ w = w + 2^i
+ end
+ flag = flag2
+ end
+ return w
+ end
+ else -- Lua 5.3+
+ extract = load[[return function( v, from, width )
+ return ( v >> from ) & ((1 << width) - 1)
+ end]]()
+ end
+end
+
+
+function base64.makeencoder( s62, s63, spad )
+ local encoder = {}
+ for b64code, char in pairs{[0]='A','B','C','D','E','F','G','H','I','J',
+ 'K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y',
+ 'Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n',
+ 'o','p','q','r','s','t','u','v','w','x','y','z','0','1','2',
+ '3','4','5','6','7','8','9',s62 or '+',s63 or'/',spad or'='} do
+ encoder[b64code] = char:byte()
+ end
+ return encoder
+end
+
+function base64.makedecoder( s62, s63, spad )
+ local decoder = {}
+ for b64code, charcode in pairs( base64.makeencoder( s62, s63, spad )) do
+ decoder[charcode] = b64code
+ end
+ return decoder
+end
+
+local DEFAULT_ENCODER = base64.makeencoder()
+local DEFAULT_DECODER = base64.makedecoder()
+
+local char, concat = string.char, table.concat
+
+function base64.encode( str, encoder, usecaching )
+ encoder = encoder or DEFAULT_ENCODER
+ local t, k, n = {}, 1, #str
+ local lastn = n % 3
+ local cache = {}
+ for i = 1, n-lastn, 3 do
+ local a, b, c = str:byte( i, i+2 )
+ local v = a*0x10000 + b*0x100 + c
+ local s
+ if usecaching then
+ s = cache[v]
+ if not s then
+ s = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[extract(v,0,6)])
+ cache[v] = s
+ end
+ else
+ s = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[extract(v,0,6)])
+ end
+ t[k] = s
+ k = k + 1
+ end
+ if lastn == 2 then
+ local a, b = str:byte( n-1, n )
+ local v = a*0x10000 + b*0x100
+ t[k] = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[64])
+ elseif lastn == 1 then
+ local v = str:byte( n )*0x10000
+ t[k] = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[64], encoder[64])
+ end
+ return concat( t )
+end
+
+function base64.decode( b64, decoder, usecaching )
+ decoder = decoder or DEFAULT_DECODER
+ local pattern = '[^%w%+%/%=]'
+ if decoder then
+ local s62, s63
+ for charcode, b64code in pairs( decoder ) do
+ if b64code == 62 then s62 = charcode
+ elseif b64code == 63 then s63 = charcode
+ end
+ end
+ pattern = ('[^%%w%%%s%%%s%%=]'):format( char(s62), char(s63) )
+ end
+ b64 = b64:gsub( pattern, '' )
+ local cache = usecaching and {}
+ local t, k = {}, 1
+ local n = #b64
+ local padding = b64:sub(-2) == '==' and 2 or b64:sub(-1) == '=' and 1 or 0
+ for i = 1, padding > 0 and n-4 or n, 4 do
+ local a, b, c, d = b64:byte( i, i+3 )
+ local s
+ if usecaching then
+ local v0 = a*0x1000000 + b*0x10000 + c*0x100 + d
+ s = cache[v0]
+ if not s then
+ local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40 + decoder[d]
+ s = char( extract(v,16,8), extract(v,8,8), extract(v,0,8))
+ cache[v0] = s
+ end
+ else
+ local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40 + decoder[d]
+ s = char( extract(v,16,8), extract(v,8,8), extract(v,0,8))
+ end
+ t[k] = s
+ k = k + 1
+ end
+ if padding == 1 then
+ local a, b, c = b64:byte( n-3, n-1 )
+ local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40
+ t[k] = char( extract(v,16,8), extract(v,8,8))
+ elseif padding == 2 then
+ local a, b = b64:byte( n-3, n-2 )
+ local v = decoder[a]*0x40000 + decoder[b]*0x1000
+ t[k] = char( extract(v,16,8))
+ end
+ return concat( t )
+end
+
+return base64
+
+--[[
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2018 Ilya Kolbin
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+--]]
diff --git a/Data/DefaultContent/Libraries/lbase64/bench.lua b/Data/DefaultContent/Libraries/lbase64/bench.lua
new file mode 100644
index 0000000..d24c1bf
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lbase64/bench.lua
@@ -0,0 +1,76 @@
+local base64 = require'base64'
+local N = 10000000
+local st = {}
+local letters = ' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
+ .. 'абвгдеёжзийклмнопрстуфхцшщчъыьэюя'
+ .. 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦШЩЧЪЫЬЭЮЯ'
+local nletters = #letters
+for i = 1, N do
+ local j = math.random( nletters )
+ st[i] = letters:sub( j, j )
+end
+local s = table.concat( st )
+local t = os.clock()
+local encoded = base64.encode( s )
+local encodetime = os.clock() - t
+
+t = os.clock()
+local decoded = base64.decode( encoded )
+local decodetime = os.clock() - t
+
+assert( s == decoded )
+print('Common text')
+print(('Encoding: %d bytes/sec'):format( math.floor(N/encodetime)))
+print(('Decoding: %d bytes/sec'):format( math.floor(N/decodetime)))
+collectgarbage()
+
+t = os.clock()
+encoded = base64.encode( s, nil, true )
+encodetime = os.clock() - t
+
+t = os.clock()
+decoded = base64.decode( encoded, nil, true )
+assert( s == decoded )
+decodetime = os.clock() - t
+print('Common text (cache)')
+print(('Encoding: %d bytes/sec'):format( math.floor(N/encodetime)))
+print(('Decoding: %d bytes/sec'):format( math.floor(N/decodetime)))
+collectgarbage()
+
+local lt = {}
+for i = 0, 255 do
+ lt[i] = string.char(i)
+end
+nletters = #lt
+for i = 1, N do
+ local j = math.random( nletters )
+ st[i] = lt[j]
+end
+s = table.concat( st )
+
+t = os.clock()
+encoded = base64.encode( s, nil )
+encodetime = os.clock() - t
+
+t = os.clock()
+decoded = base64.decode( encoded )
+decodetime = os.clock() - t
+
+assert( s == decoded )
+print('Binary')
+print(('Encoding: %d bytes/sec'):format( math.floor(N/encodetime)))
+print(('Decoding: %d bytes/sec'):format( math.floor(N/decodetime)))
+collectgarbage()
+
+t = os.clock()
+encoded = base64.encode( s, nil, true )
+encodetime = os.clock() - t
+
+t = os.clock()
+decoded = base64.decode( encoded, nil, true )
+assert( s == decoded )
+decodetime = os.clock() - t
+print('Binary (cache)')
+print(('Encoding: %d bytes/sec'):format( math.floor(N/encodetime)))
+print(('Decoding: %d bytes/sec'):format( math.floor(N/decodetime)))
+collectgarbage()
diff --git a/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-1.rockspec b/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-1.rockspec
new file mode 100644
index 0000000..f25c7b4
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-1.rockspec
@@ -0,0 +1,20 @@
+package = "base64"
+version = "1.5-1"
+source = {
+ url = "git+https://github.com/iskolbin/lbase64",
+ tag = "v1.5.1",
+}
+description = {
+ summary = "Pure Lua base64 encoder/decoder",
+ detailed = [[
+Pure Lua [base64](https://en.wikipedia.org/wiki/Base64) encoder/decoder. Works with Lua 5.1+ and LuaJIT. Fallbacks to pure Lua bit operations if bit/bit32/native bit operators are not available.]],
+ homepage = "https://github.com/iskolbin/lbase64",
+ license = "MIT/Public Domain"
+}
+dependencies = {}
+build = {
+ type = "builtin",
+ modules = {
+ base64 = "base64.lua",
+ }
+}
diff --git a/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-2.rockspec b/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-2.rockspec
new file mode 100644
index 0000000..7d0addd
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-2.rockspec
@@ -0,0 +1,20 @@
+package = "base64"
+version = "1.5-2"
+source = {
+ url = "git://github.com/iskolbin/lbase64",
+ tag = "v1.5.2",
+}
+description = {
+ summary = "Pure Lua base64 encoder/decoder",
+ detailed = [[
+Pure Lua [base64](https://en.wikipedia.org/wiki/Base64) encoder/decoder. Works with Lua 5.1+ and LuaJIT. Fallbacks to pure Lua bit operations if bit/bit32/native bit operators are not available.]],
+ homepage = "https://github.com/iskolbin/lbase64",
+ license = "MIT/Public Domain"
+}
+dependencies = {}
+build = {
+ type = "builtin",
+ modules = {
+ base64 = "base64.lua",
+ }
+}
diff --git a/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-3.rockspec b/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-3.rockspec
new file mode 100644
index 0000000..60706d3
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lbase64/rockspec/base64-1.5-3.rockspec
@@ -0,0 +1,20 @@
+package = "base64"
+version = "1.5-3"
+source = {
+ url = "git://github.com/iskolbin/lbase64",
+ tag = "v1.5.3",
+}
+description = {
+ summary = "Pure Lua base64 encoder/decoder",
+ detailed = [[
+Pure Lua base64 encoder/decoder. Works with Lua 5.1+ and LuaJIT. Fallbacks to pure Lua bit operations if bit/bit32/native bit operators are not available.]],
+ homepage = "https://github.com/iskolbin/lbase64",
+ license = "MIT/Public Domain"
+}
+dependencies = {}
+build = {
+ type = "builtin",
+ modules = {
+ base64 = "base64.lua",
+ }
+}
diff --git a/Data/DefaultContent/Libraries/lbase64/test.lua b/Data/DefaultContent/Libraries/lbase64/test.lua
new file mode 100644
index 0000000..d8efebf
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lbase64/test.lua
@@ -0,0 +1,47 @@
+local base64 = require('base64')
+
+local function test( s, b64 )
+ assert( base64.encode( s ) == b64 )
+ assert( base64.decode( b64 ) == s )
+ assert( base64.decode( base64.encode( s )) == s )
+ assert( base64.encode( s, nil, true ) == b64 )
+ assert( base64.decode( b64, nil, true ) == s )
+ assert( base64.decode( base64.encode( s, nil, true ), nil, true ) == s )
+end
+
+test( 'any carnal pleasure.', 'YW55IGNhcm5hbCBwbGVhc3VyZS4=' )
+test( 'any carnal pleasure', 'YW55IGNhcm5hbCBwbGVhc3VyZQ==' )
+test( 'any carnal pleasur', 'YW55IGNhcm5hbCBwbGVhc3Vy' )
+test( 'Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a ' ..
+ 'lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, ' ..
+ 'exceeds the short vehemence of any carnal pleasure.', 'TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb' ..
+ '24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoY' ..
+ 'XQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd' ..
+ '2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=' )
+test( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et ' ..
+ 'dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea ' ..
+ 'commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat ' ..
+ 'nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit ' ..
+ 'anim id est laborum.', 'TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwgc2VkIGRvIGVp' ..
+ 'dXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBx' ..
+ 'dWlzIG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1' ..
+ 'aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0' ..
+ 'IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBv' ..
+ 'ZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg==')
+test( '«В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!»',
+ 'wqvQkiDRh9Cw0YnQsNGFINGO0LPQsCDQttC40Lsg0LHRiyDR' ..
+ 'htC40YLRgNGD0YE/INCU0LAsINC90L4g0YTQsNC70YzRiNC40LLRi9C5INGN0LrQt9C10LzQv9C70Y/RgCHCuw==')
+test( '«В чащах юга жил бы цитрус? Да, фальшивый экземпляр!»',
+ 'wqvQkiDRh9Cw0YnQsNGFINGO0LPQsCDQttC40Lsg0LHRiyDRhtC' ..
+ '40YLRgNGD0YE/INCU0LAsINGE0LDQu9GM0YjQuNCy0YvQuSDRjdC60LfQtdC80L/Qu9GP0YAhwrs=')
+test( '\137\080\078\071\013\010\026\010\000\000\000\013\073\072\068\082\000\000\000\032\000\000\000\032\001\003\000' ..
+ '\000\000\073\180\232\183\000\000\000\006\080\076\084\069\255\255\255\000\000\000\085\194\211\126\000\000\000\018' ..
+ '\073\068\065\084\008\215\099\248\015\004\196\016\084\006\196\218\011\000\237\189\063\193\243\000\141\059\000\000' ..
+ '\000\000\073\069\078\068\174\066\096\130', 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgAQMAAABJtOi3AAAABlBMVEX///8AAABVwtN+' ..
+ 'AAAAEklEQVQI12P4DwTEEFQGxNoLAO29P8HzAI07AAAAAElFTkSuQmCC' )
+
+assert( base64.decode('YW55IGNhcm5hbCBwbGVhc3VyZS4=\n\r\\' ) == 'any carnal pleasure.' )
+
+assert( base64.decode('wйqеvнQсуkкiеDнRгhш9щCзwх0ъфYыnвQаsпNрGоFллIдNжGэOё0яLчPQsCDQttC40Lsg0LHRiyDRhtC' ..
+ '40YLRgNGD0YE/INсCмUи0тLьAбsюIЙКNЕG\n\n\n\n\r\rE0LDQu9GM0YjQuNCy0YvQuSDRjdC60LfQtdC80L/Qu9GP0YAhwrs=') ==
+ '«В чащах юга жил бы цитрус? Да, фальшивый экземпляр!»' )
diff --git a/Data/DefaultContent/Libraries/lua-csv/.gitignore b/Data/DefaultContent/Libraries/lua-csv/.gitignore
new file mode 100644
index 0000000..131f9b6
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/.gitignore
@@ -0,0 +1,2 @@
+.DS_Store
+lua/docs \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/lua-csv/AUTHORS b/Data/DefaultContent/Libraries/lua-csv/AUTHORS
new file mode 100644
index 0000000..84961bd
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/AUTHORS
@@ -0,0 +1,2 @@
+Leyland, Geoff
+Martin, Kevin
diff --git a/Data/DefaultContent/Libraries/lua-csv/LICENSE b/Data/DefaultContent/Libraries/lua-csv/LICENSE
new file mode 100644
index 0000000..d8472a0
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2013-2014 Incremental IP Limited
+Copyright (c) 2014 Kevin Martin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
diff --git a/Data/DefaultContent/Libraries/lua-csv/README.md b/Data/DefaultContent/Libraries/lua-csv/README.md
new file mode 100644
index 0000000..d10314a
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/README.md
@@ -0,0 +1,93 @@
+# Lua-CSV - delimited file reading
+
+## 1. What?
+
+Lua-CSV is a Lua module for reading delimited text files (popularly CSV and
+tab-separated files, but you can specify the separator).
+
+Lua-CSV tries to auto-detect whether a file is delimited with commas or tabs,
+copes with non-native newlines, survives newlines and quotes inside quoted
+fields and offers an iterator interface so it can handle large files.
+
+
+## 2. How?
+
+ local csv = require("csv")
+ local f = csv.open("file.csv")
+ for fields in f:lines() do
+ for i, v in ipairs(fields) do print(i, v) end
+ end
+
+`csv.open` takes a second argument `parameters`, a table of parameters
+controlling how the file is read:
+
++ `separator` sets the separator. It'll probably guess the separator
+ correctly if it's a comma or a tab (unless, say, the first field in a
+ tab-delimited file contains a comma), but if you want something else you'll
+ have to set this. It could be more than one character, but it's used as
+ part of a set: `"["..sep.."\n\r]"`
+
++ Set `header` to true if the file contains a header and each set of fields
+ will be keyed by the names in the header rather than by integer index.
+
++ `columns` provides a mechanism for column remapping.
+ Suppose you have a csv file as follows:
+
+ Word,Number
+ ONE,10
+
+ And columns is:
+
+ + `{ word = true }` then the only field in the file would be
+ `{ word = "ONE" }`
+ + `{ first = { name = "word"} }` then it would be `{ first = "ONE" }`
+ + `{ word = { transform = string.lower }}` would give `{ word = "one" }`
+ + finally,
+
+ { word = true
+ number = { transform = function(x) return tonumber(x) / 10 end }}
+
+ would give `{ word = "ONE", number = 1 }`
+
+ A column can have more than one name:
+ `{ first = { names = {"word", "worm"}}}` to help cope with badly specified
+ file formats and spelling mistakes.
+
++ `buffer_size` controls the size of the blocks the file is read in. The
+ default is 1MB. It used to be 4096 bytes which is what `pagesize` says on
+ my system, but that seems kind of small.
+
+`csv.openstring` works exactly like `csv.open` except the first argument
+is the contents of the csv file. In this case `buffer_size` is set to
+the length of the string.
+
+## 3. Requirements
+
+Lua 5.1, 5.2 or LuaJIT.
+
+
+## 4. Issues
+
++ Some whitespace-delimited files might use more than one space between
+ fields, for example if the columns are "manually" aligned:
+
+ street nr city
+ "Oneway Street" 1 Toontown
+
+ It won't cope with this - you'll get lots of extra empty fields.
+
+## 5. Wishlist
+
++ Tests would be nice.
++ So would better LDoc documentation.
+
+
+## 6. Alternatives
+
++ [Penlight](http://github.com/stevedonovan/penlight) contains delimited
+ file reading. It reads the whole file in one go.
++ The Lua Wiki contains two pages on CSV
+ [here](http://lua-users.org/wiki/LuaCsv) and
+ [here](http://lua-users.org/wiki/CsvUtils).
++ There's an example using [LPeg](http://www.inf.puc-rio.br/~roberto/lpeg/)
+ to parse CSV [here](http://www.inf.puc-rio.br/~roberto/lpeg/#CSV)
diff --git a/Data/DefaultContent/Libraries/lua-csv/lua/config.ld b/Data/DefaultContent/Libraries/lua-csv/lua/config.ld
new file mode 100644
index 0000000..af51949
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/lua/config.ld
@@ -0,0 +1,4 @@
+project = "Lua-CSV"
+title = "Lua-CSV Source Documentation"
+description = "Lua-CSV reads delimited text files"
+format = "markdown"
diff --git a/Data/DefaultContent/Libraries/lua-csv/lua/csv.lua b/Data/DefaultContent/Libraries/lua-csv/lua/csv.lua
new file mode 100644
index 0000000..64196c0
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/lua/csv.lua
@@ -0,0 +1,557 @@
+--- Read a comma or tab (or other delimiter) separated file.
+-- This version of a CSV reader differs from others I've seen in that it
+--
+-- + handles embedded newlines in fields (if they're delimited with double
+-- quotes)
+-- + is line-ending agnostic
+-- + reads the file line-by-line, so it can potientially handle large
+-- files.
+--
+-- Of course, for such a simple format, CSV is horribly complicated, so it
+-- likely gets something wrong.
+
+-- (c) Copyright 2013-2014 Incremental IP Limited.
+-- (c) Copyright 2014 Kevin Martin
+-- Available under the MIT licence. See LICENSE for more information.
+
+local DEFAULT_BUFFER_BLOCK_SIZE = 1024 * 1024
+
+
+------------------------------------------------------------------------------
+
+local function trim_space(s)
+ return s:match("^%s*(.-)%s*$")
+end
+
+
+local function fix_quotes(s)
+ -- the sub(..., -2) is to strip the trailing quote
+ return string.sub(s:gsub('""', '"'), 1, -2)
+end
+
+
+------------------------------------------------------------------------------
+
+local column_map = {}
+column_map.__index = column_map
+
+
+local function normalise_string(s)
+ return (s:lower():gsub("[^%w%d]+", " "):gsub("^ *(.-) *$", "%1"))
+end
+
+
+--- Parse a list of columns.
+-- The main job here is normalising column names and dealing with columns
+-- for which we have more than one possible name in the header.
+function column_map:new(columns)
+ local name_map = {}
+ for n, v in pairs(columns) do
+ local names
+ local t
+ if type(v) == "table" then
+ t = { transform = v.transform, default = v.default }
+ if v.name then
+ names = { normalise_string(v.name) }
+ elseif v.names then
+ names = v.names
+ for i, n in ipairs(names) do names[i] = normalise_string(n) end
+ end
+ else
+ if type(v) == "function" then
+ t = { transform = v }
+ else
+ t = {}
+ if type(v) == "string" then
+ names = { normalise_string(v) }
+ end
+ end
+ end
+
+ if not names then
+ names = { (n:lower():gsub("[^%w%d]+", " ")) }
+ end
+
+ t.name = n
+ for _, n in ipairs(names) do
+ name_map[n:lower()] = t
+ end
+ end
+
+ return setmetatable({ name_map = name_map }, column_map)
+end
+
+
+--- Map "virtual" columns to file columns.
+-- Once we've read the header, work out which columns we're interested in and
+-- what to do with them. Mostly this is about checking we've got the columns
+-- we need and writing a nice complaint if we haven't.
+function column_map:read_header(header)
+ local index_map = {}
+
+ -- Match the columns in the file to the columns in the name map
+ local found = {}
+ local found_any
+ for i, word in ipairs(header) do
+ word = normalise_string(word)
+ local r = self.name_map[word]
+ if r then
+ index_map[i] = r
+ found[r.name] = true
+ found_any = true
+ end
+ end
+
+ if not found_any then return end
+
+ -- check we found all the columns we need
+ local not_found = {}
+ for name, r in pairs(self.name_map) do
+ if not found[r.name] then
+ local nf = not_found[r.name]
+ if nf then
+ nf[#nf+1] = name
+ else
+ not_found[r.name] = { name }
+ end
+ end
+ end
+ -- If any columns are missing, assemble an error message
+ if next(not_found) then
+ local problems = {}
+ for k, v in pairs(not_found) do
+ local missing
+ if #v == 1 then
+ missing = "'"..v[1].."'"
+ else
+ missing = v[1]
+ for i = 2, #v - 1 do
+ missing = missing..", '"..v[i].."'"
+ end
+ missing = missing.." or '"..v[#v].."'"
+ end
+ problems[#problems+1] = "Couldn't find a column named "..missing
+ end
+ error(table.concat(problems, "\n"), 0)
+ end
+
+ self.index_map = index_map
+ return true
+end
+
+
+function column_map:transform(value, index)
+ local field = self.index_map[index]
+ if field then
+ if field.transform then
+ local ok
+ ok, value = pcall(field.transform, value)
+ if not ok then
+ error(("Error reading field '%s': %s"):format(field.name, value), 0)
+ end
+ end
+ return value or field.default, field.name
+ end
+end
+
+
+------------------------------------------------------------------------------
+
+local file_buffer = {}
+file_buffer.__index = file_buffer
+
+function file_buffer:new(file, buffer_block_size)
+ return setmetatable({
+ file = file,
+ buffer_block_size = buffer_block_size or DEFAULT_BUFFER_BLOCK_SIZE,
+ buffer_start = 0,
+ buffer = "",
+ }, file_buffer)
+end
+
+
+--- Cut the front off the buffer if we've already read it
+function file_buffer:truncate(p)
+ p = p - self.buffer_start
+ if p > self.buffer_block_size then
+ local remove = self.buffer_block_size *
+ math.floor((p-1) / self.buffer_block_size)
+ self.buffer = self.buffer:sub(remove + 1)
+ self.buffer_start = self.buffer_start + remove
+ end
+end
+
+
+--- Find something in the buffer, extending it if necessary
+function file_buffer:find(pattern, init)
+ while true do
+ local first, last, capture =
+ self.buffer:find(pattern, init - self.buffer_start)
+ -- if we found nothing, or the last character is at the end of the
+ -- buffer (and the match could potentially be longer) then read some
+ -- more.
+ if not first or last == #self.buffer then
+ local s = self.file:read(self.buffer_block_size)
+ if not s then
+ if not first then
+ return
+ else
+ return first + self.buffer_start, last + self.buffer_start, capture
+ end
+ end
+ self.buffer = self.buffer..s
+ else
+ return first + self.buffer_start, last + self.buffer_start, capture
+ end
+ end
+end
+
+
+--- Extend the buffer so we can see more
+function file_buffer:extend(offset)
+ local extra = offset - #self.buffer - self.buffer_start
+ if extra > 0 then
+ local size = self.buffer_block_size *
+ math.ceil(extra / self.buffer_block_size)
+ local s = self.file:read(size)
+ if not s then return end
+ self.buffer = self.buffer..s
+ end
+end
+
+
+--- Get a substring from the buffer, extending it if necessary
+function file_buffer:sub(a, b)
+ self:extend(b)
+ b = b == -1 and b or b - self.buffer_start
+ return self.buffer:sub(a - self.buffer_start, b)
+end
+
+
+--- Close a file buffer
+function file_buffer:close()
+ self.file:close()
+ self.file = nil
+end
+
+
+------------------------------------------------------------------------------
+
+local separator_candidates = { ",", "\t", "|" }
+local guess_separator_params = { record_limit = 8; }
+
+
+local function try_separator(buffer, sep, f)
+ guess_separator_params.separator = sep
+ local min, max = math.huge, 0
+ local lines, split_lines = 0, 0
+ local iterator = coroutine.wrap(function() f(buffer, guess_separator_params) end)
+ for t in iterator do
+ min = math.min(min, #t)
+ max = math.max(max, #t)
+ split_lines = split_lines + (t[2] and 1 or 0)
+ lines = lines + 1
+ end
+ if split_lines / lines > 0.75 then
+ return max - min
+ else
+ return math.huge
+ end
+end
+
+
+--- If the user hasn't specified a separator, try to work out what it is.
+function guess_separator(buffer, f)
+ local best_separator, lowest_diff = "", math.huge
+ for _, s in ipairs(separator_candidates) do
+ local ok, diff = pcall(function() return try_separator(buffer, s, f) end)
+ if ok and diff < lowest_diff then
+ best_separator = s
+ lowest_diff = diff
+ end
+ end
+
+ return best_separator
+end
+
+
+local unicode_BOMS =
+{
+ {
+ length = 2,
+ BOMS =
+ {
+ ["\254\255"] = true, -- UTF-16 big-endian
+ ["\255\254"] = true, -- UTF-16 little-endian
+ }
+ },
+ {
+ length = 3,
+ BOMS =
+ {
+ ["\239\187\191"] = true, -- UTF-8
+ }
+ }
+}
+
+
+local function find_unicode_BOM(sub)
+ for _, x in ipairs(unicode_BOMS) do
+ local code = sub(1, x.length)
+ if x.BOMS[code] then
+ return x.length
+ end
+ end
+ return 0
+end
+
+
+--- Iterate through the records in a file
+-- Since records might be more than one line (if there's a newline in quotes)
+-- and line-endings might not be native, we read the file in chunks of
+-- we read the file in chunks using a file_buffer, rather than line-by-line
+-- using io.lines.
+local function separated_values_iterator(buffer, parameters)
+ local field_start = 1
+
+ local advance
+ if buffer.truncate then
+ advance = function(n)
+ field_start = field_start + n
+ buffer:truncate(field_start)
+ end
+ else
+ advance = function(n)
+ field_start = field_start + n
+ end
+ end
+
+
+ local function field_sub(a, b)
+ b = b == -1 and b or b + field_start - 1
+ return buffer:sub(a + field_start - 1, b)
+ end
+
+
+ local function field_find(pattern, init)
+ init = init or 1
+ local f, l, c = buffer:find(pattern, init + field_start - 1)
+ if not f then return end
+ return f - field_start + 1, l - field_start + 1, c
+ end
+
+
+ -- Is there some kind of Unicode BOM here?
+ advance(find_unicode_BOM(field_sub))
+
+
+ -- Start reading the file
+ local sep = "(["..(parameters.separator or
+ guess_separator(buffer, separated_values_iterator)).."\n\r])"
+ local line_start = 1
+ local line = 1
+ local field_count, fields, starts, nonblanks = 0, {}, {}
+ local header, header_read
+ local field_start_line, field_start_column
+ local record_count = 0
+
+
+ local function problem(message)
+ error(("%s:%d:%d: %s"):
+ format(parameters.filename, field_start_line, field_start_column,
+ message), 0)
+ end
+
+
+ while true do
+ local field_end, sep_end, this_sep
+ local tidy
+ field_start_line = line
+ field_start_column = field_start - line_start + 1
+
+ -- If the field is quoted, go find the other quote
+ if field_sub(1, 1) == '"' then
+ advance(1)
+ local current_pos = 0
+ repeat
+ local a, b, c = field_find('"("?)', current_pos + 1)
+ current_pos = b
+ until c ~= '"'
+ if not current_pos then problem("unmatched quote") end
+ tidy = fix_quotes
+ field_end, sep_end, this_sep = field_find(" *([^ ])", current_pos+1)
+ if this_sep and not this_sep:match(sep) then problem("unmatched quote") end
+ else
+ field_end, sep_end, this_sep = field_find(sep, 1)
+ tidy = trim_space
+ end
+
+ -- Look for the separator or a newline or the end of the file
+ field_end = (field_end or 0) - 1
+
+ -- Read the field, then convert all the line endings to \n, and
+ -- count any embedded line endings
+ local value = field_sub(1, field_end)
+ value = value:gsub("\r\n", "\n"):gsub("\r", "\n")
+ for nl in value:gmatch("\n()") do
+ line = line + 1
+ line_start = nl + field_start
+ end
+
+ value = tidy(value)
+ if #value > 0 then nonblanks = true end
+ field_count = field_count + 1
+
+ -- Insert the value into the table for this "line"
+ local key
+ if parameters.column_map and header_read then
+ local ok
+ ok, value, key = pcall(parameters.column_map.transform,
+ parameters.column_map, value, field_count)
+ if not ok then problem(value) end
+ elseif header then
+ key = header[field_count]
+ else
+ key = field_count
+ end
+ if key then
+ fields[key] = value
+ starts[key] = { line=field_start_line, column=field_start_column }
+ end
+
+ -- if we ended on a newline then yield the fields on this line.
+ if not this_sep or this_sep == "\r" or this_sep == "\n" then
+ if parameters.column_map and not header_read then
+ header_read = parameters.column_map:read_header(fields)
+ elseif parameters.header and not header_read then
+ if nonblanks or field_count > 1 then -- ignore blank lines
+ header = fields
+ header_read = true
+ end
+ else
+ if nonblanks or field_count > 1 then -- ignore blank lines
+ coroutine.yield(fields, starts)
+ record_count = record_count + 1
+ if parameters.record_limit and
+ record_count >= parameters.record_limit then
+ break
+ end
+ end
+ end
+ field_count, fields, starts, nonblanks = 0, {}, {}
+ end
+
+ -- If we *really* didn't find a separator then we're done.
+ if not sep_end then break end
+
+ -- If we ended on a newline then count it.
+ if this_sep == "\r" or this_sep == "\n" then
+ if this_sep == "\r" and field_sub(sep_end+1, sep_end+1) == "\n" then
+ sep_end = sep_end + 1
+ end
+ line = line + 1
+ line_start = field_start + sep_end
+ end
+
+ advance(sep_end)
+ end
+end
+
+
+------------------------------------------------------------------------------
+
+local buffer_mt =
+{
+ lines = function(t)
+ return coroutine.wrap(function()
+ separated_values_iterator(t.buffer, t.parameters)
+ end)
+ end,
+ close = function(t)
+ if t.buffer.close then t.buffer:close() end
+ end,
+ name = function(t)
+ return t.parameters.filename
+ end,
+}
+buffer_mt.__index = buffer_mt
+
+
+--- Use an existing file or buffer as a stream to read csv from.
+-- (A buffer is just something that looks like a string in that we can do
+-- `buffer:sub()` and `buffer:find()`)
+-- @return a file object
+local function use(
+ buffer, -- ?string|file|buffer: the buffer to read from. If it's:
+ -- - a string, read from that;
+ -- - a file, turn it into a file_buffer;
+ -- - nil, read from stdin
+ -- otherwise assume it's already a a buffer.
+ parameters) -- ?table: parameters controlling reading the file.
+ -- See README.md
+ parameters = parameters or {}
+ parameters.filename = parameters.filename or "<unknown>"
+ parameters.column_map = parameters.columns and
+ column_map:new(parameters.columns)
+
+ if not buffer then
+ buffer = file_buffer:new(io.stdin)
+ elseif io.type(buffer) == "file" then
+ buffer = file_buffer:new(buffer)
+ end
+
+ local f = { buffer = buffer, parameters = parameters }
+ return setmetatable(f, buffer_mt)
+end
+
+
+------------------------------------------------------------------------------
+
+--- Open a file for reading as a delimited file
+-- @return a file object
+local function open(
+ filename, -- string: name of the file to open
+ parameters) -- ?table: parameters controlling reading the file.
+ -- See README.md
+ local file, message = io.open(filename, "r")
+ if not file then return nil, message end
+
+ parameters = parameters or {}
+ parameters.filename = filename
+ return use(file_buffer:new(file), parameters)
+end
+
+
+------------------------------------------------------------------------------
+
+local function makename(s)
+ local t = {}
+ t[#t+1] = "<(String) "
+ t[#t+1] = (s:gmatch("[^\n]+")() or ""):sub(1,15)
+ if #t[#t] > 14 then t[#t+1] = "..." end
+ t[#t+1] = " >"
+ return table.concat(t)
+end
+
+
+--- Open a string for reading as a delimited file
+-- @return a file object
+local function openstring(
+ filecontents, -- string: The contents of the delimited file
+ parameters) -- ?table: parameters controlling reading the file.
+ -- See README.md
+
+ parameters = parameters or {}
+
+
+ parameters.filename = parameters.filename or makename(filecontents)
+ parameters.buffer_size = parameters.buffer_size or #filecontents
+ return use(filecontents, parameters)
+end
+
+
+------------------------------------------------------------------------------
+
+return { open = open, openstring = openstring, use = use }
+
+------------------------------------------------------------------------------
diff --git a/Data/DefaultContent/Libraries/lua-csv/lua/test.lua b/Data/DefaultContent/Libraries/lua-csv/lua/test.lua
new file mode 100644
index 0000000..f418cf6
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/lua/test.lua
@@ -0,0 +1,102 @@
+pcall(require, "strict")
+local csv = require"csv"
+
+local errors = 0
+
+local function testhandle(handle, correct_result)
+ local result = {}
+ for r in handle:lines() do
+ if not r[1] then
+ local r2 = {}
+ for k, v in pairs(r) do r2[#r2+1] = k..":"..tostring(v) end
+ table.sort(r2)
+ r = r2
+ end
+ result[#result+1] = table.concat(r, ",")
+ end
+
+ handle:close()
+
+ result = table.concat(result, "!\n").."!"
+ if result ~= correct_result then
+ io.stderr:write(
+ ("Error reading '%s':\nExpected output:\n%s\n\nActual output:\n%s\n\n"):
+ format(handle:name(), correct_result, result))
+ errors = errors + 1
+ return false
+ end
+ return true
+end
+
+local function test(filename, correct_result, parameters)
+ parameters = parameters or {}
+ for i = 1, 16 do
+ parameters.buffer_size = i
+ local f = csv.open(filename, parameters)
+ local fileok = testhandle(f, correct_result)
+
+ if fileok then
+ f = io.open(filename, "r")
+ local data = f:read("*a")
+ f:close()
+
+ f = csv.openstring(data, parameters)
+ testhandle(f, correct_result)
+ end
+ end
+end
+
+test("../test-data/embedded-newlines.csv", [[
+embedded
+newline,embedded
+newline,embedded
+newline!
+embedded
+newline,embedded
+newline,embedded
+newline!]])
+
+test("../test-data/embedded-quotes.csv", [[
+embedded "quotes",embedded "quotes",embedded "quotes"!
+embedded "quotes",embedded "quotes",embedded "quotes"!]])
+
+test("../test-data/header.csv", [[
+alpha:ONE,bravo:two,charlie:3!
+alpha:four,bravo:five,charlie:6!]], {header=true})
+
+test("../test-data/header.csv", [[
+apple:one,charlie:30!
+apple:four,charlie:60!]],
+{ columns = {
+ apple = { name = "ALPHA", transform = string.lower },
+ charlie = { transform = function(x) return tonumber(x) * 10 end }}})
+
+test("../test-data/blank-line.csv", [[
+this,file,ends,with,a,blank,line!]])
+
+test("../test-data/BOM.csv", [[
+apple:one,charlie:30!
+apple:four,charlie:60!]],
+{ columns = {
+ apple = { name = "ALPHA", transform = string.lower },
+ charlie = { transform = function(x) return tonumber(x) * 10 end }}})
+
+test("../test-data/bars.txt", [[
+there's a comma in this field, but no newline,embedded
+newline,embedded
+newline!
+embedded
+newline,embedded
+newline,embedded
+newline!]])
+
+
+if errors == 0 then
+ io.stdout:write("Passed\n")
+elseif errors == 1 then
+ io.stdout:write("1 error\n")
+else
+ io.stdout:write(("%d errors\n"):format(errors))
+end
+
+os.exit(errors)
diff --git a/Data/DefaultContent/Libraries/lua-csv/makefile b/Data/DefaultContent/Libraries/lua-csv/makefile
new file mode 100644
index 0000000..dfa7596
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/makefile
@@ -0,0 +1,14 @@
+LUA= $(shell echo `which lua`)
+LUA_BINDIR= $(shell echo `dirname $(LUA)`)
+LUA_PREFIX= $(shell echo `dirname $(LUA_BINDIR)`)
+LUA_VERSION = $(shell echo `lua -v 2>&1 | cut -d " " -f 2 | cut -b 1-3`)
+LUA_SHAREDIR=$(LUA_PREFIX)/share/lua/$(LUA_VERSION)
+
+default:
+ @echo "Nothing to build. Try 'make install' or 'make test'."
+
+install:
+ cp lua/csv.lua $(LUA_SHAREDIR)
+
+test:
+ cd lua && $(LUA) test.lua
diff --git a/Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-1-1.rockspec b/Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-1-1.rockspec
new file mode 100644
index 0000000..6f280aa
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-1-1.rockspec
@@ -0,0 +1,24 @@
+package = "csv"
+version = "1-1"
+source =
+{
+ url = "git://github.com/geoffleyland/lua-csv.git",
+ branch = "master",
+ tag = "v1",
+}
+description =
+{
+ summary = "CSV and other delimited file reading",
+ homepage = "http://github.com/geoffleyland/lua-csv",
+ license = "MIT/X11",
+ maintainer = "Geoff Leyland <geoff.leyland@incremental.co.nz>"
+}
+dependencies = { "lua >= 5.1" }
+build =
+{
+ type = "builtin",
+ modules =
+ {
+ csv = "lua/csv.lua",
+ },
+}
diff --git a/Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-scm-1.rockspec b/Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-scm-1.rockspec
new file mode 100644
index 0000000..29629da
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/rockspecs/csv-scm-1.rockspec
@@ -0,0 +1,23 @@
+package = "csv"
+version = "scm-1"
+source =
+{
+ url = "git://github.com/geoffleyland/lua-csv.git",
+ branch = "master",
+}
+description =
+{
+ summary = "CSV and other delimited file reading",
+ homepage = "http://github.com/geoffleyland/lua-csv",
+ license = "MIT/X11",
+ maintainer = "Geoff Leyland <geoff.leyland@incremental.co.nz>"
+}
+dependencies = { "lua >= 5.1" }
+build =
+{
+ type = "builtin",
+ modules =
+ {
+ csv = "lua/csv.lua",
+ },
+}
diff --git a/Data/DefaultContent/Libraries/lua-csv/test-data/BOM.csv b/Data/DefaultContent/Libraries/lua-csv/test-data/BOM.csv
new file mode 100644
index 0000000..9787c0d
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/test-data/BOM.csv
@@ -0,0 +1,3 @@
+alpha,bravo,charlie
+ONE,two,3
+four,five,6 \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/lua-csv/test-data/bars.txt b/Data/DefaultContent/Libraries/lua-csv/test-data/bars.txt
new file mode 100644
index 0000000..9decabc
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/test-data/bars.txt
@@ -0,0 +1,7 @@
+there's a comma in this field, but no newline|"embedded
+newline"|"embedded
+newline"
+"embedded
+newline"|"embedded
+newline"|"embedded
+newline" \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/lua-csv/test-data/blank-line.csv b/Data/DefaultContent/Libraries/lua-csv/test-data/blank-line.csv
new file mode 100644
index 0000000..63fc515
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/test-data/blank-line.csv
@@ -0,0 +1,2 @@
+this,file,ends,with,a,blank,line
+
diff --git a/Data/DefaultContent/Libraries/lua-csv/test-data/embedded-newlines.csv b/Data/DefaultContent/Libraries/lua-csv/test-data/embedded-newlines.csv
new file mode 100644
index 0000000..67987d1
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/test-data/embedded-newlines.csv
@@ -0,0 +1,8 @@
+"embedded
+newline","embedded
+newline","embedded
+newline"
+"embedded
+newline","embedded
+newline","embedded
+newline" \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/lua-csv/test-data/embedded-quotes.csv b/Data/DefaultContent/Libraries/lua-csv/test-data/embedded-quotes.csv
new file mode 100644
index 0000000..e0c5c73
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/test-data/embedded-quotes.csv
@@ -0,0 +1,2 @@
+"embedded ""quotes""","embedded ""quotes""","embedded ""quotes"""
+"embedded ""quotes""","embedded ""quotes""","embedded ""quotes""" \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/lua-csv/test-data/header.csv b/Data/DefaultContent/Libraries/lua-csv/test-data/header.csv
new file mode 100644
index 0000000..89f702e
--- /dev/null
+++ b/Data/DefaultContent/Libraries/lua-csv/test-data/header.csv
@@ -0,0 +1,3 @@
+alpha,bravo,charlie
+ONE,two,3
+four,five,6 \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/luafun/.gitignore b/Data/DefaultContent/Libraries/luafun/.gitignore
new file mode 100644
index 0000000..0ebe4e1
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/.gitignore
@@ -0,0 +1,4 @@
+*~
+temp/
+fun.lua.c
+5.?-fun/
diff --git a/Data/DefaultContent/Libraries/luafun/.travis.yml b/Data/DefaultContent/Libraries/luafun/.travis.yml
new file mode 100644
index 0000000..2c3f4d8
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/.travis.yml
@@ -0,0 +1,74 @@
+sudo: false
+language: C
+services:
+ - docker
+
+env:
+ global:
+ - PRODUCT=lua-fun
+ matrix:
+ - OS=el DIST=7
+ - OS=fedora DIST=24
+ - OS=fedora DIST=25
+ - OS=ubuntu DIST=xenial
+ - OS=ubuntu DIST=yakkety
+ - OS=debian DIST=stretch
+
+before_deploy:
+ - git clone https://github.com/packpack/packpack.git packpack
+ - ./packpack/packpack
+
+deploy:
+ provider: packagecloud
+ username: ${PACKAGECLOUD_USER}
+ repository: ${PACKAGECLOUD_REPO}
+ token: ${PACKAGECLOUD_TOKEN}
+ dist: ${OS}/${DIST}
+ package_glob: build/*.{deb,rpm}
+ skip_cleanup: true
+ on:
+ branch: master
+ condition: -n "${OS}" && -n "${DIST}" && -n "${PACKAGECLOUD_TOKEN}"
+
+after_deploy:
+ # Prune old packages from PackageCloud, keep only the last two
+ - pip install -r ./packpack/tools/requirements.txt
+ - python ./packpack/tools/packagecloud prune ${PACKAGECLOUD_USER}/${PACKAGECLOUD_REPO} deb ${OS} ${DIST} --keep 2
+ - python ./packpack/tools/packagecloud prune ${PACKAGECLOUD_USER}/${PACKAGECLOUD_REPO} rpm ${OS} ${DIST} --keep 2
+
+cache:
+ directories:
+ - $HOME/lua-5.3.2
+
+addons:
+ apt:
+ packages:
+ - lua5.1
+ - lua5.2
+ - luajit
+
+# Ubuntu Precise on Travis doesn't have lua5.3 package
+install:
+ - |
+ [ -e ${HOME}/lua-5.3.2/src/lua ] || (\
+ wget http://www.lua.org/ftp/lua-5.3.2.tar.gz -c && \
+ tar xzf lua-5.3.2.tar.gz -C ${HOME} && \
+ make -j -C ${HOME}/lua-5.3.2 linux \
+ )
+
+script:
+ - cd tests
+ - LUAJIT=`echo /usr/bin/luajit* | cut -f 1 -d ' '`
+ - ${LUAJIT} -v
+ - ${LUAJIT} runtest *.lua
+ - lua5.1 -v
+ - lua5.1 runtest *.lua
+ - lua5.2 -v
+ - lua5.2 runtest *.lua
+ - LUA53=${HOME}/lua-5.3.2/src/lua
+ - ${LUA53} -v
+ - ${LUA53} runtest *.lua
+ - cd ..
+
+notifications:
+ email: true
diff --git a/Data/DefaultContent/Libraries/luafun/CONTRIBUTING.md b/Data/DefaultContent/Libraries/luafun/CONTRIBUTING.md
new file mode 100644
index 0000000..660ec53
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/CONTRIBUTING.md
@@ -0,0 +1,20 @@
+Contributing
+============
+
+We'd love for you to contribute to the project and make **Lua Fun** even better
+than it is today!
+
+Filling Issues
+---------------
+
+Please file bugs reports and feature requests using [GitHub Issues].
+
+[GitHub Issues]: https://github.com/luafun/luafun/issues
+
+Making Changes
+--------------
+
+If you want to contribute code, please fork the project on [GitHub], make
+changes in branch and send a pull request.
+
+[GitHub]: https://github.com/luafun/luafun
diff --git a/Data/DefaultContent/Libraries/luafun/COPYING.md b/Data/DefaultContent/Libraries/luafun/COPYING.md
new file mode 100644
index 0000000..c945d62
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/COPYING.md
@@ -0,0 +1,27 @@
+Copying
+=======
+
+**Lua Fun** source codes, logo and documentation are distributed under the
+**[MIT/X11 License]** - same as Lua and LuaJIT.
+
+Copyright (c) 2013-2017 Roman Tsisyk <roman@tsisyk.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+[MIT/X11 License]: http://www.opensource.org/licenses/mit-license.php
diff --git a/Data/DefaultContent/Libraries/luafun/README.md b/Data/DefaultContent/Libraries/luafun/README.md
new file mode 100644
index 0000000..c7a2d61
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/README.md
@@ -0,0 +1,107 @@
+Lua Functional
+==============
+
+<img src="/doc/logo.png" align="right" width="174px" height="144px" />
+
+**Lua Fun** is a high-performance functional programming library for [Lua]
+designed with [LuaJIT's trace compiler][LuaJIT] in mind.
+
+Lua Fun provides a set of more than 50 programming primitives typically
+found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and
+even Lisp. High-order functions such as ``map``, ``filter``, ``reduce``,
+``zip``, etc., make it easy to **write simple and efficient functional code**.
+
+Let's see an example:
+
+ > -- Functional style
+ > require "fun" ()
+ > -- calculate sum(x for x^2 in 1..n)
+ > n = 100
+ > print(reduce(operator.add, 0, map(function(x) return x^2 end, range(n))))
+ 328350
+
+ > -- Object-oriented style
+ > local fun = require "fun"
+ > -- calculate sum(x for x^2 in 1..n)
+ > print(fun.range(n):map(function(x) return x^2 end):reduce(operator.add, 0))
+ 328350
+
+**Lua Fun** takes full advantage of the innovative **tracing JIT compiler**
+to achieve transcendental performance on nested functional expressions.
+Functional compositions and high-order functions can be translated into
+**efficient machine code**. Can you believe it? Just try to run the example
+above with ``luajit -jdump`` and see what happens:
+
+ -- skip some initilization code --
+ ->LOOP:
+ 0bcaffd0 movaps xmm5, xmm7
+ 0bcaffd3 movaps xmm7, xmm1
+ 0bcaffd6 addsd xmm7, xmm5
+ 0bcaffda ucomisd xmm7, xmm0
+ 0bcaffde jnb 0x0bca0024 ->5
+ 0bcaffe4 movaps xmm5, xmm7
+ 0bcaffe7 mulsd xmm5, xmm5
+ 0bcaffeb addsd xmm6, xmm5
+ 0bcaffef jmp 0x0bcaffd0 ->LOOP
+ ---- TRACE 1 stop -> loop
+
+The functional chain above was translated by LuaJIT to (!) **one machine loop**
+containing just 10 CPU assembly instructions without CALL. Unbelievable!
+
+Readable? Efficient? Can your Python/Ruby/V8 do better?
+
+Status
+------
+
+**Lua Fun** is in an early alpha stage. The library fully [documented]
+[Documentation] and covered with unit tests.
+
+[![Build Status](https://travis-ci.org/luafun/luafun.png)]
+(https://travis-ci.org/luafun/luafun)
+
+LuaJIT 2.1 alpha is recommended. The library designed in mind of fact that
+[LuaJIT traces tail-, up- and down-recursion][LuaJIT-Recursion] and has a lot of
+[byte code optimizations][LuaJIT-Optimizations]. Lua 5.1-5.3 are also
+supported.
+
+This is **master** (development) branch. API may be changed without any special
+notice. Please use **stable** branch for your production deployments.
+If you still want to use **master**, please don't forget to grep `git log`
+for *Incompatible API changes* message. Thanks!
+
+Please check out [documentation][Documentation] for more information.
+
+Misc
+----
+
+**Lua Fun** is distributed under the [MIT/X11 License] -
+(same as Lua and LuaJIT).
+
+The library was written to use with [Tarantool] - an efficient in-memory
+store and an asynchronous Lua application server.
+
+See Also
+--------
+
+* [Documentation]
+* [RockSpec]
+* [RPM/DEB packages](https://packagecloud.io/rtsisyk/master)
+* lua-l@lists.lua.org
+* luajit@freelists.org
+* roman@tsisyk.com
+
+ [Lua]: http://www.lua.org/
+ [LuaJIT]: http://luajit.org/luajit.html
+ [LuaJIT-Recursion]: http://lambda-the-ultimate.org/node/3851#comment-57679
+ [LuaJIT-Optimizations]: http://wiki.luajit.org/Optimizations
+ [MIT/X11 License]: http://opensource.org/licenses/MIT
+ [Tarantool]: http://github.com/tarantool/tarantool
+ [Getting Started]: https://luafun.github.io/getting_started.html
+ [Documentation]: http://luafun.github.io/
+ [RockSpec]: https://raw.github.com/luafun/luafun/master/fun-scm-1.rockspec
+
+Please **"Star"** the project on GitHub to help it to survive! Thanks!
+
+*****
+
+**Lua Fun**. Simple, Efficient and Functional. In Lua. With JIT.
diff --git a/Data/DefaultContent/Libraries/luafun/debian/.gitignore b/Data/DefaultContent/Libraries/luafun/debian/.gitignore
new file mode 100644
index 0000000..aa3e6bf
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/debian/.gitignore
@@ -0,0 +1,8 @@
+lua-fun/
+tmp/
+trash
+files
+lua_versions
+*.install
+*.substvars
+*.log
diff --git a/Data/DefaultContent/Libraries/luafun/debian/changelog b/Data/DefaultContent/Libraries/luafun/debian/changelog
new file mode 100644
index 0000000..262c02d
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/debian/changelog
@@ -0,0 +1,5 @@
+lua-fun (0.1.3-1) unstable; urgency=medium
+
+ * Initial release. (Closes: #811482)
+
+ -- Roman Tsisyk <roman@tarantool.org> Mon, 18 Jan 2016 10:00:00 +0300
diff --git a/Data/DefaultContent/Libraries/luafun/debian/compat b/Data/DefaultContent/Libraries/luafun/debian/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/Data/DefaultContent/Libraries/luafun/debian/control b/Data/DefaultContent/Libraries/luafun/debian/control
new file mode 100644
index 0000000..f93b318
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/debian/control
@@ -0,0 +1,20 @@
+Source: lua-fun
+Section: interpreters
+Priority: optional
+Maintainer: Roman Tsisyk <roman@tarantool.org>
+Build-Depends: debhelper (>= 9), dh-lua (>= 19)
+Standards-Version: 3.9.6
+Homepage: https://github.com/luafun/luafun
+Vcs-Git: git://github.com/luafun/luafun.git
+Vcs-Browser: https://github.com/luafun/luafun
+
+Package: lua-fun
+Architecture: all
+Depends: ${misc:Depends}
+Provides: ${lua:Provides}
+XB-Lua-Versions: ${lua:Versions}
+Description: High-performance functional programming library for Lua
+ Lua Fun provides a set of more than 50 programming primitives typically
+ found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and
+ even Lisp. High-order functions such as map, filter, reduce, zip, etc.,
+ make it easy to write simple and efficient functional code.
diff --git a/Data/DefaultContent/Libraries/luafun/debian/copyright b/Data/DefaultContent/Libraries/luafun/debian/copyright
new file mode 100644
index 0000000..34f24ad
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/debian/copyright
@@ -0,0 +1,31 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: luafun
+Upstream-Contact: Roman Tsisyk <roman@tsisyk.com>
+Source: https://github.com/luafun/luafun
+
+Files: *
+Copyright: 2013-2017 Roman Tsisyk <roman@tsisyk.com>
+Comment: In the Lua community this license is better known as "MIT".
+ Unfortunately other variants of this license are also known as "MIT".
+ To obtain a machine intepretable copyright file Debian prefers to name this
+ version of the MIT license using the non ambiguous term "Expat".
+License: Expat
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ “Software”), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ .
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ .
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
diff --git a/Data/DefaultContent/Libraries/luafun/debian/lua-fun.docs b/Data/DefaultContent/Libraries/luafun/debian/lua-fun.docs
new file mode 100644
index 0000000..b43bf86
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/debian/lua-fun.docs
@@ -0,0 +1 @@
+README.md
diff --git a/Data/DefaultContent/Libraries/luafun/debian/lua5.1.dh-lua.conf b/Data/DefaultContent/Libraries/luafun/debian/lua5.1.dh-lua.conf
new file mode 100644
index 0000000..fa57bb6
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/debian/lua5.1.dh-lua.conf
@@ -0,0 +1,4 @@
+PKG_NAME=fun
+LUA_MODNAME=fun
+LUA_SOURCES=fun.lua
+LUA_TEST=tests/runtest tests/*.lua
diff --git a/Data/DefaultContent/Libraries/luafun/debian/lua5.2.dh-lua.conf b/Data/DefaultContent/Libraries/luafun/debian/lua5.2.dh-lua.conf
new file mode 100644
index 0000000..ba875b6
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/debian/lua5.2.dh-lua.conf
@@ -0,0 +1 @@
+lua5.1.dh-lua.conf \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/luafun/debian/lua5.3.dh-lua.conf b/Data/DefaultContent/Libraries/luafun/debian/lua5.3.dh-lua.conf
new file mode 100644
index 0000000..ba875b6
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/debian/lua5.3.dh-lua.conf
@@ -0,0 +1 @@
+lua5.1.dh-lua.conf \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/luafun/debian/patches/series b/Data/DefaultContent/Libraries/luafun/debian/patches/series
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/debian/patches/series
diff --git a/Data/DefaultContent/Libraries/luafun/debian/rules b/Data/DefaultContent/Libraries/luafun/debian/rules
new file mode 100644
index 0000000..9e473ed
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/debian/rules
@@ -0,0 +1,12 @@
+#!/usr/bin/make -f
+
+VERSION := $(shell dpkg-parsechangelog|grep ^Version|awk '{print $$2}')
+UVERSION := $(shell echo $(VERSION)|sed 's/-[[:digit:]]\+$$//')
+
+%:
+ dh $@ --buildsystem=lua --with lua
+
+tarball: clean
+ tar --exclude=.git --exclude=debian --exclude rpm \
+ --transform='s,^\.,luafun-$(UVERSION),S' \
+ -czf ../luafun-$(UVERSION).orig.tar.gz .
diff --git a/Data/DefaultContent/Libraries/luafun/debian/source/format b/Data/DefaultContent/Libraries/luafun/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/Data/DefaultContent/Libraries/luafun/debian/watch b/Data/DefaultContent/Libraries/luafun/debian/watch
new file mode 100644
index 0000000..40bc2ca
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/debian/watch
@@ -0,0 +1,6 @@
+# test this watch file using:
+# uscan --watchfile debian/watch --upstream-version 0.0.1 --package lua-fun
+# https://wiki.debian.org/debian/watch#GitHub
+version=3
+opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/luafun-$1\.tar\.gz/ \
+ https://github.com/luafun/luafun/tags .*/v?(\d\S*)\.tar\.gz
diff --git a/Data/DefaultContent/Libraries/luafun/doc/.gitignore b/Data/DefaultContent/Libraries/luafun/doc/.gitignore
new file mode 100644
index 0000000..e35d885
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/.gitignore
@@ -0,0 +1 @@
+_build
diff --git a/Data/DefaultContent/Libraries/luafun/doc/Makefile b/Data/DefaultContent/Libraries/luafun/doc/Makefile
new file mode 100644
index 0000000..1e1b049
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/Makefile
@@ -0,0 +1,153 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/LuaFunctional.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/LuaFunctional.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/LuaFunctional"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/LuaFunctional"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/Data/DefaultContent/Libraries/luafun/doc/_static/.keep b/Data/DefaultContent/Libraries/luafun/doc/_static/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/_static/.keep
diff --git a/Data/DefaultContent/Libraries/luafun/doc/_templates/layout.html b/Data/DefaultContent/Libraries/luafun/doc/_templates/layout.html
new file mode 100644
index 0000000..ee1fa29
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/_templates/layout.html
@@ -0,0 +1,14 @@
+{% extends "!layout.html" %}
+
+{% block footer %}
+{{ super() }}
+ <script type="text/javascript">
+(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
+
+ga('create', 'UA-45899190-2', 'auto');
+ga('send', 'pageview');
+ </script>
+{% endblock %}
diff --git a/Data/DefaultContent/Libraries/luafun/doc/about.rst b/Data/DefaultContent/Libraries/luafun/doc/about.rst
new file mode 100644
index 0000000..97da8dc
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/about.rst
@@ -0,0 +1,42 @@
+About
+=====
+
+Credits
+-------
+
+An initial prototype was designed and enginered in one evening by Roman Tsisyk.
+After that the library was completely rewritten, tested and documented
+(which took a while).
+
+The project exists only thanks to the excellent tracing just-in-time compiler
+in `LuaJIT <http://luajit.org>`_.
+
+The library works best with `Tarantool <http://tarantool.org>`_ --
+an efficient in-memory database and Lua application server.
+
+Copying
+-------
+
+Lua Fun source codes, logo and documentation are distributed under the
+`MIT License (MIT) <http://www.opensource.org/licenses/mit-license.php>`_ --
+same as LuaJIT.
+
+Copyright (c) 2013-2017 Roman Tsisyk <roman@tsisyk.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/Data/DefaultContent/Libraries/luafun/doc/basic.rst b/Data/DefaultContent/Libraries/luafun/doc/basic.rst
new file mode 100644
index 0000000..346dd78
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/basic.rst
@@ -0,0 +1,141 @@
+Basic Functions
+===============
+
+.. module:: fun
+
+The section contains functions to create iterators from Lua objects.
+
+.. function:: iter(array)
+ iter(map)
+ iter(string)
+ iter(gen, param, state)
+
+ :returns: ``gen, param, state`` -- :ref:`iterator triplet <iterator_triplet>`
+
+ Make ``gen, param, state`` iterator from the iterable object.
+ The function is a generalized version of :func:`pairs` and :func:`ipairs`.
+
+ The function distinguish between arrays and maps using ``#arg == 0``
+ check to detect maps. For arrays ``ipairs`` is used. For maps a modified
+ version of ``pairs`` is used that also returns keys. Userdata objects
+ are handled in the same way as tables.
+
+ If ``LUAJIT_ENABLE_LUA52COMPAT`` [#luajit_lua52compat]_ mode is enabled and
+ argument has metamethods ``__pairs`` (for maps) or ``__ipairs`` for (arrays),
+ call it with the table or userdata as argument and return the first three
+ results from the call [#lua52_ipairs]_.
+
+ All library iterator are suitable to use with Lua's ``for .. in`` loop.
+
+ .. code-block:: lua
+
+ > for _it, a in iter({1, 2, 3}) do print(a) end
+ 1
+ 2
+ 3
+
+ > for _it, k, v in iter({ a = 1, b = 2, c = 3}) do print(k, v) end
+ b 2
+ a 1
+ c 3
+
+ > for _it, a in iter("abcde") do print(a) end
+ a
+ b
+ c
+ d
+ e
+
+ The first cycle variable *_it* is needed to store an internal state of
+ the iterator. The value must be always ignored in loops:
+
+ .. code-block:: lua
+
+ for _it, a, b in iter({ a = 1, b = 2, c = 3}) do print(a, b) end
+ -- _it is some internal iterator state - always ignore it
+ -- a, b are values return from the iterator
+
+ Simple iterators like ``iter({1, 2, 3})`` have simple states, whereas
+ other iterators like :func:`zip` or :func:`chain` have complicated
+ internal states which values senseless for the end user.
+
+ Check out :doc:`under_the_hood` section for more details.
+
+ There is also the possibility to supply custom iterators to the
+ function:
+
+ .. code-block:: lua
+
+ > local function mypairs_gen(max, state)
+ if (state >= max) then
+ return nil
+ end
+ return state + 1, state + 1
+ end
+
+ > local function mypairs(max)
+ return mypairs_gen, max, 0
+ end
+
+ > for _it, a in iter(mypairs(10)) do print(a) end
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+
+ Iterators can return multiple values.
+
+ Check out :doc:`under_the_hood` section for more details.
+
+ .. [#luajit_lua52compat] http://luajit.org/extensions.html
+ .. [#lua52_ipairs] http://www.lua.org/manual/5.2/manual.html#pdf-ipairs
+
+.. function:: each(fun, gen, param, state)
+ iterator:each(fun)
+
+ :returns: none
+
+ Execute the *fun* for each iteration value. The function is equivalent to
+ the code below:
+
+ .. code-block:: lua
+
+ for _it, ... in iter(gen, param, state) do
+ fun(...)
+ end
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, { a = 1, b = 2, c = 3})
+ b 2
+ a 1
+ c 3
+
+ > each(print, {1, 2, 3})
+ 1
+ 2
+ 3
+
+ The function is used for its side effects. Implementation directly applies
+ *fun* to all iteration values without returning a new iterator, in contrast
+ to functions like :func:`map`.
+
+ .. seealso:: :func:`map`, :func:`reduce`
+
+.. function:: for_each(fun, gen, param, state)
+ iterator:for_each(fun)
+
+ An alias for :func:`each`.
+
+.. function:: foreach(fun, gen, param, state)
+ iterator:foreach(fun)
+
+ An alias for :func:`each`.
diff --git a/Data/DefaultContent/Libraries/luafun/doc/compositions.rst b/Data/DefaultContent/Libraries/luafun/doc/compositions.rst
new file mode 100644
index 0000000..4c789b3
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/compositions.rst
@@ -0,0 +1,140 @@
+Compositions
+============
+
+.. module:: fun
+
+.. function:: zip(...)
+ iterator1:zip(iterator2, iterator3, ...)
+
+ :param ...: iterators to "zip"
+ :type ...: iterator
+
+ :returns: an iterator
+
+ Return a new iterator where i-th return value contains the i-th element
+ from each of the iterators. The returned iterator is truncated in length
+ to the length of the shortest iterator. For multi-return iterators only the
+ first variable is used.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > dump(zip({"a", "b", "c", "d"}, {"one", "two", "three"}))
+ a one
+ b two
+ c three
+
+ > each(print, zip())
+
+ > each(print, zip(range(5), {'a', 'b', 'c'}, rands()))
+ 1 a 0.57514179487402
+ 2 b 0.79693061238668
+ 3 c 0.45174307459403
+
+ > each(print, zip(partition(function(x) return x > 7 end, range(1, 15, 1))))
+ 8 1
+ 9 2
+ 10 3
+ 11 4
+ 12 5
+ 13 6
+ 14 7
+
+.. function:: cycle(gen, param, state)
+ iterator:cycle()
+
+ :returns: a cycled version of ``{gen, param, state}`` iterator
+
+ Make a new iterator that returns elements from ``{gen, param, state}``
+ iterator until the end and then "restart" iteration using a saved clone of
+ ``{gen, param, state}``. The returned iterator is constant space and no
+ return values are buffered. Instead of that the function make a clone of the
+ source ``{gen, param, state}`` iterator. Therefore, the source iterator
+ must be pure functional to make an indentical clone. Infinity iterators
+ are supported, but are not recommended.
+
+ .. note:: ``{gen, param, state}`` must be pure functional to work properly
+ with the function.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, take(15, cycle(range(5))))
+ 1
+ 2
+ 3
+ 4
+ 5
+ 1
+ 2
+ 3
+ 4
+ 5
+ 1
+ 2
+ 3
+ 4
+ 5
+
+ > each(print, take(15, cycle(zip(range(5), {"a", "b", "c", "d", "e"}))))
+ 1 a
+ 2 b
+ 3 c
+ 4 d
+ 5 e
+ 1 a
+ 2 b
+ 3 c
+ 4 d
+ 5 e
+ 1 a
+ 2 b
+ 3 c
+ 4 d
+ 5 e
+
+.. function:: chain(...)
+ iterator1:chain(iterator2, iterator3, ...)
+
+ :param ...: iterators to chain
+ :type ...: iterator
+ :returns: a consecutive iterator from sources (left from right)
+
+ Make an iterator that returns elements from the first iterator until it is
+ exhausted, then proceeds to the next iterator, until all of the iterators
+ are exhausted. Used for treating consecutive iterators as a single iterator.
+ Infinity iterators are supported, but are not recommended.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, chain(range(2), {"a", "b", "c"}, {"one", "two", "three"}))
+ 1
+ 2
+ a
+ b
+ c
+ one
+ two
+ three
+
+ > each(print, take(15, cycle(chain(enumerate({"a", "b", "c"}),
+ {"one", "two", "three"}))))
+ 1 a
+ 2 b
+ 3 c
+ one
+ two
+ three
+ 1 a
+ 2 b
+ 3 c
+ one
+ two
+ three
+ 1 a
+ 2 b
+ 3 c
diff --git a/Data/DefaultContent/Libraries/luafun/doc/conf.py b/Data/DefaultContent/Libraries/luafun/doc/conf.py
new file mode 100644
index 0000000..ce36bbf
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/conf.py
@@ -0,0 +1,247 @@
+# -*- coding: utf-8 -*-
+#
+# Lua Functional documentation build configuration file, created by
+# sphinx-quickstart on Sat Nov 9 14:21:28 2013.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+#extensions = [ "redjack.sphinx.lua" ]
+
+# The documentation primary domain is lua
+#primary_domain = "lua"
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Lua Functional'
+copyright = u'2013-2017, Roman Tsisyk'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.1'
+# The full version, including alpha/beta/rc tags.
+release = '0.1.3'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'haiku'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {
+ #"full_logo": False,
+#}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+html_logo = "logo.png"
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+#htmlhelp_basename = 'LuaFunctionaldoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+#latex_documents = [
+ #('index', 'LuaFunctional.tex', u'Lua Functional Documentation',
+ #u'Roman Tsisyk', 'manual'),
+#]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'luafun', u'Lua Functional Documentation',
+ [u'Roman Tsisyk'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+#texinfo_documents = [
+ #('index', 'LuaFunctional', u'Lua Functional Documentation',
+ #u'Roman Tsisyk', 'LuaFunctional', 'One line description of project.',
+ #'Miscellaneous'),
+#]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
diff --git a/Data/DefaultContent/Libraries/luafun/doc/filtering.rst b/Data/DefaultContent/Libraries/luafun/doc/filtering.rst
new file mode 100644
index 0000000..2852f6c
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/filtering.rst
@@ -0,0 +1,121 @@
+Filtering
+=========
+
+.. module:: fun
+
+This section contains functions to filter values during iteration.
+
+.. function:: filter(predicate, gen, param, state)
+ iterator:filter(predicate)
+
+ :param param: an predicate to filter the iterator
+ :type param: (function(...) -> bool)
+
+ Return a new iterator of those elements that satisfy the **predicate**.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, filter(function(x) return x % 3 == 0 end, range(10)))
+ 3
+ 6
+ 9
+
+ > each(print, take(5, filter(function(i, x) return i % 3 == 0 end,
+ enumerate(duplicate('x')))))
+ 3 x
+ 6 x
+ 9 x
+ 12 x
+ 15 x
+
+ .. note:: Multireturn iterators are supported but can cause performance
+ regressions.
+
+ .. seealso:: :func:`take_while` and :func:`drop_while`.
+
+.. function:: remove_if(predicate, gen, param, state)
+ iterator:remove_if(predicate)
+
+ An alias for :func:`filter`.
+
+.. function:: grep(regexp_or_predicate, gen, param, state)
+ iterator:grep(regexp_or_predicate)
+
+ If **regexp_or_predicate** is string then the parameter is used as a regular
+ expression to build filtering predicate. Otherwise the function is just an
+ alias for :func:`filter`.
+
+ Equivalent to:
+
+ .. code-block:: lua
+
+ local fun = regexp_or_predicate
+ if type(regexp_or_predicate) == "string" then
+ fun = function(x) return string.find(x, regexp_or_predicate) ~= nil end
+ end
+ return filter(fun, gen, param, state)
+
+ Examples:
+
+ .. code-block:: lua
+
+ lines_to_grep = {
+ [[Emily]],
+ [[Chloe]],
+ [[Megan]],
+ [[Jessica]],
+ [[Emma]],
+ [[Sarah]],
+ [[Elizabeth]],
+ [[Sophie]],
+ [[Olivia]],
+ [[Lauren]]
+ }
+
+ each(print, grep("^Em", lines_to_grep))
+ --[[test
+ Emily
+ Emma
+ --test]]
+
+ each(print, grep("^P", lines_to_grep))
+ --[[test
+ --test]]
+
+ > each(print, grep(function(x) return x % 3 == 0 end, range(10)))
+ 3
+ 6
+ 9
+
+.. function:: partition(predicate, gen, param, state)
+ iterator:partition(predicate)
+
+ :param x: a value to find
+ :returns: {gen1, param1, state1}, {gen2, param2, state2}
+
+ The function returns two iterators where elements do and do not satisfy the
+ prediucate. Equivalent to:
+
+ .. code-block:: lua
+
+ return filter(predicate, gen', param', state'),
+ filter(function(...) return not predicate(...) end, gen, param, state);
+
+ The function make a clone of the source iterator. Iterators especially
+ returned in tables to work with :func:`zip` and other functions.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, zip(partition(function(i, x) return i % 3 == 0 end, range(10))))
+ 3 1
+ 6 2
+ 9 4
+
+ .. note:: ``gen, param, state`` must be pure functional to work properly
+ with the function.
+
+ .. seealso:: :func:`span`
diff --git a/Data/DefaultContent/Libraries/luafun/doc/generators.rst b/Data/DefaultContent/Libraries/luafun/doc/generators.rst
new file mode 100644
index 0000000..7132d47
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/generators.rst
@@ -0,0 +1,233 @@
+Generators
+==========
+
+.. module:: fun
+
+This section contains a number of useful generators modeled after Standard ML,
+Haskell, Python, Ruby, JavaScript and other languages.
+
+Finite Generators
+-----------------
+
+.. function:: range([start,] stop[, step])
+
+ :param start: an endpoint of the interval (see below)
+ :type start: number
+ :param stop: an endpoint of the interval (see below)
+ :type stop: number
+ :param step: a step
+ :type step: number
+
+ :returns: an iterator
+
+ The iterator to create arithmetic progressions. Iteration values are generated
+ within closed interval ``[start, stop]`` (i.e. *stop* is included).
+ If the *start* argument is omitted, it defaults to ``1`` (*stop* > 0) or
+ to ``-1`` (*stop* < 0). If the *step* argument is omitted, it defaults to
+ ``1`` (*start* <= *stop*) or to ``-1`` (*start* > *stop*). If *step* is
+ positive, the last element is the largest ``start + i * step`` less than or
+ equal to *stop*; if *step* is negative, the last element is the smallest
+ ``start + i * step`` greater than or equal to *stop*.
+ *step* must not be zero (or else an error is raised).
+ ``range(0)`` returns empty iterator.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > for _it, v in range(5) do print(v) end
+ 1
+ 2
+ 3
+ 4
+ 5
+ > for _it, v in range(-5) do print(v) end
+ -1
+ -2
+ -3
+ -4
+ -5
+ > for _it, v in range(1, 6) do print(v) end
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ > for _it, v in range(0, 20, 5) do print(v) end
+ 0
+ 5
+ 10
+ 15
+ 20
+ > for _it, v in range(0, 10, 3) do print(v) end
+ 0
+ 3
+ 6
+ 9
+ > for _it, v in range(0, 1.5, 0.2) do print(v) end
+ 0
+ 0.2
+ 0.4
+ 0.6
+ 0.8
+ 1
+ 1.2
+ 1.4
+ > for _it, v in range(0) do print(v) end
+ > for _it, v in range(1) do print(v) end
+ 1
+ > for _it, v in range(1, 0) do print(v) end
+ 1
+ 0
+ > for _it, v in range(0, 10, 0) do print(v) end
+ error: step must not be zero
+
+Infinity Generators
+-------------------
+
+.. function:: duplicate(...)
+
+ :param ...: objects to duplicate
+ :type ...: non nil
+ :returns: an iterator
+
+ The iterator returns values over and over again indefinitely. All values
+ that passed to the iterator are returned as-is during the iteration.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, take(3, duplicate('a', 'b', 'c')))
+ a b c
+ a b c
+ > each(print, take(3, duplicate('x')))
+ x
+ x
+ x
+ > for _it, a, b, c, d, e in take(3, duplicate(1, 2, 'a', 3, 'b')) do
+ print(a, b, c, d, e)
+ >> end
+ 1 2 a 3 b
+ 1 2 a 3 b
+ 1 2 a 3 b
+
+.. function:: xrepeat(...)
+
+ An alias for :func:`duplicate`.
+
+.. function:: replicate(...)
+
+ An alias for :func:`duplicate`.
+
+.. function:: tabulate(fun)
+
+ :param fun: an unary generating function
+ :type fun: function(n: uint) -> ...
+ :returns: an iterator
+
+ The iterator that returns ``fun(0)``, ``fun(1)``, ``fun(2)``, ``...`` values
+ indefinitely.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, take(5, tabulate(function(x) return 'a', 'b', 2*x end)))
+ a b 0
+ a b 2
+ a b 4
+ a b 6
+ a b 8
+ > each(print, take(5, tabulate(function(x) return x^2 end)))
+ 0
+ 1
+ 4
+ 9
+ 16
+
+.. function:: zeros()
+
+ :returns: an iterator
+
+ The iterator returns ``0`` indefinitely.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, take(5, zeros()))
+ 0
+ 0
+ 0
+ 0
+ 0
+
+.. function:: ones()
+
+ :returns: an iterator
+
+ The iterator that returns ``1`` indefinitely.
+
+ Example::
+
+ > each(print, take(5, ones()))
+ 1
+ 1
+ 1
+ 1
+ 1
+
+Random sampling
+---------------
+
+.. function:: rands([n[, m]])
+
+ :param n: an endpoint of the interval (see below)
+ :type n: uint
+ :param m: an endpoint of the interval (see below)
+ :type m: uint
+ :returns: an iterator
+
+ The iterator returns random values using :func:`math.random`.
+ If the **n** and **m** are set then the iterator returns pseudo-random
+ integers in the ``[n, m)`` interval (i.e. **m** is not included).
+ If the **m** is not set then the iterator generates pseudo-random integers
+ in the ``[0, n)`` interval. When called without arguments returns
+ pseudo-random real numbers with uniform distribution in the
+ interval ``[0, 1)``.
+
+ .. warning:: This iterator is not pure-functional and may not work as
+ expected with some library functions.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, take(10, rands(10, 20)))
+ 19
+ 17
+ 11
+ 19
+ 12
+ 13
+ 14
+ 16
+ 10
+ 11
+
+ > each(print, take(5, rands(10)))
+ 7
+ 6
+ 5
+ 9
+ 0
+
+ > each(print, take(5, rands()))
+ 0.79420629243124
+ 0.69885246563716
+ 0.5901037417281
+ 0.7532286166836
+ 0.080971251199854
+
diff --git a/Data/DefaultContent/Libraries/luafun/doc/getting_started.rst b/Data/DefaultContent/Libraries/luafun/doc/getting_started.rst
new file mode 100644
index 0000000..9a9e3de
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/getting_started.rst
@@ -0,0 +1,254 @@
+Getting Started
+===============
+
+Please jump to `Using the Library`_ section if you are familiar with Lua and
+LuaJIT.
+
+.. contents::
+
+Prerequisites
+-------------
+
+The library is designed for LuaJIT_. **LuaJIT 2.1 alpha** is high^W **Highly**
+recommended for performance reasons. Lua 5.1--5.3 are also supported.
+
+The library is platform-independent and expected to work on all platforms that
+supported by Lua(JIT). It can be also used in any Lua(JIT) based applications,
+e.g. Tarantool_ or OpenResty_.
+
+You might need diff_ tool to run test system and sphinx_ to regenerate the
+documentation from source files.
+
+.. _LuaJIT: http://luajit.org/
+.. _Tarantool: http://tarantool.org/
+.. _OpenResty: http://openresty.org/
+.. _diff: http://en.wikipedia.org/wiki/Diff
+.. _sphinx: http://sphinx-doc.org/
+
+Installing LuaJIT
+-----------------
+
+You can build LuaJIT from sources or install it from a binary archive.
+
+From Sources
+````````````
+
+1. Clone LuaJIT git repository. Please note that **v2.1** branch is needed.
+You can always select this branch using ``git checkout v2.1``.
+
+.. code-block:: bash
+
+ $ git clone http://luajit.org/git/luajit-2.0.git -b v2.1 luajit-2.1
+ Cloning into 'luajit-2.1'...
+
+2. Compile LuaJIT
+
+.. code-block:: bash
+
+ $ cd luajit-2.1/
+ luajit-2.1 $ make -j8
+
+3. Install LuaJIT
+
+.. code-block:: bash
+
+ luajit-2.1 $ make install
+ luajit-2.1 $ ln -s /usr/local/bin/luajit-2.1.0-alpha /usr/local/bin/luajit
+
+Install operation might require root permissions. However, you can install
+LuaJIT into your home directory.
+
+From a Binary Archive
+`````````````````````
+
+If operations above look too complicated for you, you always can download a
+binary archive from http://luajit.org/download.html page.
+Your favorite package manager may also have LuaJIT packages.
+
+Running LuaJIT
+``````````````
+
+Ensure that freshly installed LuaJIT works:
+
+.. code-block:: bash
+
+ $ luajit
+ LuaJIT 2.1.0-alpha -- Copyright (C) 2005-2013 Mike Pall. http://luajit.org/
+ JIT: ON SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse
+ > = 2 + 2
+ 4
+
+It is good idea to use LuaJIT CLI under ``rlwrap`` (on nix platforms):
+
+.. code-block:: bash
+
+ alias luajit="rlwrap luajit"
+ $ luajit
+ LuaJIT 2.1.0-alpha -- Copyright (C) 2005-2013 Mike Pall. http://luajit.org/
+ JIT: ON SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse
+ > = 2 + 2
+ 4
+ > = 2 + 2 <!-- You can use arrows, completion and so on, like in Bash
+
+Installing the Library
+----------------------
+
+Using LuaRocks
+``````````````
+
+Use the rockspec_ file.
+
+.. _rockspec: https://raw.github.com/luafun/luafun/master/fun-scm-1.rockspec
+
+Using git
+`````````
+1. Clone Lua Fun repository:
+
+.. code-block:: bash
+
+ git clone git://github.com/luafun/luafun.git
+ $ cd luafun
+
+2. Run tests (optional):
+
+.. code-block:: bash
+
+ luafun $ cd tests
+ luafun/tests $ ./runtest *.lua
+ Testing basic.lua
+ Testing compositions.lua
+ Testing filters.lua
+ Testing folds.lua
+ Testing generators.lua
+ Testing slices.lua
+ Testing transformations.lua
+ All tests have passed!
+
+Using wget
+``````````
+
+Just download https://raw.github.com/luafun/luafun/master/fun.lua file:
+
+.. code-block:: bash
+
+ $ wget https://raw.github.com/luafun/luafun/master/fun.lua
+
+Using the Library
+-----------------
+
+Try to run LuaJIT in the same directory where ``fun.lua`` file is located:
+
+.. code-block:: bash
+ :emphasize-lines: 4
+
+ luafun $ luajit
+ LuaJIT 2.1.0-alpha -- Copyright (C) 2005-2013 Mike Pall. http://luajit.org/
+ JIT: ON SSE2 SSE3 fold cse dce fwd dse narrow loop abc sink fuse
+ > fun = require 'fun'
+ >
+ > for _k, a in fun.range(3) do print(a) end
+ 1
+ 2
+ 3
+
+If you see an error message like ``stdin:1: module 'fun' not found:`` then
+you need to configure you Package Path (``package.path``). Please consult
+`Lua Wiki <http://lua-users.org/wiki/PackagePath>`_ for additional information.
+
+
+**Lua Fun** designed to be small ubiquitous library. It is a good idea to import
+all library functions to the global table:
+
+.. code-block:: bash
+ :emphasize-lines: 1
+
+ > for k, v in pairs(require "fun") do _G[k] = v end -- import fun.*
+ > for _k, a in range(3) do print(a) end
+ 0
+ 1
+ 2
+
+**Lua Fun** also provides a special **shortcut** to autoimport all functions:
+
+.. code-block:: bash
+ :emphasize-lines: 1
+
+ > require 'fun'() -- to import all lua.* functions to globals
+ > each(print, range(5))
+ 1
+ 2
+ 3
+ 4
+ 5
+
+Now you can use **Lua Fun**:
+
+.. code-block:: bash
+
+ > print(sum(filter(function(x) return x % 16 == 0 end, range(10000))))
+ 3130000
+
+ > each(print, take(5, tabulate(math.sin)))
+ 0
+ 2
+ 4
+ 6
+ 8
+
+ > each(print, enumerate(zip({"one", "two", "three", "four", "five"},
+ {"a", "b", "c", "d", "e"})))
+ 1 one a
+ 2 two b
+ 3 three c
+ 4 four d
+ 5 five e
+
+ > lines_to_grep = {
+ [[Emily]],
+ [[Chloe]],
+ [[Megan]],
+ [[Jessica]],
+ [[Emma]],
+ [[Sarah]],
+ [[Elizabeth]],
+ [[Sophie]],
+ [[Olivia]],
+ [[Lauren]]
+ }
+
+ > each(print, grep("Em", lines_to_grep))
+ Emily
+ Emma
+
+ > each(print, take(10, cycle(chain(
+ {enumerate({"a", "b", "c"})},
+ {"one", "two", "three"}))
+ ))
+ 0 a
+ 1 b
+ 2 c
+ one
+ two
+ three
+ 0 a
+ 1 b
+ 2 c
+ one
+
+Please note that functions support multireturn.
+
+Further Actions
+---------------
+
+- Take a look on :doc:`reference`.
+- Use :ref:`genindex` to find functions by its names.
+- Checkout **examples** from
+ `tests/ <https://github.com/luafun/luafun/tree/master/tests>`_ directory
+- Read :doc:`under_the_hood` section
+- "Star" us the on GitHub_ to help the project to survive
+- Make Great Software
+- Have fun
+
+**Lua Fun**. Simple, Efficient and Functional. In Lua. With JIT.
+
+.. _GitHub: http://github.com/luafun/luafun
diff --git a/Data/DefaultContent/Libraries/luafun/doc/index.rst b/Data/DefaultContent/Libraries/luafun/doc/index.rst
new file mode 100644
index 0000000..8d1862d
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/index.rst
@@ -0,0 +1,29 @@
+.. _library-index:
+
+###############################
+ Lua Functional Library
+###############################
+
+:Release: |version|
+:Date: |today|
+
+.. highlight:: lua
+
+Contents
+========
+
+.. toctree::
+ :maxdepth: 2
+
+ intro.rst
+ getting_started.rst
+ reference.rst
+ under_the_hood.rst
+ about.rst
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`search`
+
diff --git a/Data/DefaultContent/Libraries/luafun/doc/indexing.rst b/Data/DefaultContent/Libraries/luafun/doc/indexing.rst
new file mode 100644
index 0000000..324cfbf
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/indexing.rst
@@ -0,0 +1,74 @@
+Indexing
+========
+
+.. module:: fun
+
+This section contains functions to find elements by its values.
+
+.. function:: index(x, gen, param, state)
+ iterator:index(x)
+
+ :param x: a value to find
+ :returns: the position of the first element that equals to the **x**
+
+ The function returns the position of the first element in the given iterator
+ which is equal (using ``==``) to the query element, or ``nil`` if there is
+ no such element.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > print(index(2, range(0)))
+ nil
+
+ > print(index("b", {"a", "b", "c", "d", "e"}))
+ 2
+
+.. function:: index_of(x, gen, param, state)
+ iterator:index_of(x)
+
+ An alias for :func:`index`.
+
+.. function:: elem_index(x, gen, param, state)
+ iterator:elem_index(x)
+
+ An alias for :func:`index`.
+
+.. function:: indexes(x, gen, param, state)
+ iterator:indexes(x)
+
+ :param x: a value to find
+ :returns: an iterator which positions of elements that equal to the **x**
+
+ The function returns an iterator to positions of elements which equals to
+ the query element.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, indexes("a", {"a", "b", "c", "d", "e", "a", "b", "a", "a"}))
+ 1
+ 6
+ 9
+ 10
+
+ .. seealso:: :func:`filter`
+
+.. function:: indices(x, gen, param, state)
+ iterator:indices(x)
+
+ An alias for :func:`indexes`.
+
+.. function:: elem_indexes(x, gen, param, state)
+ iterator:elem_indexes(x)
+
+ An alias for :func:`indexes`.
+
+.. function:: elem_indices(x, gen, param, state)
+ iterator:elem_indices(x)
+
+ An alias for :func:`indexes`.
+
+
diff --git a/Data/DefaultContent/Libraries/luafun/doc/intro.rst b/Data/DefaultContent/Libraries/luafun/doc/intro.rst
new file mode 100644
index 0000000..d47c431
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/intro.rst
@@ -0,0 +1,69 @@
+Introduction
+============
+
+.. module:: fun
+
+**Lua Fun** is a high-performance functional programming library
+designed for `LuaJIT tracing just-in-time compiler
+<http://luajit.org/luajit.html>`_.
+
+The library provides a set of more than 50 programming primitives typically
+found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and
+even Lisp. High-order functions such as :func:`map`, :func:`filter`,
+:func:`reduce`, :func:`zip` will help you to **write simple and efficient
+functional code**.
+
+Let's see an example:
+
+.. code-block:: lua
+ :emphasize-lines: 2, 4
+
+ -- Functional style
+ require "fun" ()
+ n = 100
+ x = sum(map(function(x) return x^2 end, take(n, tabulate(math.sin))))
+ -- calculate sum(sin(x)^2 for x in 0..n-1)
+ print(x)
+ 50.011981355266
+
+.. code-block:: lua
+ :emphasize-lines: 2, 4
+
+ -- Object-oriented style
+ local fun = require "fun"
+ n = 100
+ x = fun.tabulate(math.sin):take(n):map(function(x) return x^2 end):sum()
+ -- calculate sum(sin(x)^2 for x in 0..n-1)
+ print(x)
+ 50.011981355266
+
+**Lua Fun** takes full advantage of the innovative **tracing JIT compiler**
+to achieve transcendental performance on nested functional expressions.
+Functional compositions and high-order functions can be translated into
+**efficient machine code**. Can you believe it? Just try to run the example above
+with ``luajit -jdump`` and see what happens:
+
+.. code-block:: none
+ :emphasize-lines: 2,14
+
+ -- skip some initilization code --
+ ->LOOP:
+ 0bcaffd0 movsd [rsp+0x8], xmm7
+ 0bcaffd6 addsd xmm4, xmm5
+ 0bcaffda ucomisd xmm6, xmm1
+ 0bcaffde jnb 0x0bca0028 ->6
+ 0bcaffe4 addsd xmm6, xmm0
+ 0bcaffe8 addsd xmm7, xmm0
+ 0bcaffec fld qword [rsp+0x8]
+ 0bcafff0 fsin
+ 0bcafff2 fstp qword [rsp]
+ 0bcafff5 movsd xmm5, [rsp]
+ 0bcafffa mulsd xmm5, xmm5
+ 0bcafffe jmp 0x0bcaffd0 ->LOOP
+ ---- TRACE 1 stop -> loop
+
+
+The functional chain above was translated by LuaJIT to (!) **one machine loop**
+containing just 10 CPU assembly instructions without CALL. Unbelievable!
+
+Readable? Efficient? Can your Python/Ruby/V8 do better?
diff --git a/Data/DefaultContent/Libraries/luafun/doc/logo.png b/Data/DefaultContent/Libraries/luafun/doc/logo.png
new file mode 100644
index 0000000..9bbeefc
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/logo.png
Binary files differ
diff --git a/Data/DefaultContent/Libraries/luafun/doc/logo.svg b/Data/DefaultContent/Libraries/luafun/doc/logo.svg
new file mode 100644
index 0000000..1a28b03
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/logo.svg
@@ -0,0 +1,758 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1440"
+ height="1440"
+ viewBox="43 -188 937 937"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="logo.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0"
+ inkscape:export-filename="/mnt/data/docs/Projects/Personal/lua-functional/doc/logo.png"
+ inkscape:export-xdpi="9"
+ inkscape:export-ydpi="9">
+ <path
+ style="fill:none;stroke:#8c8c8c;stroke-width:16.26736110999999951;stroke-linecap:butt;stroke-miterlimit:5;stroke-opacity:1;stroke-dasharray:65.06944443999999805, 130.13888889000000404;stroke-dashoffset:8.13368056000000017;stroke-linejoin:bevel"
+ d="m 973.58155,283.57775 c 0,254.76511 -206.52793,461.29304 -461.29304,461.29304 -254.76515,0 -461.293094,-206.52793 -461.293094,-461.29304 0,-254.765152 206.527944,-461.2931 461.293094,-461.2931 254.76511,0 461.29304,206.527948 461.29304,461.2931 z"
+ id="path4282"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 250.7423,53.17721 c 29.45588,-29.455878 28.94618,-82.860118 50.21763,-61.5886737 3.83457,3.8345707 18.19138,-8.2050713 20.24148,-3.2632463 93.26191,-67.02258 202.39283,-82.814868 307.85028,-49.879054 36.09059,-29.748071 38.94286,5.985418 65.3616,32.404157 18.29476,18.294756 66.53433,7.175347 57.32218,34.8338661 7.72301,6.5287109 15.21696,13.4128149 22.49443,20.6902869 139.48488,139.484874 138.85087,366.529134 -1.41522,506.795214 -13.20076,13.20077 -27.18352,25.13674 -41.78121,35.86827 0.11753,0.10989 0.24006,0.24005 0.35377,0.35376 7.32801,7.32801 -14.7794,5.93526 -22.8447,14.00055 -8.0653,8.0653 0.95061,22.54956 -6.3774,15.22155 -2.21104,-2.21104 -3.75936,-4.90791 -4.53809,-7.79318 -26.55681,15.31211 -48.92496,23.80758 -77.79886,31.78402 -12.36469,22.32067 -14.45697,24.76671 -25.49856,26.98942 -26.42114,5.29626 -16.92539,-32.7282 -39.30039,7.71415 -5.83218,10.5322 -4.69895,-9.62859 -3.70688,-20.07126 -13.58551,1.25424 -27.23228,1.76113 -40.86415,1.46978 2.43298,8.93808 -12.15669,-6.79506 -18.72531,-0.22644 -10.16421,10.16421 -10.99303,2.98276 -22.14929,-8.17351 -7.9092,-7.90919 -14.49182,12.74826 -11.76706,3.40302 -58.78521,-9.997 -115.48949,-34.70944 -164.14523,-74.19198 -12.56749,4.20346 -30.04677,-15.74065 -46.74503,-47.68522 -18.73981,-35.8665 -62.87191,-48.31168 -53.05075,-58.13285 2.27424,-2.27424 5.68495,-3.18332 9.94126,-2.91647 -59.56609,-111.47978 -59.53281,-236.82202 7.66772,-345.71641 -7.0415,-1.94668 0.60884,-14.312211 -4.54351,-19.46456 -21.27144,-21.271445 14.34543,-2.974381 43.80131,-32.430258 z"
+ id="path2506"
+ inkscape:connector-curvature="0"
+ style="fill:#d7deda;fill-opacity:0.97647005" />
+ <path
+ d="m 287.34799,21.45871 c 6.52025,-6.035087 16.97461,-2.136648 26.09844,-2.252082 21.83494,-19.90438598 48.25766,-35.746981 80.22166,-44.60753 80.62955,-22.34913 163.05343,-11.227174 228.16322,7.000201 9.31493,-10.02247 16.50699,-22.066176 26.36444,-31.266625 13.69185,-7.576755 21.2235,8.492836 23.43568,19.370001 5.21678,14.745728 20.40462,24.978509 36.11753,24.1237648 13.37752,-3.9016398 21.24609,9.4810162 11.70331,19.4281032 -0.66287,1.446206 -1.46443,2.652074 -2.34152,3.680776 19.75182,9.206453 31.14881,15.826263 31.14881,15.826263 0,0 -515.21186,34.570202 -538.20281,241.595288 0,0 3.43188,-81.53836 38.27299,-160.65582 -7.67327,-6.1893 -22.35662,-13.32826 -18.49899,-25.0117 11.3442,-3.965646 19.91446,-12.738063 28.68349,-20.549398 14.31083,-10.138919 17.14992,-28.164671 25.73394,-42.317982 0.89329,-1.838346 1.91466,-3.266548 3.09981,-4.36326 z"
+ id="path2510"
+ inkscape:connector-curvature="0"
+ style="fill:#eef0ec;fill-opacity:0.97646999;fill-rule:evenodd" />
+ <path
+ d="M 349.02532,562.43439 C 563.32391,498.23366 740.70727,495.93921 854.0712,325.4168 c 0,0 -30.7903,145.25887 -134.58891,230.61111 -0.11784,4.53991 0.12283,9.10036 -1.6651,13.26357 -5.01838,6.76194 -14.52863,7.78181 -22.309,8.18363 -1.6497,0.0325 -3.06759,-0.36899 -4.28079,-1.0257 -27.4747,17.34183 -59.17561,30.44476 -95.71065,36.50538 -0.4933,7.87185 -0.46921,16.03492 -6.07808,19.64753 -11.10367,-1.40448 -22.81156,-1.49721 -33.25929,-3.22914 -2.18379,-2.89528 -5.65439,-7.76345 -7.98455,-12.68549 -13.88598,-0.0372 -28.32681,-1.0105 -43.39817,-3.04626 -8.59541,1.89913 -17.51678,2.55753 -26.33409,2.25274 -5.85207,-0.49045 -13.89777,-0.35395 -16.09607,-7.12615 -0.16198,-0.97512 -0.14595,-2.17879 -0.14255,-3.3951 -34.76701,-8.6704 -72.39533,-22.61611 -113.19863,-42.93853 z"
+ id="path2512"
+ inkscape:connector-curvature="0"
+ style="fill:#c4ccbd;fill-opacity:0.97646999;fill-rule:evenodd" />
+ <metadata
+ id="metadata31">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>generated by pstoedit</dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs29">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 512 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="1024 : 512 : 1"
+ inkscape:persp3d-origin="512 : 341.33333 : 1"
+ id="perspective33" />
+ <marker
+ id="Arrow1Lstart"
+ style="overflow:visible"
+ orient="auto"
+ refY="0"
+ refX="0">
+ <path
+ id="path3200"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(0.8,0,0,0.8,10,0)"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z " />
+ </marker>
+ <marker
+ id="Arrow1Mend"
+ style="overflow:visible"
+ orient="auto"
+ refY="0"
+ refX="0">
+ <path
+ id="path3209"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(-0.4,0,0,-0.4,-4,0)"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z " />
+ </marker>
+ <marker
+ id="Arrow1Mstart"
+ style="overflow:visible"
+ orient="auto"
+ refY="0"
+ refX="0">
+ <path
+ id="path3206"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(0.4,0,0,0.4,4,0)"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z " />
+ </marker>
+ <linearGradient
+ x1="342.86"
+ x2="554.29"
+ y1="549.51"
+ gradientUnits="userSpaceOnUse"
+ y2="549.51"
+ id="linearGradient4218">
+ <stop
+ offset="0"
+ stop-color="#a40000"
+ id="stop4214" />
+ <stop
+ offset="1"
+ stop-color="#ec0000"
+ id="stop4216" />
+ </linearGradient>
+ <marker
+ id="Arrow1Lstart-0"
+ style="overflow:visible"
+ orient="auto"
+ refY="0"
+ refX="0">
+ <path
+ id="path3200-5"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(0.8,0,0,0.8,10,0)"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z " />
+ </marker>
+ <marker
+ id="Arrow1Mend-0"
+ style="overflow:visible"
+ orient="auto"
+ refY="0"
+ refX="0">
+ <path
+ id="path3209-0"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(-0.4,0,0,-0.4,-4,0)"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z " />
+ </marker>
+ <marker
+ id="Arrow1Mstart-7"
+ style="overflow:visible"
+ orient="auto"
+ refY="0"
+ refX="0">
+ <path
+ id="path3206-2"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(0.4,0,0,0.4,4,0)"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z " />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ inkscape:window-height="965"
+ inkscape:window-width="1280"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="0.15951335"
+ inkscape:cx="1033.4421"
+ inkscape:cy="994.65682"
+ inkscape:window-x="-4"
+ inkscape:window-y="-6"
+ inkscape:current-layer="svg2"
+ inkscape:window-maximized="1"
+ inkscape:object-paths="true"
+ inkscape:snap-nodes="false"
+ inkscape:snap-bbox="true" />
+ <title
+ id="title4">generated by pstoedit</title>
+ <!-- generated by pstoedit version:3.50 -->
+ <g
+ id="g3468"
+ transform="matrix(-1.2705261,1.2705261,1.26345,1.26345,389.29787,-726.3541)">
+ <path
+ style="fill:#c4ccbe"
+ inkscape:connector-curvature="0"
+ id="path2407"
+ d="m 551.43,460.93 a 200,200 0 1 1 -400,0 200,200 0 1 1 400,0 z"
+ transform="matrix(0.13119,0,0,0.13119,265.51,542.98)" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path2409"
+ d="m 308.24,579.84 c -12.11,1.77 -20.84,12.18 -20.83,24.08 2.76,-10.26 11.56,-17.11 22.74,-18.75 8.24,-1.2 15.98,0.09 21.81,5.16 -5.07,-7.51 -14.16,-11.89 -23.72,-10.49 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2411"
+ d="m 306.85,575.63 c -12.12,1.78 -21.59,10.51 -21.58,22.4 2.76,-10.26 11.37,-18.42 22.55,-20.06 8.24,-1.21 16.16,1.39 22,6.46 -5.08,-7.5 -13.41,-10.19 -22.97,-8.8 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path2413"
+ d="m 323.98,632.86 c 11.41,-4.43 16.84,-18.21 14.2,-29.8 -0.41,10.61 -6.99,20.49 -17.53,24.57 -7.76,3.01 -16.07,2.24 -22.89,-1.41 6.62,6.2 17.2,10.13 26.22,6.64 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2415"
+ d="m 317.07,627.04 c 11.89,-2.93 19.56,-14.15 18.4,-25.98 -1.75,10.47 -8.78,18.31 -19.75,21.02 -8.09,2 -16.98,1.31 -23.27,-3.18 5.78,6.98 15.24,10.46 24.62,8.14 z" />
+ </g>
+ <g
+ id="g3376"
+ transform="translate(-366.08185,6.8571058)">
+ <path
+ d="m 737.83252,197.3382 a 22.377738,22.503065 45 1 0 31.82414,-31.82414 22.377738,22.503065 45 1 0 -31.82414,31.82414 z"
+ id="path2419"
+ inkscape:connector-curvature="0"
+ style="fill:#c4ccbe" />
+ <path
+ d="m 741.55503,165.12884 c 8.41758,-6.2697 19.98231,-5.27575 27.15871,1.90065 -7.868,-4.51381 -17.33569,-3.30908 -25.09309,2.47733 -5.72604,4.28571 -9.64357,9.74465 -10.11809,16.33426 -1.44848,-7.59782 1.41229,-15.73981 8.05247,-20.71224 z"
+ id="path2421"
+ inkscape:connector-curvature="0"
+ style="fill:#808080" />
+ <path
+ d="m 739.86668,161.7634 c 8.40494,-6.28235 19.4163,-6.75654 26.5927,0.41986 -7.85529,-4.52652 -18.01732,-4.21941 -25.77471,1.56701 -5.71334,4.273 -8.96195,10.65497 -9.43647,17.24458 -1.46111,-7.61046 1.97837,-14.28437 8.61848,-19.23145 z"
+ id="path2423"
+ inkscape:connector-curvature="0"
+ style="fill:#ececec" />
+ <path
+ d="m 763.9913,206.64841 c -9.59025,4.25849 -21.20711,-0.75164 -26.58042,-9.35209 6.63445,6.15166 16.60009,8.11299 25.44186,4.19867 6.52039,-2.90692 11.09683,-8.39304 13.04034,-14.73336 -0.28768,7.74204 -4.32855,16.53348 -11.90178,19.88678 z"
+ id="path2425"
+ inkscape:connector-curvature="0"
+ style="fill:#808080" />
+ <path
+ d="m 764.67158,198.96863 c -8.98535,5.42242 -20.39493,3.31308 -26.83464,-4.5242 7.38449,5.25001 16.36606,5.71905 24.6661,0.70398 6.10451,-3.70395 11.0746,-9.50792 12.1951,-16.03599 0.70064,7.71394 -2.94481,15.55405 -10.02656,19.85621 z"
+ id="path2427"
+ inkscape:connector-curvature="0"
+ style="fill:#ececec" />
+ </g>
+ <path
+ style="fill:#daded5"
+ inkscape:connector-curvature="0"
+ id="path2431"
+ d="m 477.99202,72.998425 a 42.282553,42.519363 45 1 0 60.13146,-60.13146 42.282553,42.519363 45 0 0 -60.13146,60.13146 z" />
+ <path
+ style="fill:#808080"
+ inkscape:connector-curvature="0"
+ id="path2433"
+ d="m 485.01368,12.160781 c 15.90837,-11.86533063 37.7585,-9.9878703 51.30269,3.556314 -14.85053,-8.5233028 -32.74662,-6.2434466 -47.4108,4.706185 -10.80453,8.075483 -18.2072,18.409357 -19.1162,30.866291 -2.73455,-14.372566 2.68043,-29.768802 15.22431,-39.12879 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2435"
+ d="M 481.82607,5.7714423 C 497.73444,-6.093888 518.52808,-7.0008294 532.0722,6.5686943 517.20904,-1.9672427 498.05077,-1.4069521 483.38659,9.5426795 472.55672,17.618233 466.42893,29.658968 465.51993,42.115902 462.78538,27.743336 469.28219,15.13143 481.82607,5.7714423 z" />
+ <path
+ style="fill:#808080"
+ inkscape:connector-curvature="0"
+ id="path2437"
+ d="m 527.4031,90.607725 c -18.11488,8.032548 -40.04514,-1.446558 -50.22427,-17.698802 12.57394,11.633756 31.35287,15.344242 48.07236,7.92374 12.34297,-5.469804 20.96209,-15.857754 24.61908,-27.828241 -0.52236,14.647727 -8.17056,31.241159 -22.46717,37.603303 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2439"
+ d="m 528.68536,76.059235 c -16.96818,10.271897 -38.5337,6.290458 -50.706,-8.524535 13.97237,9.932101 30.94747,10.796922 46.60842,1.326872 11.53635,-6.987926 20.92999,-17.973519 23.04224,-30.294445 1.3403,14.579176 -5.5554,29.384068 -18.94466,37.492108 z" />
+ <path
+ style="fill:#daded5"
+ inkscape:connector-curvature="0"
+ id="path2455"
+ d="m 267.79765,192.31588 a 22.377735,22.503062 45 0 0 31.82414,-31.82414 22.377735,22.503062 45 1 0 -31.82414,31.82414 z" />
+ <path
+ style="fill:#808080"
+ inkscape:connector-curvature="0"
+ id="path2457"
+ d="m 271.52016,160.10652 c 8.41757,-6.26971 19.98231,-5.27575 27.1587,1.90065 -7.868,-4.51381 -17.33569,-3.30909 -25.09308,2.47733 -5.72604,4.2857 -9.64358,9.74465 -10.11809,16.33426 -1.44848,-7.59782 1.41229,-15.73981 8.05247,-20.71224 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2459"
+ d="m 269.8318,156.74107 c 8.40494,-6.28234 19.41631,-6.75653 26.5927,0.41986 -7.85529,-4.52651 -18.01731,-4.2194 -25.77471,1.56701 -5.71333,4.27301 -8.96195,10.65498 -9.43646,17.24459 -1.46111,-7.61046 1.97836,-14.28437 8.61847,-19.23146 z" />
+ <path
+ style="fill:#808080"
+ inkscape:connector-curvature="0"
+ id="path2461"
+ d="m 293.95643,201.62609 c -9.59025,4.25849 -21.20712,-0.75164 -26.58043,-9.35209 6.63446,6.15166 16.6001,8.11298 25.44187,4.19867 6.52038,-2.90692 11.09682,-8.39304 13.04033,-14.73336 -0.28768,7.74204 -4.32855,16.53348 -11.90177,19.88678 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2463"
+ d="m 294.6367,193.9463 c -8.98535,5.42242 -20.39493,3.31309 -26.83463,-4.52419 7.38449,5.25001 16.36605,5.71905 24.6661,0.70397 6.1045,-3.70395 11.0746,-9.50792 12.1951,-16.03598 0.70063,7.71394 -2.94482,15.55404 -10.02657,19.8562 z" />
+ <g
+ id="g3418"
+ transform="matrix(-0.72129759,1.0777674,1.2794218,0.85229632,104.1786,-411.8976)">
+ <path
+ style="fill:#c4ccbe"
+ inkscape:connector-curvature="0"
+ id="path2491"
+ d="m 551.43,460.93 a 200,200 0 1 1 -400,0 200,200 0 1 1 400,0 z"
+ transform="matrix(0.11832,0,0,0.11832,443.45,470.93)" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path2493"
+ d="m 481.99,504.17 c -10.93,1.6 -18.79,10.99 -18.79,21.71 2.49,-9.25 10.43,-15.43 20.51,-16.9 7.43,-1.08 14.41,0.08 19.67,4.65 -4.58,-6.77 -12.77,-10.72 -21.39,-9.46 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2495"
+ d="m 480.73,500.38 c -10.93,1.6 -19.47,9.47 -19.46,20.2 2.49,-9.26 10.25,-16.62 20.33,-18.09 7.44,-1.09 14.59,1.25 19.85,5.82 -4.58,-6.77 -12.1,-9.19 -20.72,-7.93 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path2497"
+ d="m 496.18,551.99 c 10.29,-3.99 15.19,-16.42 12.8,-26.88 -0.37,9.58 -6.3,18.48 -15.8,22.16 -7.01,2.72 -14.49,2.02 -20.64,-1.27 5.97,5.59 15.51,9.13 23.64,5.99 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2499"
+ d="m 489.95,546.74 c 10.72,-2.65 17.64,-12.76 16.6,-23.44 -1.59,9.46 -7.93,16.52 -17.82,18.97 -7.29,1.8 -15.31,1.17 -20.99,-2.87 5.21,6.3 13.75,9.43 22.21,7.34 z" />
+ </g>
+ <path
+ style="fill:#c4ccbe"
+ inkscape:connector-curvature="0"
+ id="path2568"
+ d="m 554.80317,481.06024 a 44.255169,44.503024 45 1 0 62.93678,-62.93678 44.255169,44.503024 45 1 0 -62.93678,62.93678 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path2570"
+ d="m 562.16164,412.16764 c 16.63208,-12.41215 39.50822,-10.44887 53.69676,3.73967 -15.53356,-8.92682 -34.26615,-6.54327 -49.61592,4.91506 -11.33773,8.45707 -19.08379,19.26068 -20.03247,32.31321 -2.8594,-15.03105 2.81103,-31.16284 15.95163,-40.96794 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2572"
+ d="m 558.81014,410.69291 c 16.65741,-12.41222 38.42674,-13.35989 52.60258,0.84135 -15.5462,-8.93946 -35.61678,-8.35128 -50.96654,3.10706 -11.33773,8.45706 -17.74581,21.05605 -18.68178,34.09587 -2.87204,-15.04368 3.91784,-28.25188 17.04574,-38.04428 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path2574"
+ d="m 606.5173,495.58472 c -18.95216,8.41498 -41.92007,-1.51734 -52.5659,-18.5158 13.14257,12.17697 32.82059,16.04965 50.32654,8.29754 12.90116,-5.72476 21.93976,-16.608 25.77568,-29.13646 -0.56224,15.31934 -8.55476,32.71193 -23.53632,39.35472 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2576"
+ d="m 607.86479,484.26872 c -17.75506,10.75555 -40.33361,6.57422 -53.06147,-8.92339 14.59189,10.39915 32.37771,11.31239 48.76209,1.39687 12.0821,-7.33153 21.92058,-18.81248 24.13581,-31.71651 1.38907,15.26321 -5.82532,30.76583 -19.83643,39.24303 z" />
+ <path
+ style="fill:#e2e4df;fill-opacity:0.97646999"
+ inkscape:connector-curvature="0"
+ id="path2597"
+ d="M 345.06872,36.033812 A 16.011413,35.471259 55.13194 1 0 403.29514,-4.4942038 16.011413,35.471259 55.13194 0 0 345.06872,36.033812 z" />
+ <path
+ style="fill:#808080"
+ inkscape:connector-curvature="0"
+ id="path2599"
+ d="m 369.73627,1.3206138 c 14.04909,-8.4646367 27.34393,-9.9841269 31.48295,-4.0155481 -6.64323,-3.0095266 -18.77761,0.3565111 -31.74795,8.1719766 -9.56908,5.7534627 -17.70891,12.3771497 -22.41644,19.4346937 3.02424,-7.699003 11.57672,-16.908477 22.68144,-23.5911222 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2601"
+ d="m 369.8085,-1.8597031 c 14.06179,-8.4773419 27.60129,-11.4038609 31.74031,-5.4352823 -6.63052,-3.0222316 -19.02874,-0.4536537 -31.99909,7.36181179 C 359.98064,5.8202893 352.10465,13.241435 347.38449,20.286345 350.40866,12.612682 358.72912,4.8228714 369.8085,-1.8597031 z" />
+ <path
+ style="fill:#808080"
+ inkscape:connector-curvature="0"
+ id="path2603"
+ d="m 370.70498,40.074771 c -14.19589,6.589919 -25.02096,3.870805 -26.11397,-3.981407 4.14171,5.005668 14.88605,4.874306 27.97828,-1.21841 9.6669,-4.486757 18.6181,-11.290087 24.90947,-18.390063 -5.19224,8.224517 -15.5718,18.376658 -26.77378,23.58988 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2605"
+ d="m 376.34077,31.811005 c -14.21171,7.717574 -26.61626,8.018279 -29.46055,1.184539 5.60183,3.89932 16.12193,2.400248 29.22969,-4.718763 9.68166,-5.234316 19.29282,-12.444922 24.72271,-19.5678322 -3.98792,7.9804292 -13.28747,17.0272822 -24.49185,23.1020562 z" />
+ <g
+ id="g3369">
+ <path
+ d="m 840.28494,289.31978 a 39.752241,17.207074 68.840856 0 0 32.03091,-12.58489 39.752241,17.207074 68.840856 1 0 -32.03091,12.58489 z"
+ id="path2621"
+ inkscape:connector-curvature="0"
+ style="fill:#c4ccbe" />
+ <path
+ d="m 845.41613,248.86481 c 8.36318,-0.40345 19.38864,12.22287 25.91736,29.01744 -7.3099,-13.81499 -16.43632,-21.39137 -24.16594,-21.01503 -5.67681,0.26924 -9.70339,3.94206 -10.4875,12.50902 -1.01859,-11.81806 2.13419,-20.17625 8.73608,-20.51143 z"
+ id="path2623"
+ inkscape:connector-curvature="0"
+ style="fill:#a2ae98" />
+ <path
+ d="m 843.9639,242.60999 c 8.36318,-0.40345 18.92704,9.6522 25.45576,26.44677 -7.32253,-13.82763 -17.03917,-23.29016 -24.76879,-22.91382 -5.68945,0.25661 -9.11318,5.82821 -9.89729,14.39517 -1.00588,-11.83077 2.6085,-17.61828 9.21032,-17.92812 z"
+ id="path2625"
+ inkscape:connector-curvature="0"
+ style="fill:#ececec" />
+ <path
+ d="m 864.87263,327.52783 c -9.37851,-3.50868 -20.24914,-21.67213 -25.00351,-38.67437 6.07791,14.89536 15.50768,27.27274 24.17745,30.50466 6.3916,2.37674 11.02464,-0.68961 13.19748,-7.48668 -0.64966,10.32769 -4.95465,18.42303 -12.37142,15.65639 z"
+ id="path2627"
+ inkscape:connector-curvature="0"
+ style="fill:#a2ae98" />
+ <path
+ d="m 865.90112,317.65519 c -8.86524,-1.2929 -19.68416,-15.28813 -25.47746,-32.28747 6.81418,14.38651 15.40344,23.7635 23.58479,24.95696 6.02831,0.89539 11.06693,-2.22278 12.46984,-10.06929 0.298,11.24993 -3.57367,18.43184 -10.57717,17.3998 z"
+ id="path2629"
+ inkscape:connector-curvature="0"
+ style="fill:#ececec" />
+ </g>
+ <g
+ id="g3633"
+ transform="matrix(-1.4688182,0.85217884,0.72653868,1.2603375,659.03127,-542.96386)">
+ <path
+ style="fill:#c4ccbe"
+ inkscape:connector-curvature="0"
+ id="path2443"
+ d="m 551.43,460.93 a 200,200 0 1 1 -400,0 200,200 0 1 1 400,0 z"
+ transform="matrix(0.17954,0,0,0.17954,370.24,308.37)" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path2445"
+ d="m 428.71,358.82 c -16.58,2.42 -28.52,16.67 -28.52,32.95 3.78,-14.04 15.83,-23.42 31.13,-25.65 11.28,-1.65 21.87,0.11 29.85,7.05 -6.94,-10.27 -19.38,-16.27 -32.46,-14.35 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2447"
+ d="m 426.8,353.06 c -16.58,2.43 -29.54,14.38 -29.53,30.65 3.77,-14.04 15.56,-25.21 30.86,-27.45 11.28,-1.65 22.12,1.9 30.11,8.84 -6.95,-10.27 -18.36,-13.95 -31.44,-12.04 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path2449"
+ d="m 450.24,431.38 c 15.62,-6.06 23.06,-24.92 19.44,-40.79 -0.56,14.53 -9.57,28.05 -23.99,33.63 -10.63,4.12 -21.99,3.07 -31.32,-1.92 9.06,8.47 23.54,13.85 35.87,9.08 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2451"
+ d="m 440.8,423.42 c 16.26,-4.02 26.76,-19.37 25.18,-35.57 -2.4,14.34 -12.03,25.07 -27.04,28.78 -11.06,2.73 -23.23,1.78 -31.85,-4.35 7.91,9.55 20.87,14.31 33.71,11.14 z" />
+ <g
+ id="g2530"
+ transform="matrix(0.10015,0,0,0.10015,386.4,347.37)">
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path2534"
+ d="m 329.56,392.23 c -32.32,4.72 -55.59,32.51 -55.59,64.23 7.37,-27.37 30.86,-45.64 60.68,-50 21.99,-3.21 42.63,0.22 58.19,13.76 -13.54,-20.04 -37.77,-31.72 -63.28,-27.99 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2536"
+ d="m 325.84,381.01 c -32.32,4.73 -57.58,28.03 -57.57,59.75 7.36,-27.37 30.34,-49.15 60.16,-53.51 21.99,-3.22 43.13,3.7 58.7,17.24 -13.55,-20.03 -35.78,-27.21 -61.29,-23.48 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path2538"
+ d="m 371.54,533.68 c 30.45,-11.8 44.95,-48.58 37.88,-79.51 -1.09,28.33 -18.65,54.68 -46.75,65.56 -20.72,8.03 -42.88,5.98 -61.06,-3.75 17.66,16.52 45.89,27.01 69.93,17.7 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2540"
+ d="m 353.12,518.16 c 31.71,-7.83 52.17,-37.75 49.09,-69.33 -4.68,27.96 -23.44,48.86 -52.69,56.09 -21.58,5.33 -45.3,3.49 -62.1,-8.47 15.42,18.62 40.67,27.9 65.7,21.71 z" />
+ </g>
+ <g
+ id="g3535"
+ transform="matrix(0.072158,0,0,0.072158,413.73,346.21)">
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path3539"
+ d="m 329.56,392.23 c -32.32,4.72 -55.59,32.51 -55.59,64.23 7.37,-27.37 30.86,-45.64 60.68,-50 21.99,-3.21 42.63,0.22 58.19,13.76 -13.54,-20.04 -37.77,-31.72 -63.28,-27.99 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path3541"
+ d="m 325.84,381.01 c -32.32,4.73 -57.58,28.03 -57.57,59.75 7.36,-27.37 30.34,-49.15 60.16,-53.51 21.99,-3.22 43.13,3.7 58.7,17.24 -13.55,-20.03 -35.78,-27.21 -61.29,-23.48 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path3543"
+ d="m 371.54,533.68 c 30.45,-11.8 44.95,-48.58 37.88,-79.51 -1.09,28.33 -18.65,54.68 -46.75,65.56 -20.72,8.03 -42.88,5.98 -61.06,-3.75 17.66,16.52 45.89,27.01 69.93,17.7 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path3545"
+ d="m 353.12,518.16 c 31.71,-7.83 52.17,-37.75 49.09,-69.33 -4.68,27.96 -23.44,48.86 -52.69,56.09 -21.58,5.33 -45.3,3.49 -62.1,-8.47 15.42,18.62 40.67,27.9 65.7,21.71 z" />
+ </g>
+ </g>
+ <g
+ id="g3356"
+ transform="matrix(-0.49245592,0.49245592,0.48971322,0.48971322,514.97811,37.308113)">
+ <path
+ style="fill:#c4ccbe"
+ inkscape:connector-curvature="0"
+ id="path3358"
+ d="m 551.43,460.93 a 200,200 0 1 1 -400,0 200,200 0 1 1 400,0 z"
+ transform="matrix(0.13119,0,0,0.13119,265.51,542.98)" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path3360"
+ d="m 308.24,579.84 c -12.11,1.77 -20.84,12.18 -20.83,24.08 2.76,-10.26 11.56,-17.11 22.74,-18.75 8.24,-1.2 15.98,0.09 21.81,5.16 -5.07,-7.51 -14.16,-11.89 -23.72,-10.49 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path3362"
+ d="m 306.85,575.63 c -12.12,1.78 -21.59,10.51 -21.58,22.4 2.76,-10.26 11.37,-18.42 22.55,-20.06 8.24,-1.21 16.16,1.39 22,6.46 -5.08,-7.5 -13.41,-10.19 -22.97,-8.8 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path3364"
+ d="m 323.98,632.86 c 11.41,-4.43 16.84,-18.21 14.2,-29.8 -0.41,10.61 -6.99,20.49 -17.53,24.57 -7.76,3.01 -16.07,2.24 -22.89,-1.41 6.62,6.2 17.2,10.13 26.22,6.64 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path3366"
+ d="m 317.07,627.04 c 11.89,-2.93 19.56,-14.15 18.4,-25.98 -1.75,10.47 -8.78,18.31 -19.75,21.02 -8.09,2 -16.98,1.31 -23.27,-3.18 5.78,6.98 15.24,10.46 24.62,8.14 z" />
+ </g>
+ <g
+ id="g3368"
+ transform="matrix(-0.3750593,0.3750593,0.37297044,0.37297044,648.90217,72.004088)">
+ <path
+ style="fill:#c4ccbe"
+ inkscape:connector-curvature="0"
+ id="path3370"
+ d="m 551.43,460.93 a 200,200 0 1 1 -400,0 200,200 0 1 1 400,0 z"
+ transform="matrix(0.13119,0,0,0.13119,265.51,542.98)" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path3372"
+ d="m 308.24,579.84 c -12.11,1.77 -20.84,12.18 -20.83,24.08 2.76,-10.26 11.56,-17.11 22.74,-18.75 8.24,-1.2 15.98,0.09 21.81,5.16 -5.07,-7.51 -14.16,-11.89 -23.72,-10.49 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path3374"
+ d="m 306.85,575.63 c -12.12,1.78 -21.59,10.51 -21.58,22.4 2.76,-10.26 11.37,-18.42 22.55,-20.06 8.24,-1.21 16.16,1.39 22,6.46 -5.08,-7.5 -13.41,-10.19 -22.97,-8.8 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path3376"
+ d="m 323.98,632.86 c 11.41,-4.43 16.84,-18.21 14.2,-29.8 -0.41,10.61 -6.99,20.49 -17.53,24.57 -7.76,3.01 -16.07,2.24 -22.89,-1.41 6.62,6.2 17.2,10.13 26.22,6.64 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path3378"
+ d="m 317.07,627.04 c 11.89,-2.93 19.56,-14.15 18.4,-25.98 -1.75,10.47 -8.78,18.31 -19.75,21.02 -8.09,2 -16.98,1.31 -23.27,-3.18 5.78,6.98 15.24,10.46 24.62,8.14 z" />
+ </g>
+ <g
+ id="g3380"
+ transform="matrix(-0.29120458,0.29120458,0.28958274,0.28958274,601.16283,185.29122)">
+ <path
+ style="fill:#c4ccbe"
+ inkscape:connector-curvature="0"
+ id="path3382"
+ d="m 551.43,460.93 a 200,200 0 1 1 -400,0 200,200 0 1 1 400,0 z"
+ transform="matrix(0.13119,0,0,0.13119,265.51,542.98)" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path3384"
+ d="m 308.24,579.84 c -12.11,1.77 -20.84,12.18 -20.83,24.08 2.76,-10.26 11.56,-17.11 22.74,-18.75 8.24,-1.2 15.98,0.09 21.81,5.16 -5.07,-7.51 -14.16,-11.89 -23.72,-10.49 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path3386"
+ d="m 306.85,575.63 c -12.12,1.78 -21.59,10.51 -21.58,22.4 2.76,-10.26 11.37,-18.42 22.55,-20.06 8.24,-1.21 16.16,1.39 22,6.46 -5.08,-7.5 -13.41,-10.19 -22.97,-8.8 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path3388"
+ d="m 323.98,632.86 c 11.41,-4.43 16.84,-18.21 14.2,-29.8 -0.41,10.61 -6.99,20.49 -17.53,24.57 -7.76,3.01 -16.07,2.24 -22.89,-1.41 6.62,6.2 17.2,10.13 26.22,6.64 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path3390"
+ d="m 317.07,627.04 c 11.89,-2.93 19.56,-14.15 18.4,-25.98 -1.75,10.47 -8.78,18.31 -19.75,21.02 -8.09,2 -16.98,1.31 -23.27,-3.18 5.78,6.98 15.24,10.46 24.62,8.14 z" />
+ </g>
+ <g
+ id="g3394"
+ transform="matrix(-0.7891535,0.42773099,0.33687688,0.62609944,622.48286,84.019995)">
+ <path
+ style="fill:#c4ccbe"
+ inkscape:connector-curvature="0"
+ id="path3396"
+ d="m 551.43,460.93 a 200,200 0 1 1 -400,0 200,200 0 1 1 400,0 z"
+ transform="matrix(0.13119,0,0,0.13119,265.51,542.98)" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path3398"
+ d="m 308.24,579.84 c -12.11,1.77 -20.84,12.18 -20.83,24.08 2.76,-10.26 11.56,-17.11 22.74,-18.75 8.24,-1.2 15.98,0.09 21.81,5.16 -5.07,-7.51 -14.16,-11.89 -23.72,-10.49 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path3400"
+ d="m 306.85,575.63 c -12.12,1.78 -21.59,10.51 -21.58,22.4 2.76,-10.26 11.37,-18.42 22.55,-20.06 8.24,-1.21 16.16,1.39 22,6.46 -5.08,-7.5 -13.41,-10.19 -22.97,-8.8 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path3402"
+ d="m 323.98,632.86 c 11.41,-4.43 16.84,-18.21 14.2,-29.8 -0.41,10.61 -6.99,20.49 -17.53,24.57 -7.76,3.01 -16.07,2.24 -22.89,-1.41 6.62,6.2 17.2,10.13 26.22,6.64 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path3404"
+ d="m 317.07,627.04 c 11.89,-2.93 19.56,-14.15 18.4,-25.98 -1.75,10.47 -8.78,18.31 -19.75,21.02 -8.09,2 -16.98,1.31 -23.27,-3.18 5.78,6.98 15.24,10.46 24.62,8.14 z" />
+ </g>
+ <g
+ id="g3406"
+ transform="matrix(-0.614617,0.614617,0.77796934,0.77796934,18.355513,-189.8468)">
+ <path
+ style="fill:#c4ccbe"
+ inkscape:connector-curvature="0"
+ id="path3408"
+ d="m 551.43,460.93 a 200,200 0 1 1 -400,0 200,200 0 1 1 400,0 z"
+ transform="matrix(0.13119,0,0,0.13119,265.51,542.98)" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path3410"
+ d="m 308.24,579.84 c -12.11,1.77 -20.84,12.18 -20.83,24.08 2.76,-10.26 11.56,-17.11 22.74,-18.75 8.24,-1.2 15.98,0.09 21.81,5.16 -5.07,-7.51 -14.16,-11.89 -23.72,-10.49 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path3412"
+ d="m 306.85,575.63 c -12.12,1.78 -21.59,10.51 -21.58,22.4 2.76,-10.26 11.37,-18.42 22.55,-20.06 8.24,-1.21 16.16,1.39 22,6.46 -5.08,-7.5 -13.41,-10.19 -22.97,-8.8 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path3414"
+ d="m 323.98,632.86 c 11.41,-4.43 16.84,-18.21 14.2,-29.8 -0.41,10.61 -6.99,20.49 -17.53,24.57 -7.76,3.01 -16.07,2.24 -22.89,-1.41 6.62,6.2 17.2,10.13 26.22,6.64 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path3416"
+ d="m 317.07,627.04 c 11.89,-2.93 19.56,-14.15 18.4,-25.98 -1.75,10.47 -8.78,18.31 -19.75,21.02 -8.09,2 -16.98,1.31 -23.27,-3.18 5.78,6.98 15.24,10.46 24.62,8.14 z" />
+ </g>
+ <path
+ style="fill:#ffffff;fill-opacity:1"
+ inkscape:connector-curvature="0"
+ id="path2385"
+ d="m 582.68118,214.50453 a 109.15131,109.76263 45 0 0 155.2278,-155.2278 109.15131,109.76263 45 1 0 -155.2278,155.2278 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path2387"
+ d="m 600.83503,57.45593 c 41.03425,-30.62342 97.4773,-25.78914 132.46223,9.19579 -38.35331,-22.01434 -84.55112,-16.12058 -122.41132,12.1374 -27.91905,20.84373 -47.03623,47.51633 -49.36863,79.69142 -7.06749,-37.10273 6.9296,-76.84891 39.31771,-101.02461 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path2392"
+ d="M 592.59505,40.95755 C 633.64194,10.34676 687.34298,8.0176 722.3152,43.01523 683.9619,21.0009 634.46968,22.45676 596.59684,50.7021 c -27.93169,20.83111 -43.74174,51.92889 -46.07413,84.10398 -7.06748,-37.10273 9.6716,-69.68547 42.07235,-93.84853 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path2394"
+ d="m 580.58492,213.07206 c 8.08779,7.47793 17.18006,13.6734 26.92236,18.48605 -3.04283,0.74335 -5.99806,1.87921 -8.8151,3.43279 -6.9501,-6.54354 -13.08707,-13.90022 -18.10726,-21.91884 z m 11.37155,42.95682 c 10.47612,9.7138 26.178,12.81206 40.11936,6.62829 10.15048,-5.2483 18.46379,-10.47879 10.19272,-20.37614 2.97626,0.4098 5.97821,0.69282 8.98044,0.87448 0.53553,-1.21779 1.02052,-2.48613 1.40416,-3.75418 -0.0415,1.25443 -0.19716,2.54718 -0.36544,3.8273 17.41843,0.90159 35.34213,-2.18921 52.4168,-9.76274 31.8279,-14.11433 54.15086,-40.9099 63.58742,-71.79984 -1.37249,37.78512 -21.11769,80.65145 -58.04517,97.03524 -19.04095,8.45324 -39.69533,9.3978 -59.28244,4.72667 -5.28716,-3.15268 -5.27279,0.77491 -17.08681,7.38351 -15.12111,6.70654 -33.44481,-1.22426 -41.92104,-14.78259 z" />
+ <path
+ style="fill:#ececec"
+ d="m 647.03634,236.32559 c 22.88072,-7.61067 34.7814,-10.09358 61.83807,-21.55927 32.80025,-22.03566 47.53189,-52.61097 56.96846,-83.50091 -1.37249,37.78512 -21.11769,80.65145 -58.04517,97.03524 -40.30058,17.76825 -64.67554,8.61159 -60.76136,8.02494 z"
+ id="path2528"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:#c4ccbe"
+ inkscape:connector-curvature="0"
+ id="path3289"
+ d="M 610.66836,131.5605 A 26.358341,28.663196 45 1 0 651.20424,91.02462 26.358341,28.663196 45 0 0 610.66836,131.5605 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path3291"
+ d="m 616.77879,91.89856 c 10.61452,-8.08763 24.73949,-7.43023 33.19198,1.02225 -9.42461,-5.15562 -21.08619,-3.22259 -30.87545,4.24191 -7.23719,5.51889 -12.28634,12.41268 -13.19587,20.52388 -1.40584,-9.25768 2.49938,-19.37907 10.87933,-25.78804 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path3293"
+ d="m 614.86428,87.84957 c 10.6146,-8.11296 24.13636,-9.22765 32.57614,-0.76246 -9.42458,-5.15563 -21.86868,-4.31001 -31.67062,3.16719 -7.22448,5.50619 -11.50378,13.47476 -12.40061,21.57326 -1.41855,-9.24498 3.11522,-17.59436 11.49509,-23.97799 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path3295"
+ d="m 642.2833,141.72094 c -11.96344,5.67146 -25.96062,0.0852 -32.14013,-10.18545 7.84779,7.21253 19.96738,9.14251 30.99205,3.90444 8.13211,-3.86165 14.00499,-10.82109 16.67489,-18.67114 -0.71071,9.50432 -6.08796,20.46602 -15.52681,24.95215 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path3297"
+ d="m 643.47532,132.26595 c -11.25789,7.08851 -25.15091,5.03679 -32.66349,-4.25452 8.78849,6.09496 19.79814,6.22892 30.193,-0.32504 7.65334,-4.82322 14.03414,-12.18951 15.71636,-20.23952 0.49311,9.43761 -4.34869,19.20686 -13.24588,24.81908 z" />
+ <path
+ id="path2255-5"
+ style="fill:#e99b4a;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 457.6962,165.34157 0,36.7642 26.42994,0 10.85514,38.38614 -80.70573,143.27223 39.64493,0 57.57952,-97.317 37.75707,109.2113 59.46737,-21.62602 -9.43926,-33.52027 -27.37389,9.73169 -64.18701,-184.90228 -50.02808,0 z"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#fbfbf7;fill-opacity:1"
+ inkscape:connector-curvature="0"
+ id="path2524"
+ d="m 592.65652,257.36261 a 35.279776,35.477364 45 1 0 50.17256,-50.17257 35.279776,35.477364 45 0 0 -50.17256,50.17257 z" />
+ <path
+ style="fill:#a2ae98"
+ inkscape:connector-curvature="0"
+ id="path3425"
+ d="m 616.23428,205.2186 c 13.09467,-2.43115 25.36479,4.57898 29.04525,15.95884 -6.04399,-8.88998 -17.2975,-12.4441 -29.39072,-10.20579 -8.91149,1.65929 -16.53681,5.51952 -21.01564,12.34837 2.93891,-8.90239 11.00456,-16.1847 21.36112,-18.10142 z" />
+ <path
+ style="fill:#ececec"
+ inkscape:connector-curvature="0"
+ id="path3427"
+ d="m 610.64453,201.53464 c 12.32921,-5.07701 25.66369,-2.64363 31.61487,7.72897 -7.74581,-7.44087 -19.97811,-9.83931 -31.35599,-5.15773 -8.40972,3.45699 -14.5983,10.04989 -17.58429,17.6601 1.05227,-9.31523 7.58384,-16.22583 17.3254,-20.23134 z" />
+ <path
+ style="fill:#ececec"
+ d="m 605.76803,254.22989 c 10.47613,9.7138 31.60604,-2.72358 41.76766,-16.49867 0,0 5.70421,-0.45504 -8.04842,19.26791 -4.03054,5.09183 -13.8578,17.09222 -33.71924,-2.76921 z"
+ id="path2528-8"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <g
+ id="g5190">
+ <path
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0"
+ id="path5137"
+ d="m 937.14068,-7.7167955 -6.08391,4.8107089 240.54523,75.3549016 -0.4075,-2.918744 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#787878;fill-opacity:1;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4150"
+ d="m 818.94116,5.2026955 c -0.29229,-0.1153077 -2.35517,0.3054801 -2.35517,0.3054801 l -2.95279,8.2073614 c 3.07091,7.617342 6.78428,15.488208 10.37968,23.312208 l 2.11411,1.212694 c 36.4223,68.353331 55.46431,109.598621 112.01396,203.717571 l 1.16047,-0.71178 C 898.0779,174.3516 828.9688,34.749076 828.9688,34.749076 c 0.25827,-0.0587 0.72945,-0.505187 0.57121,-0.985939 0,0 -9.09478,-20.220272 -9.09478,-20.220272 l -1.50192,-8.3424334 z"
+ style="fill:#777777;fill-opacity:1;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4174"
+ d="m 917.62673,23.735291 c 0,0 121.77467,112.372819 162.66457,147.374429 l 1.1896,-1.52322 C 1059.6975,152.95891 927.87133,27.227356 927.87133,27.227356 l 0.6206,-0.823456 -6.43964,-5.619804 c -1.08179,0.740429 -3.17482,1.165447 -4.10245,0.823639 l -0.32512,2.124011 z"
+ style="fill:#777777;fill-opacity:1;stroke:none" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0"
+ id="path4176"
+ d="m 1151.4299,-134.49903 -0.2145,-2.39061 c -32.5473,1.6736 -281.83741,34.93472 -281.83741,34.93472 l -4.34575,0.75128 c -5.6179,16.905635 220.66866,-28.17687 286.39766,-33.29539 z"
+ style="fill:#777777;fill-opacity:1;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4178"
+ d="m 930.55319,-32.548475 c 0,0 157.83041,3.755633 226.56811,10.003361 l 9.2776,-0.130698 0.6034,-1.489176 -1.422,-0.162356 c -7.6921,-0.272863 -237.88276,-15.118424 -237.88276,-15.118424 1.08971,1.203513 2.11854,2.89347 2.85841,6.898525 z"
+ style="fill:#777777;fill-opacity:1;stroke:none" />
+ <path
+ transform="matrix(0.41485831,-0.01993231,0.02026452,0.42177261,736.80359,313.50603)"
+ d="m 576.27704,-798.61469 a 208.34631,208.34631 0 1 1 -416.69263,0 208.34631,208.34631 0 1 1 416.69263,0 z"
+ sodipodi:ry="208.34631"
+ sodipodi:rx="208.34631"
+ sodipodi:cy="-798.61469"
+ sodipodi:cx="367.93073"
+ id="path4616"
+ style="fill:#777777;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.50190154,0,0,0.50190154,243.91433,-188.39601)"
+ d="m 1256.725,224.69398 a 35.47731,35.47731 0 1 1 -70.9546,0 35.47731,35.47731 0 1 1 70.9546,0 z"
+ sodipodi:ry="35.47731"
+ sodipodi:rx="35.47731"
+ sodipodi:cy="224.69398"
+ sodipodi:cx="1221.2477"
+ id="path5111"
+ style="fill:#ececec;fill-opacity:0.97647005;fill-rule:nonzero;stroke:none"
+ sodipodi:type="arc" />
+ <path
+ inkscape:transform-center-y="254.9588"
+ inkscape:transform-center-x="22.693568"
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0"
+ id="rect5145"
+ d="m 1176.6252,68.80541 c 0.9274,2.633527 -1.1442,6.475631 -3.3527,7.655075 -9.7843,-1.500395 -20.7497,-3.890343 -30.5339,-5.390738 3.2747,-6.559499 4.2071,-9.966553 6.4,-17.247252 8.4686,5.868813 19.0182,9.114104 27.4866,14.982915 z"
+ style="fill:#787878;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+ </g>
+</svg>
diff --git a/Data/DefaultContent/Libraries/luafun/doc/make.bat b/Data/DefaultContent/Libraries/luafun/doc/make.bat
new file mode 100644
index 0000000..0f68e89
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/make.bat
@@ -0,0 +1,190 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\LuaFunctional.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\LuaFunctional.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
diff --git a/Data/DefaultContent/Libraries/luafun/doc/operators.rst b/Data/DefaultContent/Libraries/luafun/doc/operators.rst
new file mode 100644
index 0000000..2f3edd4
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/operators.rst
@@ -0,0 +1,203 @@
+Operators
+=========
+
+.. module:: fun.operator
+
+This auxiliary module exports a set of Lua operators as intrinsic functions
+to use with the library high-order primitives.
+
+.. contents::
+
+.. note:: **op** can be used as a shortcut to **operator**.
+
+Comparison operators
+--------------------
+
+.. seealso:: `Lua Relational Operators
+ <http://www.lua.org/manual/5.2/manual.html#3.4.3>`_
+
+.. function:: le(a, b)
+
+ :returns: **a** <= **b**
+
+.. function:: lt(a, b)
+
+ :returns: **a** < **b**
+
+.. function:: eq(a, b)
+
+ :returns: **a** == **b**
+
+.. function:: ne(a, b)
+
+ :returns: **a** ~= **b**
+
+.. function:: ge(a, b)
+
+ :returns: **a** >= **b**
+
+.. function:: gt(a, b)
+
+ :returns: **a** > **b**
+
+Arithmetic operators
+--------------------
+
+.. seealso:: `Lua Arithmetic Operators
+ <http://www.lua.org/manual/5.2/manual.html#3.4.1>`_
+
+.. function:: add(a, b)
+
+ :returns: **a** + **b**
+
+.. function:: div(a, b)
+
+ An alias for :func:`truediv`.
+
+.. function:: truediv(a, b)
+
+ :returns: **a** / **b**
+
+ Performs "true" float division.
+ Examples:
+
+ .. code-block:: lua
+
+ > print(operator.div(10, 3))
+ 3.3333333333333
+ > print(operator.div(-10, 3))
+ -3.3333333333333
+
+.. function:: floordiv(a, b)
+
+ :returns: math.floor(**a** / **b**)
+
+ Performs division where a result is rounded down. Examples:
+
+ .. code-block:: lua
+
+ > print(operator.floordiv(10, 3))
+ 3
+ > print(operator.floordiv(12, 3))
+ 4
+ > print(operator.floordiv(-10, 3))
+ -4
+ > print(operator.floordiv(-12, 3))
+ -4
+
+.. function:: intdiv(a, b)
+
+ Performs C-like integer division.
+
+ Equvalent to:
+
+ .. code-block:: lua
+
+ function(a, b)
+ local q = a / b
+ if a >= 0 then return math.floor(q) else return math.ceil(q) end
+ end
+
+ Examples:
+
+ .. code-block:: lua
+
+ > print(operator.floordiv(10, 3))
+ 3
+ > print(operator.floordiv(12, 3))
+ 4
+ > print(operator.floordiv(-10, 3))
+ -3
+ > print(operator.floordiv(-12, 3))
+ -4
+
+.. function:: mod(a, b)
+
+ :returns: **a** % **b**
+
+ .. note:: Result has same sign as **divisor**. Modulo in Lua is defined as
+ ``a % b == a - math.floor(a/b)*b``.
+
+ Examples:
+
+ .. code-block:: lua
+ :emphasize-lines: 5-6
+
+ > print(operator.mod(10, 2))
+ 0
+ > print(operator.mod(10, 3))
+ 2
+ print(operator.mod(-10, 3))
+ 2 -- == -1 in C, Java, JavaScript and but not in Lua, Python, Haskell!
+
+.. function:: neq(a)
+
+ :returns: -**a**
+
+.. function:: unm(a)
+
+ Unary minus. An alias for :func:`neq`.
+
+.. function:: pow(a, b)
+
+ :returns: math.pow(**a**, **b**)
+
+.. function:: sub(a, b)
+
+ :returns: **a** - **b**
+
+String operators
+----------------
+
+.. seealso:: `Lua Concatenation Operator
+ <http://www.lua.org/manual/5.2/manual.html#3.4.5>`_
+
+.. function:: concat(a, b)
+
+ :returns: **a** .. **b**
+
+.. function:: len(a)
+
+ :returns: # **a**
+
+.. function:: length(a)
+
+ An alias for :func:`len`.
+
+Logical operators
+-----------------
+
+.. seealso:: `Lua Logical Operators
+ <http://www.lua.org/manual/5.2/manual.html#3.4.4>`_
+
+.. function:: land(a, b)
+
+ :returns: **a** and **b**
+
+.. function:: lor(a, b)
+
+ :returns: **a** or **b**
+
+.. function:: lnot(a)
+
+ :returns: not **a**
+
+.. function:: truth(a)
+
+ :returns: not not **a**
+
+ Return ``true`` if **a** is true, and ``false`` otherwise. Examples:
+
+ .. code-block:: lua
+
+ > print(operator.truth(1))
+ true
+ > print(operator.truth(0))
+ true -- It is Lua, baby!
+ > print(operator.truth(nil))
+ false
+ > print(operator.truth(""))
+ true
+ > print(operator.truth({}))
+ true
+
diff --git a/Data/DefaultContent/Libraries/luafun/doc/reducing.rst b/Data/DefaultContent/Libraries/luafun/doc/reducing.rst
new file mode 100644
index 0000000..f7b89da
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/reducing.rst
@@ -0,0 +1,323 @@
+Reducing
+========
+
+.. module:: fun
+
+The section contains functions to analyze iteration values and recombine
+through use of a given combining operation the results of recursively processing
+its constituent parts, building up a return value
+
+.. contents::
+
+.. note:: An attempt to use infinity iterators with the most function from
+ the module causes an infinite loop.
+
+Folds
+-----
+
+.. function:: foldl(accfun, initval, gen, param, state)
+ iterator:reduce(accfun, initval)
+
+ :param accfun: an accumulating function
+ :type param: (function(prevval, ...) -> val)
+ :param initval: an initial value that passed to **accfun** on the first
+ iteration
+
+ The function reduces the iterator from left to right using the binary
+ operator **accfun** and the initial value **initval**.
+ Equivalent to::
+
+ local val = initval
+ for _k, ... in gen, param, state do
+ val = accfun(val, ...)
+ end
+ return val
+
+ Examples:
+
+ .. code-block:: lua
+
+ > print(foldl(function(acc, x) return acc + x end, 0, range(5)))
+ 15
+
+ > print(foldl(operator.add, 0, range(5)))
+ 15
+
+ > print(foldl(function(acc, x, y) return acc + x * y; end, 0,
+ zip(range(1, 5), {4, 3, 2, 1})))
+ 20
+
+.. function:: reduce(accfun, initval, gen, param, state)
+ iterator:reduce(accfun, initval)
+
+ An alias to :func:`foldl`.
+
+.. function:: length(gen, param, state)
+ iterator:length()
+
+ :returns: a number of elements in ``gen, param, state`` iterator.
+
+ Return a number of elements in ``gen, param, state`` iterator.
+ This function is equivalent to ``#obj`` for basic array and string iterators.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > print(length({"a", "b", "c", "d", "e"}))
+ 5
+
+ > print(length({}))
+ 0
+
+ > print(length(range(0)))
+ 0
+
+ .. warning:: An attempt to call this function on an infinite iterator will
+ result an infinite loop.
+
+ .. note:: This function has ``O(n)`` complexity for all iterators except
+ basic array and string iterators.
+
+.. function:: totable(gen, param, state)
+
+ :returns: a new table (array) from iterated values.
+
+ The function reduces the iterator from left to right using ``table.insert``.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > local tab = totable("abcdef")
+ > print(type(tab), #tab)
+ table 6
+ > each(print, tab)
+ a
+ b
+ c
+ d
+ e
+ f
+
+.. function:: tomap(gen, param, state)
+
+ :returns: a new table (map) from iterated values.
+
+ The function reduces the iterator from left to right using
+ ``tab[val1] = val2`` expression.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > local tab = tomap(zip(range(1, 7), 'abcdef'))
+ > print(type(tab), #tab)
+ table 6
+ > each(print, iter(tab))
+ a
+ b
+ c
+ d
+ e
+ f
+
+Predicates
+----------
+
+.. function:: is_prefix_of(iterator1, iterator2)
+ iterator1:is_prefix_of(iterator2)
+
+ The function takes two iterators and returns ``true`` if the first iterator
+ is a prefix of the second.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > print(is_prefix_of({"a"}, {"a", "b", "c"}))
+ true
+
+ > print(is_prefix_of(range(6), range(5)))
+ false
+
+.. function:: is_null(gen, param, state)
+ iterator:is_null()
+
+ :returns: true when `gen, param, state`` iterator is empty or finished.
+ :returns: false otherwise.
+
+ Example::
+
+ > print(is_null({"a", "b", "c", "d", "e"}))
+ false
+
+ > print(is_null({}))
+ true
+
+ > print(is_null(range(0)))
+ true
+
+.. function:: all(predicate, gen, param, state)
+ iterator:all(predicate)
+
+ :param predicate: a predicate
+
+ Returns true if all return values of iterator satisfy the **predicate**.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > print(all(function(x) return x end, {true, true, true, true}))
+ true
+
+ > print(all(function(x) return x end, {true, true, true, false}))
+ false
+
+.. function:: every(predicate, gen, param, state)
+
+ An alias for :func:`all`.
+
+.. function:: any(predicate, gen, param, state)
+ iterator:any(predicate)
+
+ :param predicate: a predicate
+
+ Returns ``true`` if at least one return values of iterator satisfy the
+ **predicate**. The iteration stops on the first such value. Therefore,
+ infinity iterators that have at least one satisfying value might work.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > print(any(function(x) return x end, {false, false, false, false}))
+ false
+
+ > print(any(function(x) return x end, {false, false, false, true}))
+ true
+
+.. function:: some(predicate, gen, param, state)
+
+ An alias for :func:`any`.
+
+Special folds
+-------------
+
+.. function:: sum(gen, param, state)
+ iterator:sum()
+
+ Sum up all iteration values. An optimized alias for::
+
+ foldl(operator.add, 0, gen, param, state)
+
+ For an empty iterator ``0`` is returned.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > print(sum(range(5)))
+ 15
+
+.. function:: product(gen, param, state)
+ iterator:product()
+
+ Multiply all iteration values. An optimized alias for::
+
+ foldl(operator.mul, 1, gen, param, state)
+
+ For an empty iterator ``1`` is returned.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > print(product(range(1, 5)))
+ 120
+
+.. function:: min(gen, param, state)
+ iterator:min()
+
+ Return a minimum value from the iterator using :func:`operator.min` or ``<``
+ for numbers and other types respectivly. The iterator must be
+ non-null, otherwise an error is raised.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > print(min(range(1, 10, 1)))
+ 1
+
+ > print(min({"f", "d", "c", "d", "e"}))
+ c
+
+ > print(min({}))
+ error: min: iterator is empty
+
+.. function:: minimum(gen, param, state)
+
+ An alias for :func:`min`.
+
+.. function:: min_by(cmp, gen, param, state)
+ iterator:min_by(cmp)
+
+ Return a minimum value from the iterator using the **cmp** as a ``<``
+ operator. The iterator must be non-null, otherwise an error is raised.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > function min_cmp(a, b) if -a < -b then return a else return b end end
+ > print(min_by(min_cmp, range(1, 10, 1)))
+ 9
+
+.. function:: minimum_by(cmp, gen, param, state)
+
+ An alias for :func:`min_by`.
+
+.. function:: max(gen, param, state)
+ iterator:max()
+
+ Return a maximum value from the iterator using :func:`operator.max` or ``>``
+ for numbers and other types respectivly.
+
+ The iterator must be non-null, otherwise an error is raised.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > print(max(range(1, 10, 1)))
+ 9
+
+ > print(max({"f", "d", "c", "d", "e"}))
+ f
+
+ > print(max({}))
+ error: max: iterator is empty
+
+.. function:: maximum(gen, param, state)
+
+ An alias for :func:`max`.
+
+.. function:: max_by(cmp, gen, param, state)
+ iterator:max_by(cmp)
+
+ Return a maximum value from the iterator using the **cmp** as a `>`
+ operator. The iterator must be non-null, otherwise an error is raised.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > function max_cmp(a, b) if -a > -b then return a else return b end end
+ > print(max_by(max_cmp, range(1, 10, 1)))
+ 1
+
+.. function:: maximum_by(cmp, gen, param, state)
+
+ An alias for :func:`max_by`.
diff --git a/Data/DefaultContent/Libraries/luafun/doc/reference.rst b/Data/DefaultContent/Libraries/luafun/doc/reference.rst
new file mode 100644
index 0000000..f1f9cfc
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/reference.rst
@@ -0,0 +1,14 @@
+API Reference
+=============
+
+.. toctree::
+
+ basic.rst
+ generators.rst
+ slicing.rst
+ indexing.rst
+ filtering.rst
+ reducing.rst
+ transformations.rst
+ compositions.rst
+ operators.rst \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/luafun/doc/slicing.rst b/Data/DefaultContent/Libraries/luafun/doc/slicing.rst
new file mode 100644
index 0000000..1af642f
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/slicing.rst
@@ -0,0 +1,246 @@
+Slicing
+=======
+
+.. module:: fun
+
+This section contains functions to make subsequences from iterators.
+
+Basic
+-----
+
+.. function:: nth(n, gen, param, state)
+ iterator:nth(n)
+
+ :param uint n: a sequential number (indexed starting from ``1``,
+ like Lua tables)
+ :returns: **n**-th element of ``gen, param, state`` iterator
+
+ This function returns the **n**-th element of ``gen, param, state``
+ iterator. If the iterator does not have **n** items then ``nil`` is returned.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > print(nth(2, range(5)))
+ 2
+
+ > print(nth(10, range(5)))
+ nil
+
+ > print(nth(2, {"a", "b", "c", "d", "e"}))
+ b
+
+ > print(nth(2, enumerate({"a", "b", "c", "d", "e"})))
+ 2 b
+
+ This function is optimized for basic array and string iterators and has
+ ``O(1)`` complexity for these cases.
+
+.. function:: head(gen, param, state)
+ iterator:head()
+
+ :returns: a first element of ``gen, param, state`` iterator
+
+ Extract the first element of ``gen, param, state`` iterator.
+ If the iterator is empty then an error is raised.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > print(head({"a", "b", "c", "d", "e"}))
+ a
+ > print(head({}))
+ error: head: iterator is empty
+ > print(head(range(0)))
+ error: head: iterator is empty
+ > print(head(enumerate({"a", "b"})))
+ 1 a
+
+.. function:: car(gen, param, state)
+
+ An alias for :func:`head`.
+
+.. function:: tail(gen, param, state)
+ iterator:tail()
+
+ :returns: ``gen, param, state`` iterator without a first element
+
+ Return a copy of ``gen, param, state`` iterator without its first element.
+ If the iterator is empty then an empty iterator is returned.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, tail({"a", "b", "c", "d", "e"}))
+ b
+ c
+ d
+ e
+ > each(print, tail({}))
+ > each(print, tail(range(0)))
+ > each(print, tail(enumerate({"a", "b", "c"})))
+ 2 b
+ 3 c
+
+.. function:: cdr(gen, param, state)
+
+ An alias for :func:`tail`.
+
+Subsequences
+------------
+
+.. function:: take_n(n, gen, param, state)
+ iterator:take_n(n)
+
+ :param n: a number of elements to take
+ :type n: uint
+ :returns: an iterator on the subsequence of first **n** elements
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, take_n(5, range(10)))
+ 1
+ 2
+ 3
+ 4
+ 5
+
+ > each(print, take_n(5, enumerate(duplicate('x'))))
+ 1 x
+ 2 x
+ 3 x
+ 4 x
+ 5 x
+
+.. function:: take_while(predicate, gen, param, state)
+ iterator:take_while(predicate)
+
+ :type predicate: function(...) -> bool
+ :returns: an iterator on the longest prefix of ``gen, param, state``
+ elements that satisfy **predicate**.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, take_while(function(x) return x < 5 end, range(10)))
+ 1
+ 2
+ 3
+ 4
+
+ > each(print, take_while(function(i, a) return i ~=a end,
+ enumerate({5, 3, 4, 4, 2})))
+ 1 5
+ 2 3
+ 3 4
+
+ .. seealso:: :func:`filter`
+
+.. function:: take(n_or_predicate, gen, param, state)
+ iterator:take(n_or_predicate)
+
+ An alias for :func:`take_n` and :func:`take_while` that autodetects
+ required function based on **n_or_predicate** type.
+
+.. function:: drop_n(n, gen, param, state)
+ iterator:drop_n(n)
+
+ :param n: the number of elements to drop
+ :type n: uint
+ :returns: ``gen, param, state`` iterator after skipping first **n**
+ elements
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, drop_n(2, range(5)))
+ 3
+ 4
+ 5
+
+ > each(print, drop_n(2, enumerate({'a', 'b', 'c', 'd', 'e'})))
+ 3 c
+ 4 d
+ 5 e
+
+.. function:: drop_while(predicate, gen, param, state)
+ iterator:drop_while(predicate)
+
+ :type predicate: function(...) -> bool
+ :returns: ``gen, param, state`` after skipping the longest prefix
+ of elements that satisfy **predicate**.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, drop_while(function(x) return x < 5 end, range(10)))
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+
+ .. seealso:: :func:`filter`
+
+.. function:: drop(n_or_predicate, gen, param, state)
+ iterator:drop(n_or_predicate)
+
+ An alias for :func:`drop_n` and :func:`drop_while` that autodetects
+ required function based on **n_or_predicate** type.
+
+
+.. function:: span(n_or_predicate, gen, param, state)
+ iterator:span(n_or_predicate)
+
+ :type n_or_predicate: function(...) -> bool or uint
+ :returns: iterator, iterator
+
+ Return an iterator pair where the first operates on the longest prefix
+ (possibly empty) of ``gen, param, state`` iterator of elements that
+ satisfy **predicate** and second operates the remainder of
+ ``gen, param, state`` iterator.
+ Equivalent to:
+
+ .. code-block:: lua
+
+ return take(n_or_predicate, gen, param, state),
+ drop(n_or_predicate, gen, param, state);
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, zip(span(function(x) return x < 5 end, range(10))))
+ 1 5
+ 2 6
+ 3 7
+ 4 8
+
+ > each(print, zip(span(5, range(10))))
+ 1 6
+ 2 7
+ 3 8
+ 4 9
+ 5 10
+
+ .. note:: ``gen, param, state`` must be pure functional to work properly
+ with the function.
+
+ .. seealso:: :func:`partition`
+
+.. function:: split(n_or_predicate, gen, param, state)
+
+ An alias for :func:`span`.
+
+.. function:: split_at(n, gen, param, state)
+
+ An alias for :func:`span`.
diff --git a/Data/DefaultContent/Libraries/luafun/doc/transformations.rst b/Data/DefaultContent/Libraries/luafun/doc/transformations.rst
new file mode 100644
index 0000000..e446d2f
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/transformations.rst
@@ -0,0 +1,87 @@
+Transformations
+===============
+
+.. module:: fun
+
+.. function:: map(fun, gen, param, state)
+ iterator:map(fun)
+
+ :param fun: a function to apply
+ :type fun: (function(...) -> ...)
+ :returns: a new iterator
+
+ Return a new iterator by applying the **fun** to each element of
+ ``gen, param, state`` iterator. The mapping is performed on the fly
+ and no values are buffered.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, map(function(x) return 2 * x end, range(4)))
+ 2
+ 4
+ 6
+ 8
+
+ fun = function(...) return 'map', ... end
+ > each(print, map(fun, range(4)))
+ map 1
+ map 2
+ map 3
+ map 4
+
+.. function:: enumerate(gen, param, state)
+ iterator:enumerate()
+
+ :returns: a new iterator
+
+ Return a new iterator by enumerating all elements of the
+ ``gen, param, state`` iterator starting from ``1``. The mapping is performed
+ on the fly and no values are buffered.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, enumerate({"a", "b", "c", "d", "e"}))
+ 1 a
+ 2 b
+ 3 c
+ 4 d
+ 5 e
+
+ > each(print, enumerate(zip({"one", "two", "three", "four", "five"},
+ {"a", "b", "c", "d", "e"})))
+ 1 one a
+ 2 two b
+ 3 three c
+ 4 four d
+ 5 five e
+
+.. function:: intersperse(x, gen, param, state)
+ iterator:intersperse(x)
+
+ :type x: any
+ :returns: a new iterator
+
+ Return a new iterator where the **x** value is interspersed between the
+ elements of the source iterator. The **x** value can also be added as a
+ last element of returning iterator if the source iterator contains the odd
+ number of elements.
+
+ Examples:
+
+ .. code-block:: lua
+
+ > each(print, intersperse("x", {"a", "b", "c", "d", "e"}))
+ a
+ x
+ b
+ x
+ c
+ x
+ d
+ x
+ e
+ x
diff --git a/Data/DefaultContent/Libraries/luafun/doc/under_the_hood.rst b/Data/DefaultContent/Libraries/luafun/doc/under_the_hood.rst
new file mode 100644
index 0000000..802659e
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/doc/under_the_hood.rst
@@ -0,0 +1,154 @@
+Under the Hood
+==============
+
+.. module:: fun
+
+The section shed some light on the internal library structure and working
+principles.
+
+Iterators
+---------
+
+A basic primitive of the library after functions is an iterator. Most functions
+takes an iterator and returns a new iteraror(s). Iterators all the way down!
+[#iterators]_.
+
+The simplest iterator is (surprise!) :func:`pairs` and :func:`ipairs`
+Lua functions. Have you ever tried to call, say, :func:`ipairs` function
+without using it inside a ``for`` loop? Try to do that on any Lua
+implementation:
+
+.. _iterator_triplet:
+.. code-block:: bash
+
+ > =ipairs({'a', 'b', 'c'})
+ function: builtin#6 table: 0x40f80e38 0
+
+The function returned three strange values which look useless without a ``for``
+loop. We call these values **iterator triplet**.
+Let's see how each value is used for:
+
+``gen`` -- first value
+ A generating function that can produce a next value on each iteration.
+ Usually returns a new ``state`` and iteration values (multireturn).
+
+``param`` -- second value
+ A permanent (constant) parameter of a generating function is used to create
+ specific instance of the generating function. For example, a table itself
+ for ``ipairs`` case.
+
+``state`` -- third value
+ A some transient state of an iterator that is changed after each iteration.
+ For example, an array index for ``ipairs`` case.
+
+Try to call ``gen`` function manually:
+
+ .. code-block:: lua
+
+ > gen, param, state = ipairs({'a', 'b', 'c'})
+ > =gen(param, state)
+ 1 a
+
+The ``gen`` function returned a new state ``1`` and the next iteration
+value ``a``. The second call to ``gen`` with the new state will return the next
+state and the next iteration value. When the iterator finishes to the end
+the ``nil`` value is returned instead of the next state.
+
+**Please do not panic!** You do not have to use these values directly.
+It is just a nice trick to get ``for .. in`` loop working in Lua.
+
+Iterations
+----------
+
+What happens when you type the following code into a Lua console::
+
+ for _it, x in ipairs({'a', 'b', 'c'}) do print(x) end
+
+According to Lua reference manual [#lua_for]_ the code above is equivalent to::
+
+ do
+ -- Initialize the iterator
+ local gen, param, state = ipairs({'a', 'b', 'c'})
+ while true do
+ -- Next iteration
+ local state, var_1, ···, var_n = gen(param, state)
+ if state == nil then break end
+ -- Assign values to our variables
+ _it = state
+ x = var_1
+ -- Execute the code block
+ print(x)
+ end
+ end
+
+What does it mean for us?
+
+* An iterator can be used together with ``for .. in`` to generate a loop
+* An iterator is fully defined using ``gen``, ``param`` and ``state`` iterator
+ triplet
+* The ``nil`` state marks the end of an iteration
+* An iterator can return an arbitrary number of values (multireturn)
+* It is possible to make some wrapping functions to take an iterator and
+
+ return a new modified iterator
+
+**The library provides a set of iterators** that can be used like ``pairs``
+and ``ipairs``.
+
+Iterator Types
+--------------
+
+Pure functional iterators
+`````````````````````````
+
+Iterators can be either pure functional or have some side effects and returns
+different values for some initial conditions [#pure_function]_. An **iterator is
+pure functional** if it meets the following criteria:
+
+- ``gen`` function always returns the same values for the same ``param`` and
+ ``state`` values (idempotence property)
+- ``param`` and ``state`` values are not modified during ``gen`` call and
+ a new ``state`` object is returned instead (referential transparency
+ property).
+
+Pure functional iterators are very important for us. Pure functional iterator
+can be safety cloned or reapplied without creating side effects. Many library
+function use these properties.
+
+Finite iterators
+````````````````
+
+Iterators can be **finite** (sooner or later end up) or **infinite**
+(never end).
+Since there is no way to determine automatically if an iterator is finite or
+not [#turing]_ the library function can not automatically resolve infinite
+loops. It is your obligation to do not pass infinite iterator to reducing
+functions.
+
+Tracing JIT
+-----------
+
+Tracing just-in-time compilation is a technique used by virtual machines to
+optimize the execution of a program at runtime. This is done by recording a
+linear sequence of frequently executed operations, compiling them to native
+machine code and executing them.
+
+First profiling information for loops is collected. After a hot loop has been
+identified, a special tracing mode is entered which records all executed
+operations of that loop. This sequence of operations is called a **trace**.
+The trace is then optimized and compiled to machine code (trace). When this
+loop is executed again the compiled trace is called instead of the program
+counterpart [#tracing_jit]_.
+
+Why the tracing JIT is important for us? The LuaJIT tracing compiler can detect
+tail-, up- and down-recursion [#luajit-recursion]_, unroll compositions of
+functions and inline high-order functions [#luajit-optimizations]_.
+All of these concepts make the foundation for functional programming.
+
+.. [#iterators] http://en.wikipedia.org/wiki/Turtles_all_the_way_down
+.. [#lua_for] http://www.lua.org/manual/5.2/manual.html#3.3.5
+.. [#pure_function] http://en.wikipedia.org/wiki/Pure_function
+.. [#turing] `Proved by Turing <http://en.wikipedia.org/wiki/Halting_problem>`_
+.. [#tracing_jit] http://en.wikipedia.org/wiki/Tracing_just-in-time_compilation
+.. [#luajit-recursion] http://lambda-the-ultimate.org/node/3851#comment-57679
+.. [#luajit-optimizations] http://wiki.luajit.org/Optimizations
diff --git a/Data/DefaultContent/Libraries/luafun/fun-scm-1.rockspec b/Data/DefaultContent/Libraries/luafun/fun-scm-1.rockspec
new file mode 100644
index 0000000..8f22022
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/fun-scm-1.rockspec
@@ -0,0 +1,34 @@
+package = "fun"
+version = "scm-1"
+
+source = {
+ url = "git://github.com/luafun/luafun.git",
+}
+
+description = {
+ summary = "High-performance functional programming library for Lua",
+ homepage = "https://luafun.github.io/",
+ license = "MIT/X11",
+ maintainer = "Roman Tsisyk <roman@tarantool.org>",
+ detailed = [[
+Lua Fun is a high-performance functional programming library for Lua
+designed with LuaJIT's trace compiler in mind.
+
+Lua Fun provides a set of more than 50 programming primitives typically
+found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and
+even Lisp. High-order functions such as map, filter, reduce, zip, etc.,
+make it easy to write simple and efficient functional code.
+]]
+}
+
+dependencies = {
+ "lua"
+}
+
+build = {
+ type = "builtin",
+ modules = {
+ fun = "fun.lua",
+ },
+ copy_directories = { "tests" },
+}
diff --git a/Data/DefaultContent/Libraries/luafun/fun.lua b/Data/DefaultContent/Libraries/luafun/fun.lua
new file mode 100644
index 0000000..2427bb2
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/fun.lua
@@ -0,0 +1,1058 @@
+---
+--- Lua Fun - a high-performance functional programming library for LuaJIT
+---
+--- Copyright (c) 2013-2017 Roman Tsisyk <roman@tsisyk.com>
+---
+--- Distributed under the MIT/X11 License. See COPYING.md for more details.
+---
+
+local exports = {}
+local methods = {}
+
+-- compatibility with Lua 5.1/5.2
+local unpack = rawget(table, "unpack") or unpack
+
+--------------------------------------------------------------------------------
+-- Tools
+--------------------------------------------------------------------------------
+
+local return_if_not_empty = function(state_x, ...)
+ if state_x == nil then
+ return nil
+ end
+ return ...
+end
+
+local call_if_not_empty = function(fun, state_x, ...)
+ if state_x == nil then
+ return nil
+ end
+ return state_x, fun(...)
+end
+
+local function deepcopy(orig) -- used by cycle()
+ local orig_type = type(orig)
+ local copy
+ if orig_type == 'table' then
+ copy = {}
+ for orig_key, orig_value in next, orig, nil do
+ copy[deepcopy(orig_key)] = deepcopy(orig_value)
+ end
+ else
+ copy = orig
+ end
+ return copy
+end
+
+local iterator_mt = {
+ -- usually called by for-in loop
+ __call = function(self, param, state)
+ return self.gen(param, state)
+ end;
+ __tostring = function(self)
+ return '<generator>'
+ end;
+ -- add all exported methods
+ __index = methods;
+}
+
+local wrap = function(gen, param, state)
+ return setmetatable({
+ gen = gen,
+ param = param,
+ state = state
+ }, iterator_mt), param, state
+end
+exports.wrap = wrap
+
+local unwrap = function(self)
+ return self.gen, self.param, self.state
+end
+methods.unwrap = unwrap
+
+--------------------------------------------------------------------------------
+-- Basic Functions
+--------------------------------------------------------------------------------
+
+local nil_gen = function(_param, _state)
+ return nil
+end
+
+local string_gen = function(param, state)
+ local state = state + 1
+ if state > #param then
+ return nil
+ end
+ local r = string.sub(param, state, state)
+ return state, r
+end
+
+local ipairs_gen = ipairs({}) -- get the generating function from ipairs
+
+local pairs_gen = pairs({ a = 0 }) -- get the generating function from pairs
+local map_gen = function(tab, key)
+ local value
+ local key, value = pairs_gen(tab, key)
+ return key, key, value
+end
+
+local rawiter = function(obj, param, state)
+ assert(obj ~= nil, "invalid iterator")
+ if type(obj) == "table" then
+ local mt = getmetatable(obj);
+ if mt ~= nil then
+ if mt == iterator_mt then
+ return obj.gen, obj.param, obj.state
+ elseif mt.__ipairs ~= nil then
+ return mt.__ipairs(obj)
+ elseif mt.__pairs ~= nil then
+ return mt.__pairs(obj)
+ end
+ end
+ if #obj > 0 then
+ -- array
+ return ipairs(obj)
+ else
+ -- hash
+ return map_gen, obj, nil
+ end
+ elseif (type(obj) == "function") then
+ return obj, param, state
+ elseif (type(obj) == "string") then
+ if #obj == 0 then
+ return nil_gen, nil, nil
+ end
+ return string_gen, obj, 0
+ end
+ error(string.format('object %s of type "%s" is not iterable',
+ obj, type(obj)))
+end
+
+local iter = function(obj, param, state)
+ return wrap(rawiter(obj, param, state))
+end
+exports.iter = iter
+
+local method0 = function(fun)
+ return function(self)
+ return fun(self.gen, self.param, self.state)
+ end
+end
+
+local method1 = function(fun)
+ return function(self, arg1)
+ return fun(arg1, self.gen, self.param, self.state)
+ end
+end
+
+local method2 = function(fun)
+ return function(self, arg1, arg2)
+ return fun(arg1, arg2, self.gen, self.param, self.state)
+ end
+end
+
+local export0 = function(fun)
+ return function(gen, param, state)
+ return fun(rawiter(gen, param, state))
+ end
+end
+
+local export1 = function(fun)
+ return function(arg1, gen, param, state)
+ return fun(arg1, rawiter(gen, param, state))
+ end
+end
+
+local export2 = function(fun)
+ return function(arg1, arg2, gen, param, state)
+ return fun(arg1, arg2, rawiter(gen, param, state))
+ end
+end
+
+local each = function(fun, gen, param, state)
+ repeat
+ state = call_if_not_empty(fun, gen(param, state))
+ until state == nil
+end
+methods.each = method1(each)
+exports.each = export1(each)
+methods.for_each = methods.each
+exports.for_each = exports.each
+methods.foreach = methods.each
+exports.foreach = exports.each
+
+--------------------------------------------------------------------------------
+-- Generators
+--------------------------------------------------------------------------------
+
+local range_gen = function(param, state)
+ local stop, step = param[1], param[2]
+ local state = state + step
+ if state > stop then
+ return nil
+ end
+ return state, state
+end
+
+local range_rev_gen = function(param, state)
+ local stop, step = param[1], param[2]
+ local state = state + step
+ if state < stop then
+ return nil
+ end
+ return state, state
+end
+
+local range = function(start, stop, step)
+ if step == nil then
+ if stop == nil then
+ if start == 0 then
+ return nil_gen, nil, nil
+ end
+ stop = start
+ start = stop > 0 and 1 or -1
+ end
+ step = start <= stop and 1 or -1
+ end
+
+ assert(type(start) == "number", "start must be a number")
+ assert(type(stop) == "number", "stop must be a number")
+ assert(type(step) == "number", "step must be a number")
+ assert(step ~= 0, "step must not be zero")
+
+ if (step > 0) then
+ return wrap(range_gen, {stop, step}, start - step)
+ elseif (step < 0) then
+ return wrap(range_rev_gen, {stop, step}, start - step)
+ end
+end
+exports.range = range
+
+local duplicate_table_gen = function(param_x, state_x)
+ return state_x + 1, unpack(param_x)
+end
+
+local duplicate_fun_gen = function(param_x, state_x)
+ return state_x + 1, param_x(state_x)
+end
+
+local duplicate_gen = function(param_x, state_x)
+ return state_x + 1, param_x
+end
+
+local duplicate = function(...)
+ if select('#', ...) <= 1 then
+ return wrap(duplicate_gen, select(1, ...), 0)
+ else
+ return wrap(duplicate_table_gen, {...}, 0)
+ end
+end
+exports.duplicate = duplicate
+exports.replicate = duplicate
+exports.xrepeat = duplicate
+
+local tabulate = function(fun)
+ assert(type(fun) == "function")
+ return wrap(duplicate_fun_gen, fun, 0)
+end
+exports.tabulate = tabulate
+
+local zeros = function()
+ return wrap(duplicate_gen, 0, 0)
+end
+exports.zeros = zeros
+
+local ones = function()
+ return wrap(duplicate_gen, 1, 0)
+end
+exports.ones = ones
+
+local rands_gen = function(param_x, _state_x)
+ return 0, math.random(param_x[1], param_x[2])
+end
+
+local rands_nil_gen = function(_param_x, _state_x)
+ return 0, math.random()
+end
+
+local rands = function(n, m)
+ if n == nil and m == nil then
+ return wrap(rands_nil_gen, 0, 0)
+ end
+ assert(type(n) == "number", "invalid first arg to rands")
+ if m == nil then
+ m = n
+ n = 0
+ else
+ assert(type(m) == "number", "invalid second arg to rands")
+ end
+ assert(n < m, "empty interval")
+ return wrap(rands_gen, {n, m - 1}, 0)
+end
+exports.rands = rands
+
+--------------------------------------------------------------------------------
+-- Slicing
+--------------------------------------------------------------------------------
+
+local nth = function(n, gen_x, param_x, state_x)
+ assert(n > 0, "invalid first argument to nth")
+ -- An optimization for arrays and strings
+ if gen_x == ipairs_gen then
+ return param_x[n]
+ elseif gen_x == string_gen then
+ if n <= #param_x then
+ return string.sub(param_x, n, n)
+ else
+ return nil
+ end
+ end
+ for i=1,n-1,1 do
+ state_x = gen_x(param_x, state_x)
+ if state_x == nil then
+ return nil
+ end
+ end
+ return return_if_not_empty(gen_x(param_x, state_x))
+end
+methods.nth = method1(nth)
+exports.nth = export1(nth)
+
+local head_call = function(state, ...)
+ if state == nil then
+ error("head: iterator is empty")
+ end
+ return ...
+end
+
+local head = function(gen, param, state)
+ return head_call(gen(param, state))
+end
+methods.head = method0(head)
+exports.head = export0(head)
+exports.car = exports.head
+methods.car = methods.head
+
+local tail = function(gen, param, state)
+ state = gen(param, state)
+ if state == nil then
+ return wrap(nil_gen, nil, nil)
+ end
+ return wrap(gen, param, state)
+end
+methods.tail = method0(tail)
+exports.tail = export0(tail)
+exports.cdr = exports.tail
+methods.cdr = methods.tail
+
+local take_n_gen_x = function(i, state_x, ...)
+ if state_x == nil then
+ return nil
+ end
+ return {i, state_x}, ...
+end
+
+local take_n_gen = function(param, state)
+ local n, gen_x, param_x = param[1], param[2], param[3]
+ local i, state_x = state[1], state[2]
+ if i >= n then
+ return nil
+ end
+ return take_n_gen_x(i + 1, gen_x(param_x, state_x))
+end
+
+local take_n = function(n, gen, param, state)
+ assert(n >= 0, "invalid first argument to take_n")
+ return wrap(take_n_gen, {n, gen, param}, {0, state})
+end
+methods.take_n = method1(take_n)
+exports.take_n = export1(take_n)
+
+local take_while_gen_x = function(fun, state_x, ...)
+ if state_x == nil or not fun(...) then
+ return nil
+ end
+ return state_x, ...
+end
+
+local take_while_gen = function(param, state_x)
+ local fun, gen_x, param_x = param[1], param[2], param[3]
+ return take_while_gen_x(fun, gen_x(param_x, state_x))
+end
+
+local take_while = function(fun, gen, param, state)
+ assert(type(fun) == "function", "invalid first argument to take_while")
+ return wrap(take_while_gen, {fun, gen, param}, state)
+end
+methods.take_while = method1(take_while)
+exports.take_while = export1(take_while)
+
+local take = function(n_or_fun, gen, param, state)
+ if type(n_or_fun) == "number" then
+ return take_n(n_or_fun, gen, param, state)
+ else
+ return take_while(n_or_fun, gen, param, state)
+ end
+end
+methods.take = method1(take)
+exports.take = export1(take)
+
+local drop_n = function(n, gen, param, state)
+ assert(n >= 0, "invalid first argument to drop_n")
+ local i
+ for i=1,n,1 do
+ state = gen(param, state)
+ if state == nil then
+ return wrap(nil_gen, nil, nil)
+ end
+ end
+ return wrap(gen, param, state)
+end
+methods.drop_n = method1(drop_n)
+exports.drop_n = export1(drop_n)
+
+local drop_while_x = function(fun, state_x, ...)
+ if state_x == nil or not fun(...) then
+ return state_x, false
+ end
+ return state_x, true, ...
+end
+
+local drop_while = function(fun, gen_x, param_x, state_x)
+ assert(type(fun) == "function", "invalid first argument to drop_while")
+ local cont, state_x_prev
+ repeat
+ state_x_prev = deepcopy(state_x)
+ state_x, cont = drop_while_x(fun, gen_x(param_x, state_x))
+ until not cont
+ if state_x == nil then
+ return wrap(nil_gen, nil, nil)
+ end
+ return wrap(gen_x, param_x, state_x_prev)
+end
+methods.drop_while = method1(drop_while)
+exports.drop_while = export1(drop_while)
+
+local drop = function(n_or_fun, gen_x, param_x, state_x)
+ if type(n_or_fun) == "number" then
+ return drop_n(n_or_fun, gen_x, param_x, state_x)
+ else
+ return drop_while(n_or_fun, gen_x, param_x, state_x)
+ end
+end
+methods.drop = method1(drop)
+exports.drop = export1(drop)
+
+local split = function(n_or_fun, gen_x, param_x, state_x)
+ return take(n_or_fun, gen_x, param_x, state_x),
+ drop(n_or_fun, gen_x, param_x, state_x)
+end
+methods.split = method1(split)
+exports.split = export1(split)
+methods.split_at = methods.split
+exports.split_at = exports.split
+methods.span = methods.split
+exports.span = exports.split
+
+--------------------------------------------------------------------------------
+-- Indexing
+--------------------------------------------------------------------------------
+
+local index = function(x, gen, param, state)
+ local i = 1
+ for _k, r in gen, param, state do
+ if r == x then
+ return i
+ end
+ i = i + 1
+ end
+ return nil
+end
+methods.index = method1(index)
+exports.index = export1(index)
+methods.index_of = methods.index
+exports.index_of = exports.index
+methods.elem_index = methods.index
+exports.elem_index = exports.index
+
+local indexes_gen = function(param, state)
+ local x, gen_x, param_x = param[1], param[2], param[3]
+ local i, state_x = state[1], state[2]
+ local r
+ while true do
+ state_x, r = gen_x(param_x, state_x)
+ if state_x == nil then
+ return nil
+ end
+ i = i + 1
+ if r == x then
+ return {i, state_x}, i
+ end
+ end
+end
+
+local indexes = function(x, gen, param, state)
+ return wrap(indexes_gen, {x, gen, param}, {0, state})
+end
+methods.indexes = method1(indexes)
+exports.indexes = export1(indexes)
+methods.elem_indexes = methods.indexes
+exports.elem_indexes = exports.indexes
+methods.indices = methods.indexes
+exports.indices = exports.indexes
+methods.elem_indices = methods.indexes
+exports.elem_indices = exports.indexes
+
+--------------------------------------------------------------------------------
+-- Filtering
+--------------------------------------------------------------------------------
+
+local filter1_gen = function(fun, gen_x, param_x, state_x, a)
+ while true do
+ if state_x == nil or fun(a) then break; end
+ state_x, a = gen_x(param_x, state_x)
+ end
+ return state_x, a
+end
+
+-- call each other
+local filterm_gen
+local filterm_gen_shrink = function(fun, gen_x, param_x, state_x)
+ return filterm_gen(fun, gen_x, param_x, gen_x(param_x, state_x))
+end
+
+filterm_gen = function(fun, gen_x, param_x, state_x, ...)
+ if state_x == nil then
+ return nil
+ end
+ if fun(...) then
+ return state_x, ...
+ end
+ return filterm_gen_shrink(fun, gen_x, param_x, state_x)
+end
+
+local filter_detect = function(fun, gen_x, param_x, state_x, ...)
+ if select('#', ...) < 2 then
+ return filter1_gen(fun, gen_x, param_x, state_x, ...)
+ else
+ return filterm_gen(fun, gen_x, param_x, state_x, ...)
+ end
+end
+
+local filter_gen = function(param, state_x)
+ local fun, gen_x, param_x = param[1], param[2], param[3]
+ return filter_detect(fun, gen_x, param_x, gen_x(param_x, state_x))
+end
+
+local filter = function(fun, gen, param, state)
+ return wrap(filter_gen, {fun, gen, param}, state)
+end
+methods.filter = method1(filter)
+exports.filter = export1(filter)
+methods.remove_if = methods.filter
+exports.remove_if = exports.filter
+
+local grep = function(fun_or_regexp, gen, param, state)
+ local fun = fun_or_regexp
+ if type(fun_or_regexp) == "string" then
+ fun = function(x) return string.find(x, fun_or_regexp) ~= nil end
+ end
+ return filter(fun, gen, param, state)
+end
+methods.grep = method1(grep)
+exports.grep = export1(grep)
+
+local partition = function(fun, gen, param, state)
+ local neg_fun = function(...)
+ return not fun(...)
+ end
+ return filter(fun, gen, param, state),
+ filter(neg_fun, gen, param, state)
+end
+methods.partition = method1(partition)
+exports.partition = export1(partition)
+
+--------------------------------------------------------------------------------
+-- Reducing
+--------------------------------------------------------------------------------
+
+local foldl_call = function(fun, start, state, ...)
+ if state == nil then
+ return nil, start
+ end
+ return state, fun(start, ...)
+end
+
+local foldl = function(fun, start, gen_x, param_x, state_x)
+ while true do
+ state_x, start = foldl_call(fun, start, gen_x(param_x, state_x))
+ if state_x == nil then
+ break;
+ end
+ end
+ return start
+end
+methods.foldl = method2(foldl)
+exports.foldl = export2(foldl)
+methods.reduce = methods.foldl
+exports.reduce = exports.foldl
+
+local length = function(gen, param, state)
+ if gen == ipairs_gen or gen == string_gen then
+ return #param
+ end
+ local len = 0
+ repeat
+ state = gen(param, state)
+ len = len + 1
+ until state == nil
+ return len - 1
+end
+methods.length = method0(length)
+exports.length = export0(length)
+
+local is_null = function(gen, param, state)
+ return gen(param, deepcopy(state)) == nil
+end
+methods.is_null = method0(is_null)
+exports.is_null = export0(is_null)
+
+local is_prefix_of = function(iter_x, iter_y)
+ local gen_x, param_x, state_x = iter(iter_x)
+ local gen_y, param_y, state_y = iter(iter_y)
+
+ local r_x, r_y
+ for i=1,10,1 do
+ state_x, r_x = gen_x(param_x, state_x)
+ state_y, r_y = gen_y(param_y, state_y)
+ if state_x == nil then
+ return true
+ end
+ if state_y == nil or r_x ~= r_y then
+ return false
+ end
+ end
+end
+methods.is_prefix_of = is_prefix_of
+exports.is_prefix_of = is_prefix_of
+
+local all = function(fun, gen_x, param_x, state_x)
+ local r
+ repeat
+ state_x, r = call_if_not_empty(fun, gen_x(param_x, state_x))
+ until state_x == nil or not r
+ return state_x == nil
+end
+methods.all = method1(all)
+exports.all = export1(all)
+methods.every = methods.all
+exports.every = exports.all
+
+local any = function(fun, gen_x, param_x, state_x)
+ local r
+ repeat
+ state_x, r = call_if_not_empty(fun, gen_x(param_x, state_x))
+ until state_x == nil or r
+ return not not r
+end
+methods.any = method1(any)
+exports.any = export1(any)
+methods.some = methods.any
+exports.some = exports.any
+
+local sum = function(gen, param, state)
+ local s = 0
+ local r = 0
+ repeat
+ s = s + r
+ state, r = gen(param, state)
+ until state == nil
+ return s
+end
+methods.sum = method0(sum)
+exports.sum = export0(sum)
+
+local product = function(gen, param, state)
+ local p = 1
+ local r = 1
+ repeat
+ p = p * r
+ state, r = gen(param, state)
+ until state == nil
+ return p
+end
+methods.product = method0(product)
+exports.product = export0(product)
+
+local min_cmp = function(m, n)
+ if n < m then return n else return m end
+end
+
+local max_cmp = function(m, n)
+ if n > m then return n else return m end
+end
+
+local min = function(gen, param, state)
+ local state, m = gen(param, state)
+ if state == nil then
+ error("min: iterator is empty")
+ end
+
+ local cmp
+ if type(m) == "number" then
+ -- An optimization: use math.min for numbers
+ cmp = math.min
+ else
+ cmp = min_cmp
+ end
+
+ for _, r in gen, param, state do
+ m = cmp(m, r)
+ end
+ return m
+end
+methods.min = method0(min)
+exports.min = export0(min)
+methods.minimum = methods.min
+exports.minimum = exports.min
+
+local min_by = function(cmp, gen_x, param_x, state_x)
+ local state_x, m = gen_x(param_x, state_x)
+ if state_x == nil then
+ error("min: iterator is empty")
+ end
+
+ for _, r in gen_x, param_x, state_x do
+ m = cmp(m, r)
+ end
+ return m
+end
+methods.min_by = method1(min_by)
+exports.min_by = export1(min_by)
+methods.minimum_by = methods.min_by
+exports.minimum_by = exports.min_by
+
+local max = function(gen_x, param_x, state_x)
+ local state_x, m = gen_x(param_x, state_x)
+ if state_x == nil then
+ error("max: iterator is empty")
+ end
+
+ local cmp
+ if type(m) == "number" then
+ -- An optimization: use math.max for numbers
+ cmp = math.max
+ else
+ cmp = max_cmp
+ end
+
+ for _, r in gen_x, param_x, state_x do
+ m = cmp(m, r)
+ end
+ return m
+end
+methods.max = method0(max)
+exports.max = export0(max)
+methods.maximum = methods.max
+exports.maximum = exports.max
+
+local max_by = function(cmp, gen_x, param_x, state_x)
+ local state_x, m = gen_x(param_x, state_x)
+ if state_x == nil then
+ error("max: iterator is empty")
+ end
+
+ for _, r in gen_x, param_x, state_x do
+ m = cmp(m, r)
+ end
+ return m
+end
+methods.max_by = method1(max_by)
+exports.max_by = export1(max_by)
+methods.maximum_by = methods.maximum_by
+exports.maximum_by = exports.maximum_by
+
+local totable = function(gen_x, param_x, state_x)
+ local tab, key, val = {}
+ while true do
+ state_x, val = gen_x(param_x, state_x)
+ if state_x == nil then
+ break
+ end
+ table.insert(tab, val)
+ end
+ return tab
+end
+methods.totable = method0(totable)
+exports.totable = export0(totable)
+
+local tomap = function(gen_x, param_x, state_x)
+ local tab, key, val = {}
+ while true do
+ state_x, key, val = gen_x(param_x, state_x)
+ if state_x == nil then
+ break
+ end
+ tab[key] = val
+ end
+ return tab
+end
+methods.tomap = method0(tomap)
+exports.tomap = export0(tomap)
+
+--------------------------------------------------------------------------------
+-- Transformations
+--------------------------------------------------------------------------------
+
+local map_gen = function(param, state)
+ local gen_x, param_x, fun = param[1], param[2], param[3]
+ return call_if_not_empty(fun, gen_x(param_x, state))
+end
+
+local map = function(fun, gen, param, state)
+ return wrap(map_gen, {gen, param, fun}, state)
+end
+methods.map = method1(map)
+exports.map = export1(map)
+
+local enumerate_gen_call = function(state, i, state_x, ...)
+ if state_x == nil then
+ return nil
+ end
+ return {i + 1, state_x}, i, ...
+end
+
+local enumerate_gen = function(param, state)
+ local gen_x, param_x = param[1], param[2]
+ local i, state_x = state[1], state[2]
+ return enumerate_gen_call(state, i, gen_x(param_x, state_x))
+end
+
+local enumerate = function(gen, param, state)
+ return wrap(enumerate_gen, {gen, param}, {1, state})
+end
+methods.enumerate = method0(enumerate)
+exports.enumerate = export0(enumerate)
+
+local intersperse_call = function(i, state_x, ...)
+ if state_x == nil then
+ return nil
+ end
+ return {i + 1, state_x}, ...
+end
+
+local intersperse_gen = function(param, state)
+ local x, gen_x, param_x = param[1], param[2], param[3]
+ local i, state_x = state[1], state[2]
+ if i % 2 == 1 then
+ return {i + 1, state_x}, x
+ else
+ return intersperse_call(i, gen_x(param_x, state_x))
+ end
+end
+
+-- TODO: interperse must not add x to the tail
+local intersperse = function(x, gen, param, state)
+ return wrap(intersperse_gen, {x, gen, param}, {0, state})
+end
+methods.intersperse = method1(intersperse)
+exports.intersperse = export1(intersperse)
+
+--------------------------------------------------------------------------------
+-- Compositions
+--------------------------------------------------------------------------------
+
+local function zip_gen_r(param, state, state_new, ...)
+ if #state_new == #param / 2 then
+ return state_new, ...
+ end
+
+ local i = #state_new + 1
+ local gen_x, param_x = param[2 * i - 1], param[2 * i]
+ local state_x, r = gen_x(param_x, state[i])
+ if state_x == nil then
+ return nil
+ end
+ table.insert(state_new, state_x)
+ return zip_gen_r(param, state, state_new, r, ...)
+end
+
+local zip_gen = function(param, state)
+ return zip_gen_r(param, state, {})
+end
+
+-- A special hack for zip/chain to skip last two state, if a wrapped iterator
+-- has been passed
+local numargs = function(...)
+ local n = select('#', ...)
+ if n >= 3 then
+ -- Fix last argument
+ local it = select(n - 2, ...)
+ if type(it) == 'table' and getmetatable(it) == iterator_mt and
+ it.param == select(n - 1, ...) and it.state == select(n, ...) then
+ return n - 2
+ end
+ end
+ return n
+end
+
+local zip = function(...)
+ local n = numargs(...)
+ if n == 0 then
+ return wrap(nil_gen, nil, nil)
+ end
+ local param = { [2 * n] = 0 }
+ local state = { [n] = 0 }
+
+ local i, gen_x, param_x, state_x
+ for i=1,n,1 do
+ local it = select(n - i + 1, ...)
+ gen_x, param_x, state_x = rawiter(it)
+ param[2 * i - 1] = gen_x
+ param[2 * i] = param_x
+ state[i] = state_x
+ end
+
+ return wrap(zip_gen, param, state)
+end
+methods.zip = zip
+exports.zip = zip
+
+local cycle_gen_call = function(param, state_x, ...)
+ if state_x == nil then
+ local gen_x, param_x, state_x0 = param[1], param[2], param[3]
+ return gen_x(param_x, deepcopy(state_x0))
+ end
+ return state_x, ...
+end
+
+local cycle_gen = function(param, state_x)
+ local gen_x, param_x, state_x0 = param[1], param[2], param[3]
+ return cycle_gen_call(param, gen_x(param_x, state_x))
+end
+
+local cycle = function(gen, param, state)
+ return wrap(cycle_gen, {gen, param, state}, deepcopy(state))
+end
+methods.cycle = method0(cycle)
+exports.cycle = export0(cycle)
+
+-- call each other
+local chain_gen_r1
+local chain_gen_r2 = function(param, state, state_x, ...)
+ if state_x == nil then
+ local i = state[1]
+ i = i + 1
+ if param[3 * i - 1] == nil then
+ return nil
+ end
+ local state_x = param[3 * i]
+ return chain_gen_r1(param, {i, state_x})
+ end
+ return {state[1], state_x}, ...
+end
+
+chain_gen_r1 = function(param, state)
+ local i, state_x = state[1], state[2]
+ local gen_x, param_x = param[3 * i - 2], param[3 * i - 1]
+ return chain_gen_r2(param, state, gen_x(param_x, state[2]))
+end
+
+local chain = function(...)
+ local n = numargs(...)
+ if n == 0 then
+ return wrap(nil_gen, nil, nil)
+ end
+
+ local param = { [3 * n] = 0 }
+ local i, gen_x, param_x, state_x
+ for i=1,n,1 do
+ local elem = select(i, ...)
+ gen_x, param_x, state_x = iter(elem)
+ param[3 * i - 2] = gen_x
+ param[3 * i - 1] = param_x
+ param[3 * i] = state_x
+ end
+
+ return wrap(chain_gen_r1, param, {1, param[3]})
+end
+methods.chain = chain
+exports.chain = chain
+
+--------------------------------------------------------------------------------
+-- Operators
+--------------------------------------------------------------------------------
+
+local operator = {
+ ----------------------------------------------------------------------------
+ -- Comparison operators
+ ----------------------------------------------------------------------------
+ lt = function(a, b) return a < b end,
+ le = function(a, b) return a <= b end,
+ eq = function(a, b) return a == b end,
+ ne = function(a, b) return a ~= b end,
+ ge = function(a, b) return a >= b end,
+ gt = function(a, b) return a > b end,
+
+ ----------------------------------------------------------------------------
+ -- Arithmetic operators
+ ----------------------------------------------------------------------------
+ add = function(a, b) return a + b end,
+ div = function(a, b) return a / b end,
+ floordiv = function(a, b) return math.floor(a/b) end,
+ intdiv = function(a, b)
+ local q = a / b
+ if a >= 0 then return math.floor(q) else return math.ceil(q) end
+ end,
+ mod = function(a, b) return a % b end,
+ mul = function(a, b) return a * b end,
+ neq = function(a) return -a end,
+ unm = function(a) return -a end, -- an alias
+ pow = function(a, b) return a ^ b end,
+ sub = function(a, b) return a - b end,
+ truediv = function(a, b) return a / b end,
+
+ ----------------------------------------------------------------------------
+ -- String operators
+ ----------------------------------------------------------------------------
+ concat = function(a, b) return a..b end,
+ len = function(a) return #a end,
+ length = function(a) return #a end, -- an alias
+
+ ----------------------------------------------------------------------------
+ -- Logical operators
+ ----------------------------------------------------------------------------
+ land = function(a, b) return a and b end,
+ lor = function(a, b) return a or b end,
+ lnot = function(a) return not a end,
+ truth = function(a) return not not a end,
+}
+exports.operator = operator
+methods.operator = operator
+exports.op = operator
+methods.op = operator
+
+--------------------------------------------------------------------------------
+-- module definitions
+--------------------------------------------------------------------------------
+
+-- a special syntax sugar to export all functions to the global table
+setmetatable(exports, {
+ __call = function(t, override)
+ for k, v in pairs(t) do
+ if rawget(_G, k) ~= nil then
+ local msg = 'function ' .. k .. ' already exists in global scope.'
+ if override then
+ rawset(_G, k, v)
+ print('WARNING: ' .. msg .. ' Overwritten.')
+ else
+ print('NOTICE: ' .. msg .. ' Skipped.')
+ end
+ else
+ rawset(_G, k, v)
+ end
+ end
+ end,
+})
+
+return exports
diff --git a/Data/DefaultContent/Libraries/luafun/rpm/lua-fun.spec b/Data/DefaultContent/Libraries/luafun/rpm/lua-fun.spec
new file mode 100644
index 0000000..b200c76
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/rpm/lua-fun.spec
@@ -0,0 +1,76 @@
+%define luaver 5.3
+%define luapkgdir %{_datadir}/lua/%{luaver}
+# LuaJIT is compatible with Lua 5.1 and uses the same directory for modules
+%global ljpkgdir %{_datadir}/lua/5.1
+
+Name: lua-fun
+Version: 0.1.3
+Release: 1%{?dist}
+Summary: Functional programming library for Lua
+Group: Development/Libraries
+License: MIT
+URL: https://github.com/luafun/luafun
+Source0: https://github.com/luafun/luafun/archive/%{version}/luafun-%{version}.tar.gz
+BuildArch: noarch
+BuildRequires: luajit >= 2.0
+BuildRequires: lua >= 5.1
+Requires: lua >= 5.1
+
+%package -n luajit-fun
+Summary: Functional programming library for LuaJIT
+Requires: luajit >= 2.0
+
+%description -n lua-fun
+Lua Fun is a high-performance functional programming library for Lua
+designed with LuaJIT's trace compiler in mind.
+
+Lua Fun provides a set of more than 50 programming primitives typically
+found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and
+even Lisp. High-order functions such as map, filter, reduce, zip, etc.,
+make it easy to write simple and efficient functional code.
+
+This package provides a module for Lua %{luaver}.
+
+%description -n luajit-fun
+Lua Fun is a high-performance functional programming library for Lua
+designed with LuaJIT's trace compiler in mind.
+
+Lua Fun provides a set of more than 50 programming primitives typically
+found in languages like Standard ML, Haskell, Erlang, JavaScript, Python and
+even Lisp. High-order functions such as map, filter, reduce, zip, etc.,
+make it easy to write simple and efficient functional code.
+
+This package provides a module for LuaJIT.
+
+%prep
+%setup -q -n luafun-%{version}
+
+%build
+# nothing to do
+
+%install
+# Install for Lua
+mkdir -p %{buildroot}%{luapkgdir}
+cp -av fun.lua %{buildroot}%{luapkgdir}/fun.lua
+# Install for LuaJIT
+mkdir -p %{buildroot}%{ljpkgdir}
+cp -av fun.lua %{buildroot}%{ljpkgdir}/fun.lua
+
+%check
+cd tests
+luajit ./runtest *.lua
+lua ./runtest *.lua
+
+%files -n lua-fun
+%{luapkgdir}/fun.lua
+%doc README.md CONTRIBUTING.md
+%license COPYING.md
+
+%files -n luajit-fun
+%{ljpkgdir}/fun.lua
+%doc README.md CONTRIBUTING.md
+%license COPYING.md
+
+%changelog
+* Mon Jan 18 2016 Roman Tsisyk <roman@tarantool.org> - 0.1.3-1
+- Initial version.
diff --git a/Data/DefaultContent/Libraries/luafun/tests/.gitignore b/Data/DefaultContent/Libraries/luafun/tests/.gitignore
new file mode 100644
index 0000000..ce0a7f3
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/tests/.gitignore
@@ -0,0 +1 @@
+*.new
diff --git a/Data/DefaultContent/Libraries/luafun/tests/basic.lua b/Data/DefaultContent/Libraries/luafun/tests/basic.lua
new file mode 100644
index 0000000..97e7aae
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/tests/basic.lua
@@ -0,0 +1,332 @@
+--------------------------------------------------------------------------------
+-- iter
+--------------------------------------------------------------------------------
+
+--
+-- Arrays
+--
+
+for _it, a in iter({1, 2, 3}) do print(a) end
+--[[test
+1
+2
+3
+--test]]
+
+for _it, a in iter(iter(iter({1, 2, 3}))) do print(a) end
+--[[test
+1
+2
+3
+--test]]
+
+for _it, a in wrap(wrap(iter({1, 2, 3}))) do print(a) end
+--[[test
+1
+2
+3
+--test]]
+
+for _it, a in wrap(wrap(ipairs({1, 2, 3}))) do print(a) end
+--[[test
+1
+2
+3
+--test]]
+
+for _it, a in iter({}) do print(a) end
+--[[test
+--test]]
+
+for _it, a in iter(iter(iter({}))) do print(a) end
+--[[test
+--test]]
+
+for _it, a in wrap(wrap(iter({}))) do print(a) end
+--[[test
+--test]]
+
+for _it, a in wrap(wrap(ipairs({}))) do print(a) end
+--[[test
+--test]]
+
+-- Check that ``iter`` for arrays is equivalent to ``ipairs``
+local t = {1, 2, 3}
+gen1, param1, state1 = iter(t):unwrap()
+gen2, param2, state2 = ipairs(t)
+print(gen1 == gen2, param1 == param2, state1 == state2)
+--[[test
+true true true
+--test]]
+
+-- Test that ``wrap`` do nothing for wrapped iterators
+gen1, param1, state1 = iter({1, 2, 3})
+gen2, param2, state2 = wrap(gen1, param1, state1):unwrap()
+print(gen1 == gen2, param1 == param2, state1 == state2)
+--[[test
+true true true
+--test]]
+
+--
+-- Maps
+--
+
+local t = {}
+for _it, k, v in iter({ a = 1, b = 2, c = 3}) do t[#t + 1] = k end
+table.sort(t)
+for _it, v in iter(t) do print(v) end
+--[[test
+a
+b
+c
+--test]]
+
+local t = {}
+for _it, k, v in iter(iter(iter({ a = 1, b = 2, c = 3}))) do t[#t + 1] = k end
+table.sort(t)
+for _it, v in iter(t) do print(v) end
+--[[test
+a
+b
+c
+--test]]
+
+for _it, k, v in iter({}) do print(k, v) end
+--[[test
+--test]]
+
+for _it, k, v in iter(iter(iter({}))) do print(k, v) end
+--[[test
+--test]]
+
+--
+-- String
+--
+
+for _it, a in iter("abcde") do print(a) end
+--[[test
+a
+b
+c
+d
+e
+--test]]
+
+for _it, a in iter(iter(iter("abcde"))) do print(a) end
+--[[test
+a
+b
+c
+d
+e
+--test]]
+
+for _it, a in iter("") do print(a) end
+--[[test
+--test]]
+
+for _it, a in iter(iter(iter(""))) do print(a) end
+--[[test
+--test]]
+
+--
+-- Custom generators
+--
+
+local function mypairs_gen(max, state)
+ if (state >= max) then
+ return nil
+ end
+ return state + 1, state + 1
+end
+
+local function mypairs(max)
+ return mypairs_gen, max, 0
+end
+
+for _it, a in iter(mypairs(10)) do print(a) end
+--[[test
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+--test]]
+
+--
+-- Invalid values
+--
+
+for _it, a in iter(1) do print(a) end
+--[[test
+error: object 1 of type "number" is not iterable
+--test]]
+
+for _it, a in iter(1, 2, 3, 4, 5, 6, 7) do print(a) end
+--[[test
+error: object 1 of type "number" is not iterable
+--test]]
+
+--------------------------------------------------------------------------------
+-- each
+--------------------------------------------------------------------------------
+
+each(print, {1, 2, 3})
+--[[test
+1
+2
+3
+--test]]
+
+each(print, iter({1, 2, 3}))
+--[[test
+1
+2
+3
+--test]]
+
+each(print, {})
+--[[test
+--test]]
+
+
+each(print, iter({}))
+--[[test
+--test]]
+
+local keys, vals = {}, {}
+each(function(k, v)
+ keys[#keys + 1] = k
+ vals[#vals + 1] = v
+end, { a = 1, b = 2, c = 3})
+table.sort(keys)
+table.sort(vals)
+each(print, keys)
+each(print, vals)
+--[[test
+a
+b
+c
+1
+2
+3
+--test]]
+
+each(print, "abc")
+--[[test
+a
+b
+c
+--test]]
+
+each(print, iter("abc"))
+--[[test
+a
+b
+c
+--test]]
+
+print(for_each == each) -- an alias
+--[[test
+true
+--test]]
+
+print(foreach == each) -- an alias
+--[[test
+true
+--test]]
+
+--------------------------------------------------------------------------------
+-- totable
+--------------------------------------------------------------------------------
+
+local tab = totable(range(5))
+print(type(tab), #tab)
+each(print, tab)
+--[[test
+table 5
+1
+2
+3
+4
+5
+--test]]
+
+local tab = totable(range(0))
+print(type(tab), #tab)
+--[[test
+table 0
+--test]]
+
+local tab = totable("abcdef")
+print(type(tab), #tab)
+each(print, tab)
+--[[test
+table 6
+a
+b
+c
+d
+e
+f
+--test]]
+
+local unpack = rawget(table, "unpack") or unpack
+local tab = totable({ 'a', {'b', 'c'}, {'d', 'e', 'f'}})
+print(type(tab), #tab)
+each(print, tab[1])
+each(print, map(unpack, drop(1, tab)))
+--[[test
+table 3
+a
+b c
+d e f
+--test]]
+
+--------------------------------------------------------------------------------
+-- tomap
+--------------------------------------------------------------------------------
+
+local tab = tomap(zip(range(1, 7), 'abcdef'))
+print(type(tab), #tab)
+each(print, iter(tab))
+--[[test
+table 6
+a
+b
+c
+d
+e
+f
+--test]]
+
+local tab = tomap({a = 1, b = 2, c = 3})
+print(type(tab), #tab)
+local t = {}
+for _it, k, v in iter(tab) do t[v] = k end
+table.sort(t)
+for k, v in ipairs(t) do print(k, v) end
+--[[test
+table 0
+1 a
+2 b
+3 c
+--test]]
+
+local tab = tomap(enumerate("abcdef"))
+print(type(tab), #tab)
+each(print, tab)
+--[[test
+table 6
+a
+b
+c
+d
+e
+f
+--test]]
diff --git a/Data/DefaultContent/Libraries/luafun/tests/compositions.lua b/Data/DefaultContent/Libraries/luafun/tests/compositions.lua
new file mode 100644
index 0000000..7b81d88
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/tests/compositions.lua
@@ -0,0 +1,170 @@
+--------------------------------------------------------------------------------
+-- zip
+--------------------------------------------------------------------------------
+
+dump(zip({"a", "b", "c", "d"}, {"one", "two", "three"}))
+--[[test
+a one
+b two
+c three
+--test]]
+
+dump(zip())
+--[[test
+--test]]
+
+dump(zip(range(0)))
+--[[test
+error: invalid iterator
+--test]]
+
+dump(zip(range(0), range(0)))
+--[[test
+error: invalid iterator
+--test]]
+
+print(nth(10, zip(range(1, 100, 3), range(1, 100, 5), range(1, 100, 7))))
+--[[test
+28 46 64
+--test]]
+
+dump(zip(partition(function(x) return x > 7 end, range(1, 15, 1))))
+--[[test
+8 1
+9 2
+10 3
+11 4
+12 5
+13 6
+14 7
+--test]]
+
+--------------------------------------------------------------------------------
+-- cycle
+--------------------------------------------------------------------------------
+
+dump(take(15, cycle({"a", "b", "c", "d", "e"})))
+--[[test
+a
+b
+c
+d
+e
+a
+b
+c
+d
+e
+a
+b
+c
+d
+e
+--test]]
+
+
+dump(take(15, cycle(range(5))))
+--[[test
+1
+2
+3
+4
+5
+1
+2
+3
+4
+5
+1
+2
+3
+4
+5
+--test]]
+
+dump(take(15, cycle(zip(range(5), {"a", "b", "c", "d", "e"}))))
+--[[test
+1 a
+2 b
+3 c
+4 d
+5 e
+1 a
+2 b
+3 c
+4 d
+5 e
+1 a
+2 b
+3 c
+4 d
+5 e
+--test]]
+
+--------------------------------------------------------------------------------
+-- chain
+--------------------------------------------------------------------------------
+
+dump(chain(range(2)))
+--[[test
+1
+2
+--test]]
+
+dump(chain(range(2), {"a", "b", "c"}, {"one", "two", "three"}))
+--[[test
+1
+2
+a
+b
+c
+one
+two
+three
+--test]]
+
+dump(take(15, cycle(chain(enumerate({"a", "b", "c"}),
+ {"one", "two", "three"}))))
+--[[test
+1 a
+2 b
+3 c
+one
+two
+three
+1 a
+2 b
+3 c
+one
+two
+three
+1 a
+2 b
+3 c
+--test]]
+
+local tab = {}
+local keys = {}
+for _it, k, v in chain({ a = 11, b = 12, c = 13}, { d = 21, e = 22 }) do
+ tab[k] = v
+ table.insert(keys, k)
+end
+table.sort(keys)
+for _, key in ipairs(keys) do print(key, tab[key]) end
+--[[test
+a 11
+b 12
+c 13
+d 21
+e 22
+--test]]
+
+dump(chain(range(0), range(0), range(0)))
+--[[test
+error: invalid iterator
+--test]]
+
+dump(chain(range(0), range(1), range(0)))
+--[[test
+error: invalid iterator
+--test]]
diff --git a/Data/DefaultContent/Libraries/luafun/tests/filtering.lua b/Data/DefaultContent/Libraries/luafun/tests/filtering.lua
new file mode 100644
index 0000000..a5fdfe2
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/tests/filtering.lua
@@ -0,0 +1,102 @@
+--------------------------------------------------------------------------------
+-- filter
+--------------------------------------------------------------------------------
+
+dump(filter(function(x) return x % 3 == 0 end, range(10)))
+--[[test
+3
+6
+9
+--test]]
+
+dump(filter(function(x) return x % 3 == 0 end, range(0)))
+--[[test
+--test]]
+
+
+dump(take(5, filter(function(i, x) return i % 3 == 0 end,
+ enumerate(duplicate('x')))))
+--[[test
+3 x
+6 x
+9 x
+12 x
+15 x
+--test]]
+
+function filter_fun(a, b, c)
+ if a % 16 == 0 then
+ return true
+ else
+ return false
+ end
+end
+
+function test3(a, b, c)
+ return a, c, b
+end
+
+n = 50
+dump(filter(filter_fun, map(test3, zip(range(0, n, 1),
+ range(0, n, 2), range(0, n, 3)))))
+--[[test
+0 0 0
+16 48 32
+--test]]
+
+print(remove_if == filter) -- an alias
+--[[test
+true
+--test]]
+
+--------------------------------------------------------------------------------
+-- grep
+--------------------------------------------------------------------------------
+
+lines_to_grep = {
+ [[Lorem ipsum dolor sit amet, consectetur adipisicing elit, ]],
+ [[sed do eiusmod tempor incididunt ut labore et dolore magna ]],
+ [[aliqua. Ut enim ad minim veniam, quis nostrud exercitation ]],
+ [[ullamco laboris nisi ut aliquip ex ea commodo consequat.]],
+ [[Duis aute irure dolor in reprehenderit in voluptate velit ]],
+ [[esse cillum dolore eu fugiat nulla pariatur. Excepteur sint ]],
+ [[occaecat cupidatat non proident, sunt in culpa qui officia ]],
+ [[deserunt mollit anim id est laborum.]]
+}
+
+dump(grep("lab", lines_to_grep))
+--[[test
+sed do eiusmod tempor incididunt ut labore et dolore magna
+ullamco laboris nisi ut aliquip ex ea commodo consequat.
+deserunt mollit anim id est laborum.
+--test]]
+
+lines_to_grep = {
+ [[Emily]],
+ [[Chloe]],
+ [[Megan]],
+ [[Jessica]],
+ [[Emma]],
+ [[Sarah]],
+ [[Elizabeth]],
+ [[Sophie]],
+ [[Olivia]],
+ [[Lauren]]
+}
+
+dump(grep("^Em", lines_to_grep))
+--[[test
+Emily
+Emma
+--test]]
+
+--------------------------------------------------------------------------------
+-- partition
+--------------------------------------------------------------------------------
+
+dump(zip(partition(function(i, x) return i % 3 == 0 end, range(10))))
+--[[test
+3 1
+6 2
+9 4
+--test]]
diff --git a/Data/DefaultContent/Libraries/luafun/tests/generators.lua b/Data/DefaultContent/Libraries/luafun/tests/generators.lua
new file mode 100644
index 0000000..7a89ebf
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/tests/generators.lua
@@ -0,0 +1,287 @@
+--------------------------------------------------------------------------------
+-- range
+--------------------------------------------------------------------------------
+
+dump(range(0))
+print('--')
+for i=1,0 do print(i) end
+--[[test
+--
+--test]]
+
+dump(range(0, 0))
+print('--')
+for i=0,0 do print(i) end
+--[[test
+0
+--
+0
+--test]]
+
+dump(range(5))
+print('--')
+for i=1,5 do print(i) end
+--[[test
+1
+2
+3
+4
+5
+--
+1
+2
+3
+4
+5
+--test]]
+
+dump(range(0, 5))
+print('--')
+for i=0,5 do print(i) end
+--[[test
+0
+1
+2
+3
+4
+5
+--
+0
+1
+2
+3
+4
+5
+--test]]
+
+dump(range(0, 5, 1))
+print('--')
+for i=0,5,1 do print(i) end
+--[[test
+0
+1
+2
+3
+4
+5
+--
+0
+1
+2
+3
+4
+5
+--test]]
+
+dump(range(0, 10, 2))
+print('--')
+for i=0,10,2 do print(i) end
+--[[test
+0
+2
+4
+6
+8
+10
+--
+0
+2
+4
+6
+8
+10
+--test]]
+
+dump(range(-5))
+print('--')
+for i=-1,-5,-1 do print(i) end
+--[[test
+-1
+-2
+-3
+-4
+-5
+--
+-1
+-2
+-3
+-4
+-5
+--test]]
+
+dump(range(0, -5, 1))
+print('--')
+for i=0,-5,1 do print(i) end
+--[[test
+--
+--test]]
+
+dump(range(0, -5, -1))
+print('--')
+for i=0,-5,-1 do print(i) end
+--[[test
+0
+-1
+-2
+-3
+-4
+-5
+--
+0
+-1
+-2
+-3
+-4
+-5
+--test]]
+
+dump(range(0, -10, -2))
+print('--')
+for i=0,-10,-2 do print(i) end
+--[[test
+0
+-2
+-4
+-6
+-8
+-10
+--
+0
+-2
+-4
+-6
+-8
+-10
+--test]]
+
+dump(range(1.2, 1.6, 0.1))
+--[[test
+1.2
+1.3
+1.4
+1.5
+--test]]
+
+-- Invalid step
+dump(range(0, 5, 0))
+--[[test
+error: step must not be zero
+--test]]
+
+--------------------------------------------------------------------------------
+-- duplicate
+--------------------------------------------------------------------------------
+
+dump(take(5, duplicate(48)))
+--[[test
+48
+48
+48
+48
+48
+--test]]
+
+dump(take(5, duplicate(1,2,3,4,5)))
+--[[test
+1 2 3 4 5
+1 2 3 4 5
+1 2 3 4 5
+1 2 3 4 5
+1 2 3 4 5
+--test]]
+
+print(xrepeat == duplicate) -- an alias
+--[[test
+true
+--test]]
+
+print(replicate == duplicate) -- an alias
+--[[test
+true
+--test]]
+
+--------------------------------------------------------------------------------
+-- tabulate
+--------------------------------------------------------------------------------
+
+dump(take(5, tabulate(function(x) return 2 * x end)))
+--[[test
+0
+2
+4
+6
+8
+--test]]
+
+--------------------------------------------------------------------------------
+-- zeros
+--------------------------------------------------------------------------------
+
+dump(take(5, zeros()))
+--[[test
+0
+0
+0
+0
+0
+--test]]
+
+--------------------------------------------------------------------------------
+-- ones
+--------------------------------------------------------------------------------
+
+dump(take(5, ones()))
+--[[test
+1
+1
+1
+1
+1
+--test]]
+
+--------------------------------------------------------------------------------
+-- rands
+--------------------------------------------------------------------------------
+
+print(all(function(x) return x >= 0 and x < 1 end, take(5, rands())))
+--[[test
+true
+--test]]
+
+dump(take(5, rands(0)))
+--[[test
+error: empty interval
+--test]]
+
+print(all(function(x) return math.floor(x) == x end, take(5, rands(10))))
+--[[test
+true
+--test]]
+
+print(all(function(x) return math.floor(x) == x end, take(5, rands(1024))))
+--[[test
+true
+--test]]
+
+dump(take(5, rands(0, 1)))
+--[[test
+0
+0
+0
+0
+0
+--test]]
+
+dump(take(5, rands(5, 6)))
+--[[test
+5
+5
+5
+5
+5
+--test]]
+
+print(all(function(x) return x >= 10 and x < 20 end, take(20, rands(10, 20))))
+--[[test
+true
+--test]]
diff --git a/Data/DefaultContent/Libraries/luafun/tests/indexing.lua b/Data/DefaultContent/Libraries/luafun/tests/indexing.lua
new file mode 100644
index 0000000..febc1ae
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/tests/indexing.lua
@@ -0,0 +1,83 @@
+--------------------------------------------------------------------------------
+-- index
+--------------------------------------------------------------------------------
+
+print(index(2, range(5)))
+--[[test
+2
+--test]]
+
+print(index(10, range(5)))
+--[[test
+nil
+--test]]
+
+print(index(2, range(0)))
+--[[test
+nil
+--test]]
+
+print(index("b", {"a", "b", "c", "d", "e"}))
+--[[test
+2
+--test]]
+
+print(index(1, enumerate({"a", "b", "c", "d", "e"})))
+--[[test
+1
+--test]]
+
+print(index("b", "abcdef"))
+--[[test
+2
+--test]]
+
+print(index_of == index) -- an alias
+--[[test
+true
+--test]]
+
+print(elem_index == index) -- an alias
+--[[test
+true
+--test]]
+
+--------------------------------------------------------------------------------
+-- indexes
+--------------------------------------------------------------------------------
+
+dump(indexes("a", {"a", "b", "c", "d", "e", "a", "b", "c", "d", "a", "a"}))
+--[[test
+1
+6
+10
+11
+--test]]
+
+dump(indexes("f", {"a", "b", "c", "d", "e", "a", "b", "c", "d", "a", "a"}))
+--[[test
+--test]]
+
+dump(indexes("f", {}))
+--[[test
+--test]]
+
+dump(indexes(1, enumerate({"a", "b", "c", "d", "e"})))
+--[[test
+1
+--test]]
+
+print(indices == indexes) -- an alias
+--[[test
+true
+--test]]
+
+print(elem_indexes == indexes) -- an alias
+--[[test
+true
+--test]]
+
+print(elem_indices == indexes) -- an alias
+--[[test
+true
+--test]]
diff --git a/Data/DefaultContent/Libraries/luafun/tests/operators.lua b/Data/DefaultContent/Libraries/luafun/tests/operators.lua
new file mode 100644
index 0000000..98ab7bb
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/tests/operators.lua
@@ -0,0 +1,322 @@
+--
+-- All these functions are fully covered by Lua tests.
+-- This test just checks that all functions were defined correctly.
+--
+
+print(op == operator) -- an alias
+--[[test
+true
+--test]]
+
+--------------------------------------------------------------------------------
+-- Comparison operators
+--------------------------------------------------------------------------------
+
+local comparators = { 'le', 'lt', 'eq', 'ne', 'ge', 'gt' }
+for _k, op in iter(comparators) do
+ print('op', op)
+ print('==')
+ print('num:')
+ print(operator[op](0, 1))
+ print(operator[op](1, 0))
+ print(operator[op](0, 0))
+ print('str:')
+ print(operator[op]("abc", "cde"))
+ print(operator[op]("cde", "abc"))
+ print(operator[op]("abc", "abc"))
+ print('')
+end
+--[[test
+op le
+==
+num:
+true
+false
+true
+str:
+true
+false
+true
+
+op lt
+==
+num:
+true
+false
+false
+str:
+true
+false
+false
+
+op eq
+==
+num:
+false
+false
+true
+str:
+false
+false
+true
+
+op ne
+==
+num:
+true
+true
+false
+str:
+true
+true
+false
+
+op ge
+==
+num:
+false
+true
+true
+str:
+false
+true
+true
+
+op gt
+==
+num:
+false
+true
+false
+str:
+false
+true
+false
+
+--test]]
+
+--------------------------------------------------------------------------------
+-- Arithmetic operators
+--------------------------------------------------------------------------------
+
+print(operator.add(-1.0, 1.0))
+print(operator.add(0, 0))
+print(operator.add(12, 2))
+--[[test
+0
+0
+14
+--test]]
+
+print(operator.div(10, 2))
+print(operator.div(10, 3))
+print(operator.div(-10, 3))
+--[[test
+5
+3.3333333333333
+-3.3333333333333
+--test]]
+
+print(operator.floordiv(10, 3))
+print(operator.floordiv(11, 3))
+print(operator.floordiv(12, 3))
+print(operator.floordiv(-10, 3))
+print(operator.floordiv(-11, 3))
+print(operator.floordiv(-12, 3))
+--[[test
+3
+3
+4
+-4
+-4
+-4
+--test]]
+
+print(operator.intdiv(10, 3))
+print(operator.intdiv(11, 3))
+print(operator.intdiv(12, 3))
+print(operator.intdiv(-10, 3))
+print(operator.intdiv(-11, 3))
+print(operator.intdiv(-12, 3))
+--[[test
+3
+3
+4
+-3
+-3
+-4
+--test]]
+
+print(operator.truediv(10, 3))
+print(operator.truediv(11, 3))
+print(operator.truediv(12, 3))
+print(operator.truediv(-10, 3))
+print(operator.truediv(-11, 3))
+print(operator.truediv(-12, 3))
+--[[test
+3.3333333333333
+3.6666666666667
+4
+-3.3333333333333
+-3.6666666666667
+-4
+--test]]
+
+print(operator.mod(10, 2))
+print(operator.mod(10, 3))
+print(operator.mod(-10, 3))
+--[[test
+0
+1
+2
+--test]]
+
+print(operator.mul(10, 0.1))
+print(operator.mul(0, 0))
+print(operator.mul(-1, -1))
+--[[test
+1
+0
+1
+--test]]
+
+print(operator.neq(1))
+print(operator.neq(0) == 0)
+print(operator.neq(-0) == 0)
+print(operator.neq(-1))
+--[[test
+-1
+true
+true
+1
+--test]]
+
+print(operator.unm(1))
+print(operator.unm(0) == 0)
+print(operator.unm(-0) == 0)
+print(operator.unm(-1))
+--[[test
+-1
+true
+true
+1
+--test]]
+
+print(operator.pow(2, 3))
+print(operator.pow(0, 10))
+print(operator.pow(2, 0))
+--[[test
+8
+0
+1
+--test]]
+
+print(operator.sub(2, 3))
+print(operator.sub(0, 10))
+print(operator.sub(2, 2))
+--[[test
+-1
+-10
+0
+--test]]
+
+--------------------------------------------------------------------------------
+-- String operators
+--------------------------------------------------------------------------------
+
+print(operator.concat("aa", "bb"))
+print(operator.concat("aa", ""))
+print(operator.concat("", "bb"))
+--[[test
+aabb
+aa
+bb
+--test]]
+
+print(operator.len(""))
+print(operator.len("ab"))
+print(operator.len("abcd"))
+--[[test
+0
+2
+4
+--test]]
+
+print(operator.length(""))
+print(operator.length("ab"))
+print(operator.length("abcd"))
+--[[test
+0
+2
+4
+--test]]
+
+----------------------------------------------------------------------------
+-- Logical operators
+----------------------------------------------------------------------------
+
+print(operator.land(true, true))
+print(operator.land(true, false))
+print(operator.land(false, true))
+print(operator.land(false, false))
+print(operator.land(1, 0))
+print(operator.land(0, 1))
+print(operator.land(1, 1))
+print(operator.land(0, 0))
+--[[test
+true
+false
+false
+false
+0
+1
+1
+0
+--test]]
+
+print(operator.lor(true, true))
+print(operator.lor(true, false))
+print(operator.lor(false, true))
+print(operator.lor(false, false))
+print(operator.lor(1, 0))
+print(operator.lor(0, 1))
+print(operator.lor(1, 1))
+print(operator.lor(0, 0))
+--[[test
+true
+true
+true
+false
+1
+0
+1
+0
+--test]]
+
+print(operator.lnot(true))
+print(operator.lnot(false))
+print(operator.lor(1))
+print(operator.lor(0))
+--[[test
+false
+true
+1
+0
+--test]]
+
+print(operator.truth(true))
+print(operator.truth(false))
+print(operator.truth(1))
+print(operator.truth(0))
+print(operator.truth(nil))
+print(operator.truth(""))
+print(operator.truth({}))
+--[[test
+true
+false
+true
+true
+false
+true
+true
+--test]]
diff --git a/Data/DefaultContent/Libraries/luafun/tests/reducing.lua b/Data/DefaultContent/Libraries/luafun/tests/reducing.lua
new file mode 100644
index 0000000..8e4aaeb
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/tests/reducing.lua
@@ -0,0 +1,289 @@
+--------------------------------------------------------------------------------
+-- foldl
+--------------------------------------------------------------------------------
+
+print(foldl(function(acc, x) return acc + x end, 0, range(5)))
+--[[test
+15
+--test]]
+
+print(foldl(operator.add, 0, range(5)))
+--[[test
+15
+--test]]
+
+print(foldl(function(acc, x, y) return acc + x * y; end, 0,
+ zip(range(1, 5), {4, 3, 2, 1})))
+--[[test
+20
+--test]]
+
+print(reduce == foldl) -- an alias
+--[[test
+true
+--test]]
+
+--------------------------------------------------------------------------------
+-- length
+--------------------------------------------------------------------------------
+
+print(length({"a", "b", "c", "d", "e"}))
+--[[test
+5
+--test]]
+
+print(length({}))
+--[[test
+0
+--test]]
+
+print(length(range(0)))
+--[[test
+0
+--test]]
+
+--------------------------------------------------------------------------------
+-- is_null
+--------------------------------------------------------------------------------
+
+print(is_null({"a", "b", "c", "d", "e"}))
+--[[test
+false
+--test]]
+
+print(is_null({}))
+--[[test
+true
+--test]]
+
+print(is_null(range(0)))
+--[[test
+true
+--test]]
+
+local gen, init, state = range(5)
+print(is_null(gen, init, state))
+dump(gen, init, state)
+--[[test
+false
+1
+2
+3
+4
+5
+--test]]
+
+--------------------------------------------------------------------------------
+-- is_prefix_of
+--------------------------------------------------------------------------------
+
+print(is_prefix_of({"a"}, {"a", "b", "c"}))
+--[[test
+true
+--test]]
+
+print(is_prefix_of({}, {"a", "b", "c"}))
+--[[test
+true
+--test]]
+
+print(is_prefix_of({}, {}))
+--[[test
+true
+--test]]
+
+print(is_prefix_of({"a"}, {}))
+--[[test
+false
+--test]]
+
+print(is_prefix_of(range(5), range(6)))
+--[[test
+true
+--test]]
+
+print(is_prefix_of(range(6), range(5)))
+--[[test
+false
+--test]]
+
+--------------------------------------------------------------------------------
+-- all
+--------------------------------------------------------------------------------
+
+print(all(function(x) return x end, {true, true, true, true}))
+--[[test
+true
+--test]]
+
+print(all(function(x) return x end, {true, true, true, false}))
+--[[test
+false
+--test]]
+
+print(all(function(x) return x end, {}))
+--[[test
+true
+--test]]
+
+print(every == all) -- an alias
+--[[test
+true
+--test]]
+
+--------------------------------------------------------------------------------
+-- any
+--------------------------------------------------------------------------------
+
+print(any(function(x) return x end, {false, false, false, false}))
+--[[test
+false
+--test]]
+
+print(any(function(x) return x end, {false, false, false, true}))
+--[[test
+true
+--test]]
+
+print(any(function(x) return x end, {}))
+--[[test
+false
+--test]]
+
+print(some == any) -- an alias
+--[[test
+true
+--test]]
+
+--------------------------------------------------------------------------------
+-- sum
+--------------------------------------------------------------------------------
+
+print(sum(range(1, 5)))
+--[[test
+15
+--test]]
+
+print(sum(range(1, 5, 0.5)))
+--[[test
+27
+--test]]
+
+print(sum(range(0)))
+--[[test
+0
+--test]]
+
+--------------------------------------------------------------------------------
+-- product
+--------------------------------------------------------------------------------
+
+print(product(range(1, 5)))
+--[[test
+120
+--test]]
+
+print(product(range(1, 5, 0.5)))
+--[[test
+7087.5
+--test]]
+
+print(product(range(0)))
+--[[test
+1
+--test]]
+
+
+--------------------------------------------------------------------------------
+-- min
+--------------------------------------------------------------------------------
+
+print(min(range(1, 10, 1)))
+--[[test
+1
+--test]]
+
+print(min({"f", "d", "c", "d", "e"}))
+--[[test
+c
+--test]]
+
+print(min({}))
+--[[test
+error: min: iterator is empty
+--test]]
+
+print(minimum == min) -- an alias
+--[[test
+true
+--test]]
+
+--------------------------------------------------------------------------------
+-- min_by
+--------------------------------------------------------------------------------
+
+function min_cmp(a, b) if -a < -b then return a else return b end end
+--[[test
+--test]]
+
+print(min_by(min_cmp, range(1, 10, 1)))
+--[[test
+10
+--test]]
+
+print(min_by(min_cmp, {}))
+--[[test
+error: min: iterator is empty
+--test]]
+
+print(minimum_by == min_by) -- an alias
+--[[test
+true
+--test]]
+
+--------------------------------------------------------------------------------
+-- max
+--------------------------------------------------------------------------------
+
+print(max(range(1, 10, 1)))
+--[[test
+10
+--test]]
+
+print(max({"f", "d", "c", "d", "e"}))
+--[[test
+f
+--test]]
+
+print(max({}))
+--[[test
+error: max: iterator is empty
+--test]]
+
+print(maximum == max) -- an alias
+--[[test
+true
+--test]]
+
+--------------------------------------------------------------------------------
+-- max_by
+--------------------------------------------------------------------------------
+
+function max_cmp(a, b) if -a > -b then return a else return b end end
+--[[test
+--test]]
+
+print(max_by(max_cmp, range(1, 10, 1)))
+--[[test
+1
+--test]]
+
+print(max_by(max_cmp, {}))
+--[[test
+error: max: iterator is empty
+--test]]
+
+print(maximum_by == maximum_by) -- an alias
+--[[test
+true
+--test]]
diff --git a/Data/DefaultContent/Libraries/luafun/tests/runtest b/Data/DefaultContent/Libraries/luafun/tests/runtest
new file mode 100644
index 0000000..f6774f6
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/tests/runtest
@@ -0,0 +1,114 @@
+#!/usr/bin/env lua
+
+package.path = "../?.lua;"..package.path
+require "fun" ()
+function dump(gen, init, state) each(print, gen, init, state) end
+
+local unpack = rawget(table, "unpack") or unpack
+local loadstring = rawget(_G, "loadstring") or load
+
+function file_print(file, ...)
+ local n, i = select("#",...)
+ for i=1,n do
+ local x = select(i, ...)
+ if type(x) == "number" and math.floor(x) == math.ceil(x) then
+ -- A special hack for Lua 5.3: remove .0 for integer
+ x = string.match(select(i,...), '^-?%d+')
+ end
+ file:write(tostring(x))
+ if i~=n then
+ file:write(' ')
+ end
+ end
+ file:write('\n')
+end
+
+local globals = {}
+setmetatable(_G, {
+ __newindex = function(t,k,v)
+ local info = debug.getinfo(2, "S")
+ if info.short_src:sub(1,7) ~= '[string' then
+ local file = info.short_src
+ local func = debug.getinfo(2, "n").name or ""
+ local line = info.linedefined
+ globals[file..':'..line..':'..k] = {file, line, func, k}
+ end
+ rawset(t, k, v)
+ end
+})
+
+local function process(test_name)
+ io.write("Testing ", test_name, "\n")
+ local new_name = test_name..".new"
+ local test_file = io.open(test_name, 'r')
+ local content = test_file:read("*a");
+ test_file:close()
+
+ local new_file = io.open(new_name, 'w')
+
+ local prev_print = print
+ print = function(...) file_print(new_file, ...) end
+
+ io.flush()
+ local expr
+ for expr in content:gmatch("(.-)%s*--%[%[test.-test%]%]") do
+ new_file:write(expr)
+ new_file:write("\n--[[test\n")
+ local res, err = loadstring(expr)
+ if res then
+ res, err = pcall(res, expr)
+ end
+ if not res then
+ new_file:write('error: ', err:match(".-:%d+:%s*(.*)"), "\n")
+ end
+ new_file:write("--test]]")
+ end
+ new_file:write("\n")
+ new_file:close()
+
+ print = prev_print
+
+ local r = os.execute(string.format('diff -U4 "%s" "%s" 2>&1',
+ test_name, new_name))
+ if r then
+ os.remove(new_name)
+ return true
+ else
+ return false
+ end
+end
+
+if #arg <= 0 then
+ io.write("Usage: runtest *.lua", "\n")
+ os.exit(1)
+end
+
+local failed, i = {}
+for i=1,#arg,1 do
+ local test_name = arg[i]
+ if not process(test_name) then
+ table.insert(failed, test_name)
+ end
+end
+
+if #failed > 0 then
+ io.write("\n")
+ io.write("Failed tests:", "\n")
+ for _k,test_name in ipairs(failed) do
+ io.write(" ", test_name, "\n")
+ end
+ io.write("\n", "Please review *.new files and update tests", "\n")
+end
+
+if next(globals) then
+ io.write("\n")
+ io.write("Some global variables have been declared by mistake:", "\n")
+ for k, pollution in pairs(globals) do
+ local file, line, func, var = unpack(pollution)
+ io.write(file..":"..line.." function "..func.."() = var '"..var.."'", "\n")
+ end
+ io.write("\n", "Please declare them with the local statement", "\n")
+elseif #failed == 0 then
+ io.write("All tests have passed!", "\n")
+ os.exit(0)
+end
diff --git a/Data/DefaultContent/Libraries/luafun/tests/slicing.lua b/Data/DefaultContent/Libraries/luafun/tests/slicing.lua
new file mode 100644
index 0000000..c4678c4
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/tests/slicing.lua
@@ -0,0 +1,339 @@
+--------------------------------------------------------------------------------
+-- nth
+--------------------------------------------------------------------------------
+
+print(nth(2, range(5)))
+--[[test
+2
+--test]]
+
+print(nth(10, range(5)))
+--[[test
+nil
+--test]]
+
+print(nth(2, range(0)))
+--[[test
+nil
+--test]]
+
+print(nth(2, {"a", "b", "c", "d", "e"}))
+--[[test
+b
+--test]]
+
+print(nth(2, enumerate({"a", "b", "c", "d", "e"})))
+--[[test
+2 b
+--test]]
+
+print(nth(1, "abcdef"))
+--[[test
+a
+--test]]
+
+print(nth(2, "abcdef"))
+--[[test
+b
+--test]]
+
+print(nth(6, "abcdef"))
+--[[test
+f
+--test]]
+
+print(nth(0, "abcdef"))
+--[[test
+error: invalid first argument to nth
+--test]]
+
+print(nth(7, "abcdef"))
+--[[test
+nil
+--test]]
+
+--------------------------------------------------------------------------------
+-- head
+--------------------------------------------------------------------------------
+
+print(head({"a", "b", "c", "d", "e"}))
+--[[test
+a
+--test]]
+
+print(head({}))
+--[[test
+error: head: iterator is empty
+--test]]
+
+print(head(range(0)))
+--[[test
+error: head: iterator is empty
+--test]]
+
+print(head(enumerate({"a", "b"})))
+--[[test
+1 a
+--test]]
+
+print(car == head) -- an alias
+--[[test
+true
+--test]]
+
+--------------------------------------------------------------------------------
+-- tail
+--------------------------------------------------------------------------------
+
+dump(tail({"a", "b", "c", "d", "e"}))
+--[[test
+b
+c
+d
+e
+--test]]
+
+dump(tail({}))
+--[[test
+--test]]
+
+dump(tail(range(0)))
+--[[test
+--test]]
+
+dump(tail(enumerate({"a", "b"})))
+--[[test
+2 b
+--test]]
+
+print(cdr == tail) -- an alias
+--[[test
+true
+--test]]
+
+
+--------------------------------------------------------------------------------
+-- take_n
+--------------------------------------------------------------------------------
+
+dump(take_n(0, duplicate(48)))
+--[[test
+--test]]
+
+dump(take_n(5, range(0)))
+--[[test
+--test]]
+
+dump(take_n(1, duplicate(48)))
+--[[test
+48
+--test]]
+
+dump(take_n(5, duplicate(48)))
+--[[test
+48
+48
+48
+48
+48
+--test]]
+
+dump(take_n(5, enumerate(duplicate('x'))))
+--[[test
+1 x
+2 x
+3 x
+4 x
+5 x
+--test]]
+
+--------------------------------------------------------------------------------
+-- take_while
+--------------------------------------------------------------------------------
+
+dump(take_while(function(x) return x < 5 end, range(10)))
+--[[test
+1
+2
+3
+4
+--test]]
+
+dump(take_while(function(x) return x < 5 end, range(0)))
+--[[test
+--test]]
+
+dump(take_while(function(x) return x > 100 end, range(10)))
+--[[test
+--test]]
+
+dump(take_while(function(i, a) return i ~=a end, enumerate({5, 2, 1, 3, 4})))
+--[[test
+1 5
+--test]]
+
+--------------------------------------------------------------------------------
+-- take
+--------------------------------------------------------------------------------
+
+dump(take(function(x) return x < 5 end, range(10)))
+--[[test
+1
+2
+3
+4
+--test]]
+
+dump(take(5, duplicate(48)))
+--[[test
+48
+48
+48
+48
+48
+--test]]
+
+--------------------------------------------------------------------------------
+-- drop_n
+--------------------------------------------------------------------------------
+
+dump(drop_n(5, range(10)))
+--[[test
+6
+7
+8
+9
+10
+--test]]
+
+dump(drop_n(0, range(5)))
+--[[test
+1
+2
+3
+4
+5
+--test]]
+
+dump(drop_n(5, range(0)))
+--[[test
+--test]]
+
+dump(drop_n(2, enumerate({'a', 'b', 'c', 'd', 'e'})))
+--[[test
+3 c
+4 d
+5 e
+--test]]
+
+--------------------------------------------------------------------------------
+-- drop_while
+--------------------------------------------------------------------------------
+
+dump(drop_while(function(x) return x < 5 end, range(10)))
+--[[test
+5
+6
+7
+8
+9
+10
+--test]]
+
+dump(drop_while(function(x) return x < 5 end, range(0)))
+--[[test
+--test]]
+
+dump(drop_while(function(x) return x > 100 end, range(10)))
+--[[test
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+--test]]
+
+dump(drop_while(function(i, a) return i ~=a end, enumerate({5, 2, 1, 3, 4})))
+--[[test
+2 2
+3 1
+4 3
+5 4
+--test]]
+
+dump(drop_while(function(i, a) return i ~=a end,
+ zip({1, 2, 3, 4, 5}, {5, 4, 3, 2, 1})))
+--[[test
+3 3
+4 2
+5 1
+--test]]
+
+--------------------------------------------------------------------------------
+-- drop
+--------------------------------------------------------------------------------
+
+dump(drop(5, range(10)))
+--[[test
+6
+7
+8
+9
+10
+--test]]
+
+dump(drop(function(x) return x < 5 end, range(10)))
+--[[test
+5
+6
+7
+8
+9
+10
+--test]]
+
+
+--------------------------------------------------------------------------------
+-- span
+--------------------------------------------------------------------------------
+
+dump(zip(span(function(x) return x < 5 end, range(10))))
+--[[test
+1 5
+2 6
+3 7
+4 8
+--test]]
+
+dump(zip(span(5, range(10))))
+--[[test
+1 6
+2 7
+3 8
+4 9
+5 10
+--test]]
+
+dump(zip(span(function(x) return x < 5 end, range(0))))
+--[[test
+--test]]
+
+dump(zip(span(function(x) return x < 5 end, range(5))))
+--[[test
+1 5
+--test]]
+
+print(split == span) -- an alias
+--[[test
+true
+--test]]
+
+print(split_at == span) -- an alias
+--[[test
+true
+--test]]
diff --git a/Data/DefaultContent/Libraries/luafun/tests/transformations.lua b/Data/DefaultContent/Libraries/luafun/tests/transformations.lua
new file mode 100644
index 0000000..b4fddab
--- /dev/null
+++ b/Data/DefaultContent/Libraries/luafun/tests/transformations.lua
@@ -0,0 +1,107 @@
+--------------------------------------------------------------------------------
+-- map
+--------------------------------------------------------------------------------
+
+fun = function(...) return 'map', ... end
+
+dump(map(fun, range(0)))
+--[[test
+--test]]
+
+
+dump(map(fun, range(4)))
+--[[test
+map 1
+map 2
+map 3
+map 4
+--test]]
+
+dump(map(fun, enumerate({"a", "b", "c", "d", "e"})))
+--[[test
+map 1 a
+map 2 b
+map 3 c
+map 4 d
+map 5 e
+--test]]
+
+dump(map(function(x) return 2 * x end, range(4)))
+--[[test
+2
+4
+6
+8
+--test]]
+
+fun = nil
+--[[test
+--test]]
+
+--------------------------------------------------------------------------------
+-- enumerate
+--------------------------------------------------------------------------------
+
+dump(enumerate({"a", "b", "c", "d", "e"}))
+--[[test
+1 a
+2 b
+3 c
+4 d
+5 e
+--test]]
+
+dump(enumerate(enumerate(enumerate({"a", "b", "c", "d", "e"}))))
+--[[test
+1 1 1 a
+2 2 2 b
+3 3 3 c
+4 4 4 d
+5 5 5 e
+--test]]
+
+dump(enumerate(zip({"one", "two", "three", "four", "five"},
+ {"a", "b", "c", "d", "e"})))
+--[[test
+1 one a
+2 two b
+3 three c
+4 four d
+5 five e
+--test]]
+
+--------------------------------------------------------------------------------
+-- intersperse
+--------------------------------------------------------------------------------
+
+dump(intersperse("x", {}))
+
+dump(intersperse("x", {"a", "b", "c", "d", "e"}))
+--[[test
+a
+x
+b
+x
+c
+x
+d
+x
+e
+x
+--test]]
+
+dump(intersperse("x", {"a", "b", "c", "d", "e", "f"}))
+--[[test
+a
+x
+b
+x
+c
+x
+d
+x
+e
+x
+f
+x
+--test]]
diff --git a/Data/DefaultContent/Libraries/md5.lua/.travis.yml b/Data/DefaultContent/Libraries/md5.lua/.travis.yml
new file mode 100644
index 0000000..90bd434
--- /dev/null
+++ b/Data/DefaultContent/Libraries/md5.lua/.travis.yml
@@ -0,0 +1,34 @@
+language: python
+sudo: false
+
+env:
+ - LUA="lua=5.1"
+ - LUA="lua=5.2"
+ - LUA="lua=5.3"
+ - LUA="luajit=2.0"
+ - LUA="luajit=2.1"
+
+before_install:
+ - pip install hererocks
+ - hererocks lua_install -r^ --$LUA
+ - export PATH=$PATH:$PWD/lua_install/bin # Add directory with all installed binaries to PATH
+
+install:
+ - luarocks install busted
+ - luarocks install luacov
+ - luarocks install luacov-coveralls
+
+script:
+ - busted --verbose --coverage
+
+after_success:
+ - luacov-coveralls --exclude $TRAVIS_BUILD_DIR/lua_install
+
+branches:
+ except:
+ - gh-pages
+
+notifications:
+ email:
+ on_success: change
+ on_failure: always
diff --git a/Data/DefaultContent/Libraries/md5.lua/CHANGELOG.md b/Data/DefaultContent/Libraries/md5.lua/CHANGELOG.md
new file mode 100644
index 0000000..a48c47a
--- /dev/null
+++ b/Data/DefaultContent/Libraries/md5.lua/CHANGELOG.md
@@ -0,0 +1,5 @@
+
+# 1.1.0
+
+* Fixes error with long strings in Lua 5.1 (@pgimeno)
+* Adds incremental mode (@pgimeno)
diff --git a/Data/DefaultContent/Libraries/md5.lua/MIT-LICENSE.txt b/Data/DefaultContent/Libraries/md5.lua/MIT-LICENSE.txt
new file mode 100644
index 0000000..1630e47
--- /dev/null
+++ b/Data/DefaultContent/Libraries/md5.lua/MIT-LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2013 Enrique García Cota + Adam Baldwin + hanzao + Equi 4 Software
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Data/DefaultContent/Libraries/md5.lua/README.md b/Data/DefaultContent/Libraries/md5.lua/README.md
new file mode 100644
index 0000000..ee7bbd8
--- /dev/null
+++ b/Data/DefaultContent/Libraries/md5.lua/README.md
@@ -0,0 +1,62 @@
+md5.lua [![Build Status](https://travis-ci.org/kikito/md5.lua.svg)](https://travis-ci.org/kikito/md5.lua)
+=========================================================================================================
+
+This pure-Lua module computes md5 in Lua 5.1, Lua 5.2 and LuaJIT, using native bit-manipulation libraries when available, and falling back to table-based manipulation of integers in 5.1.
+
+It implements md5.sum and md5.sumhex like the [kernel project md5 package](http://www.keplerproject.org/md5/), but it's done completely in Lua, with no dependencies on other libs or C files.
+
+Usage
+=====
+
+Simple example:
+
+ local md5 = require 'md5'
+
+ local md5_as_data = md5.sum(message) -- returns raw bytes
+ local md5_as_hex = md5.sumhexa(message) -- returns a hex string
+ local md5_as_hex2 = md5.tohex(md5_as_data) -- returns the same string as md5_as_hex
+
+Incremental example (for computing md5 of streams, or big files which have to be loaded in chunks - new since 1.1.0):
+
+ local m = md5.new()
+ m:update('some bytes')
+ m:update('some more bytes')
+ m:update('etc')
+ return md5.tohex(m:finish())
+
+Credits
+=======
+
+This is a cleanup of an implementation by Adam Baldwin - https://gist.github.com/evilpacket/3647908
+
+Which in turn was a mix of the bitwise lib, http://luaforge.net/projects/bit/ by hanzhao (`abrash_han - at - hotmail.com`),
+and http://equi4.com/md5/md5calc.lua, by Equi 4 Software.
+
+Lua 5.2 and LuaJIT compatibility by [Positive07](https://github.com/kikito/md5.lua/pull/2)
+
+A very important fix and the incremental variant by [pgimeno](https://github.com/kikito/md5.lua/pull/10)
+
+
+License
+=======
+
+This library, as well as all the previous ones in which is based, is released under the MIT license (See license file for details).
+
+Specs
+=====
+
+The specs for this library are implemented with [busted](http://ovinelabs.com/busted/). In order to run them, install busted and then:
+
+ cd path/to/where/the/spec/folder/is
+ busted
+
+Install
+=======
+
+Either copy the file or using luarocks:
+
+ luarocks install --server=http://luarocks.org/manifests/kikito md5
+
+
+
+
diff --git a/Data/DefaultContent/Libraries/md5.lua/md5.lua b/Data/DefaultContent/Libraries/md5.lua/md5.lua
new file mode 100644
index 0000000..5e73ba6
--- /dev/null
+++ b/Data/DefaultContent/Libraries/md5.lua/md5.lua
@@ -0,0 +1,396 @@
+local md5 = {
+ _VERSION = "md5.lua 1.1.0",
+ _DESCRIPTION = "MD5 computation in Lua (5.1-3, LuaJIT)",
+ _URL = "https://github.com/kikito/md5.lua",
+ _LICENSE = [[
+ MIT LICENSE
+
+ Copyright (c) 2013 Enrique García Cota + Adam Baldwin + hanzao + Equi 4 Software
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ ]]
+}
+
+-- bit lib implementions
+
+local char, byte, format, rep, sub =
+ string.char, string.byte, string.format, string.rep, string.sub
+local bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift
+
+local ok, bit = pcall(require, 'bit')
+if ok then
+ bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift = bit.bor, bit.band, bit.bnot, bit.bxor, bit.rshift, bit.lshift
+else
+ ok, bit = pcall(require, 'bit32')
+
+ if ok then
+
+ bit_not = bit.bnot
+
+ local tobit = function(n)
+ return n <= 0x7fffffff and n or -(bit_not(n) + 1)
+ end
+
+ local normalize = function(f)
+ return function(a,b) return tobit(f(tobit(a), tobit(b))) end
+ end
+
+ bit_or, bit_and, bit_xor = normalize(bit.bor), normalize(bit.band), normalize(bit.bxor)
+ bit_rshift, bit_lshift = normalize(bit.rshift), normalize(bit.lshift)
+
+ else
+
+ local function tbl2number(tbl)
+ local result = 0
+ local power = 1
+ for i = 1, #tbl do
+ result = result + tbl[i] * power
+ power = power * 2
+ end
+ return result
+ end
+
+ local function expand(t1, t2)
+ local big, small = t1, t2
+ if(#big < #small) then
+ big, small = small, big
+ end
+ -- expand small
+ for i = #small + 1, #big do
+ small[i] = 0
+ end
+ end
+
+ local to_bits -- needs to be declared before bit_not
+
+ bit_not = function(n)
+ local tbl = to_bits(n)
+ local size = math.max(#tbl, 32)
+ for i = 1, size do
+ if(tbl[i] == 1) then
+ tbl[i] = 0
+ else
+ tbl[i] = 1
+ end
+ end
+ return tbl2number(tbl)
+ end
+
+ -- defined as local above
+ to_bits = function (n)
+ if(n < 0) then
+ -- negative
+ return to_bits(bit_not(math.abs(n)) + 1)
+ end
+ -- to bits table
+ local tbl = {}
+ local cnt = 1
+ local last
+ while n > 0 do
+ last = n % 2
+ tbl[cnt] = last
+ n = (n-last)/2
+ cnt = cnt + 1
+ end
+
+ return tbl
+ end
+
+ bit_or = function(m, n)
+ local tbl_m = to_bits(m)
+ local tbl_n = to_bits(n)
+ expand(tbl_m, tbl_n)
+
+ local tbl = {}
+ for i = 1, #tbl_m do
+ if(tbl_m[i]== 0 and tbl_n[i] == 0) then
+ tbl[i] = 0
+ else
+ tbl[i] = 1
+ end
+ end
+
+ return tbl2number(tbl)
+ end
+
+ bit_and = function(m, n)
+ local tbl_m = to_bits(m)
+ local tbl_n = to_bits(n)
+ expand(tbl_m, tbl_n)
+
+ local tbl = {}
+ for i = 1, #tbl_m do
+ if(tbl_m[i]== 0 or tbl_n[i] == 0) then
+ tbl[i] = 0
+ else
+ tbl[i] = 1
+ end
+ end
+
+ return tbl2number(tbl)
+ end
+
+ bit_xor = function(m, n)
+ local tbl_m = to_bits(m)
+ local tbl_n = to_bits(n)
+ expand(tbl_m, tbl_n)
+
+ local tbl = {}
+ for i = 1, #tbl_m do
+ if(tbl_m[i] ~= tbl_n[i]) then
+ tbl[i] = 1
+ else
+ tbl[i] = 0
+ end
+ end
+
+ return tbl2number(tbl)
+ end
+
+ bit_rshift = function(n, bits)
+ local high_bit = 0
+ if(n < 0) then
+ -- negative
+ n = bit_not(math.abs(n)) + 1
+ high_bit = 0x80000000
+ end
+
+ local floor = math.floor
+
+ for i=1, bits do
+ n = n/2
+ n = bit_or(floor(n), high_bit)
+ end
+ return floor(n)
+ end
+
+ bit_lshift = function(n, bits)
+ if(n < 0) then
+ -- negative
+ n = bit_not(math.abs(n)) + 1
+ end
+
+ for i=1, bits do
+ n = n*2
+ end
+ return bit_and(n, 0xFFFFFFFF)
+ end
+ end
+end
+
+-- convert little-endian 32-bit int to a 4-char string
+local function lei2str(i)
+ local f=function (s) return char( bit_and( bit_rshift(i, s), 255)) end
+ return f(0)..f(8)..f(16)..f(24)
+end
+
+-- convert raw string to big-endian int
+local function str2bei(s)
+ local v=0
+ for i=1, #s do
+ v = v * 256 + byte(s, i)
+ end
+ return v
+end
+
+-- convert raw string to little-endian int
+local function str2lei(s)
+ local v=0
+ for i = #s,1,-1 do
+ v = v*256 + byte(s, i)
+ end
+ return v
+end
+
+-- cut up a string in little-endian ints of given size
+local function cut_le_str(s,...)
+ local o, r = 1, {}
+ local args = {...}
+ for i=1, #args do
+ table.insert(r, str2lei(sub(s, o, o + args[i] - 1)))
+ o = o + args[i]
+ end
+ return r
+end
+
+local swap = function (w) return str2bei(lei2str(w)) end
+
+-- An MD5 mplementation in Lua, requires bitlib (hacked to use LuaBit from above, ugh)
+-- 10/02/2001 jcw@equi4.com
+
+local CONSTS = {
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
+ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476
+}
+
+local f=function (x,y,z) return bit_or(bit_and(x,y),bit_and(-x-1,z)) end
+local g=function (x,y,z) return bit_or(bit_and(x,z),bit_and(y,-z-1)) end
+local h=function (x,y,z) return bit_xor(x,bit_xor(y,z)) end
+local i=function (x,y,z) return bit_xor(y,bit_or(x,-z-1)) end
+local z=function (ff,a,b,c,d,x,s,ac)
+ a=bit_and(a+ff(b,c,d)+x+ac,0xFFFFFFFF)
+ -- be *very* careful that left shift does not cause rounding!
+ return bit_or(bit_lshift(bit_and(a,bit_rshift(0xFFFFFFFF,s)),s),bit_rshift(a,32-s))+b
+end
+
+local function transform(A,B,C,D,X)
+ local a,b,c,d=A,B,C,D
+ local t=CONSTS
+
+ a=z(f,a,b,c,d,X[ 0], 7,t[ 1])
+ d=z(f,d,a,b,c,X[ 1],12,t[ 2])
+ c=z(f,c,d,a,b,X[ 2],17,t[ 3])
+ b=z(f,b,c,d,a,X[ 3],22,t[ 4])
+ a=z(f,a,b,c,d,X[ 4], 7,t[ 5])
+ d=z(f,d,a,b,c,X[ 5],12,t[ 6])
+ c=z(f,c,d,a,b,X[ 6],17,t[ 7])
+ b=z(f,b,c,d,a,X[ 7],22,t[ 8])
+ a=z(f,a,b,c,d,X[ 8], 7,t[ 9])
+ d=z(f,d,a,b,c,X[ 9],12,t[10])
+ c=z(f,c,d,a,b,X[10],17,t[11])
+ b=z(f,b,c,d,a,X[11],22,t[12])
+ a=z(f,a,b,c,d,X[12], 7,t[13])
+ d=z(f,d,a,b,c,X[13],12,t[14])
+ c=z(f,c,d,a,b,X[14],17,t[15])
+ b=z(f,b,c,d,a,X[15],22,t[16])
+
+ a=z(g,a,b,c,d,X[ 1], 5,t[17])
+ d=z(g,d,a,b,c,X[ 6], 9,t[18])
+ c=z(g,c,d,a,b,X[11],14,t[19])
+ b=z(g,b,c,d,a,X[ 0],20,t[20])
+ a=z(g,a,b,c,d,X[ 5], 5,t[21])
+ d=z(g,d,a,b,c,X[10], 9,t[22])
+ c=z(g,c,d,a,b,X[15],14,t[23])
+ b=z(g,b,c,d,a,X[ 4],20,t[24])
+ a=z(g,a,b,c,d,X[ 9], 5,t[25])
+ d=z(g,d,a,b,c,X[14], 9,t[26])
+ c=z(g,c,d,a,b,X[ 3],14,t[27])
+ b=z(g,b,c,d,a,X[ 8],20,t[28])
+ a=z(g,a,b,c,d,X[13], 5,t[29])
+ d=z(g,d,a,b,c,X[ 2], 9,t[30])
+ c=z(g,c,d,a,b,X[ 7],14,t[31])
+ b=z(g,b,c,d,a,X[12],20,t[32])
+
+ a=z(h,a,b,c,d,X[ 5], 4,t[33])
+ d=z(h,d,a,b,c,X[ 8],11,t[34])
+ c=z(h,c,d,a,b,X[11],16,t[35])
+ b=z(h,b,c,d,a,X[14],23,t[36])
+ a=z(h,a,b,c,d,X[ 1], 4,t[37])
+ d=z(h,d,a,b,c,X[ 4],11,t[38])
+ c=z(h,c,d,a,b,X[ 7],16,t[39])
+ b=z(h,b,c,d,a,X[10],23,t[40])
+ a=z(h,a,b,c,d,X[13], 4,t[41])
+ d=z(h,d,a,b,c,X[ 0],11,t[42])
+ c=z(h,c,d,a,b,X[ 3],16,t[43])
+ b=z(h,b,c,d,a,X[ 6],23,t[44])
+ a=z(h,a,b,c,d,X[ 9], 4,t[45])
+ d=z(h,d,a,b,c,X[12],11,t[46])
+ c=z(h,c,d,a,b,X[15],16,t[47])
+ b=z(h,b,c,d,a,X[ 2],23,t[48])
+
+ a=z(i,a,b,c,d,X[ 0], 6,t[49])
+ d=z(i,d,a,b,c,X[ 7],10,t[50])
+ c=z(i,c,d,a,b,X[14],15,t[51])
+ b=z(i,b,c,d,a,X[ 5],21,t[52])
+ a=z(i,a,b,c,d,X[12], 6,t[53])
+ d=z(i,d,a,b,c,X[ 3],10,t[54])
+ c=z(i,c,d,a,b,X[10],15,t[55])
+ b=z(i,b,c,d,a,X[ 1],21,t[56])
+ a=z(i,a,b,c,d,X[ 8], 6,t[57])
+ d=z(i,d,a,b,c,X[15],10,t[58])
+ c=z(i,c,d,a,b,X[ 6],15,t[59])
+ b=z(i,b,c,d,a,X[13],21,t[60])
+ a=z(i,a,b,c,d,X[ 4], 6,t[61])
+ d=z(i,d,a,b,c,X[11],10,t[62])
+ c=z(i,c,d,a,b,X[ 2],15,t[63])
+ b=z(i,b,c,d,a,X[ 9],21,t[64])
+
+ return bit_and(A+a,0xFFFFFFFF),bit_and(B+b,0xFFFFFFFF),
+ bit_and(C+c,0xFFFFFFFF),bit_and(D+d,0xFFFFFFFF)
+end
+
+----------------------------------------------------------------
+
+local function md5_update(self, s)
+ self.pos = self.pos + #s
+ s = self.buf .. s
+ for ii = 1, #s - 63, 64 do
+ local X = cut_le_str(sub(s,ii,ii+63),4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4)
+ assert(#X == 16)
+ X[0] = table.remove(X,1) -- zero based!
+ self.a,self.b,self.c,self.d = transform(self.a,self.b,self.c,self.d,X)
+ end
+ self.buf = sub(s, math.floor(#s/64)*64 + 1, #s)
+ return self
+end
+
+local function md5_finish(self)
+ local msgLen = self.pos
+ local padLen = 56 - msgLen % 64
+
+ if msgLen % 64 > 56 then padLen = padLen + 64 end
+
+ if padLen == 0 then padLen = 64 end
+
+ local s = char(128) .. rep(char(0),padLen-1) .. lei2str(bit_and(8*msgLen, 0xFFFFFFFF)) .. lei2str(math.floor(msgLen/0x20000000))
+ md5_update(self, s)
+
+ assert(self.pos % 64 == 0)
+ return lei2str(self.a) .. lei2str(self.b) .. lei2str(self.c) .. lei2str(self.d)
+end
+
+----------------------------------------------------------------
+
+function md5.new()
+ return { a = CONSTS[65], b = CONSTS[66], c = CONSTS[67], d = CONSTS[68],
+ pos = 0,
+ buf = '',
+ update = md5_update,
+ finish = md5_finish }
+end
+
+function md5.tohex(s)
+ return format("%08x%08x%08x%08x", str2bei(sub(s, 1, 4)), str2bei(sub(s, 5, 8)), str2bei(sub(s, 9, 12)), str2bei(sub(s, 13, 16)))
+end
+
+function md5.sum(s)
+ return md5.new():update(s):finish()
+end
+
+function md5.sumhexa(s)
+ return md5.tohex(md5.sum(s))
+end
+
+return md5
diff --git a/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-0.rockspec b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-0.rockspec
new file mode 100644
index 0000000..4103148
--- /dev/null
+++ b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-0.rockspec
@@ -0,0 +1,21 @@
+package = "md5"
+version = "1.0-0"
+source = {
+ url = "https://github.com/kikito/md5.lua/archive/v1.0.0.tar.gz",
+ dir = "md5.lua-1.0.0"
+}
+description = {
+ summary = "MD5 sum in pure Lua, with no C and no external dependencies",
+ detailed = "This pure-Lua module computes md5 in Lua 5.1, Lua 5.2 and LuaJIT, using native bit-manipulation libraries when available, and falling back to table-based manipulation of integers in 5.1",
+ homepage = "https://github.com/kikito/md5.lua",
+ license = "MIT"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ md5 = "md5.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-1.rockspec b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-1.rockspec
new file mode 100644
index 0000000..f9f5203
--- /dev/null
+++ b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-1.rockspec
@@ -0,0 +1,21 @@
+package = "md5"
+version = "1.0-1"
+source = {
+ url = "https://github.com/kikito/md5.lua/archive/v1.0.1.tar.gz",
+ dir = "md5.lua-1.0.1"
+}
+description = {
+ summary = "MD5 sum in pure Lua, with no C and no external dependencies",
+ detailed = "This pure-Lua module computes md5 in Lua 5.1, Lua 5.2 and LuaJIT, using native bit-manipulation libraries when available, and falling back to table-based manipulation of integers in 5.1",
+ homepage = "https://github.com/kikito/md5.lua",
+ license = "MIT"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ md5 = "md5.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-2.rockspec b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-2.rockspec
new file mode 100644
index 0000000..c8034f9
--- /dev/null
+++ b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.0-2.rockspec
@@ -0,0 +1,21 @@
+package = "md5"
+version = "1.0-2"
+source = {
+ url = "https://github.com/kikito/md5.lua/archive/v1.0.2.tar.gz",
+ dir = "md5.lua-1.0.2"
+}
+description = {
+ summary = "MD5 sum in pure Lua, with no C and no external dependencies",
+ detailed = "This pure-Lua module computes md5 in Lua 5.1, Lua 5.2 and LuaJIT, using native bit-manipulation libraries when available, and falling back to table-based manipulation of integers in 5.1",
+ homepage = "https://github.com/kikito/md5.lua",
+ license = "MIT"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ md5 = "md5.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.1-0.rockspec b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.1-0.rockspec
new file mode 100644
index 0000000..ef1b392
--- /dev/null
+++ b/Data/DefaultContent/Libraries/md5.lua/rockspecs/md5-1.1-0.rockspec
@@ -0,0 +1,21 @@
+package = "md5"
+version = "1.1-0"
+source = {
+ url = "https://github.com/kikito/md5.lua/archive/v1.1.0.tar.gz",
+ dir = "md5.lua-1.1.0"
+}
+description = {
+ summary = "MD5 sum in pure Lua, with no C and no external dependencies",
+ detailed = "This pure-Lua module computes md5 in Lua 5.1, Lua 5.2 and LuaJIT, using native bit-manipulation libraries when available, and falling back to table-based manipulation of integers in 5.1",
+ homepage = "https://github.com/kikito/md5.lua",
+ license = "MIT"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ md5 = "md5.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/md5.lua/spec/md5_spec.lua b/Data/DefaultContent/Libraries/md5.lua/spec/md5_spec.lua
new file mode 100644
index 0000000..69dde39
--- /dev/null
+++ b/Data/DefaultContent/Libraries/md5.lua/spec/md5_spec.lua
@@ -0,0 +1,40 @@
+local md5 = require('md5')
+
+local function hex2bin(hex)
+ local result, _ = hex:gsub('..', function(hexval)
+ return string.char(tonumber(hexval, 16))
+ end)
+ return result
+end
+
+describe('md5', function()
+ describe('md5.sumhexa', function()
+ it('works', function()
+ assert.equal(md5.sumhexa("asdf"), '912ec803b2ce49e4a541068d495ab570')
+ assert.equal(md5.sumhexa('The quick brown fox jumps over the lazy dog'), '9e107d9d372bb6826bd81d3542a419d6')
+ assert.equal(md5.sumhexa('The quick brown fox jumps over the lazy dog.'), 'e4d909c290d0fb1ca068ffaddf22cbd0')
+ assert.equal(md5.sumhexa(''), 'd41d8cd98f00b204e9800998ecf8427e')
+ assert.equal(md5.sumhexa(('1'):rep(824)), 'a126fd3611ab8d9b7e8a3384e2fa78a0')
+ assert.equal(md5.sumhexa(('1'):rep(1528)), '3750b6a29d923b633e05d6ae76895664')
+ local state = md5.new()
+ state:update('Hello')
+ state:update(', World!')
+ assert.equal(md5.tohex(state:finish()), '65a8e27d8879283831b664bd8b7f0ad4')
+ end)
+ end)
+
+ describe('md5.sum', function()
+ it('works', function()
+ assert.equal(md5.sum("asdf"), hex2bin '912ec803b2ce49e4a541068d495ab570')
+ assert.equal(md5.sum('The quick brown fox jumps over the lazy dog'), hex2bin '9e107d9d372bb6826bd81d3542a419d6')
+ assert.equal(md5.sum('The quick brown fox jumps over the lazy dog.'), hex2bin 'e4d909c290d0fb1ca068ffaddf22cbd0')
+ assert.equal(md5.sum(''), hex2bin 'd41d8cd98f00b204e9800998ecf8427e')
+ assert.equal(md5.sum(('1'):rep(824)), hex2bin 'a126fd3611ab8d9b7e8a3384e2fa78a0')
+ assert.equal(md5.sum(('1'):rep(1528)), hex2bin '3750b6a29d923b633e05d6ae76895664')
+ local state = md5.new()
+ state:update('Hello')
+ state:update(', World!')
+ assert.equal(state:finish(), hex2bin '65a8e27d8879283831b664bd8b7f0ad4')
+ end)
+ end)
+end)
diff --git a/Data/DefaultContent/Libraries/middleclass/.travis.yml b/Data/DefaultContent/Libraries/middleclass/.travis.yml
new file mode 100644
index 0000000..53998d6
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/.travis.yml
@@ -0,0 +1,36 @@
+language: python
+sudo: false
+
+env:
+ - LUA="lua=5.1"
+ - LUA="lua=5.2"
+ - LUA="lua=5.3"
+ - LUA="luajit=2.0"
+ - LUA="luajit=2.1"
+
+before_install:
+ - pip install hererocks
+ - hererocks lua_install -r^ --$LUA
+ - export PATH=$PATH:$PWD/lua_install/bin # Add directory with all installed binaries to PATH
+
+install:
+ - luarocks install luacheck
+ - luarocks install busted
+ - luarocks install luacov
+ - luarocks install luacov-coveralls
+
+script:
+ - luacheck --no-unused-args --std max+busted *.lua spec
+ - busted --verbose --coverage
+
+after_success:
+ - luacov-coveralls --exclude $TRAVIS_BUILD_DIR/lua_install
+
+branches:
+ except:
+ - gh-pages
+
+notifications:
+ email:
+ on_success: change
+ on_failure: always
diff --git a/Data/DefaultContent/Libraries/middleclass/CHANGELOG.md b/Data/DefaultContent/Libraries/middleclass/CHANGELOG.md
new file mode 100644
index 0000000..5f8b93a
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/CHANGELOG.md
@@ -0,0 +1,55 @@
+middleclass changelog
+====================
+
+# Version 4.1.1
+
+* Fixed a bug in which `static` values which evaluated to `false` were not available
+ in subclasses (#51, thanks @qaisjp for the patch!)
+* `isInstanceOf` does not throw an error any more when its first parameter is a
+ primitive (#55) (This effectively undoes the change introduced in 4.1.0)
+
+
+# Version 4.1.0
+
+* Simplifies implementation of `isInstanceOf` and `isSubclassOf`. They will now raise an error if their first
+ parameter (the `self`) isn't an instance or a class respectively.
+
+# Version 4.0.0
+
+* Unified the method and metamethod lookup into a single algorithm
+* Added the capacity of setting up the `__index` metamethod in classes
+* Removed global `Object` (classes created with `class(<name>)` have no superclass now)
+* Removed default method `Class:implements(<mixin>)`
+* Renamed several internal functions
+
+# Version 3.2.0
+
+* Changed the way metamethods were handled to fix certain bugs (un-stubbed metamethods could not be inherited)
+
+# Version 3.1.0
+
+* Added Lua 5.3 metamethod support (`__band`, `__bor`, `__bxor`, `__shl`, `__bnot`)
+
+# Version 3.0.1
+
+* Added `__len`, `__ipairs` and `__pairs` metamethods for Lua 5.2
+
+# Version 3.0
+
+* Anything that behaves reasonably like a class can be a class (no internal list of classes)
+* The `class` global function is now just the return value of `require
+'middleclass'`. It is a callable table, but works exactly as before.
+* The global variable `Object` becomes `class.Object`
+* The global function `instanceOf` becomes `class.Object.isInstanceOf`. Parameter order is reversed.
+* The global function `subclassOf` becomes `class.Object.static.isSubclassOf`. Parameter order is reversed.
+* The global function `implements` becomes `class.Object.static.implements`. Parameter order is reversed.
+* Specs have been translated from telescope to busted
+
+# Version 2.0
+
+* Static methods are now separated from instance methods
+* class.superclass has now become class.super
+* It's now possible to do class.subclasses
+* middleclass is now a single file; init.lua has dissapeared
+* license is changed from BSD to MIT. License included in source FTW
+
diff --git a/Data/DefaultContent/Libraries/middleclass/MIT-LICENSE.txt b/Data/DefaultContent/Libraries/middleclass/MIT-LICENSE.txt
new file mode 100644
index 0000000..525287a
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/MIT-LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2011 Enrique García Cota
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Data/DefaultContent/Libraries/middleclass/README.md b/Data/DefaultContent/Libraries/middleclass/README.md
new file mode 100644
index 0000000..fc1153b
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/README.md
@@ -0,0 +1,80 @@
+middleclass
+===========
+
+[![Build Status](https://travis-ci.org/kikito/middleclass.png?branch=master)](https://travis-ci.org/kikito/middleclass)
+[![Coverage Status](https://coveralls.io/repos/kikito/middleclass/badge.svg?branch=master&service=github)](https://coveralls.io/github/kikito/middleclass?branch=master)
+
+A simple OOP library for Lua. It has inheritance, metamethods (operators), class variables and weak mixin support.
+
+Quick Look
+==========
+
+```lua
+local class = require 'middleclass'
+
+local Fruit = class('Fruit') -- 'Fruit' is the class' name
+
+function Fruit:initialize(sweetness)
+ self.sweetness = sweetness
+end
+
+Fruit.static.sweetness_threshold = 5 -- class variable (also admits methods)
+
+function Fruit:isSweet()
+ return self.sweetness > Fruit.sweetness_threshold
+end
+
+local Lemon = class('Lemon', Fruit) -- subclassing
+
+function Lemon:initialize()
+ Fruit.initialize(self, 1) -- invoking the superclass' initializer
+end
+
+local lemon = Lemon:new()
+
+print(lemon:isSweet()) -- false
+```
+
+Documentation
+=============
+
+See the [github wiki page](https://github.com/kikito/middleclass/wiki) for examples & documentation.
+
+You can read the `CHANGELOG.md` file to see what has changed on each version of this library.
+
+If you need help updating to a new middleclass version, read `UPDATING.md`.
+
+Installation
+============
+
+Just copy the middleclass.lua file wherever you want it (for example on a lib/ folder). Then write this in any Lua file where you want to use it:
+
+```lua
+local class = require 'middleclass'
+```
+
+Specs
+=====
+
+This project uses [busted](http://olivinelabs.com/busted/) for its specs. If you want to run the specs, you will have to install it first. Then just execute the following:
+
+```bash
+cd /folder/where/the/spec/folder/is
+busted
+```
+
+Performance tests
+=================
+
+Middleclass also comes with a small performance test suite. Just run the following command:
+
+```bash
+lua performance/run.lua
+```
+
+License
+=======
+
+Middleclass is distributed under the MIT license.
+
+
diff --git a/Data/DefaultContent/Libraries/middleclass/UPDATING.md b/Data/DefaultContent/Libraries/middleclass/UPDATING.md
new file mode 100644
index 0000000..83855c9
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/UPDATING.md
@@ -0,0 +1,69 @@
+Updating from 3.x to 4.x
+========================
+
+In middleclass 4.0 there is no global `Object` class any more. Classes created with `class(<name>)` don't have a superclass any more.
+If you need a global `Object` class, you must create it explicitly and then use it when creating new classes:
+
+```lua
+local Object = class('Object')
+
+...
+
+local MyClass = class('MyClass', Object)
+```
+
+If you are using a library which depends on the internal implementation of middleclass they might not work with middleclass 4.0. You might need to update those other libraries.
+
+Middleclass 4.0 comes with support for `__index` metamethod support. If your library manipulated the classes' `__instanceDict` internal attribute, you might do the same thing now using `__index` instead.
+
+Also note that the class method `:implements` has been removed.
+
+Updating from 2.x to 3.x
+========================
+
+Middleclass used to expose several global variables on the main scope. It does not do that anymore.
+
+`class` is now returned by `require 'middleclass'`, and it is not set globally. So you can do this:
+
+```lua
+local class = require 'middleclass'
+local MyClass = class('MyClass') -- works as before
+```
+
+`Object` is not a global variable any more. But you can get it from `class.Object`
+
+```lua
+local class = require 'middleclass'
+local Object = class.Object
+
+print(Object) -- prints 'class Object'
+```
+
+The public functions `instanceOf`, `subclassOf` and `includes` have been replaced by `Object.isInstanceOf`, `Object.static.isSubclassOf` and `Object.static.includes`.
+
+Prior to 3.x:
+
+```lua
+instanceOf(MyClass, obj)
+subclassOf(Object, aClass)
+includes(aMixin, aClass)
+```
+
+Since 3.x:
+
+```lua
+obj:isInstanceOf(MyClass)
+aClass:isSubclassOf(Object)
+aClass:includes(aMixin)
+```
+
+The 3.x code snippet will throw an error if `obj` is not an object, or if `aClass` is not a class (since they will not implement `isInstanceOf`, `isSubclassOf` or `includes`).
+If you are unsure of whether `obj` and `aClass` are an object or a class, you can use the methods in `Object`. They are prepared to work with random types, not just classes and instances:
+
+```lua
+Object.isInstanceOf(obj, MyClass)
+Object.isSubclassOf(aClass, Object)
+Object.includes(aClass, aMixin)
+```
+
+Notice that the parameter order is not the same now as it was in 2.x. Also note the change in naming: `isInstanceOf` instead of `instanceOf`, and `isSubclassOf` instead of `subclassOf`.
diff --git a/Data/DefaultContent/Libraries/middleclass/middleclass.lua b/Data/DefaultContent/Libraries/middleclass/middleclass.lua
new file mode 100644
index 0000000..7e36bcd
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/middleclass.lua
@@ -0,0 +1,183 @@
+local middleclass = {
+ _VERSION = 'middleclass v4.1.1',
+ _DESCRIPTION = 'Object Orientation for Lua',
+ _URL = 'https://github.com/kikito/middleclass',
+ _LICENSE = [[
+ MIT LICENSE
+
+ Copyright (c) 2011 Enrique García Cota
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ ]]
+}
+
+local function _createIndexWrapper(aClass, f)
+ if f == nil then
+ return aClass.__instanceDict
+ else
+ return function(self, name)
+ local value = aClass.__instanceDict[name]
+
+ if value ~= nil then
+ return value
+ elseif type(f) == "function" then
+ return (f(self, name))
+ else
+ return f[name]
+ end
+ end
+ end
+end
+
+local function _propagateInstanceMethod(aClass, name, f)
+ f = name == "__index" and _createIndexWrapper(aClass, f) or f
+ aClass.__instanceDict[name] = f
+
+ for subclass in pairs(aClass.subclasses) do
+ if rawget(subclass.__declaredMethods, name) == nil then
+ _propagateInstanceMethod(subclass, name, f)
+ end
+ end
+end
+
+local function _declareInstanceMethod(aClass, name, f)
+ aClass.__declaredMethods[name] = f
+
+ if f == nil and aClass.super then
+ f = aClass.super.__instanceDict[name]
+ end
+
+ _propagateInstanceMethod(aClass, name, f)
+end
+
+local function _tostring(self) return "class " .. self.name end
+local function _call(self, ...) return self:new(...) end
+
+local function _createClass(name, super)
+ local dict = {}
+ dict.__index = dict
+
+ local aClass = { name = name, super = super, static = {},
+ __instanceDict = dict, __declaredMethods = {},
+ subclasses = setmetatable({}, {__mode='k'}) }
+
+ if super then
+ setmetatable(aClass.static, {
+ __index = function(_,k)
+ local result = rawget(dict,k)
+ if result == nil then
+ return super.static[k]
+ end
+ return result
+ end
+ })
+ else
+ setmetatable(aClass.static, { __index = function(_,k) return rawget(dict,k) end })
+ end
+
+ setmetatable(aClass, { __index = aClass.static, __tostring = _tostring,
+ __call = _call, __newindex = _declareInstanceMethod })
+
+ return aClass
+end
+
+local function _includeMixin(aClass, mixin)
+ assert(type(mixin) == 'table', "mixin must be a table")
+
+ for name,method in pairs(mixin) do
+ if name ~= "included" and name ~= "static" then aClass[name] = method end
+ end
+
+ for name,method in pairs(mixin.static or {}) do
+ aClass.static[name] = method
+ end
+
+ if type(mixin.included)=="function" then mixin:included(aClass) end
+ return aClass
+end
+
+local DefaultMixin = {
+ __tostring = function(self) return "instance of " .. tostring(self.class) end,
+
+ initialize = function(self, ...) end,
+
+ isInstanceOf = function(self, aClass)
+ return type(aClass) == 'table'
+ and type(self) == 'table'
+ and (self.class == aClass
+ or type(self.class) == 'table'
+ and type(self.class.isSubclassOf) == 'function'
+ and self.class:isSubclassOf(aClass))
+ end,
+
+ static = {
+ allocate = function(self)
+ assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'")
+ return setmetatable({ class = self }, self.__instanceDict)
+ end,
+
+ new = function(self, ...)
+ assert(type(self) == 'table', "Make sure that you are using 'Class:new' instead of 'Class.new'")
+ local instance = self:allocate()
+ instance:initialize(...)
+ return instance
+ end,
+
+ subclass = function(self, name)
+ assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'")
+ assert(type(name) == "string", "You must provide a name(string) for your class")
+
+ local subclass = _createClass(name, self)
+
+ for methodName, f in pairs(self.__instanceDict) do
+ _propagateInstanceMethod(subclass, methodName, f)
+ end
+ subclass.initialize = function(instance, ...) return self.initialize(instance, ...) end
+
+ self.subclasses[subclass] = true
+ self:subclassed(subclass)
+
+ return subclass
+ end,
+
+ subclassed = function(self, other) end,
+
+ isSubclassOf = function(self, other)
+ return type(other) == 'table' and
+ type(self.super) == 'table' and
+ ( self.super == other or self.super:isSubclassOf(other) )
+ end,
+
+ include = function(self, ...)
+ assert(type(self) == 'table', "Make sure you that you are using 'Class:include' instead of 'Class.include'")
+ for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end
+ return self
+ end
+ }
+}
+
+function middleclass.class(name, super)
+ assert(type(name) == 'string', "A name (string) is needed for the new class")
+ return super and super:subclass(name) or _includeMixin(_createClass(name), DefaultMixin)
+end
+
+setmetatable(middleclass, { __call = function(_, ...) return middleclass.class(...) end })
+
+return middleclass
diff --git a/Data/DefaultContent/Libraries/middleclass/performance/run.lua b/Data/DefaultContent/Libraries/middleclass/performance/run.lua
new file mode 100644
index 0000000..8d8ba47
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/performance/run.lua
@@ -0,0 +1,43 @@
+local class = require 'middleclass'
+
+time = require 'performance/time'
+
+time('class creation', function()
+ local A = class('A')
+end)
+
+local A = class('A')
+
+time('instance creation', function()
+ local a = A:new()
+end)
+
+function A:foo()
+ return 1
+end
+
+local a = A:new()
+
+time('instance method invocation', function()
+ a:foo()
+end)
+
+local B = class('B', A)
+
+local b = B:new()
+
+time('inherited method invocation', function()
+ b:foo()
+end)
+
+function A.static:bar()
+ return 2
+end
+
+time('class method invocation', function()
+ A:bar()
+end)
+
+time('inherited class method invocation', function()
+ B:bar()
+end)
diff --git a/Data/DefaultContent/Libraries/middleclass/performance/time.lua b/Data/DefaultContent/Libraries/middleclass/performance/time.lua
new file mode 100644
index 0000000..dd02455
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/performance/time.lua
@@ -0,0 +1,13 @@
+return function(title, f)
+
+ collectgarbage()
+
+ local startTime = os.clock()
+
+ for i=0,10000 do f() end
+
+ local endTime = os.clock()
+
+ print( title, endTime - startTime )
+
+end
diff --git a/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.0-0.rockspec b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.0-0.rockspec
new file mode 100644
index 0000000..f9ec58c
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.0-0.rockspec
@@ -0,0 +1,21 @@
+package = "middleclass"
+version = "3.0-0"
+source = {
+ url = "https://github.com/kikito/middleclass/archive/v3.0.0.tar.gz",
+ dir = "middleclass-3.0.0"
+}
+description = {
+ summary = "A simple OOP library for Lua",
+ detailed = "It has inheritance, metamethods (operators), class variables and weak mixin support",
+ homepage = "https://github.com/kikito/middleclass",
+ license = "MIT"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ middleclass = "middleclass.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.1-0.rockspec b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.1-0.rockspec
new file mode 100644
index 0000000..24a233e
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.1-0.rockspec
@@ -0,0 +1,21 @@
+package = "middleclass"
+version = "3.1-0"
+source = {
+ url = "https://github.com/kikito/middleclass/archive/v3.1.0.tar.gz",
+ dir = "middleclass-3.1.0"
+}
+description = {
+ summary = "A simple OOP library for Lua",
+ detailed = "It has inheritance, metamethods (operators), class variables and weak mixin support",
+ homepage = "https://github.com/kikito/middleclass",
+ license = "MIT"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ middleclass = "middleclass.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.2-0.rockspec b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.2-0.rockspec
new file mode 100644
index 0000000..03e3b30
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-3.2-0.rockspec
@@ -0,0 +1,21 @@
+package = "middleclass"
+version = "3.2-0"
+source = {
+ url = "https://github.com/kikito/middleclass/archive/v3.2.0.tar.gz",
+ dir = "middleclass-3.2.0"
+}
+description = {
+ summary = "A simple OOP library for Lua",
+ detailed = "It has inheritance, metamethods (operators), class variables and weak mixin support",
+ homepage = "https://github.com/kikito/middleclass",
+ license = "MIT"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ middleclass = "middleclass.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.0-0.rockspec b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.0-0.rockspec
new file mode 100644
index 0000000..517984e
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.0-0.rockspec
@@ -0,0 +1,21 @@
+package = "middleclass"
+version = "4.0-0"
+source = {
+ url = "https://github.com/kikito/middleclass/archive/v4.0.0.tar.gz",
+ dir = "middleclass-4.0.0"
+}
+description = {
+ summary = "A simple OOP library for Lua",
+ detailed = "It has inheritance, metamethods (operators), class variables and weak mixin support",
+ homepage = "https://github.com/kikito/middleclass",
+ license = "MIT"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ middleclass = "middleclass.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1-0.rockspec b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1-0.rockspec
new file mode 100644
index 0000000..dc710e9
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1-0.rockspec
@@ -0,0 +1,21 @@
+package = "middleclass"
+version = "4.1-0"
+source = {
+ url = "https://github.com/kikito/middleclass/archive/v4.1.0.tar.gz",
+ dir = "middleclass-4.1.0"
+}
+description = {
+ summary = "A simple OOP library for Lua",
+ detailed = "It has inheritance, metamethods (operators), class variables and weak mixin support",
+ homepage = "https://github.com/kikito/middleclass",
+ license = "MIT"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ middleclass = "middleclass.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1.1-0.rockspec b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1.1-0.rockspec
new file mode 100644
index 0000000..ddaacd9
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/rockspecs/middleclass-4.1.1-0.rockspec
@@ -0,0 +1,21 @@
+package = "middleclass"
+version = "4.1.1-0"
+source = {
+ url = "https://github.com/kikito/middleclass/archive/v4.1.1.tar.gz",
+ dir = "middleclass-4.1.1"
+}
+description = {
+ summary = "A simple OOP library for Lua",
+ detailed = "It has inheritance, metamethods (operators), class variables and weak mixin support",
+ homepage = "https://github.com/kikito/middleclass",
+ license = "MIT"
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ middleclass = "middleclass.lua"
+ }
+}
diff --git a/Data/DefaultContent/Libraries/middleclass/spec/class_spec.lua b/Data/DefaultContent/Libraries/middleclass/spec/class_spec.lua
new file mode 100644
index 0000000..144cb9f
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/spec/class_spec.lua
@@ -0,0 +1,28 @@
+local class = require 'middleclass'
+
+describe('class()', function()
+
+ describe('when given no params', function()
+ it('it throws an error', function()
+ assert.error(class)
+ end)
+ end)
+
+ describe('when given a name', function()
+ it('the resulting class has the correct name and Object as its superclass', function()
+ local TheClass = class('TheClass')
+ assert.equal(TheClass.name, 'TheClass')
+ assert.is_nil(TheClass.super)
+ end)
+ end)
+
+ describe('when given a name and a superclass', function()
+ it('the resulting class has the correct name and superclass', function()
+ local TheSuperClass = class('TheSuperClass')
+ local TheSubClass = class('TheSubClass', TheSuperClass)
+ assert.equal(TheSubClass.name, 'TheSubClass')
+ assert.equal(TheSubClass.super, TheSuperClass)
+ end)
+ end)
+
+end)
diff --git a/Data/DefaultContent/Libraries/middleclass/spec/classes_spec.lua b/Data/DefaultContent/Libraries/middleclass/spec/classes_spec.lua
new file mode 100644
index 0000000..7942f18
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/spec/classes_spec.lua
@@ -0,0 +1,138 @@
+local class = require 'middleclass'
+
+describe('A Class', function()
+
+ describe('Default stuff', function()
+
+ local AClass
+
+ before_each(function()
+ AClass = class('AClass')
+ end)
+
+ describe('name', function()
+ it('is correctly set', function()
+ assert.equal(AClass.name, 'AClass')
+ end)
+ end)
+
+ describe('tostring', function()
+ it('returns "class *name*"', function()
+ assert.equal(tostring(AClass), 'class AClass')
+ end)
+ end)
+
+ describe('()', function()
+ it('returns an object, like Class:new()', function()
+ local obj = AClass()
+ assert.equal(obj.class, AClass)
+ end)
+ end)
+
+ describe('include', function()
+ it('throws an error when used without the :', function()
+ assert.error(function() AClass.include() end)
+ end)
+ it('throws an error when passed a non-table:', function()
+ assert.error(function() AClass:include(1) end)
+ end)
+ end)
+
+ describe('subclass', function()
+
+ it('throws an error when used without the :', function()
+ assert.error(function() AClass.subclass() end)
+ end)
+
+ it('throws an error when no name is given', function()
+ assert.error( function() AClass:subclass() end)
+ end)
+
+ describe('when given a subclass name', function()
+
+ local SubClass
+
+ before_each(function()
+ function AClass.static:subclassed(other) self.static.child = other end
+ SubClass = AClass:subclass('SubClass')
+ end)
+
+ it('it returns a class with the correct name', function()
+ assert.equal(SubClass.name, 'SubClass')
+ end)
+
+ it('it returns a class with the correct superclass', function()
+ assert.equal(SubClass.super, AClass)
+ end)
+
+ it('it invokes the subclassed hook method', function()
+ assert.equal(SubClass, AClass.child)
+ end)
+
+ it('it includes the subclass in the list of subclasses', function()
+ assert.is_true(AClass.subclasses[SubClass])
+ end)
+
+ end)
+
+ end)
+
+ end)
+
+
+
+ describe('attributes', function()
+
+ local A, B
+
+ before_each(function()
+ A = class('A')
+ A.static.foo = 'foo'
+
+ B = class('B', A)
+ end)
+
+ it('are available after being initialized', function()
+ assert.equal(A.foo, 'foo')
+ end)
+
+ it('are available for subclasses', function()
+ assert.equal(B.foo, 'foo')
+ end)
+
+ it('are overridable by subclasses, without affecting the superclasses', function()
+ B.static.foo = 'chunky bacon'
+ assert.equal(B.foo, 'chunky bacon')
+ assert.equal(A.foo, 'foo')
+ end)
+
+ end)
+
+ describe('methods', function()
+
+ local A, B
+
+ before_each(function()
+ A = class('A')
+ function A.static:foo() return 'foo' end
+
+ B = class('B', A)
+ end)
+
+ it('are available after being initialized', function()
+ assert.equal(A:foo(), 'foo')
+ end)
+
+ it('are available for subclasses', function()
+ assert.equal(B:foo(), 'foo')
+ end)
+
+ it('are overridable by subclasses, without affecting the superclasses', function()
+ function B.static:foo() return 'chunky bacon' end
+ assert.equal(B:foo(), 'chunky bacon')
+ assert.equal(A:foo(), 'foo')
+ end)
+
+ end)
+
+end)
diff --git a/Data/DefaultContent/Libraries/middleclass/spec/default_methods_spec.lua b/Data/DefaultContent/Libraries/middleclass/spec/default_methods_spec.lua
new file mode 100644
index 0000000..91fd9b8
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/spec/default_methods_spec.lua
@@ -0,0 +1,236 @@
+local class = require 'middleclass'
+
+describe('Default methods', function()
+ local Object
+ before_each(function()
+ Object = class('Object')
+ end)
+
+ describe('name', function()
+ it('is correctly set', function()
+ assert.equal(Object.name, 'Object')
+ end)
+ end)
+
+ describe('tostring', function()
+ it('returns "class Object"', function()
+ assert.equal(tostring(Object), 'class Object')
+ end)
+ end)
+
+ describe('()', function()
+ it('returns an object, like Object:new()', function()
+ local obj = Object()
+ assert.is_true(obj:isInstanceOf(Object))
+ end)
+ end)
+
+ describe('subclass', function()
+
+ it('throws an error when used without the :', function()
+ assert.error(function() Object.subclass() end)
+ end)
+
+ it('throws an error when no name is given', function()
+ assert.error( function() Object:subclass() end)
+ end)
+
+ describe('when given a class name', function()
+
+ local SubClass
+
+ before_each(function()
+ SubClass = Object:subclass('SubClass')
+ end)
+
+ it('it returns a class with the correct name', function()
+ assert.equal(SubClass.name, 'SubClass')
+ end)
+
+ it('it returns a class with the correct superclass', function()
+ assert.equal(SubClass.super, Object)
+ end)
+
+ it('it includes the subclass in the list of subclasses', function()
+ assert.is_true(Object.subclasses[SubClass])
+ end)
+
+ end)
+
+ end)
+
+ describe('instance creation', function()
+
+ local SubClass
+
+ before_each(function()
+ SubClass = class('SubClass')
+ function SubClass:initialize() self.mark=true end
+ end)
+
+ describe('allocate', function()
+
+ it('allocates instances properly', function()
+ local instance = SubClass:allocate()
+ assert.equal(instance.class, SubClass)
+ assert.equal(tostring(instance), "instance of " .. tostring(SubClass))
+ end)
+
+ it('throws an error when used without the :', function()
+ assert.error(Object.allocate)
+ end)
+
+ it('does not call the initializer', function()
+ local allocated = SubClass:allocate()
+ assert.is_nil(allocated.mark)
+ end)
+
+ it('can be overriden', function()
+
+ local previousAllocate = SubClass.static.allocate
+
+ function SubClass.static:allocate()
+ local instance = previousAllocate(SubClass)
+ instance.mark = true
+ return instance
+ end
+
+ local allocated = SubClass:allocate()
+ assert.is_true(allocated.mark)
+ end)
+
+ end)
+
+ describe('new', function()
+
+ it('initializes instances properly', function()
+ local instance = SubClass:new()
+ assert.equal(instance.class, SubClass)
+ end)
+
+ it('throws an error when used without the :', function()
+ assert.error(SubClass.new)
+ end)
+
+ it('calls the initializer', function()
+ local initialized = SubClass:new()
+ assert.is_true(initialized.mark)
+ end)
+
+ end)
+
+ describe('isInstanceOf', function()
+
+ describe('primitives', function()
+ local o = Object:new()
+ local primitives = {nil, 1, 'hello', {}, function() end, Object:new()}
+
+ describe('used as classes', function()
+ for _,primitive in pairs(primitives) do
+ local theType = type(primitive)
+ it('object:isInstanceOf(, '.. theType ..') returns false', function()
+ assert.is_falsy(o:isInstanceOf(primitive))
+ end)
+ end
+ end)
+
+ describe('used as instances', function()
+ for _,primitive in pairs(primitives) do
+ local theType = type(primitive)
+ it('Object.isInstanceOf('.. theType ..', Object) returns false without error', function()
+ assert.is_falsy(Object.isInstanceOf(primitive, Object))
+ end)
+ end
+ end)
+
+
+ end)
+
+ describe('An instance', function()
+ local Class1 = class('Class1')
+ local Class2 = class('Class2', Class1)
+ local Class3 = class('Class3', Class2)
+ local UnrelatedClass = class('Unrelated')
+
+ local o1, o2, o3 = Class1:new(), Class2:new(), Class3:new()
+
+ it('isInstanceOf its class', function()
+ assert.is_true(o1:isInstanceOf(Class1))
+ assert.is_true(o2:isInstanceOf(Class2))
+ assert.is_true(o3:isInstanceOf(Class3))
+ end)
+
+ it('is instanceOf its class\' superclasses', function()
+ assert.is_true(o2:isInstanceOf(Class1))
+ assert.is_true(o3:isInstanceOf(Class1))
+ assert.is_true(o3:isInstanceOf(Class2))
+ end)
+
+ it('is not instanceOf its class\' subclasses', function()
+ assert.is_false(o1:isInstanceOf(Class2))
+ assert.is_false(o1:isInstanceOf(Class3))
+ assert.is_false(o2:isInstanceOf(Class3))
+ end)
+
+ it('is not instanceOf an unrelated class', function()
+ assert.is_false(o1:isInstanceOf(UnrelatedClass))
+ assert.is_false(o2:isInstanceOf(UnrelatedClass))
+ assert.is_false(o3:isInstanceOf(UnrelatedClass))
+ end)
+
+ end)
+
+ end)
+
+ end)
+
+ describe('isSubclassOf', function()
+
+ it('returns false for instances', function()
+ assert.is_false(Object:isSubclassOf(Object:new()))
+ end)
+
+ describe('on primitives', function()
+ local primitives = {nil, 1, 'hello', {}, function() end}
+
+ for _,primitive in pairs(primitives) do
+ local theType = type(primitive)
+ it('returns false for ' .. theType, function()
+ assert.is_false(Object:isSubclassOf(primitive))
+ end)
+ end
+
+ end)
+
+ describe('Any class (except Object)', function()
+ local Class1 = class('Class1')
+ local Class2 = class('Class2', Class1)
+ local Class3 = class('Class3', Class2)
+ local UnrelatedClass = class('Unrelated')
+
+ it('is subclassOf its direct superclass', function()
+ assert.is_true(Class2:isSubclassOf(Class1))
+ assert.is_true(Class3:isSubclassOf(Class2))
+ end)
+
+ it('is subclassOf its ancestors', function()
+ assert.is_true(Class3:isSubclassOf(Class1))
+ end)
+
+ it('is a subclassOf its class\' subclasses', function()
+ assert.is_true(Class2:isSubclassOf(Class1))
+ assert.is_true(Class3:isSubclassOf(Class1))
+ assert.is_true(Class3:isSubclassOf(Class2))
+ end)
+
+ it('is not a subclassOf an unrelated class', function()
+ assert.is_false(Class1:isSubclassOf(UnrelatedClass))
+ assert.is_false(Class2:isSubclassOf(UnrelatedClass))
+ assert.is_false(Class3:isSubclassOf(UnrelatedClass))
+ end)
+
+ end)
+ end)
+end)
+
+
diff --git a/Data/DefaultContent/Libraries/middleclass/spec/instances_spec.lua b/Data/DefaultContent/Libraries/middleclass/spec/instances_spec.lua
new file mode 100644
index 0000000..d9ac52c
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/spec/instances_spec.lua
@@ -0,0 +1,65 @@
+local class = require 'middleclass'
+
+describe('An instance', function()
+
+ describe('attributes', function()
+
+ local Person
+
+ before_each(function()
+ Person = class('Person')
+ function Person:initialize(name)
+ self.name = name
+ end
+ end)
+
+ it('are available in the instance after being initialized', function()
+ local bob = Person:new('bob')
+ assert.equal(bob.name, 'bob')
+ end)
+
+ it('are available in the instance after being initialized by a superclass', function()
+ local AgedPerson = class('AgedPerson', Person)
+ function AgedPerson:initialize(name, age)
+ Person.initialize(self, name)
+ self.age = age
+ end
+
+ local pete = AgedPerson:new('pete', 31)
+ assert.equal(pete.name, 'pete')
+ assert.equal(pete.age, 31)
+ end)
+
+ end)
+
+ describe('methods', function()
+
+ local A, B, a, b
+
+ before_each(function()
+ A = class('A')
+ function A:overridden() return 'foo' end
+ function A:regular() return 'regular' end
+
+ B = class('B', A)
+ function B:overridden() return 'bar' end
+
+ a = A:new()
+ b = B:new()
+ end)
+
+ it('are available for any instance', function()
+ assert.equal(a:overridden(), 'foo')
+ end)
+
+ it('are inheritable', function()
+ assert.equal(b:regular(), 'regular')
+ end)
+
+ it('are overridable', function()
+ assert.equal(b:overridden(), 'bar')
+ end)
+
+ end)
+
+end)
diff --git a/Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_2.lua b/Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_2.lua
new file mode 100644
index 0000000..2ea6c9b
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_2.lua
@@ -0,0 +1,85 @@
+local class = require 'middleclass'
+
+local it = require('busted').it
+local describe = require('busted').describe
+local before_each = require('busted').before_each
+local assert = require('busted').assert
+
+describe('Lua 5.2 Metamethods', function()
+ local Vector, v
+ before_each(function()
+ Vector= class('Vector')
+ function Vector.initialize(a,x,y,z) a.x, a.y, a.z = x,y,z end
+ function Vector.__eq(a,b) return a.x==b.x and a.y==b.y and a.z==b.z end
+
+ function Vector.__len(a) return 3 end
+ function Vector.__pairs(a)
+ local t = {x=a.x,y=a.y,z=a.z}
+ return coroutine.wrap(function()
+ for k,val in pairs(t) do
+ coroutine.yield(k,val)
+ end
+ end)
+ end
+ function Vector.__ipairs(a)
+ local t = {a.x,a.y,a.z}
+ return coroutine.wrap(function()
+ for k,val in ipairs(t) do
+ coroutine.yield(k,val)
+ end
+ end)
+ end
+
+ v = Vector:new(1,2,3)
+ end)
+
+ it('implements __len', function()
+ assert.equal(#v, 3)
+ end)
+
+ it('implements __pairs',function()
+ local output = {}
+ for k,val in pairs(v) do
+ output[k] = val
+ end
+ assert.are.same(output,{x=1,y=2,z=3})
+ end)
+
+ it('implements __ipairs',function()
+ local output = {}
+ for _,i in ipairs(v) do
+ output[#output+1] = i
+ end
+ assert.are.same(output,{1,2,3})
+ end)
+
+ describe('Inherited Metamethods', function()
+ local Vector2, v2
+ before_each(function()
+ Vector2= class('Vector2', Vector)
+ function Vector2:initialize(x,y,z) Vector.initialize(self,x,y,z) end
+
+ v2 = Vector2:new(1,2,3)
+ end)
+
+ it('implements __len', function()
+ assert.equal(#v2, 3)
+ end)
+
+ it('implements __pairs',function()
+ local output = {}
+ for k,val in pairs(v2) do
+ output[k] = val
+ end
+ assert.are.same(output,{x=1,y=2,z=3})
+ end)
+
+ it('implements __ipairs',function()
+ local output = {}
+ for _,i in ipairs(v2) do
+ output[#output+1] = i
+ end
+ assert.are.same(output,{1,2,3})
+ end)
+ end)
+end)
diff --git a/Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_3.lua b/Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_3.lua
new file mode 100644
index 0000000..e74f6d7
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/spec/metamethods_lua_5_3.lua
@@ -0,0 +1,106 @@
+local class = require 'middleclass'
+
+local it = require('busted').it
+local describe = require('busted').describe
+local before_each = require('busted').before_each
+local assert = require('busted').assert
+
+describe('Lua 5.3 Metamethods', function()
+ local Vector, v, last_gc
+ before_each(function()
+ Vector= class('Vector')
+ function Vector.initialize(a,x,y,z) a.x, a.y, a.z = x,y,z end
+ function Vector.__eq(a,b) return a.x==b.x and a.y==b.y and a.z==b.z end
+ function Vector.__pairs(a)
+ local t = {x=a.x,y=a.y,z=a.z}
+ return coroutine.wrap(function()
+ for k,val in pairs(t) do
+ coroutine.yield(k,val)
+ end
+ end)
+ end
+ function Vector.__len(a) return 3 end
+
+ function Vector.__gc(a) last_gc = {a.class.name, a.x, a.y, a.z} end
+ function Vector.__band(a,n) return a.class:new(a.x & n, a.y & n, a.z & n) end
+ function Vector.__bor(a,n) return a.class:new(a.x | n, a.y | n, a.z | n) end
+ function Vector.__bxor(a,n) return a.class:new(a.x ~ n, a.y ~ n, a.z ~ n) end
+ function Vector.__shl(a,n) return a.class:new(a.x << n, a.y << n, a.z << n) end
+ function Vector.__shr(a,n) return a.class:new(a.x >> n, a.y >> n, a.z >> n) end
+ function Vector.__bnot(a) return a.class:new(~a.x, ~a.y, ~a.z) end
+
+ v = Vector:new(1,2,3)
+ end)
+
+ it('implements __gc', function()
+ collectgarbage()
+ v = nil
+ collectgarbage()
+ assert.are.same(last_gc, {"Vector",1,2,3})
+ end)
+
+ it('implements __band', function()
+ assert.equal(v & 1, Vector(1,0,1))
+ end)
+
+ it('implements __bor', function()
+ assert.equal(v | 0, Vector(1,2,3))
+ end)
+
+ it('implements __bxor', function()
+ assert.equal(v | 1, Vector(1,3,3))
+ end)
+
+ it('implements __shl', function()
+ assert.equal(v << 1, Vector(2,4,6))
+ end)
+
+ it('implements __shr', function()
+ assert.equal(v >> 1, Vector(0,1,1))
+ end)
+
+ it('implements __bnot', function()
+ assert.equal(~v, Vector(-2,-3,-4))
+ end)
+
+ describe('Inherited Metamethods', function()
+ local Vector2, v2
+ before_each(function()
+ Vector2= class('Vector2', Vector)
+ function Vector2:initialize(x,y,z) Vector.initialize(self,x,y,z) end
+
+ v2 = Vector2:new(1,2,3)
+ end)
+
+ it('implements __gc', function()
+ collectgarbage()
+ v2 = nil
+ collectgarbage()
+ assert.are.same(last_gc, {"Vector2",1,2,3})
+ end)
+
+ it('implements __band', function()
+ assert.equal(v2 & 1, Vector2(1,0,1))
+ end)
+
+ it('implements __bor', function()
+ assert.equal(v2 | 0, Vector2(1,2,3))
+ end)
+
+ it('implements __bxor', function()
+ assert.equal(v2 | 1, Vector2(1,3,3))
+ end)
+
+ it('implements __shl', function()
+ assert.equal(v2 << 1, Vector2(2,4,6))
+ end)
+
+ it('implements __shr', function()
+ assert.equal(v2 >> 1, Vector2(0,1,1))
+ end)
+
+ it('implements __bnot', function()
+ assert.equal(~v2, Vector2(-2,-3,-4))
+ end)
+ end)
+end)
diff --git a/Data/DefaultContent/Libraries/middleclass/spec/metamethods_spec.lua b/Data/DefaultContent/Libraries/middleclass/spec/metamethods_spec.lua
new file mode 100644
index 0000000..73bf883
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/spec/metamethods_spec.lua
@@ -0,0 +1,317 @@
+local class = require 'middleclass'
+
+local function is_lua_5_2_compatible()
+ return type(rawlen) == 'function'
+end
+
+local function is_lua_5_3_compatible()
+ return type(string.unpack) == 'function'
+end
+
+if is_lua_5_2_compatible() then
+ require 'spec/metamethods_lua_5_2'
+end
+
+if is_lua_5_3_compatible() then
+ require 'spec.metamethods_lua_5_3'
+end
+
+describe('Metamethods', function()
+ describe('Custom Metamethods', function()
+ local Vector, v, w
+ before_each(function()
+ Vector= class('Vector')
+ function Vector.initialize(a,x,y,z) a.x, a.y, a.z = x,y,z end
+ function Vector.__tostring(a) return a.class.name .. '[' .. a.x .. ',' .. a.y .. ',' .. a.z .. ']' end
+ function Vector.__eq(a,b) return a.x==b.x and a.y==b.y and a.z==b.z end
+ function Vector.__lt(a,b) return a() < b() end
+ function Vector.__le(a,b) return a() <= b() end
+ function Vector.__add(a,b) return a.class:new(a.x+b.x, a.y+b.y ,a.z+b.z) end
+ function Vector.__sub(a,b) return a.class:new(a.x-b.x, a.y-b.y, a.z-b.z) end
+ function Vector.__div(a,s) return a.class:new(a.x/s, a.y/s, a.z/s) end
+ function Vector.__unm(a) return a.class:new(-a.x, -a.y, -a.z) end
+ function Vector.__concat(a,b) return a.x*b.x+a.y*b.y+a.z*b.z end
+ function Vector.__call(a) return math.sqrt(a.x*a.x+a.y*a.y+a.z*a.z) end
+ function Vector.__pow(a,b)
+ return a.class:new(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x)
+ end
+ function Vector.__mul(a,b)
+ if type(b)=="number" then return a.class:new(a.x*b, a.y*b, a.z*b) end
+ if type(a)=="number" then return b.class:new(a*b.x, a*b.y, a*b.z) end
+ end
+ Vector.__metatable = "metatable of a vector"
+ Vector.__mode = "k"
+
+ v = Vector:new(1,2,3)
+ w = Vector:new(2,4,6)
+ end)
+
+ it('implements __tostring', function()
+ assert.equal(tostring(v), "Vector[1,2,3]")
+ end)
+
+ it('implements __eq', function()
+ assert.equal(v, v)
+ end)
+
+ it('implements __lt', function()
+ assert.is_true(v < w)
+ end)
+
+ it('implements __le', function()
+ assert.is_true(v <= w)
+ end)
+
+ it('implements __add', function()
+ assert.equal(v+w, Vector(3,6,9))
+ end)
+
+ it('implements __sub', function()
+ assert.equal(w-v, Vector(1,2,3))
+ end)
+
+ it('implements __div', function()
+ assert.equal(w/2, Vector(1,2,3))
+ end)
+
+ it('implements __concat', function()
+ assert.equal(v..w, 28)
+ end)
+
+ it('implements __call', function()
+ assert.equal(v(), math.sqrt(14))
+ end)
+
+ it('implements __pow', function()
+ assert.equal(v^w, Vector(0,0,0))
+ end)
+
+ it('implements __mul', function()
+ assert.equal(4*v, Vector(4,8,12))
+ end)
+
+ it('implements __metatable', function()
+ assert.equal("metatable of a vector", getmetatable(v))
+ end)
+
+ it('implements __mode', function()
+ v[{}] = true
+ collectgarbage()
+ for k in pairs(v) do assert.not_table(k) end
+ end)
+
+ --[[
+ it('implements __index', function()
+ assert.equal(b[1], 3)
+ end)
+ --]]
+
+ describe('Inherited Metamethods', function()
+ local Vector2, v2, w2
+ before_each(function()
+ Vector2= class('Vector2', Vector)
+ function Vector2:initialize(x,y,z) Vector.initialize(self,x,y,z) end
+
+ v2 = Vector2:new(1,2,3)
+ w2 = Vector2:new(2,4,6)
+ end)
+
+ it('implements __tostring', function()
+ assert.equal(tostring(v2), "Vector2[1,2,3]")
+ end)
+
+ it('implements __eq', function()
+ assert.equal(v2, v2)
+ end)
+
+ it('implements __lt', function()
+ assert.is_true(v2 < w2)
+ end)
+
+ it('implements __le', function()
+ assert.is_true(v2 <= w2)
+ end)
+
+ it('implements __add', function()
+ assert.equal(v2+w2, Vector2(3,6,9))
+ end)
+
+ it('implements __sub', function()
+ assert.equal(w2-v2, Vector2(1,2,3))
+ end)
+
+ it('implements __div', function()
+ assert.equal(w2/2, Vector2(1,2,3))
+ end)
+
+ it('implements __concat', function()
+ assert.equal(v2..w2, 28)
+ end)
+
+ it('implements __call', function()
+ assert.equal(v2(), math.sqrt(14))
+ end)
+
+ it('implements __pow', function()
+ assert.equal(v2^w2, Vector2(0,0,0))
+ end)
+
+ it('implements __mul', function()
+ assert.equal(4*v2, Vector2(4,8,12))
+ end)
+
+ it('implements __metatable', function()
+ assert.equal("metatable of a vector", getmetatable(v2))
+ end)
+
+ it('implements __mode', function()
+ v2[{}] = true
+ collectgarbage()
+ for k in pairs(v2) do assert.not_table(k) end
+ end)
+
+ it('allows inheriting further', function()
+ local Vector3 = class('Vector3', Vector2)
+ local v3 = Vector3(1,2,3)
+ local w3 = Vector3(3,4,5)
+ assert.equal(v3+w3, Vector3(4,6,8))
+ end)
+
+ describe('Updates', function()
+ it('overrides __add', function()
+ Vector2.__add = function(a, b) return Vector.__add(a, b)/2 end
+ assert.equal(v2+w2, Vector2(1.5,3,4.5))
+ end)
+
+ it('updates __add', function()
+ Vector.__add = Vector.__sub
+ assert.equal(v2+w2, Vector2(-1,-2,-3))
+ end)
+
+ it('does not update __add after overriding', function()
+ Vector2.__add = function(a, b) return Vector.__add(a, b)/2 end
+ Vector.__add = Vector.__sub
+ assert.equal(v2+w2, Vector2(-0.5,-1,-1.5))
+ end)
+
+ it('reverts __add override', function()
+ Vector2.__add = function(a, b) return Vector.__add(a, b)/2 end
+ Vector2.__add = nil
+ assert.equal(v2+w2, Vector2(3,6,9))
+ end)
+ end)
+ end)
+ end)
+
+ describe('Custom __index and __newindex', function()
+ describe('Tables', function()
+ local Proxy, fallback, p
+ before_each(function()
+ Proxy = class('Proxy')
+ fallback = {foo = 'bar', common = 'fallback'}
+ Proxy.__index = fallback
+ Proxy.__newindex = fallback
+ Proxy.common = 'class'
+ p = Proxy()
+ end)
+
+ it('uses __index', function()
+ assert.equal(p.foo, 'bar')
+ end)
+
+ it('does not use __index when field exists in class', function()
+ assert.equal(p.common, 'class')
+ end)
+
+ it('uses __newindex', function()
+ p.key = 'value'
+ assert.equal(fallback.key, 'value')
+ end)
+
+ it('uses __newindex when field exists in class', function()
+ p.common = 'value'
+ assert.equal(p.common, 'class')
+ assert.equal(Proxy.common, 'class')
+ assert.equal(fallback.common, 'value')
+ end)
+ end)
+
+ describe('Functions', function()
+ local Namespace, Rectangle, r
+ before_each(function()
+ Namespace = class('Namespace')
+ function Namespace:__index(name)
+ local getter = self.class[name.."Getter"]
+ if getter then return getter(self) end
+ end
+ function Namespace:__newindex(name, value)
+ local setter = self.class[name.."Setter"]
+ if setter then setter(self, value) else rawset(self, name, value) end
+ end
+ Rectangle = class('Rectangle', Namespace)
+ function Rectangle:initialize(x, y, scale)
+ self._scale, self.x, self.y = 1, x, y
+ self.scale = scale
+ end
+ function Rectangle:scaleGetter() return self._scale end
+ function Rectangle:scaleSetter(v)
+ self.x = self.x*v/self._scale
+ self.y = self.y*v/self._scale
+ self._scale = v
+ end
+ function Rectangle:areaGetter() return self.x * self.y end
+ r = Rectangle(3, 4, 2)
+ end)
+
+ it('uses setter', function()
+ assert.equal(r.x, 6)
+ assert.equal(r.y, 8)
+ r.scale = 3
+ assert.equal(r.x, 9)
+ assert.equal(r.y, 12)
+ end)
+
+ it('uses getters', function()
+ assert.equal(r.scale, 2)
+ assert.equal(r.area, 48)
+ end)
+
+ it('updates inherited __index', function()
+ function Namespace.__index() return 42 end
+ assert.equal(r.area, 42)
+ function Rectangle.__index() return 24 end
+ assert.equal(r.area, 24)
+ function Namespace.__index() return 96 end
+ assert.equal(r.area, 24)
+ Rectangle.__index = nil
+ assert.equal(r.area, 96)
+ end)
+ end)
+ end)
+
+ describe('Default Metamethods', function()
+
+ local Peter, peter
+
+ before_each(function()
+ Peter = class('Peter')
+ peter = Peter()
+ end)
+
+ describe('A Class', function()
+ it('has a call metamethod properly set', function()
+ assert.is_true(peter:isInstanceOf(Peter))
+ end)
+ it('has a tostring metamethod properly set', function()
+ assert.equal(tostring(Peter), 'class Peter')
+ end)
+ end)
+
+ describe('An instance', function()
+ it('has a tostring metamethod, returning a different result from Object.__tostring', function()
+ assert.equal(tostring(peter), 'instance of class Peter')
+ end)
+ end)
+ end)
+
+end)
diff --git a/Data/DefaultContent/Libraries/middleclass/spec/mixins_spec.lua b/Data/DefaultContent/Libraries/middleclass/spec/mixins_spec.lua
new file mode 100644
index 0000000..ef592a1
--- /dev/null
+++ b/Data/DefaultContent/Libraries/middleclass/spec/mixins_spec.lua
@@ -0,0 +1,53 @@
+local class = require 'middleclass'
+
+describe('A Mixin', function()
+
+ local Mixin1, Mixin2, Class1, Class2
+
+ before_each(function()
+ Mixin1, Mixin2 = {},{}
+
+ function Mixin1:included(theClass) theClass.includesMixin1 = true end
+ function Mixin1:foo() return 'foo' end
+ function Mixin1:bar() return 'bar' end
+ Mixin1.static = {}
+ Mixin1.static.bazzz = function() return 'bazzz' end
+
+
+ function Mixin2:baz() return 'baz' end
+
+ Class1 = class('Class1'):include(Mixin1, Mixin2)
+ function Class1:foo() return 'foo1' end
+
+ Class2 = class('Class2', Class1)
+ function Class2:bar2() return 'bar2' end
+ end)
+
+ it('invokes the "included" method when included', function()
+ assert.is_true(Class1.includesMixin1)
+ end)
+
+ it('has all its functions (except "included") copied to its target class', function()
+ assert.equal(Class1:bar(), 'bar')
+ assert.is_nil(Class1.included)
+ end)
+
+ it('makes its functions available to subclasses', function()
+ assert.equal(Class2:baz(), 'baz')
+ end)
+
+ it('allows overriding of methods in the same class', function()
+ assert.equal(Class2:foo(), 'foo1')
+ end)
+
+ it('allows overriding of methods on subclasses', function()
+ assert.equal(Class2:bar2(), 'bar2')
+ end)
+
+ it('makes new static methods available in classes', function()
+ assert.equal(Class1:bazzz(), 'bazzz')
+ assert.equal(Class2:bazzz(), 'bazzz')
+ end)
+
+end)
+
diff --git a/Data/DefaultContent/Libraries/socket/README.txt b/Data/DefaultContent/Libraries/socket/README.txt
new file mode 100644
index 0000000..7f61184
--- /dev/null
+++ b/Data/DefaultContent/Libraries/socket/README.txt
@@ -0,0 +1 @@
+https://github.com/diegonehab/luasocket \ No newline at end of file
diff --git a/Data/DefaultContent/Libraries/socket/core.dll b/Data/DefaultContent/Libraries/socket/core.dll
new file mode 100644
index 0000000..9febf20
--- /dev/null
+++ b/Data/DefaultContent/Libraries/socket/core.dll
Binary files differ
diff --git a/Data/DefaultContent/Textures/blank.png b/Data/DefaultContent/Textures/blank.png
new file mode 100644
index 0000000..877e031
--- /dev/null
+++ b/Data/DefaultContent/Textures/blank.png
Binary files differ
diff --git a/Data/DefaultContent/readme.txt b/Data/DefaultContent/readme.txt
new file mode 100644
index 0000000..5a01d86
--- /dev/null
+++ b/Data/DefaultContent/readme.txt
@@ -0,0 +1,6 @@
+运行时必须的内置资源,包括
+* 引擎模块
+* 扩展模块
+* 内置Shader
+* 内置模型
+* 内置贴图 \ No newline at end of file
diff --git a/Data/Libraries/GameLab/Editor/Animation/init.lua b/Data/Libraries/GameLab/Editor/Animation/init.lua
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Data/Libraries/GameLab/Editor/Animation/init.lua
diff --git a/Data/Libraries/GameLab/Editor/AssetManager.lua b/Data/Libraries/GameLab/Editor/AssetManager.lua
new file mode 100644
index 0000000..34d32ec
--- /dev/null
+++ b/Data/Libraries/GameLab/Editor/AssetManager.lua
@@ -0,0 +1,8 @@
+local AssetManager = GameLab.Editor.AssetManager or {}
+GameLab.Editor.AssetManager = AssetManager
+
+AssetManager.LoadAsset = function()
+
+end
+
+return AssetManager \ No newline at end of file
diff --git a/Data/Libraries/GameLab/Editor/GUI/EditorWindow.lua b/Data/Libraries/GameLab/Editor/GUI/EditorWindow.lua
new file mode 100644
index 0000000..4f0525f
--- /dev/null
+++ b/Data/Libraries/GameLab/Editor/GUI/EditorWindow.lua
@@ -0,0 +1,23 @@
+local EditorWindow = GameLab.Class("GameLab.Editor.GUI.EditorWindow")
+
+EditorWindow.Ctor = function(self, title)
+ self.title = title -- 编辑器名称
+ self.guiWindow = nil -- 绑定的GUIWindow
+end
+
+EditorWindow.OnGUI = function(self)
+end
+
+EditorWindow.OnUpdate = function(self)
+end
+
+EditorWindow.OnStart = function(self)
+end
+
+EditorWindow.OnStop = function(self)
+end
+
+EditorWindow.OnFocus = function(self)
+end
+
+return EditorWindow \ No newline at end of file
diff --git a/Data/Libraries/GameLab/Editor/GUI/Functions.lua b/Data/Libraries/GameLab/Editor/GUI/Functions.lua
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Data/Libraries/GameLab/Editor/GUI/Functions.lua
diff --git a/Data/Libraries/GameLab/Editor/GUI/init.lua b/Data/Libraries/GameLab/Editor/GUI/init.lua
new file mode 100644
index 0000000..def4237
--- /dev/null
+++ b/Data/Libraries/GameLab/Editor/GUI/init.lua
@@ -0,0 +1,10 @@
+GameLab.Editor.GUI = GameLab.Editor.GUI or {}
+local m = GameLab.Editor.GUI
+
+local import = GameLab.import(...)
+
+m.EditorWindow = import("EditorWindow")
+
+import("Functions")
+
+return m \ No newline at end of file
diff --git a/Data/Libraries/GameLab/Editor/Resource/init.lua b/Data/Libraries/GameLab/Editor/Resource/init.lua
new file mode 100644
index 0000000..c44dd0c
--- /dev/null
+++ b/Data/Libraries/GameLab/Editor/Resource/init.lua
@@ -0,0 +1 @@
+-- 资源管理
diff --git a/Data/Libraries/GameLab/Editor/init.lua b/Data/Libraries/GameLab/Editor/init.lua
new file mode 100644
index 0000000..99a8091
--- /dev/null
+++ b/Data/Libraries/GameLab/Editor/init.lua
@@ -0,0 +1,2 @@
+
+
diff --git a/Data/Libraries/LuaPanda/LuaPanda.lua b/Data/Libraries/LuaPanda/LuaPanda.lua
new file mode 100644
index 0000000..c5c307c
--- /dev/null
+++ b/Data/Libraries/LuaPanda/LuaPanda.lua
@@ -0,0 +1,3606 @@
+-- Tencent is pleased to support the open source community by making LuaPanda available.
+-- Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+-- Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+-- https://opensource.org/licenses/BSD-3-Clause
+-- Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+
+-- API:
+-- LuaPanda.printToVSCode(logStr, printLevel, type)
+-- 打印日志到VSCode Output下 LuaPanda Debugger 中
+-- @printLevel: debug(0)/info(1)/error(2) 这里的日志等级需高于launch.json中配置等级日志才能输出 (可选参数,默认0)
+-- @type(可选参数,默认0): 0:VSCode output console 1:VSCode tip 2:VSCode debug console
+
+-- LuaPanda.BP()
+-- 强制打断点,可以在协程中使用。建议使用以下写法:
+-- local ret = LuaPanda and LuaPanda.BP and LuaPanda.BP();
+-- 如果成功加入断点ret返回true,否则是nil
+
+-- LuaPanda.getInfo()
+-- 返回获取调试器信息。包括版本号,是否使用lib库,系统是否支持loadstring(load方法)。返回值类型string, 推荐在调试控制台中使用。
+
+-- LuaPanda.testBreakpoint()
+-- 测试断点,用于分析路径错误导致断点无法停止的情况。测试方法是
+-- 1. launch.json 中开启 stopOnEntry, 或者在代码中加入LuaPanda.BP()。
+-- 2. 运行调试器和 lua 进程,当停止在 stopOnEntry 或者 LuaPanda.BP() 时在调试控制台输入 LuaPanda.testBreakpoint()
+-- 3. 根据提示更新断点后再次输入 LuaPanda.testBreakpoint()。此时系统会输出一些提示,帮助用户分析断点可能无法停止的原因。
+
+-- LuaPanda.doctor()
+-- 返回对当前环境的诊断信息,提示可能存在的问题。返回值类型string, 推荐在调试控制台中使用。
+
+-- LuaPanda.getBreaks()
+-- 获取断点信息,推荐在调试控制台中使用。
+
+-- LuaPanda.serializeTable(table)
+-- 把table序列化为字符串,返回值类型是string。
+
+-- LuaPanda.stopAttach()
+-- 断开连接,停止attach,本次被调试程序运行过程无法再次进行attach连接。
+
+-- 其他说明:
+-- 关于真机调试,首次使用真机调试时要注意下方"用户设置项"中的配置
+-- 1. 确定 attach 开关打开: openAttachMode = true; 这样可以避免先启动手机app之后启动调试器无法连接。
+-- 2. 把连接时间放长: connectTimeoutSec 设置为 0.5 或者 1。首次尝试真机调试时这个值可以设置大一点,之后再根据自己的网络状况向下调整。
+-- 调试方法可以参考 github 文档
+
+--用户设置项
+local openAttachMode = true; --是否开启attach模式。attach模式开启后可以在任意时刻启动vscode连接调试。缺点是没有连接调试时也会略降低lua执行效率(会不断进行attach请求)
+local attachInterval = 1; --attach间隔时间(s)
+local connectTimeoutSec = 0.005; --lua进程作为Client时, 连接超时时间, 单位s. 时间过长等待attach时会造成卡顿,时间过短可能无法连接。建议值0.005 - 0.05
+local listeningTimeoutSec = 0.5; -- lua进程作为Server时,连接超时时间, 单位s. 时间过长等待attach时会造成卡顿,时间过短可能无法连接。建议值0.1 - 1
+local userDotInRequire = true; --兼容require中使用 require(a.b) 和 require(a/b) 的形式引用文件夹中的文件,默认无需修改
+local traversalUserData = false; --如果可以的话(取决于userdata原表中的__pairs),展示userdata中的元素。 如果在调试器中展开userdata时有错误,请关闭此项.
+local customGetSocketInstance = nil; --支持用户实现一个自定义调用luasocket的函数,函数返回值必须是一个socket实例。例: function() return require("socket.core").tcp() end;
+local consoleLogLevel = 2; --打印在控制台(print)的日志等级 0 : all/ 1: info/ 2: error.
+--用户设置项END
+
+local debuggerVer = "3.2.0"; --debugger版本号
+LuaPanda = {};
+local this = LuaPanda;
+local tools = {}; --引用的开源工具,包括json解析和table展开工具等
+this.tools = tools;
+this.curStackId = 0;
+--json处理
+local json;
+--hook状态列表
+local hookState = {
+ DISCONNECT_HOOK = 0, --断开连接
+ LITE_HOOK = 1, --全局无断点
+ MID_HOOK = 2, --全局有断点,本文件无断点
+ ALL_HOOK = 3, --本文件有断点
+};
+--运行状态列表
+local runState = {
+ DISCONNECT = 0, --未连接
+ WAIT_CMD = 1, --已连接,等待命令
+ STOP_ON_ENTRY = 2, --初始状态
+ RUN = 3,
+ STEPOVER = 4,
+ STEPIN = 5,
+ STEPOUT = 6,
+ STEPOVER_STOP = 7,
+ STEPIN_STOP = 8,
+ STEPOUT_STOP = 9,
+ HIT_BREAKPOINT = 10
+};
+
+local TCPSplitChar = "|*|"; --json协议分隔符,请不要修改
+local MAX_TIMEOUT_SEC = 3600 * 24; --网络最大超时等待时间
+--当前运行状态
+local currentRunState;
+local currentHookState;
+--断点信息
+local breaks = {}; --保存断点的数组
+this.breaks = breaks; --供hookLib调用
+local recCallbackId = "";
+--VSCode端传过来的配置,在VSCode端的launch配置,传过来并赋值
+local luaFileExtension = ""; --vscode传过来的脚本后缀
+local cwd = ""; --工作路径
+local DebuggerFileName = ""; --Debugger文件名(原始,未经path处理), 函数中会自动获取
+local DebuggerToolsName = "";
+local lastRunFunction = {}; --上一个执行过的函数。在有些复杂场景下(find,getcomponent)一行会挺两次
+local currentCallStack = {}; --获取当前调用堆栈信息
+local hitBP = false; --BP()中的强制断点命中标记
+local TempFilePath_luaString = ""; --VSCode端配置的临时文件存放路径
+local recordHost; --记录连接端IP
+local recordPort; --记录连接端口号
+local sock; --lua socket 文件描述符
+local server; --server 描述符
+local OSType; --VSCode识别出的系统类型,也可以自行设置。Windows_NT | Linux | Darwin
+local clibPath; --chook库在VScode端的路径,也可自行设置。
+local hookLib; --chook库的引用实例
+local adapterVer; --VScode传来的adapter版本号
+local truncatedOPath; --VScode中用户设置的用于截断opath路径的标志,注意这里可以接受lua魔法字符
+local distinguishSameNameFile = false; --是否区分lua同名文件中的断点,在VScode launch.json 中 distinguishSameNameFile 控制
+--标记位
+local logLevel = 1; --日志等级all/info/error. 此设置对应的是VSCode端设置的日志等级.
+local variableRefIdx = 1; --变量索引
+local variableRefTab = {}; --变量记录table
+local lastRunFilePath = ""; --最后执行的文件路径
+local pathCaseSensitivity = true; --路径是否发大小写敏感,这个选项接收VScode设置,请勿在此处更改
+local recvMsgQueue = {}; --接收的消息队列
+local coroutinePool = setmetatable({}, {__mode = "v"}); --保存用户协程的队列
+local winDiskSymbolUpper = false;--设置win下盘符的大小写。以此确保从VSCode中传入的断点路径,cwd和从lua虚拟机获得的文件路径盘符大小写一致
+local isNeedB64EncodeStr = false;-- 记录是否使用base64编码字符串
+local loadclibErrReason = 'launch.json文件的配置项useCHook被设置为false.';
+local OSTypeErrTip = "";
+local pathErrTip = ""
+local winDiskSymbolTip = "";
+local isAbsolutePath = false;
+local stopOnEntry; --用户在VSCode端设置的是否打开stopOnEntry
+local userSetUseClib; --用户在VSCode端设置的是否是用clib库
+local autoPathMode = false;
+local autoExt; --调试器启动时自动获取到的后缀, 用于检测lua虚拟机返回的路径是否带有文件后缀。他可以是空值或者".lua"等
+local luaProcessAsServer;
+local testBreakpointFlag = false; -- 测试断点的标志位。结合 LuaPanda.testBreakpoint() 测试断点无法停止的原因
+--Step控制标记位
+local stepOverCounter = 0; --STEPOVER over计数器
+local stepOutCounter = 0; --STEPOVER out计数器
+local HOOK_LEVEL = 3; --调用栈偏移量,使用clib时为3,lua中不再使用此变量,而是通过函数getSpecificFunctionStackLevel获取
+local isUseLoadstring = 0;
+local debugger_loadString;
+--临时变量
+local recordBreakPointPath; --记录最后一个[可能命中]的断点,用于getInfo以及doctor的断点测试
+local coroutineCreate; --用来记录lua原始的coroutine.create函数
+local stopConnectTime = 0; --用来临时记录stop断开连接的时间
+local isInMainThread;
+local receiveMsgTimer = 0;
+local isUserSetClibPath = false; --用户是否在本文件中自设了clib路径
+local hitBpTwiceCheck; -- 命中断点的Vscode校验结果,默认true (true是命中,false是未命中)
+local formatPathCache = {}; -- getinfo -> format
+function this.formatPathCache() return formatPathCache; end
+local fakeBreakPointCache = {}; --其中用 路径-{行号列表} 形式保存错误命中信息
+function this.fakeBreakPointCache() return fakeBreakPointCache; end
+--5.1/5.3兼容
+if _VERSION == "Lua 5.1" then
+ debugger_loadString = loadstring;
+else
+ debugger_loadString = load;
+end
+
+--用户在控制台输入信息的环境变量
+local env = setmetatable({ }, {
+ __index = function( _ , varName )
+ local ret = this.getWatchedVariable( varName, _G.LuaPanda.curStackId , false);
+ return ret;
+ end,
+
+ __newindex = function( _ , varName, newValue )
+ this.setVariableValue( varName, _G.LuaPanda.curStackId, newValue);
+ end
+});
+
+-----------------------------------------------------------------------------
+-- 流程
+-----------------------------------------------------------------------------
+
+---this.bindServer 当lua进程作为Server时,server绑定函数
+--- server 在bind时创建, 连接成功后关闭listen , disconnect时置空。reconnect时会查询server,没有的话重新绑定,如果已存在直接accept
+function this.bindServer(host, port)
+ server = sock
+ server:settimeout(listeningTimeoutSec);
+ assert(server:bind(host, port));
+ server:setoption("reuseaddr", true); --防止已连接状态下新的连接进入,不再reuse
+ assert(server:listen(0));
+end
+
+-- 以lua作为服务端的形式启动调试器
+-- @host 绑定ip , 默认 0.0.0.0
+-- @port 绑定port, 默认 8818
+function this.startServer(host, port)
+ host = tostring(host or "0.0.0.0") ;
+ port = tonumber(port) or 8818;
+ luaProcessAsServer = true;
+ this.printToConsole("Debugger start as SERVER. bind host:" .. host .. " port:".. tostring(port), 1);
+ if sock ~= nil then
+ this.printToConsole("[Warning] 调试器已经启动,请不要再次调用start()" , 1);
+ return;
+ end
+
+ --尝试初次连接
+ this.changeRunState(runState.DISCONNECT);
+ if not this.reGetSock() then
+ this.printToConsole("[Error] LuaPanda debugger start success , but get Socket fail , please install luasocket!", 2);
+ return;
+ end
+ recordHost = host;
+ recordPort = port;
+
+ this.bindServer(recordHost, recordPort);
+ local connectSuccess = server:accept();
+ sock = connectSuccess;
+
+ if connectSuccess then
+ this.printToConsole("First connect success!");
+ this.connectSuccess();
+ else
+ this.printToConsole("First connect failed!");
+ this.changeHookState(hookState.DISCONNECT_HOOK);
+ end
+end
+
+-- 启动调试器
+-- @host adapter端ip, 默认127.0.0.1
+-- @port adapter端port ,默认8818
+function this.start(host, port)
+ host = tostring(host or "127.0.0.1") ;
+ port = tonumber(port) or 8818;
+ this.printToConsole("Debugger start as CLIENT. connect host:" .. host .. " port:".. tostring(port), 1);
+ if sock ~= nil then
+ this.printToConsole("[Warning] 调试器已经启动,请不要再次调用start()" , 1);
+ return;
+ end
+
+ --尝试初次连接
+ this.changeRunState(runState.DISCONNECT);
+ if not this.reGetSock() then
+ this.printToConsole("[Error] Start debugger but get Socket fail , please install luasocket!", 2);
+ return;
+ end
+ recordHost = host;
+ recordPort = port;
+
+ sock:settimeout(connectTimeoutSec);
+ local connectSuccess = this.sockConnect(sock);
+
+ if connectSuccess then
+ this.printToConsole("First connect success!");
+ this.connectSuccess();
+ else
+ this.printToConsole("First connect failed!");
+ this.changeHookState(hookState.DISCONNECT_HOOK);
+ end
+end
+
+function this.sockConnect(sock)
+ if sock then
+ local connectSuccess, status = sock:connect(recordHost, recordPort);
+ if status == "connection refused" or (not connectSuccess and status == "already connected") then
+ this.reGetSock();
+ end
+
+ return connectSuccess
+ end
+ return nil;
+end
+
+-- 连接成功,开始初始化
+function this.connectSuccess()
+ if server then
+ server:close(); -- 停止listen
+ end
+
+ this.changeRunState(runState.WAIT_CMD);
+ this.printToConsole("connectSuccess", 1);
+ --设置初始状态
+ local ret = this.debugger_wait_msg();
+
+ --获取debugger文件路径
+ if DebuggerFileName == "" then
+ local info = debug.getinfo(1, "S")
+ for k,v in pairs(info) do
+ if k == "source" then
+ DebuggerFileName = tostring(v);
+ -- 从代码中去后缀
+ autoExt = DebuggerFileName:gsub('.*[Ll][Uu][Aa][Pp][Aa][Nn][Dd][Aa]', '');
+
+ if hookLib ~= nil then
+ hookLib.sync_debugger_path(DebuggerFileName);
+ end
+ end
+ end
+ end
+ if DebuggerToolsName == "" then
+ DebuggerToolsName = tools.getFileSource();
+ if hookLib ~= nil then
+ hookLib.sync_tools_path(DebuggerToolsName);
+ end
+ end
+
+ if ret == false then
+ this.printToVSCode("[debugger error]初始化未完成, 建立连接但接收初始化消息失败。请更换端口重试", 2);
+ return;
+ end
+ this.printToVSCode("debugger init success", 1);
+
+ this.changeHookState(hookState.ALL_HOOK);
+ if hookLib == nil then
+ --协程调试
+ this.changeCoroutinesHookState();
+ end
+
+end
+
+--重置数据
+function this.clearData()
+ OSType = nil;
+ clibPath = nil;
+ -- reset breaks
+ breaks = {};
+ formatPathCache = {};
+ fakeBreakPointCache = {};
+ this.breaks = breaks;
+ if hookLib ~= nil then
+ hookLib.sync_breakpoints(); --清空断点信息
+ hookLib.clear_pathcache(); --清空路径缓存
+ end
+end
+
+-- 本次连接过程中停止attach ,以提高运行效率
+function this.stopAttach()
+ openAttachMode = false;
+ this.printToConsole("Debugger stopAttach", 1);
+ this.clearData()
+ this.changeHookState( hookState.DISCONNECT_HOOK );
+ stopConnectTime = os.time();
+ this.changeRunState(runState.DISCONNECT);
+ if sock ~= nil then
+ sock:close();
+ if luaProcessAsServer and server then server = nil; end;
+ end
+end
+
+--断开连接
+function this.disconnect()
+ this.printToConsole("Debugger disconnect", 1);
+ this.clearData()
+ this.changeHookState( hookState.DISCONNECT_HOOK );
+ stopConnectTime = os.time();
+ this.changeRunState(runState.DISCONNECT);
+
+ if sock ~= nil then
+ sock:close();
+ sock = nil;
+ server = nil;
+ end
+
+ if recordHost == nil or recordPort == nil then
+ --异常情况处理, 在调用LuaPanda.start()前首先调用了LuaPanda.disconnect()
+ this.printToConsole("[Warning] User call LuaPanda.disconnect() before set debug ip & port, please call LuaPanda.start() first!", 2);
+ return;
+ end
+
+ this.reGetSock();
+end
+
+function this.replaceCoroutineFuncs()
+ if hookLib == nil then
+ if coroutineCreate == nil and type(coroutine.create) == "function" then
+ this.printToConsole("change coroutine.create");
+ coroutineCreate = coroutine.create;
+ coroutine.create = function(...)
+ local co = coroutineCreate(...)
+ table.insert(coroutinePool, co);
+ --运行状态下,创建协程即启动hook
+ this.changeCoroutineHookState(co, currentHookState);
+ return co;
+ end
+ end
+ end
+end
+
+-----------------------------------------------------------------------------
+-- 调试器通用方法
+-----------------------------------------------------------------------------
+-- 返回断点信息
+function this.getBreaks()
+ return breaks;
+end
+
+---testBreakpoint 测试断点
+function this.testBreakpoint()
+ if recordBreakPointPath and recordBreakPointPath ~= "" then
+ -- testBreakpointFlag = false;
+ return this.breakpointTestInfo();
+ else
+ local strTable = {};
+ strTable[#strTable + 1] = "正在准备进行断点测试,请按照如下步骤操作\n"
+ strTable[#strTable + 1] = "1. 请[删除]当前项目中所有断点;\n"
+ strTable[#strTable + 1] = "2. 在当前停止行打一个断点;\n"
+ strTable[#strTable + 1] = "3. 再次运行 'LuaPanda.testBreakpoint()'"
+ testBreakpointFlag = true;
+
+ return table.concat(strTable);
+ end
+end
+
+-- 返回路径相关信息
+-- cwd:配置的工程路径 | info["source"]:通过 debug.getinfo 获得执行文件的路径 | format:格式化后的文件路径
+function this.breakpointTestInfo()
+ local ly = this.getSpecificFunctionStackLevel(lastRunFunction.func);
+ if type(ly) ~= "number" then
+ ly = 2;
+ end
+ local runSource = lastRunFunction["source"];
+ if runSource == nil and hookLib ~= nil then
+ runSource = this.getPath(tostring(hookLib.get_last_source()));
+ end
+ local info = debug.getinfo(ly, "S");
+ local NormalizedPath = this.formatOpath(info["source"]);
+ NormalizedPath = this.truncatedPath(NormalizedPath, truncatedOPath);
+
+ local strTable = {}
+ local FormatedPath = tostring(runSource);
+ strTable[#strTable + 1] = "\n- BreakPoint Test:"
+ strTable[#strTable + 1] = "\nUser set lua extension: ." .. tostring(luaFileExtension);
+ strTable[#strTable + 1] = "\nAuto get lua extension: " .. tostring(autoExt);
+ if truncatedOPath and truncatedOPath ~= '' then
+ strTable[#strTable + 1] = "\nUser set truncatedOPath: " .. truncatedOPath;
+ end
+ strTable[#strTable + 1] = "\nGetInfo: ".. info["source"];
+ strTable[#strTable + 1] = "\nNormalized: " .. NormalizedPath;
+ strTable[#strTable + 1] = "\nFormated: " .. FormatedPath;
+ if recordBreakPointPath and recordBreakPointPath ~= "" then
+ strTable[#strTable + 1] = "\nBreakpoint: " .. recordBreakPointPath;
+ end
+
+ if not autoPathMode then
+ if isAbsolutePath then
+ strTable[#strTable + 1] = "\n说明:从lua虚拟机获取到的是绝对路径,Formated使用GetInfo路径。" .. winDiskSymbolTip;
+ else
+ strTable[#strTable + 1] = "\n说明:从lua虚拟机获取到的路径(GetInfo)是相对路径,调试器运行依赖的绝对路径(Formated)是来源于cwd+GetInfo拼接。如Formated路径错误请尝试调整cwd或改变VSCode打开文件夹的位置。也可以在Formated对应的文件下打一个断点,调整直到Formated和Breaks Info中断点路径完全一致。" .. winDiskSymbolTip;
+ end
+ else
+ strTable[#strTable + 1] = "\n说明:自动路径(autoPathMode)模式已开启。";
+ if recordBreakPointPath and recordBreakPointPath ~= "" then
+ if string.find(recordBreakPointPath , FormatedPath, (-1) * string.len(FormatedPath) , true) then
+ -- 短路径断点命中
+ if distinguishSameNameFile == false then
+ strTable[#strTable + 1] = "本文件中断点可正常命中。"
+ strTable[#strTable + 1] = "同名文件中的断点识别(distinguishSameNameFile) 未开启,请确保 VSCode 断点不要存在于同名 lua 文件中。";
+ else
+ strTable[#strTable + 1] = "同名文件中的断点识别(distinguishSameNameFile) 已开启。";
+ if string.find(recordBreakPointPath, NormalizedPath, 1, true) then
+ strTable[#strTable + 1] = "本文件中断点可被正常命中"
+ else
+ strTable[#strTable + 1] = "断点可能无法被命中,因为 lua 虚拟机中获得的路径 Normalized 不是断点路径 Breakpoint 的子串。 如有需要,可以在 launch.json 中设置 truncatedOPath 来去除 Normalized 部分路径。"
+ end
+ end
+ else
+ strTable[#strTable + 1] = "断点未被命中,原因是 Formated 不是 Breakpoint 路径的子串,或者 Formated 和 Breakpoint 文件后缀不一致"
+ end
+ else
+ strTable[#strTable + 1] = "如果要进行断点测试,请使用 LuaPanda.testBreakpoint()。"
+ end
+ end
+ return table.concat(strTable)
+end
+
+--返回版本号等配置
+function this.getBaseInfo()
+ local strTable = {};
+ local jitVer = "";
+ if jit and jit.version then
+ jitVer = "," .. tostring(jit.version);
+ end
+
+ strTable[#strTable + 1] = "Lua Ver:" .. _VERSION .. jitVer .." | Adapter Ver:" .. tostring(adapterVer) .. " | Debugger Ver:" .. tostring(debuggerVer);
+ local moreInfoStr = "";
+ if hookLib ~= nil then
+ local clibVer, forluaVer = hookLib.sync_getLibVersion();
+ local clibStr = forluaVer ~= nil and tostring(clibVer) .. " for " .. tostring(math.ceil(forluaVer)) or tostring(clibVer);
+ strTable[#strTable + 1] = " | hookLib Ver:" .. clibStr;
+ moreInfoStr = moreInfoStr .. "说明: 已加载 libpdebug 库.";
+ else
+ moreInfoStr = moreInfoStr .. "说明: 未能加载 libpdebug 库。原因请使用 LuaPanda.doctor() 查看";
+ end
+
+ local outputIsUseLoadstring = false
+ if type(isUseLoadstring) == "number" and isUseLoadstring == 1 then
+ outputIsUseLoadstring = true;
+ end
+
+ strTable[#strTable + 1] = " | supportREPL:".. tostring(outputIsUseLoadstring);
+ strTable[#strTable + 1] = " | useBase64EncodeString:".. tostring(isNeedB64EncodeStr);
+ strTable[#strTable + 1] = " | codeEnv:" .. tostring(OSType);
+ strTable[#strTable + 1] = " | distinguishSameNameFile:" .. tostring(distinguishSameNameFile) .. '\n';
+
+ strTable[#strTable + 1] = moreInfoStr;
+ if OSTypeErrTip ~= nil and OSTypeErrTip ~= '' then
+ strTable[#strTable + 1] = '\n' ..OSTypeErrTip;
+ end
+ return table.concat(strTable);
+end
+
+--自动诊断当前环境的错误,并输出信息
+function this.doctor()
+ local strTable = {};
+ if debuggerVer ~= adapterVer then
+ strTable[#strTable + 1] = "\n- 建议更新版本\nLuaPanda VSCode插件版本是" .. adapterVer .. ", LuaPanda.lua文件版本是" .. debuggerVer .. "。建议检查并更新到最新版本。";
+ strTable[#strTable + 1] = "\n更新方式 : https://github.com/Tencent/LuaPanda/blob/master/Docs/Manual/update.md";
+ strTable[#strTable + 1] = "\nRelease版本: https://github.com/Tencent/LuaPanda/releases";
+ end
+ --plibdebug
+ if hookLib == nil then
+ strTable[#strTable + 1] = "\n\n- libpdebug 库没有加载\n";
+ if userSetUseClib then
+ --用户允许使用clib插件
+ if isUserSetClibPath == true then
+ --用户自设了clib地址
+ strTable[#strTable + 1] = "用户使用 LuaPanda.lua 中 clibPath 变量指定了 plibdebug 的位置: " .. clibPath;
+ if this.tryRequireClib("libpdebug", clibPath) then
+ strTable[#strTable + 1] = "\n引用成功";
+ else
+ strTable[#strTable + 1] = "\n引用错误:" .. loadclibErrReason;
+ end
+ else
+ --使用默认clib地址
+ local clibExt, platform;
+ if OSType == "Darwin" then clibExt = "/?.so;"; platform = "mac";
+ elseif OSType == "Linux" then clibExt = "/?.so;"; platform = "linux";
+ else clibExt = "/?.dll;"; platform = "win"; end
+ local lua_ver;
+ if _VERSION == "Lua 5.1" then
+ lua_ver = "501";
+ else
+ lua_ver = "503";
+ end
+ local x86Path = clibPath .. platform .."/x86/".. lua_ver .. clibExt;
+ local x64Path = clibPath .. platform .."/x86_64/".. lua_ver .. clibExt;
+
+ strTable[#strTable + 1] = "尝试引用x64库: ".. x64Path;
+ if this.tryRequireClib("libpdebug", x64Path) then
+ strTable[#strTable + 1] = "\n引用成功";
+ else
+ strTable[#strTable + 1] = "\n引用错误:" .. loadclibErrReason;
+ strTable[#strTable + 1] = "\n尝试引用x86库: ".. x86Path;
+ if this.tryRequireClib("libpdebug", x86Path) then
+ strTable[#strTable + 1] = "\n引用成功";
+ else
+ strTable[#strTable + 1] = "\n引用错误:" .. loadclibErrReason;
+ end
+ end
+ end
+ else
+ strTable[#strTable + 1] = "原因是" .. loadclibErrReason;
+ end
+ end
+
+ --path
+ --尝试直接读当前getinfo指向的文件,看能否找到。如果能,提示正确,如果找不到,给出提示,建议玩家在这个文件中打一个断点
+ --检查断点,文件和当前文件的不同,给出建议
+ local runSource = lastRunFilePath;
+ if hookLib ~= nil then
+ runSource = this.getPath(tostring(hookLib.get_last_source()));
+ end
+
+ -- 在精确路径模式下的路径错误检测
+ if not autoPathMode and runSource and runSource ~= "" then
+ -- 读文件
+ local isFileExist = this.fileExists(runSource);
+ if not isFileExist then
+ strTable[#strTable + 1] = "\n\n- 路径存在问题\n";
+ --解析路径,得到文件名,到断点路径中查这个文件名
+ local pathArray = this.stringSplit(runSource, '/');
+ --如果pathArray和断点能匹配上
+ local fileMatch= false;
+ for key, _ in pairs(this.getBreaks()) do
+ if string.find(key, pathArray[#pathArray], 1, true) then
+ --和断点匹配了
+ fileMatch = true;
+ -- retStr = retStr .. "\n请对比如下路径:\n";
+ strTable[#strTable + 1] = this.breakpointTestInfo();
+ strTable[#strTable + 1] = "\nfilepath: " .. key;
+ if isAbsolutePath then
+ strTable[#strTable + 1] = "\n说明:从lua虚拟机获取到的是绝对路径,format使用getinfo路径。";
+ else
+ strTable[#strTable + 1] = "\n说明:从lua虚拟机获取到的是相对路径,调试器运行依赖的绝对路径(format)是来源于cwd+getinfo拼接。";
+ end
+ strTable[#strTable + 1] = "\nfilepath是VSCode通过获取到的文件正确路径 , 对比format和filepath,调整launch.json中CWD,或改变VSCode打开文件夹的位置。使format和filepath一致即可。\n如果format和filepath路径仅大小写不一致,设置launch.json中 pathCaseSensitivity:false 可忽略路径大小写";
+ end
+ end
+
+ if fileMatch == false then
+ --未能和断点匹配
+ strTable[#strTable + 1] = "\n找不到文件:" .. runSource .. ", 请检查路径是否正确。\n或者在VSCode文件" .. pathArray[#pathArray] .. "中打一个断点后,再执行一次doctor命令,查看路径分析结果。";
+ end
+ end
+ end
+
+ --日志等级对性能的影响
+ if logLevel < 1 or consoleLogLevel < 1 then
+ strTable[#strTable + 1] = "\n\n- 日志等级\n";
+ if logLevel < 1 then
+ strTable[#strTable + 1] = "当前日志等级是" .. logLevel .. ", 会产生大量日志,降低调试速度。建议调整launch.json中logLevel:1";
+ end
+ if consoleLogLevel < 1 then
+ strTable[#strTable + 1] = "当前console日志等级是" .. consoleLogLevel .. ", 过低的日志等级会降低调试速度,建议调整LuaPanda.lua文件头部consoleLogLevel=2";
+ end
+ end
+
+ if #strTable == 0 then
+ strTable[#strTable + 1] = "未检测出问题";
+ end
+ return table.concat(strTable);
+end
+
+function this.fileExists(path)
+ local f=io.open(path,"r");
+ if f~= nil then io.close(f) return true else return false end
+ end
+
+--返回一些信息,帮助用户定位问题
+function this.getInfo()
+ --用户设置项
+ local strTable = {};
+ strTable[#strTable + 1] = "\n- Base Info: \n";
+ strTable[#strTable + 1] = this.getBaseInfo();
+ --已经加载C库,x86/64 未能加载,原因
+ strTable[#strTable + 1] = "\n\n- User Setting: \n";
+ strTable[#strTable + 1] = "stopOnEntry:" .. tostring(stopOnEntry) .. ' | ';
+ -- strTable[#strTable + 1] = "luaFileExtension:" .. luaFileExtension .. ' | ';
+ strTable[#strTable + 1] = "logLevel:" .. logLevel .. ' | ' ;
+ strTable[#strTable + 1] = "consoleLogLevel:" .. consoleLogLevel .. ' | ';
+ strTable[#strTable + 1] = "pathCaseSensitivity:" .. tostring(pathCaseSensitivity) .. ' | ';
+ strTable[#strTable + 1] = "attachMode:".. tostring(openAttachMode).. ' | ';
+ strTable[#strTable + 1] = "autoPathMode:".. tostring(autoPathMode).. ' | ';
+
+ if userSetUseClib then
+ strTable[#strTable + 1] = "useCHook:true";
+ else
+ strTable[#strTable + 1] = "useCHook:false";
+ end
+
+ if logLevel == 0 or consoleLogLevel == 0 then
+ strTable[#strTable + 1] = "\n说明:日志等级过低,会影响执行效率。请调整logLevel和consoleLogLevel值 >= 1";
+ end
+
+ strTable[#strTable + 1] = "\n\n- Path Info: \n";
+ strTable[#strTable + 1] = "clibPath: " .. tostring(clibPath) .. '\n';
+ strTable[#strTable + 1] = "debugger: " .. DebuggerFileName .. " | " .. this.getPath(DebuggerFileName) .. '\n';
+ strTable[#strTable + 1] = "cwd : " .. cwd .. '\n';
+ strTable[#strTable + 1] = this.breakpointTestInfo();
+
+ if pathErrTip ~= nil and pathErrTip ~= '' then
+ strTable[#strTable + 1] = '\n' .. pathErrTip;
+ end
+
+ strTable[#strTable + 1] = "\n\n- Breaks Info: \nUse 'LuaPanda.getBreaks()' to watch.";
+ return table.concat(strTable);
+end
+
+--判断是否在协程中
+function this.isInMain()
+ return isInMainThread;
+end
+
+--添加路径,尝试引用库。完成后把cpath还原,返回引用结果true/false
+-- @libName 库名
+-- path lib的cpath路径
+function this.tryRequireClib(libName , libPath)
+ this.printToVSCode("tryRequireClib search : [" .. libName .. "] in "..libPath);
+ local savedCpath = package.cpath;
+ package.cpath = package.cpath .. ';' .. libPath;
+ this.printToVSCode("package.cpath:" .. package.cpath);
+ local status, err = pcall(function() hookLib = require(libName) end);
+ if status then
+ if type(hookLib) == "table" and this.getTableMemberNum(hookLib) > 0 then
+ this.printToVSCode("tryRequireClib success : [" .. libName .. "] in "..libPath);
+ package.cpath = savedCpath;
+ return true;
+ else
+ loadclibErrReason = "tryRequireClib fail : require success, but member function num <= 0; [" .. libName .. "] in "..libPath;
+ this.printToVSCode(loadclibErrReason);
+ hookLib = nil;
+ package.cpath = savedCpath;
+ return false;
+ end
+ else
+ -- 此处考虑到tryRequireClib会被调用两次,日志级别设置为0,防止输出不必要的信息。
+ loadclibErrReason = err;
+ this.printToVSCode("[Require clib error]: " .. err, 0);
+ end
+ package.cpath = savedCpath;
+ return false
+end
+------------------------字符串处理-------------------------
+-- 倒序查找字符串 a.b/c查找/ , 返回4
+-- @str 被查找的长串
+-- @subPattern 查找的子串, 也可以是pattern
+-- @plain plane text / pattern
+-- @return 未找到目标串返回nil. 否则返回倒序找到的字串位置
+function this.revFindString(str, subPattern, plain)
+ local revStr = string.reverse(str);
+ local _, idx = string.find(revStr, subPattern, 1, plain);
+ if idx == nil then return nil end;
+ return string.len(revStr) - idx + 1;
+end
+
+-- 反序裁剪字符串 如:print(subString("a.b/c", "/"))输出c
+-- @return 未找到目标串返回nil. 否则返回被裁剪后的字符串
+function this.revSubString(str, subStr, plain)
+ local idx = this.revFindString(str, subStr, plain)
+ if idx == nil then return nil end;
+ return string.sub(str, idx + 1, str.length)
+end
+
+-- 把字符串按reps分割成并放入table
+-- @str 目标串
+-- @reps 分割符。注意这个分隔符是一个pattern
+function this.stringSplit( str, separator )
+ local retStrTable = {}
+ string.gsub(str, '[^' .. separator ..']+', function ( word )
+ table.insert(retStrTable, word)
+ end)
+ return retStrTable;
+end
+
+-- 保存CallbackId(通信序列号)
+function this.setCallbackId( id )
+ if id ~= nil and id ~= "0" then
+ recCallbackId = tostring(id);
+ end
+end
+
+-- 读取CallbackId(通信序列号)。读取后记录值将被置空
+function this.getCallbackId()
+ if recCallbackId == nil then
+ recCallbackId = "0";
+ end
+ local id = recCallbackId;
+ recCallbackId = "0";
+ return id;
+end
+
+-- reference from https://www.lua.org/pil/20.1.html
+function this.trim (s)
+ return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
+end
+
+--返回table中成员数量(数字key和非数字key之和)
+-- @t 目标table
+-- @return 元素数量
+function this.getTableMemberNum(t)
+ local retNum = 0;
+ if type(t) ~= "table" then
+ this.printToVSCode("[debugger Error] getTableMemberNum get "..tostring(type(t)), 2)
+ return retNum;
+ end
+ for k,v in pairs(t) do
+ retNum = retNum + 1;
+ end
+ return retNum;
+end
+
+-- 生成一个消息Table
+function this.getMsgTable(cmd ,callbackId)
+ callbackId = callbackId or 0;
+ local msgTable = {};
+ msgTable["cmd"] = cmd;
+ msgTable["callbackId"] = callbackId;
+ msgTable["info"] = {};
+ return msgTable;
+end
+
+function this.serializeTable(tab, name)
+ local sTable = tools.serializeTable(tab, name);
+ return sTable;
+end
+------------------------日志打印相关-------------------------
+-- 把日志打印在VSCode端
+-- @str: 日志内容
+-- @printLevel: all(0)/info(1)/error(2)
+-- @type: 0:vscode console 1:vscode tip
+function this.printToVSCode(str, printLevel, type)
+ type = type or 0;
+ printLevel = printLevel or 0;
+ if currentRunState == runState.DISCONNECT or logLevel > printLevel then
+ return;
+ end
+
+ local sendTab = {};
+ sendTab["callbackId"] = "0";
+ if type == 0 then
+ sendTab["cmd"] = "output";
+ elseif type == 1 then
+ sendTab["cmd"] = "tip";
+ else -- type == 2
+ sendTab["cmd"] = "debug_console";
+ end
+ sendTab["info"] = {};
+ sendTab["info"]["logInfo"] = tostring(str);
+ this.sendMsg(sendTab);
+end
+
+-- 把日志打印在控制台
+-- @str: 日志内容
+-- @printLevel: all(0)/info(1)/error(2)
+function this.printToConsole(str, printLevel)
+ printLevel = printLevel or 0;
+ if consoleLogLevel > printLevel then
+ return;
+ end
+ print("[LuaPanda] ".. tostring(str));
+end
+
+-----------------------------------------------------------------------------
+-- 提升兼容性方法
+-----------------------------------------------------------------------------
+--生成平台无关的路径。
+--return:nil(error)/path
+function this.genUnifiedPath(path)
+ if path == "" or path == nil then
+ return "";
+ end
+ --大小写不敏感时,路径全部转为小写
+ if pathCaseSensitivity == false then
+ path = string.lower(path);
+ end
+ --统一路径全部替换成/
+ path = string.gsub(path, [[\]], "/");
+ --处理 /../ /./
+ local pathTab = this.stringSplit(path, '/');
+ local newPathTab = {};
+ for k, v in ipairs(pathTab) do
+ if v == '.' then
+ --continue
+ elseif v == ".." and #newPathTab >= 1 and newPathTab[#newPathTab]:sub(2,2) ~= ':' then
+ --newPathTab有元素,最后一项不是X:
+ table.remove(newPathTab);
+ else
+ table.insert(newPathTab, v);
+ end
+ end
+ --重新拼合后如果是mac路径第一位是/
+ local newpath = table.concat(newPathTab, '/');
+ if path:sub(1,1) == '/' then
+ newpath = '/'.. newpath;
+ end
+
+ --win下按照winDiskSymbolUpper的设置修改盘符大小
+ if "Windows_NT" == OSType then
+ if winDiskSymbolUpper then
+ newpath = newpath:gsub("^%a:", string.upper);
+ winDiskSymbolTip = "路径中Windows盘符已转为大写。"
+ else
+ newpath = newpath:gsub("^%a:", string.lower);
+ winDiskSymbolTip = "路径中Windows盘符已转为小写。"
+ end
+ end
+
+ return newpath;
+end
+
+function this.getCacheFormatPath(source)
+ if source == nil then return formatPathCache end;
+ return formatPathCache[source];
+end
+
+function this.setCacheFormatPath(source, dest)
+ formatPathCache[source] = dest;
+end
+
+-- 处理 opath(info.source) 的函数, 生成一个规范的路径函数(和VScode端checkRightPath逻辑完全一致)
+function this.formatOpath(opath)
+ -- delete @
+ if opath:sub(1,1) == '@' then
+ opath = opath:sub(2);
+ end
+ -- change ./ to /
+ if opath:sub(1,2) == './' then
+ opath = opath:sub(2);
+ end
+
+ opath = this.genUnifiedPath(opath);
+
+ -- lower
+ if pathCaseSensitivity == false then
+ opath = string.lower(opath);
+ end
+ --把filename去除后缀
+ if autoExt == nil or autoExt == '' then
+ -- 在虚拟机返回路径没有后缀的情况下,用户必须自设后缀
+ -- 确定filePath中最后一个.xxx 不等于用户配置的后缀, 则把所有的. 转为 /
+ if not opath:find(luaFileExtension , (-1) * luaFileExtension:len(), true) then
+ -- getinfo 路径没有后缀,把 . 全部替换成 / ,我们不允许用户在文件(或文件夹)名称中出现"." , 因为无法区分
+ opath = string.gsub(opath, "%.", "/");
+ else
+ -- 有后缀,那么把除后缀外的部分中的. 转为 /
+ opath = this.changePotToSep(opath, luaFileExtension);
+ end
+ else
+ -- 虚拟机路径有后缀
+ opath = this.changePotToSep(opath, autoExt);
+ end
+
+ -- 截取 路径+文件名 (不带后缀)
+ -- change pot to /
+ -- opath = string.gsub(opath, "%.", "/");
+ return opath;
+end
+
+-----------------------------------------------------------------------------
+-- 内存相关
+-----------------------------------------------------------------------------
+function this.sendLuaMemory()
+ local luaMem = collectgarbage("count");
+ local sendTab = {};
+ sendTab["callbackId"] = "0";
+ sendTab["cmd"] = "refreshLuaMemory";
+ sendTab["info"] = {};
+ sendTab["info"]["memInfo"] = tostring(luaMem);
+ this.sendMsg(sendTab);
+end
+
+-----------------------------------------------------------------------------
+-- 网络相关方法
+-----------------------------------------------------------------------------
+-- 刷新socket
+-- @return true/false 刷新成功/失败
+function this.reGetSock()
+ if server then return true end
+
+ if sock ~= nil then
+ pcall(function() sock:close() end);
+ end
+
+ --call slua-unreal luasocket
+ sock = lua_extension and lua_extension.luasocket and lua_extension.luasocket().tcp();
+ if sock == nil then
+ --call normal luasocket
+ if pcall(function() sock = require("socket.core").tcp(); end) then
+ this.printToConsole("reGetSock success");
+ else
+ --call custom function to get socket
+ if customGetSocketInstance and pcall( function() sock = customGetSocketInstance(); end ) then
+ this.printToConsole("reGetSock custom success");
+ else
+ this.printToConsole("[Error] reGetSock fail", 2);
+ return false;
+ end
+ end
+ else
+ --set ue4 luasocket
+ this.printToConsole("reGetSock ue4 success");
+ end
+ return true;
+end
+
+-- 定时(以函数return为时机) 进行attach连接
+-- 返回值 hook 可以继续往下走时返回1 ,无需继续时返回0
+function this.reConnect()
+ if currentHookState == hookState.DISCONNECT_HOOK then
+ if os.time() - stopConnectTime < attachInterval then
+ -- 未到重连时间
+ -- this.printToConsole("Reconnect time less than 1s");
+ -- this.printToConsole("os.time:".. os.time() .. " | stopConnectTime:" ..stopConnectTime);
+ return 0;
+ end
+ this.printToConsole("Reconnect !");
+ if sock == nil then
+ this.reGetSock();
+ end
+
+ local connectSuccess;
+ if luaProcessAsServer == true and currentRunState == runState.DISCONNECT then
+ -- 在 Server 模式下,以及当前处于未连接状态下,才尝试accept新链接。如果不判断可能会出现多次连接,导致sock被覆盖
+ if server == nil then
+ this.bindServer(recordHost, recordPort);
+ end
+
+ sock = server:accept();
+ connectSuccess = sock;
+ else
+ sock:settimeout(connectTimeoutSec);
+ connectSuccess = this.sockConnect(sock);
+ end
+
+ if connectSuccess then
+ this.printToConsole("reconnect success");
+ this.connectSuccess();
+ return 1;
+ else
+ this.printToConsole("reconnect failed" );
+ stopConnectTime = os.time();
+ return 0;
+ end
+ end
+ -- 不必重连,正常继续运行
+ return 1;
+end
+
+-- 向adapter发消息
+-- @sendTab 消息体table
+function this.sendMsg( sendTab )
+ if isNeedB64EncodeStr and sendTab["info"] ~= nil then
+ for _, v in ipairs(sendTab["info"]) do
+ if v["type"] == "string" then
+ v["value"] = tools.base64encode(v["value"])
+ end
+ end
+ end
+
+ local sendStr = json.encode(sendTab);
+ if currentRunState == runState.DISCONNECT then
+ this.printToConsole("[debugger error] disconnect but want sendMsg:" .. sendStr, 2);
+ this.disconnect();
+ return;
+ end
+
+ local succ,err;
+ if pcall(function() succ,err = sock:send(sendStr..TCPSplitChar.."\n"); end) then
+ if succ == nil then
+ if err == "closed" then
+ this.disconnect();
+ end
+ end
+ end
+end
+
+-- 处理 收到的消息
+-- @dataStr 接收的消息json
+function this.dataProcess( dataStr )
+ this.printToVSCode("debugger get:"..dataStr);
+ local dataTable = json.decode(dataStr);
+ if dataTable == nil then
+ this.printToVSCode("[error] Json is error", 2);
+ return;
+ end
+
+ if dataTable.callbackId ~= "0" then
+ this.setCallbackId(dataTable.callbackId);
+ end
+
+ if dataTable.cmd == "continue" then
+ local info = dataTable.info;
+ if info.isFakeHit == "true" and info.fakeBKPath and info.fakeBKLine then
+ -- 设置校验结果标志位,以便hook流程知道结果
+ hitBpTwiceCheck = false;
+ if hookLib ~= nil and hookLib.set_bp_twice_check_res then
+ -- 把结果同步给C
+ hookLib.set_bp_twice_check_res(0);
+ end
+ -- 把假断点的信息加入cache
+ if nil == fakeBreakPointCache[info.fakeBKPath] then
+ fakeBreakPointCache[info.fakeBKPath] = {};
+ end
+ table.insert(fakeBreakPointCache[info.fakeBKPath] ,info.fakeBKLine);
+ else
+ this.changeRunState(runState.RUN);
+ end
+ local msgTab = this.getMsgTable("continue", this.getCallbackId());
+ this.sendMsg(msgTab);
+
+ elseif dataTable.cmd == "stopOnStep" then
+ this.changeRunState(runState.STEPOVER);
+ local msgTab = this.getMsgTable("stopOnStep", this.getCallbackId());
+ this.sendMsg(msgTab);
+ this.changeHookState(hookState.ALL_HOOK);
+
+ elseif dataTable.cmd == "stopOnStepIn" then
+ this.changeRunState(runState.STEPIN);
+ local msgTab = this.getMsgTable("stopOnStepIn", this.getCallbackId());
+ this.sendMsg(msgTab);
+ this.changeHookState(hookState.ALL_HOOK);
+
+ elseif dataTable.cmd == "stopOnStepOut" then
+ this.changeRunState(runState.STEPOUT);
+ local msgTab = this.getMsgTable("stopOnStepOut", this.getCallbackId());
+ this.sendMsg(msgTab);
+ this.changeHookState(hookState.ALL_HOOK);
+
+ elseif dataTable.cmd == "setBreakPoint" then
+ this.printToVSCode("dataTable.cmd == setBreakPoint");
+ -- 设置断点时,把 fakeBreakPointCache 清空。这是一个简单的做法,也可以清除具体的条目
+ fakeBreakPointCache = {}
+ local bkPath = dataTable.info.path;
+ bkPath = this.genUnifiedPath(bkPath);
+ if testBreakpointFlag then
+ recordBreakPointPath = bkPath;
+ end
+ if autoPathMode then
+ -- 自动路径模式下,仅保留文件名
+ -- table[文件名.后缀] -- [fullpath] -- [line , type]
+ -- | - [fullpath] -- [line , type]
+
+ local bkShortPath = this.getFilenameFromPath(bkPath);
+ if breaks[bkShortPath] == nil then
+ breaks[bkShortPath] = {};
+ end
+ breaks[bkShortPath][bkPath] = dataTable.info.bks;
+ -- 当v为空时,从断点列表中去除文件
+ for k, v in pairs(breaks[bkShortPath]) do
+ if next(v) == nil then
+ breaks[bkShortPath][k] = nil;
+ end
+ end
+ else
+ if breaks[bkPath] == nil then
+ breaks[bkPath] = {};
+ end
+ -- 两级 bk path 是为了和自动路径模式结构保持一致
+ breaks[bkPath][bkPath] = dataTable.info.bks;
+ -- 当v为空时,从断点列表中去除文件
+ for k, v in pairs(breaks[bkPath]) do
+ if next(v) == nil then
+ breaks[bkPath][k] = nil;
+ end
+ end
+ end
+
+ -- 当v为空时,从断点列表中去除文件
+ for k, v in pairs(breaks) do
+ if next(v) == nil then
+ breaks[k] = nil;
+ end
+ end
+
+ --sync breaks to c
+ if hookLib ~= nil then
+ hookLib.sync_breakpoints();
+ end
+
+ if currentRunState ~= runState.WAIT_CMD then
+ if hookLib == nil then
+ local fileBP, G_BP =this.checkHasBreakpoint(lastRunFilePath);
+ if fileBP == false then
+ if G_BP == true then
+ this.changeHookState(hookState.MID_HOOK);
+ else
+ this.changeHookState(hookState.LITE_HOOK);
+ end
+ else
+ this.changeHookState(hookState.ALL_HOOK);
+ end
+ end
+ else
+ local msgTab = this.getMsgTable("setBreakPoint", this.getCallbackId());
+ this.sendMsg(msgTab);
+ return;
+ end
+ --其他时机收到breaks消息
+ local msgTab = this.getMsgTable("setBreakPoint", this.getCallbackId());
+ this.sendMsg(msgTab);
+ -- 打印调试信息
+ this.printToVSCode("LuaPanda.getInfo()\n" .. this.getInfo())
+ this.debugger_wait_msg();
+ elseif dataTable.cmd == "setVariable" then
+ if currentRunState == runState.STOP_ON_ENTRY or
+ currentRunState == runState.HIT_BREAKPOINT or
+ currentRunState == runState.STEPOVER_STOP or
+ currentRunState == runState.STEPIN_STOP or
+ currentRunState == runState.STEPOUT_STOP then
+ local msgTab = this.getMsgTable("setVariable", this.getCallbackId());
+ local varRefNum = tonumber(dataTable.info.varRef);
+ local newValue = tostring(dataTable.info.newValue);
+ local needFindVariable = true; --如果变量是基础类型,直接赋值,needFindVariable = false; 如果变量是引用类型,needFindVariable = true
+ local varName = tostring(dataTable.info.varName);
+ -- 根据首末含有" ' 判断 newValue 是否是字符串
+ local first_chr = string.sub(newValue, 1, 1);
+ local end_chr = string.sub(newValue, -1, -1);
+ if first_chr == end_chr then
+ if first_chr == "'" or first_chr == '"' then
+ newValue = string.sub(newValue, 2, -2);
+ needFindVariable = false;
+ end
+ end
+ --数字,nil,false,true的处理
+ if newValue == "nil" and needFindVariable == true then newValue = nil; needFindVariable = false;
+ elseif newValue == "true" and needFindVariable == true then newValue = true; needFindVariable = false;
+ elseif newValue == "false" and needFindVariable == true then newValue = false; needFindVariable = false;
+ elseif tonumber(newValue) and needFindVariable == true then newValue = tonumber(newValue); needFindVariable = false;
+ end
+
+ -- 如果新值是基础类型,则不需遍历
+ if dataTable.info.stackId ~= nil and tonumber(dataTable.info.stackId) ~= nil and tonumber(dataTable.info.stackId) > 1 then
+ this.curStackId = tonumber(dataTable.info.stackId);
+ else
+ this.printToVSCode("未能获取到堆栈层级,默认使用 this.curStackId;")
+ end
+
+ if varRefNum < 10000 then
+ -- 如果修改的是一个 引用变量,那么可直接赋值。但还是要走变量查询过程。查找和赋值过程都需要steakId。 目前给引用变量赋值Object,steak可能有问题
+ msgTab.info = this.createSetValueRetTable(varName, newValue, needFindVariable, this.curStackId, variableRefTab[varRefNum]);
+ else
+ -- 如果修改的是一个基础类型
+ local setLimit; --设置检索变量的限定区域
+ if varRefNum >= 10000 and varRefNum < 20000 then setLimit = "local";
+ elseif varRefNum >= 20000 and varRefNum < 30000 then setLimit = "global";
+ elseif varRefNum >= 30000 then setLimit = "upvalue";
+ end
+ msgTab.info = this.createSetValueRetTable(varName, newValue, needFindVariable, this.curStackId, nil, setLimit);
+ end
+
+ this.sendMsg(msgTab);
+ this.debugger_wait_msg();
+ end
+
+ elseif dataTable.cmd == "getVariable" then
+ --仅在停止时处理消息,其他时刻收到此消息,丢弃
+ if currentRunState == runState.STOP_ON_ENTRY or
+ currentRunState == runState.HIT_BREAKPOINT or
+ currentRunState == runState.STEPOVER_STOP or
+ currentRunState == runState.STEPIN_STOP or
+ currentRunState == runState.STEPOUT_STOP then
+ --发送变量给游戏,并保持之前的状态,等待再次接收数据
+ --dataTable.info.varRef 10000~20000局部变量
+ -- 20000~30000全局变量
+ -- 30000~ upvalue
+ -- 1000~2000局部变量的查询,2000~3000全局,3000~4000upvalue
+ local msgTab = this.getMsgTable("getVariable", this.getCallbackId());
+ local varRefNum = tonumber(dataTable.info.varRef);
+ if varRefNum < 10000 then
+ --查询变量, 此时忽略 stackId
+ local varTable = this.getVariableRef(dataTable.info.varRef, true);
+ msgTab.info = varTable;
+ elseif varRefNum >= 10000 and varRefNum < 20000 then
+ --局部变量
+ if dataTable.info.stackId ~= nil and tonumber(dataTable.info.stackId) > 1 then
+ this.curStackId = tonumber(dataTable.info.stackId);
+ if type(currentCallStack[this.curStackId - 1]) ~= "table" or type(currentCallStack[this.curStackId - 1].func) ~= "function" then
+ local str = "getVariable getLocal currentCallStack " .. this.curStackId - 1 .. " Error\n" .. this.serializeTable(currentCallStack, "currentCallStack");
+ this.printToVSCode(str, 2);
+ msgTab.info = {};
+ else
+ local stackId = this.getSpecificFunctionStackLevel(currentCallStack[this.curStackId - 1].func); --去除偏移量
+ local varTable = this.getVariable(stackId, true);
+ msgTab.info = varTable;
+ end
+ end
+
+ elseif varRefNum >= 20000 and varRefNum < 30000 then
+ --全局变量
+ local varTable = this.getGlobalVariable();
+ msgTab.info = varTable;
+ elseif varRefNum >= 30000 then
+ --upValue
+ if dataTable.info.stackId ~= nil and tonumber(dataTable.info.stackId) > 1 then
+ this.curStackId = tonumber(dataTable.info.stackId);
+ if type(currentCallStack[this.curStackId - 1]) ~= "table" or type(currentCallStack[this.curStackId - 1].func) ~= "function" then
+ local str = "getVariable getUpvalue currentCallStack " .. this.curStackId - 1 .. " Error\n" .. this.serializeTable(currentCallStack, "currentCallStack");
+ this.printToVSCode(str, 2);
+ msgTab.info = {};
+ else
+ local varTable = this.getUpValueVariable(currentCallStack[this.curStackId - 1 ].func, true);
+ msgTab.info = varTable;
+ end
+ end
+ end
+ this.sendMsg(msgTab);
+ this.debugger_wait_msg();
+ end
+ elseif dataTable.cmd == "initSuccess" then
+ --初始化会传过来一些变量,这里记录这些变量
+ --Base64
+ if dataTable.info.isNeedB64EncodeStr == "true" then
+ isNeedB64EncodeStr = true;
+ else
+ isNeedB64EncodeStr = false;
+ end
+ --path
+ luaFileExtension = dataTable.info.luaFileExtension;
+ local TempFilePath = dataTable.info.TempFilePath;
+ if TempFilePath:sub(-1, -1) == [[\]] or TempFilePath:sub(-1, -1) == [[/]] then
+ TempFilePath = TempFilePath:sub(1, -2);
+ end
+ TempFilePath_luaString = TempFilePath;
+ cwd = this.genUnifiedPath(dataTable.info.cwd);
+ --logLevel
+ logLevel = tonumber(dataTable.info.logLevel) or 1;
+ --autoPathMode
+ if dataTable.info.autoPathMode == "true" then
+ autoPathMode = true;
+ else
+ autoPathMode = false;
+ end
+
+ if dataTable.info.pathCaseSensitivity == "true" then
+ pathCaseSensitivity = true;
+ truncatedOPath = dataTable.info.truncatedOPath or "";
+ else
+ pathCaseSensitivity = false;
+ truncatedOPath = string.lower(dataTable.info.truncatedOPath or "");
+ end
+
+ if dataTable.info.distinguishSameNameFile == "true" then
+ distinguishSameNameFile = true;
+ else
+ distinguishSameNameFile = false;
+ end
+
+ --OS type
+ if nil == OSType then
+ --用户未主动设置OSType, 接收VSCode传来的数据
+ if type(dataTable.info.OSType) == "string" then
+ OSType = dataTable.info.OSType;
+ else
+ OSType = "Windows_NT";
+ OSTypeErrTip = "未能检测出OSType, 可能是node os库未能加载,系统使用默认设置Windows_NT"
+ end
+ else
+ --用户自设OSType, 使用用户的设置
+ end
+
+ --检测用户是否自设了clib路径
+ isUserSetClibPath = false;
+ if nil == clibPath then
+ --用户未设置clibPath, 接收VSCode传来的数据
+ if type(dataTable.info.clibPath) == "string" then
+ clibPath = dataTable.info.clibPath;
+ else
+ clibPath = "";
+ pathErrTip = "未能正确获取libpdebug库所在位置, 可能无法加载libpdebug库。";
+ end
+ else
+ --用户自设clibPath
+ isUserSetClibPath = true;
+ end
+
+ --查找c++的hook库是否存在. 当lua5.4时默认不使用c库
+ if tostring(dataTable.info.useCHook) == "true" and "Lua 5.4" ~= _VERSION then
+ userSetUseClib = true; --用户确定使用clib
+ if isUserSetClibPath == true then --如果用户自设了clib路径
+ if luapanda_chook ~= nil then
+ hookLib = luapanda_chook;
+ else
+ if not(this.tryRequireClib("libpdebug", clibPath)) then
+ this.printToVSCode("Require clib failed, use Lua to continue debug, use LuaPanda.doctor() for more information.", 1);
+ end
+ end
+ else
+ local clibExt, platform;
+ if OSType == "Darwin" then clibExt = "/?.so;"; platform = "mac";
+ elseif OSType == "Linux" then clibExt = "/?.so;"; platform = "linux";
+ else clibExt = "/?.dll;"; platform = "win"; end
+
+ local lua_ver;
+ if _VERSION == "Lua 5.1" then
+ lua_ver = "501";
+ else
+ lua_ver = "503";
+ end
+
+ local x86Path = clibPath.. platform .."/x86/".. lua_ver .. clibExt;
+ local x64Path = clibPath.. platform .."/x86_64/".. lua_ver .. clibExt;
+
+ if luapanda_chook ~= nil then
+ hookLib = luapanda_chook;
+ else
+ if not(this.tryRequireClib("libpdebug", x64Path) or this.tryRequireClib("libpdebug", x86Path)) then
+ this.printToVSCode("Require clib failed, use Lua to continue debug, use LuaPanda.doctor() for more information.", 1);
+ end
+ end
+ end
+ else
+ userSetUseClib = false;
+ end
+
+ --adapter版本信息
+ adapterVer = tostring(dataTable.info.adapterVersion);
+ local msgTab = this.getMsgTable("initSuccess", this.getCallbackId());
+ --回传是否使用了lib,是否有loadstring函数
+ local isUseHookLib = 0;
+ if hookLib ~= nil then
+ isUseHookLib = 1;
+ --同步数据给c hook
+ local luaVerTable = this.stringSplit(debuggerVer , '%.');
+ local luaVerNum = luaVerTable[1] * 10000 + luaVerTable[2] * 100 + luaVerTable[3];
+ if hookLib.sync_lua_debugger_ver then
+ hookLib.sync_lua_debugger_ver(luaVerNum);
+ end
+ -- hookLib.sync_config(logLevel, pathCaseSensitivity and 1 or 0, autoPathMode and 1 or 0);
+ hookLib.sync_config(logLevel, pathCaseSensitivity and 1 or 0);
+ hookLib.sync_tempfile_path(TempFilePath_luaString);
+ hookLib.sync_cwd(cwd);
+ hookLib.sync_file_ext(luaFileExtension);
+ end
+ --detect LoadString
+ isUseLoadstring = 0;
+ if debugger_loadString ~= nil and type(debugger_loadString) == "function" then
+ if(pcall(debugger_loadString("return 0"))) then
+ isUseLoadstring = 1;
+ end
+ end
+ local tab = { debuggerVer = tostring(debuggerVer) , UseHookLib = tostring(isUseHookLib) , UseLoadstring = tostring(isUseLoadstring), isNeedB64EncodeStr = tostring(isNeedB64EncodeStr) };
+ msgTab.info = tab;
+ this.sendMsg(msgTab);
+ --上面getBK中会判断当前状态是否WAIT_CMD, 所以最后再切换状态。
+ stopOnEntry = dataTable.info.stopOnEntry;
+ if dataTable.info.stopOnEntry == "true" then
+ this.changeRunState(runState.STOP_ON_ENTRY); --停止在STOP_ON_ENTRY再接收breaks消息
+ else
+ this.debugger_wait_msg(1); --等待1s bk消息 如果收到或超时(没有断点)就开始运行
+ this.changeRunState(runState.RUN);
+ end
+
+ elseif dataTable.cmd == "getWatchedVariable" then
+ local msgTab = this.getMsgTable("getWatchedVariable", this.getCallbackId());
+ local stackId = tonumber(dataTable.info.stackId);
+ --loadstring系统函数, watch插件加载
+ if isUseLoadstring == 1 then
+ --使用loadstring
+ this.curStackId = stackId;
+ local retValue = this.processWatchedExp(dataTable.info);
+ msgTab.info = retValue
+ this.sendMsg(msgTab);
+ this.debugger_wait_msg();
+ return;
+ else
+ --旧的查找方式
+ local wv = this.getWatchedVariable(dataTable.info.varName, stackId, true);
+ if wv ~= nil then
+ msgTab.info = wv;
+ end
+ this.sendMsg(msgTab);
+ this.debugger_wait_msg();
+ end
+ elseif dataTable.cmd == "stopRun" then
+ --停止hook,已不在处理任何断点信息,也就不会产生日志等。发送消息后等待前端主动断开连接
+ local msgTab = this.getMsgTable("stopRun", this.getCallbackId());
+ this.sendMsg(msgTab);
+ if not luaProcessAsServer then
+ this.disconnect();
+ end
+ elseif "LuaGarbageCollect" == dataTable.cmd then
+ this.printToVSCode("collect garbage!");
+ collectgarbage("collect");
+ --回收后刷一下内存
+ this.sendLuaMemory();
+ this.debugger_wait_msg();
+ elseif "runREPLExpression" == dataTable.cmd then
+ this.curStackId = tonumber(dataTable.info.stackId);
+ local retValue = this.processExp(dataTable.info);
+ local msgTab = this.getMsgTable("runREPLExpression", this.getCallbackId());
+ msgTab.info = retValue
+ this.sendMsg(msgTab);
+ this.debugger_wait_msg();
+ else
+ end
+end
+
+-- 变量赋值的处理函数。基本逻辑是先从当前栈帧(curStackId)中取 newValue 代表的变量,找到之后再把找到的值通过setVariableValue写回。
+-- @varName 被设置值的变量名
+-- @newValue 新值的名字,它是一个string
+-- @needFindVariable 是否需要查找引用变量。(用户输入的是否是一个Object)
+-- @curStackId 当前栈帧(查找和变量赋值用)
+-- @assigndVar 被直接赋值(省去查找过程)
+-- @setLimit 赋值时的限制范围(local upvalue global)
+function this.createSetValueRetTable(varName, newValue, needFindVariable, curStackId, assigndVar , setLimit)
+ local info;
+ local getVarRet;
+ -- needFindVariable == true,则使用getWatchedVariable处理(可选, 用来支持 a = b (b为变量的情况))。
+ if needFindVariable == false then
+ getVarRet = {};
+ getVarRet[1] = {variablesReference = 0, value = newValue, name = varName, type = type(newValue)};
+ else
+ getVarRet = this.getWatchedVariable( tostring(newValue), curStackId, true);
+ end
+ if getVarRet ~= nil then
+ -- newValue赋变量真实值
+ local realVarValue;
+ local displayVarValue = getVarRet[1].value;
+ if needFindVariable == true then
+ if tonumber(getVarRet[1].variablesReference) > 0 then
+ realVarValue = variableRefTab[tonumber(getVarRet[1].variablesReference)];
+ else
+ if getVarRet[1].type == 'number' then realVarValue = tonumber(getVarRet[1].value) end
+ if getVarRet[1].type == 'string' then
+ realVarValue = tostring(getVarRet[1].value);
+ local first_chr = string.sub(realVarValue, 1, 1);
+ local end_chr = string.sub(realVarValue, -1, -1);
+ if first_chr == end_chr then
+ if first_chr == "'" or first_chr == '"' then
+ realVarValue = string.sub(realVarValue, 2, -2);
+ displayVarValue = realVarValue;
+ end
+ end
+ end
+ if getVarRet[1].type == 'boolean' then
+ if getVarRet[1].value == "true" then
+ realVarValue = true;
+ else
+ realVarValue = false;
+ end
+ end
+ if getVarRet[1].type == 'nil' then realVarValue = nil end
+ end
+ else
+ realVarValue = getVarRet[1].value;
+ end
+
+ local setVarRet;
+ if type(assigndVar) ~= table then
+ setVarRet = this.setVariableValue( varName, curStackId, realVarValue, setLimit );
+ else
+ assigndVar[varName] = realVarValue;
+ setVarRet = true;
+ end
+
+ if getVarRet[1].type == "string" then
+ displayVarValue = '"' .. displayVarValue .. '"';
+ end
+
+ if setVarRet ~= false and setVarRet ~= nil then
+ local retTip = "变量 ".. varName .." 赋值成功";
+ info = { success = "true", name = getVarRet[1].name , type = getVarRet[1].type , value = displayVarValue, variablesReference = tostring(getVarRet[1].variablesReference), tip = retTip};
+ else
+ info = { success = "false", type = type(realVarValue), value = displayVarValue, tip = "找不到要设置的变量"};
+ end
+
+ else
+ info = { success = "false", type = nil, value = nil, tip = "输入的值无意义"};
+ end
+ return info
+end
+
+--接收消息
+--这里维护一个接收消息队列,因为Lua端未做隔断符保护,变量赋值时请注意其中不要包含隔断符 |*|
+-- @timeoutSec 超时时间
+-- @return boolean 成功/失败
+function this.receiveMessage( timeoutSec )
+ timeoutSec = timeoutSec or MAX_TIMEOUT_SEC;
+ sock:settimeout(timeoutSec);
+ --如果队列中还有消息,直接取出来交给dataProcess处理
+ if #recvMsgQueue > 0 then
+ local saved_cmd = recvMsgQueue[1];
+ table.remove(recvMsgQueue, 1);
+ this.dataProcess(saved_cmd);
+ return true;
+ end
+
+ if currentRunState == runState.DISCONNECT then
+ this.disconnect();
+ return false;
+ end
+
+ if sock == nil then
+ this.printToConsole("[debugger error]接收信息失败 | reason: socket == nil", 2);
+ return;
+ end
+ local response, err = sock:receive();
+ if response == nil then
+ if err == "closed" then
+ this.printToConsole("[debugger error]接收信息失败 | reason:"..err, 2);
+ this.disconnect();
+ end
+ return false;
+ else
+
+ --判断是否是一条消息,分拆
+ local proc_response = string.sub(response, 1, -1 * (TCPSplitChar:len() + 1 ));
+ local match_res = string.find(proc_response, TCPSplitChar, 1, true);
+ if match_res == nil then
+ --单条
+ this.dataProcess(proc_response);
+ else
+ --有粘包
+ repeat
+ --待处理命令
+ local str1 = string.sub(proc_response, 1, match_res - 1);
+ table.insert(recvMsgQueue, str1);
+ --剩余匹配
+ local str2 = string.sub(proc_response, match_res + TCPSplitChar:len() , -1);
+ match_res = string.find(str2, TCPSplitChar, 1, true);
+ until not match_res
+ this.receiveMessage();
+ end
+ return true;
+ end
+end
+
+--这里不用循环,在外面处理完消息会在调用回来
+-- @timeoutSec 等待时间s
+-- @entryFlag 入口标记,用来标识是从哪里调入的
+function this.debugger_wait_msg(timeoutSec)
+ timeoutSec = timeoutSec or MAX_TIMEOUT_SEC;
+
+ if currentRunState == runState.WAIT_CMD then
+ local ret = this.receiveMessage(timeoutSec);
+ return ret;
+ end
+
+ if currentRunState == runState.STEPOVER or
+ currentRunState == runState.STEPIN or
+ currentRunState == runState.STEPOUT or
+ currentRunState == runState.RUN then
+ this.receiveMessage(0);
+ return
+ end
+
+ if currentRunState == runState.STEPOVER_STOP or
+ currentRunState == runState.STEPIN_STOP or
+ currentRunState == runState.STEPOUT_STOP or
+ currentRunState == runState.HIT_BREAKPOINT or
+ currentRunState == runState.STOP_ON_ENTRY
+ then
+ this.sendLuaMemory();
+ this.receiveMessage(MAX_TIMEOUT_SEC);
+ return
+ end
+end
+
+-----------------------------------------------------------------------------
+-- 调试器核心方法
+-----------------------------------------------------------------------------
+
+------------------------堆栈管理-------------------------
+
+
+--getStackTable需要建立stackTable,保存每层的lua函数实例(用来取upvalue),保存函数展示层级和ly的关系(便于根据前端传来的stackId查局部变量)
+-- @level 要获取的层级
+function this.getStackTable( level )
+ local functionLevel = 0
+ if hookLib ~= nil then
+ functionLevel = level or HOOK_LEVEL;
+ else
+ functionLevel = level or this.getSpecificFunctionStackLevel(lastRunFunction.func);
+ end
+ local stackTab = {};
+ local userFuncSteakLevel = 0; --用户函数的steaklevel
+ local clevel = 0
+ repeat
+ local info = debug.getinfo(functionLevel, "SlLnf")
+ if info == nil then
+ break;
+ end
+ if info.source ~= "=[C]" then
+ local ss = {};
+ ss.file = this.getPath(info);
+ local oPathFormated = this.formatOpath(info.source) ; --从lua虚拟机获得的原始路径, 它用于帮助定位VScode端原始lua文件的位置(存在重名文件的情况)。
+ ss.oPath = this.truncatedPath(oPathFormated, truncatedOPath);
+ ss.name = "文件名"; --这里要做截取
+ ss.line = tostring(info.currentline);
+ --使用hookLib时,堆栈有偏移量,这里统一调用栈顶编号2
+ local ssindex = functionLevel - 3;
+ if hookLib ~= nil then
+ ssindex = ssindex + 2;
+ end
+ ss.index = tostring(ssindex);
+ table.insert(stackTab,ss);
+ --把数据存入currentCallStack
+ local callStackInfo = {};
+ callStackInfo.name = ss.file;
+ callStackInfo.line = ss.line;
+ callStackInfo.func = info.func; --保存的function
+ callStackInfo.realLy = functionLevel; --真实堆栈层functionLevel(仅debug时用)
+ table.insert(currentCallStack, callStackInfo);
+
+ --level赋值
+ if userFuncSteakLevel == 0 then
+ userFuncSteakLevel = functionLevel;
+ end
+ else
+ local callStackInfo = {};
+ callStackInfo.name = info.source;
+ callStackInfo.line = info.currentline; --C函数行号
+ callStackInfo.func = info.func; --保存的function
+ callStackInfo.realLy = functionLevel; --真实堆栈层functionLevel(仅debug时用)
+ table.insert(currentCallStack, callStackInfo);
+ clevel = clevel + 1
+ end
+ functionLevel = functionLevel + 1;
+ until info == nil
+ return stackTab, userFuncSteakLevel;
+end
+
+-- 把路径中去除后缀部分的.变为/,
+-- @filePath 被替换的路径
+-- @ext 后缀(后缀前的 . 不会被替换)
+function this.changePotToSep(filePath, ext)
+ local idx = filePath:find(ext, (-1) * ext:len() , true)
+ if idx then
+ local tmp = filePath:sub(1, idx - 1):gsub("%.", "/");
+ filePath = tmp .. ext;
+ end
+ return filePath;
+end
+
+--- this.truncatedPath 从 beTruncatedPath 字符串中去除 rep 匹配到的部分
+function this.truncatedPath(beTruncatedPath, rep)
+ if beTruncatedPath and beTruncatedPath ~= '' and rep and rep ~= "" then
+ local _, lastIdx = string.find(beTruncatedPath , rep);
+ if lastIdx then
+ beTruncatedPath = string.sub(beTruncatedPath, lastIdx + 1);
+ end
+ end
+ return beTruncatedPath;
+end
+
+--这个方法是根据的cwd和luaFileExtension对getInfo获取到的路径进行标准化
+-- @info getInfo获取的包含调用信息table
+function this.getPath( info )
+ local filePath = info;
+ if type(info) == "table" then
+ filePath = info.source;
+ end
+ --尝试从Cache中获取路径
+ local cachePath = this.getCacheFormatPath(filePath);
+ if cachePath~= nil and type(cachePath) == "string" then
+ return cachePath;
+ end
+
+ -- originalPath是getInfo的原始路径,后面用来填充路径缓存的key
+ local originalPath = filePath;
+
+ --如果路径头部有@,去除
+ if filePath:sub(1,1) == '@' then
+ filePath = filePath:sub(2);
+ end
+
+ --如果路径头部有./,去除
+ if filePath:sub(1,2) == './' then
+ filePath = filePath:sub(3);
+ end
+ -- getPath的参数路径可能来自于hook, 也可能是一个已标准的路径
+ if userDotInRequire then
+ if autoExt == nil or autoExt == '' then
+ -- 在虚拟机返回路径没有后缀的情况下,用户必须自设后缀
+ -- 确定filePath中最后一个.xxx 不等于用户配置的后缀, 则把所有的. 转为 /
+ if not filePath:find(luaFileExtension , (-1) * luaFileExtension:len(), true) then
+ -- getinfo 路径没有后缀,把 . 全部替换成 / ,我们不允许用户在文件(或文件夹)名称中出现"." , 因为无法区分
+ filePath = string.gsub(filePath, "%.", "/");
+ else
+ -- 有后缀,那么把除后缀外的部分中的. 转为 /
+ filePath = this.changePotToSep(filePath, luaFileExtension);
+ end
+
+ else
+ -- 虚拟机路径有后缀
+ filePath = this.changePotToSep(filePath, autoExt);
+ end
+ end
+
+ --后缀处理
+ if luaFileExtension ~= "" then
+ --判断后缀中是否包含%1等魔法字符.用于从lua虚拟机获取到的路径含.的情况
+ if string.find(luaFileExtension, "%%%d") then
+ filePath = string.gsub(filePath, "%.[%w%.]+$", luaFileExtension);
+ else
+ filePath = string.gsub(filePath, "%.[%w%.]+$", "");
+ filePath = filePath .. "." .. luaFileExtension;
+ end
+ end
+
+
+ if not autoPathMode then
+ --绝对路径和相对路径的处理 | 若在Mac下以/开头,或者在Win下以*:开头,说明是绝对路径,不需要再拼。
+ if filePath:sub(1,1) == [[/]] or filePath:sub(1,2):match("^%a:") then
+ isAbsolutePath = true;
+ else
+ isAbsolutePath = false;
+ if cwd ~= "" then
+ --查看filePath中是否包含cwd
+ local matchRes = string.find(filePath, cwd, 1, true);
+ if matchRes == nil then
+ filePath = cwd.."/"..filePath;
+ end
+ end
+ end
+ end
+ filePath = this.genUnifiedPath(filePath);
+
+ if autoPathMode then
+ -- 自动路径模式下,只保留文件名
+ filePath = this.getFilenameFromPath(filePath)
+ end
+ --放入Cache中缓存
+ this.setCacheFormatPath(originalPath, filePath);
+ return filePath;
+end
+
+--从路径中获取[文件名.后缀]
+function this.getFilenameFromPath(path)
+ if path == nil then
+ return '';
+ end
+
+ return string.match(path, "([^/]*)$");
+end
+
+--获取当前函数的堆栈层级
+--原理是向上查找,遇到DebuggerFileName就调过。但是可能存在代码段和C导致不确定性。目前使用getSpecificFunctionStackLevel代替。
+function this.getCurrentFunctionStackLevel()
+ -- print(debug.traceback("===getCurrentFunctionStackLevel Stack trace==="))
+ local funclayer = 2;
+ repeat
+ local info = debug.getinfo(funclayer, "S"); --通过name来判断
+ if info ~= nil then
+ local matchRes = ((info.source == DebuggerFileName) or (info.source == DebuggerToolsName));
+ if matchRes == false then
+ return (funclayer - 1);
+ end
+ end
+ funclayer = funclayer + 1;
+ until not info
+ return 0;
+end
+
+--获取指定函数的堆栈层级
+--通常用来获取最后一个用户函数的层级,用法是从currentCallStack取用户点击的栈,再使用本函数取对应层级。
+-- @func 被获取层级的function
+function this.getSpecificFunctionStackLevel( func )
+ local funclayer = 2;
+ repeat
+ local info = debug.getinfo(funclayer, "f"); --通过name来判断
+ if info ~= nil then
+ if info.func == func then
+ return (funclayer - 1);
+ end
+ end
+ funclayer = funclayer + 1;
+ until not info
+ return 0;
+end
+
+--检查当前堆栈是否是Lua
+-- @checkLayer 指定的栈层
+function this.checkCurrentLayerisLua( checkLayer )
+ local info = debug.getinfo(checkLayer, "S");
+ if info == nil then
+ return nil;
+ end
+ info.source = this.genUnifiedPath(info.source);
+ if info ~= nil then
+ for k,v in pairs(info) do
+ if k == "what" then
+ if v == "C" then
+ return false;
+ else
+ return true;
+ end
+ end
+ end
+ end
+ return nil;
+end
+
+-- 在 fakeBreakPointCache 中查询此断点是否真实存在
+-- 因为同名文件的影响, 有些断点是命中错误的。经过VScode校验后,这些错误命中的断点信息被存在fakeBreakPointCache中
+function this.checkRealHitBreakpoint( oPath, line )
+ -- 在假命中列表中搜索,如果本行有过假命中记录,返回 false
+ if oPath and fakeBreakPointCache[oPath] then
+ for _, value in ipairs(fakeBreakPointCache[oPath]) do
+ if tonumber(value) == tonumber(line) then
+ this.printToVSCode("cache hit bp in same name file. source:" .. tostring(oPath) .. " line:" .. tostring(line));
+ return false;
+ end
+ end
+ end
+ return true;
+end
+
+------------------------断点处理-------------------------
+--- this.isHitBreakpoint 判断断点是否命中。这个方法在c mod以及lua中都有调用
+-- @param breakpointPath 文件名+后缀
+-- @param opath getinfo path
+-- @param curLine 当前执行行号
+function this.isHitBreakpoint(breakpointPath, opath, curLine)
+ if breaks[breakpointPath] then
+ local oPathFormated;
+ for fullpath, fullpathNode in pairs(breaks[breakpointPath]) do
+ recordBreakPointPath = fullpath; --这里是为了兼容用户断点行号没有打对的情况
+ local line_hit,cur_node = false,{};
+ for _, node in ipairs(fullpathNode) do
+ if tonumber(node["line"]) == tonumber(curLine) then
+ line_hit = true; -- fullpath 文件中 有行号命中
+ cur_node = node;
+ recordBreakPointPath = fullpath; --行号命中后,再设置一次,保证路径准确
+ break;
+ end
+ end
+
+ -- 在lua端不知道是否有同名文件,基本思路是先取文件名,用文件名和breakpointArray 进行匹配。
+ -- 当文件名匹配上时,可能存在多个同名文件中存在断点的情况。这时候需要用 oPath 和 fullpath 进行对比,取出正确的。
+ -- 当本地文件中有断点,lua做了初步命中后,可能存在 stack , 断点文件有同名的情况。这就需要vscode端也需要checkfullpath函数,使用opath进行文件校验。
+ if line_hit then
+ if oPathFormated == nil then
+ -- 为了避免性能消耗,仅在行号命中时才处理 opath 到标准化路径
+ oPathFormated = this.formatOpath(opath);
+ -- 截取
+ oPathFormated = this.truncatedPath(oPathFormated, truncatedOPath);
+ end
+
+ if (not distinguishSameNameFile) or (string.match(fullpath, oPathFormated ) and this.checkRealHitBreakpoint(opath, curLine)) then
+ -- type是TS中的枚举类型,其定义在BreakPoint.tx文件中
+ -- enum BreakpointType {
+ -- conditionBreakpoint = 0,
+ -- logPoint,
+ -- lineBreakpoint
+ -- }
+
+ -- 处理断点
+ if cur_node["type"] == "0" then
+ -- condition breakpoint
+ -- 注意此处不要使用尾调用,否则会影响调用栈,导致Lua5.3和Lua5.1中调用栈层级不同
+ local conditionRet = this.IsMeetCondition(cur_node["condition"]);
+ -- this.printToVSCode("Condition BK: condition:" .. cur_node["condition"] .. " conditionRet " .. tostring(conditionRet));
+ return conditionRet;
+ elseif cur_node["type"] == "1" then
+ -- log point
+ this.printToVSCode("[LogPoint Output]: " .. cur_node["logMessage"], 2, 2);
+ return false;
+ else
+ -- line breakpoint
+ return true;
+ end
+ end
+ end
+ end
+ else
+ testBreakpointFlag = false; --如果用户打开了测试断点的标志位而未主动关闭,会在lua继续运行时关闭。
+ recordBreakPointPath = ''; --当切换文件时置空,避免提示给用户错误信息
+ end
+ return false;
+end
+
+-- 条件断点处理函数
+-- 返回true表示条件成立
+-- @conditionExp 条件表达式
+function this.IsMeetCondition(conditionExp)
+ -- 判断条件之前更新堆栈信息
+ currentCallStack = {};
+ variableRefTab = {};
+ variableRefIdx = 1;
+ if hookLib then
+ this.getStackTable(4);
+ else
+ this.getStackTable();
+ end
+
+ this.curStackId = 2; --在用户空间最上层执行
+
+ local conditionExpTable = {["varName"] = conditionExp}
+ local retTable = this.processWatchedExp(conditionExpTable)
+
+ local isMeetCondition = false;
+ local function HandleResult()
+ if retTable[1]["isSuccess"] == "true" then
+ if retTable[1]["value"] == "nil" or (retTable[1]["value"] == "false" and retTable[1]["type"] == "boolean") then
+ isMeetCondition = false;
+ else
+ isMeetCondition = true;
+ end
+ else
+ isMeetCondition = false;
+ end
+ end
+
+ xpcall(HandleResult, function() isMeetCondition = false; end)
+ return isMeetCondition;
+end
+
+--加入断点函数
+function this.BP()
+ this.printToConsole("BP()");
+ if hookLib == nil then
+ if currentHookState == hookState.DISCONNECT_HOOK then
+ this.printToConsole("BP() but NO HOOK");
+ return;
+ end
+
+ local co, isMain = coroutine.running();
+ if _VERSION == "Lua 5.1" then
+ if co == nil then
+ isMain = true;
+ else
+ isMain = false;
+ end
+ end
+
+ if isMain == true then
+ this.printToConsole("BP() in main");
+ else
+ this.printToConsole("BP() in coroutine");
+ debug.sethook(co, this.debug_hook, "lrc");
+ end
+ hitBP = true;
+ else
+ if hookLib.get_libhook_state() == hookState.DISCONNECT_HOOK then
+ this.printToConsole("BP() but NO C HOOK");
+ return;
+ end
+
+ --clib, set hitBP
+ hookLib.sync_bp_hit(1);
+ end
+ this.changeHookState(hookState.ALL_HOOK);
+ return true;
+end
+
+-- 检查当前文件中是否有断点
+-- 如果填写参数fileName 返回fileName中有无断点, 全局有无断点
+-- fileName为空,返回全局是否有断点
+function this.checkHasBreakpoint(fileName)
+ local hasBk = false;
+ --有无全局断点
+ if next(breaks) == nil then
+ hasBk = false;
+ else
+ hasBk = true;
+ end
+ --当前文件中是否有断点
+ if fileName ~= nil then
+ return breaks[fileName] ~= nil, hasBk;
+ else
+ return hasBk;
+ end
+end
+
+function this.checkfuncHasBreakpoint(sLine, eLine, fileName)
+ if breaks[fileName] == nil then
+ return false;
+ end
+ sLine = tonumber(sLine);
+ eLine = tonumber(eLine);
+
+ --起始行号>结束行号,或者sLine = eLine = 0
+ if sLine >= eLine then
+ return true;
+ end
+
+ if this.getTableMemberNum(breaks[fileName]) <= 0 then
+ return false;
+ else
+ for k,v in pairs(breaks[fileName]) do
+ for _, node in ipairs(v) do
+ if tonumber(node.line) > sLine and tonumber(node.line) <= eLine then
+ return true;
+ end
+ end
+ end
+ end
+ return false;
+end
+------------------------HOOK模块-------------------------
+-- 钩子函数
+-- @event 执行状态(call,return,line)
+-- @line 行号
+function this.debug_hook(event, line)
+ if this.reConnect() == 0 then return; end
+
+ if logLevel == 0 then
+ local logTable = {"-----enter debug_hook-----\n", "event:", event, " line:", tostring(line), " currentHookState:",currentHookState," currentRunState:", currentRunState};
+ local logString = table.concat(logTable);
+ this.printToVSCode(logString);
+ end
+
+ --litehook 仅非阻塞接收断点
+ if currentHookState == hookState.LITE_HOOK then
+ local ti = os.time();
+ if ti - receiveMsgTimer > 1 then
+ this.debugger_wait_msg(0);
+ receiveMsgTimer = ti;
+ end
+ return;
+ end
+
+ --运行中
+ local info;
+ local co, isMain = coroutine.running();
+ if _VERSION == "Lua 5.1" then
+ if co == nil then
+ isMain = true;
+ else
+ isMain = false;
+ end
+ end
+ isInMainThread = isMain;
+ if isMain == true then
+ info = debug.getinfo(2, "Slf")
+ else
+ info = debug.getinfo(co, 2, "Slf")
+ end
+ info.event = event;
+
+ this.real_hook_process(info);
+end
+
+function this.real_hook_process(info)
+ local jumpFlag = false;
+ local event = info.event;
+
+ --如果当前行在Debugger中,不做处理
+ local matchRes = ((info.source == DebuggerFileName) or (info.source == DebuggerToolsName));
+ if matchRes == true then
+ return;
+ end
+
+ --即使MID hook在C中, 或者是Run或者单步时也接收消息
+ if currentRunState == runState.RUN or
+ currentRunState == runState.STEPOVER or
+ currentRunState == runState.STEPIN or
+ currentRunState == runState.STEPOUT then
+ local ti = os.time();
+ if ti - receiveMsgTimer > 1 then
+ this.debugger_wait_msg(0);
+ receiveMsgTimer = ti;
+ end
+ end
+
+ --不处理C函数
+ if info.source == "=[C]" then
+ this.printToVSCode("current method is C");
+ return;
+ end
+
+ --不处理 slua "temp buffer"
+ if info.source == "temp buffer" then
+ this.printToVSCode("current method is in temp buffer");
+ return;
+ end
+
+ --不处理 xlua "chunk"
+ if info.source == "chunk" then
+ this.printToVSCode("current method is in chunk");
+ return;
+ end
+
+ --lua 代码段的处理,目前暂不调试代码段。
+ if info.short_src:match("%[string \"") then
+ --当shortSrc中出现[string时]。要检查一下source, 区别是路径还是代码段. 方法是看路径中有没有\t \n ;
+ if info.source:match("[\n;=]") then
+ --是代码段,调过
+ this.printToVSCode("hook jump Code String!");
+ jumpFlag = true;
+ end
+ end
+
+ --标准路径处理
+ if jumpFlag == false then
+ info.orininal_source = info.source; --使用 info.orininal_source 记录lua虚拟机传来的原始路径
+ info.source = this.getPath(info);
+ end
+ --本次执行的函数和上次执行的函数作对比,防止在一行停留两次
+ if lastRunFunction["currentline"] == info["currentline"] and lastRunFunction["source"] == info["source"] and lastRunFunction["func"] == info["func"] and lastRunFunction["event"] == event then
+ this.printToVSCode("run twice");
+ end
+ --记录最后一次调用信息
+ if jumpFlag == false then
+ lastRunFunction = info;
+ lastRunFunction["event"] = event;
+ lastRunFilePath = info.source;
+ end
+ --输出函数信息到前台
+ if logLevel == 0 and jumpFlag == false then
+ local logTable = {"[lua hook] event:", tostring(event), " currentRunState:",tostring(currentRunState)," currentHookState:",tostring(currentHookState)," jumpFlag:", tostring(jumpFlag)};
+ for k,v in pairs(info) do
+ table.insert(logTable, tostring(k));
+ table.insert(logTable, ":");
+ table.insert(logTable, tostring(v));
+ table.insert(logTable, " ");
+ end
+ local logString = table.concat(logTable);
+ this.printToVSCode(logString);
+ end
+
+ --仅在line时做断点判断。进了断点之后不再进入本次STEP类型的判断,用Aflag做标记
+ local isHit = false;
+ if tostring(event) == "line" and jumpFlag == false then
+ if currentRunState == runState.RUN or currentRunState == runState.STEPOVER or currentRunState == runState.STEPIN or currentRunState == runState.STEPOUT then
+ --断点判断
+ isHit = this.isHitBreakpoint(info.source, info.orininal_source, info.currentline) or hitBP;
+ if isHit == true then
+ this.printToVSCode("HitBreakpoint!");
+ --备份信息
+ local recordStepOverCounter = stepOverCounter;
+ local recordStepOutCounter = stepOutCounter;
+ local recordCurrentRunState = currentRunState;
+ --计数器清0
+ stepOverCounter = 0;
+ stepOutCounter = 0;
+ this.changeRunState(runState.HIT_BREAKPOINT);
+ hitBpTwiceCheck = true; -- 命中标志默认设置为true, 如果校验通过,会保留这个标记,校验失败会修改
+ if hitBP then
+ hitBP = false; --hitBP是断点硬性命中标记
+ --发消息并等待
+ this.SendMsgWithStack("stopOnCodeBreakpoint");
+ else
+ --发消息并等待
+ this.SendMsgWithStack("stopOnBreakpoint");
+ --若二次校验未命中,恢复状态
+ if hitBpTwiceCheck == false then
+ isHit = false;
+ -- 确认未命中,把状态恢复,继续运行
+ this.changeRunState(recordCurrentRunState);
+ stepOverCounter = recordStepOverCounter;
+ stepOutCounter = recordStepOutCounter;
+ end
+ end
+ end
+ end
+ end
+
+ if isHit == true then
+ return;
+ end
+
+ if currentRunState == runState.STEPOVER then
+ -- line stepOverCounter!= 0 不作操作
+ -- line stepOverCounter == 0 停止
+ if event == "line" and stepOverCounter <= 0 and jumpFlag == false then
+ stepOverCounter = 0;
+ this.changeRunState(runState.STEPOVER_STOP)
+ this.SendMsgWithStack("stopOnStep");
+ elseif event == "return" or event == "tail return" then
+ --5.1中是tail return
+ if stepOverCounter ~= 0 then
+ stepOverCounter = stepOverCounter - 1;
+ end
+ elseif event == "call" then
+ stepOverCounter = stepOverCounter + 1;
+ end
+ elseif currentRunState == runState.STOP_ON_ENTRY then
+ --在Lua入口点处直接停住
+ if event == "line" and jumpFlag == false then
+ --初始化内存分析的变量
+ -- MemProfiler.getSystemVar();
+ --这里要判断一下是Lua的入口点,否则停到
+ this.SendMsgWithStack("stopOnEntry");
+ end
+ elseif currentRunState == runState.STEPIN then
+ if event == "line" and jumpFlag == false then
+ this.changeRunState(runState.STEPIN_STOP)
+ this.SendMsgWithStack("stopOnStepIn");
+ end
+ elseif currentRunState == runState.STEPOUT then
+ --line 不做操作
+ --in 计数器+1
+ --out 计数器-1
+ if jumpFlag == false then
+ if stepOutCounter <= -1 then
+ stepOutCounter = 0;
+ this.changeRunState(runState.STEPOUT_STOP)
+ this.SendMsgWithStack("stopOnStepOut");
+ end
+ end
+
+ if event == "return" or event == "tail return" then
+ stepOutCounter = stepOutCounter - 1;
+ elseif event == "call" then
+ stepOutCounter = stepOutCounter + 1;
+ end
+ end
+
+ --在RUN时检查并改变状态
+ if hookLib == nil then
+ if currentRunState == runState.RUN and jumpFlag == false and currentHookState ~= hookState.DISCONNECT_HOOK then
+ local fileBP, G_BP = this.checkHasBreakpoint(lastRunFilePath);
+ if fileBP == false then
+ --文件无断点
+ if G_BP == true then
+ this.changeHookState(hookState.MID_HOOK);
+ else
+ this.changeHookState(hookState.LITE_HOOK);
+ end
+ else
+ --文件有断点, 判断函数内是否有断点
+ local funHasBP = this.checkfuncHasBreakpoint(lastRunFunction.linedefined, lastRunFunction.lastlinedefined, lastRunFilePath);
+ if funHasBP then
+ --函数定义范围内
+ this.changeHookState(hookState.ALL_HOOK);
+ else
+ this.changeHookState(hookState.MID_HOOK);
+ end
+ end
+
+ --MID_HOOK状态下,return需要在下一次hook检查文件(return时,还是当前文件,检查文件时状态无法转换)
+ if (event == "return" or event == "tail return") and currentHookState == hookState.MID_HOOK then
+ this.changeHookState(hookState.ALL_HOOK);
+ end
+ end
+ end
+end
+
+-- 向Vscode发送标准通知消息,cmdStr是消息类型
+-- @cmdStr 命令字
+function this.SendMsgWithStack(cmdStr)
+ local msgTab = this.getMsgTable(cmdStr);
+ local userFuncLevel = 0;
+ msgTab["stack"] , userFuncLevel= this.getStackTable();
+ if userFuncLevel ~= 0 then
+ lastRunFunction["func"] = debug.getinfo( (userFuncLevel - 1) , 'f').func;
+ end
+ this.sendMsg(msgTab);
+ this.debugger_wait_msg();
+end
+
+-- hook状态改变
+-- @s 目标状态
+function this.changeHookState( s )
+ if hookLib == nil and currentHookState == s then
+ return;
+ end
+
+ this.printToConsole("change hook state :"..s)
+ if s ~= hookState.DISCONNECT_HOOK then
+ this.printToVSCode("change hook state : "..s)
+ end
+
+ currentHookState = s;
+ if s == hookState.DISCONNECT_HOOK then
+ --为了实现通用attach模式,require即开始hook,利用r作为时机发起连接
+ if openAttachMode == true then
+ if hookLib then hookLib.lua_set_hookstate(hookState.DISCONNECT_HOOK); else debug.sethook(this.debug_hook, "r", 1000000); end
+ else
+ if hookLib then hookLib.endHook(); else debug.sethook(); end
+ end
+ elseif s == hookState.LITE_HOOK then
+ if hookLib then hookLib.lua_set_hookstate(hookState.LITE_HOOK); else debug.sethook(this.debug_hook, "r"); end
+ elseif s == hookState.MID_HOOK then
+ if hookLib then hookLib.lua_set_hookstate(hookState.MID_HOOK); else debug.sethook(this.debug_hook, "rc"); end
+ elseif s == hookState.ALL_HOOK then
+ if hookLib then hookLib.lua_set_hookstate(hookState.ALL_HOOK); else debug.sethook(this.debug_hook, "lrc");end
+ end
+ --coroutine
+ if hookLib == nil then
+ this.changeCoroutinesHookState();
+ end
+end
+
+-- 运行状态机,状态变更
+-- @s 目标状态
+-- @isFromHooklib 1:从libc库中发来的状态改变 | 0:lua发来的状态改变
+function this.changeRunState(s , isFromHooklib)
+ local msgFrom;
+ if isFromHooklib == 1 then
+ msgFrom = "libc";
+ else
+ msgFrom = "lua";
+ end
+
+ --WAIT_CMD状态会等待接收消息,以下两个状态下不能发消息
+ this.printToConsole("changeRunState :"..s.. " | from:"..msgFrom);
+ if s ~= runState.DISCONNECT and s ~= runState.WAIT_CMD then
+ this.printToVSCode("changeRunState :"..s.." | from:"..msgFrom);
+ end
+
+ if hookLib ~= nil and isFromHooklib ~= 1 then
+ hookLib.lua_set_runstate(s);
+ end
+ currentRunState = s;
+ --状态切换时,清除记录栈信息的状态
+ currentCallStack = {};
+ variableRefTab = {};
+ variableRefIdx = 1;
+end
+
+-- 修改协程状态
+-- @s hook标志位
+function this.changeCoroutinesHookState(s)
+ s = s or currentHookState;
+ this.printToConsole("change [Coroutine] HookState: "..tostring(s));
+ for k ,co in pairs(coroutinePool) do
+ if coroutine.status(co) == "dead" then
+ coroutinePool[k] = nil
+ else
+ this.changeCoroutineHookState(co, s)
+ end
+ end
+end
+
+function this.changeCoroutineHookState(co, s)
+ if s == hookState.DISCONNECT_HOOK then
+ if openAttachMode == true then
+ debug.sethook(co, this.debug_hook, "r", 1000000);
+ else
+ debug.sethook(co, this.debug_hook, "");
+ end
+ elseif s == hookState.LITE_HOOK then
+ debug.sethook(co , this.debug_hook, "r");
+ elseif s == hookState.MID_HOOK then
+ debug.sethook(co , this.debug_hook, "rc");
+ elseif s == hookState.ALL_HOOK then
+ debug.sethook(co , this.debug_hook, "lrc");
+ end
+end
+-------------------------变量处理相关-----------------------------
+
+--清空REPL的env环境
+function this.clearEnv()
+ if this.getTableMemberNum(env) > 0 then
+ --清空env table
+ env = setmetatable({}, getmetatable(env));
+ end
+end
+
+--返回REPL的env环境
+function this.showEnv()
+ return env;
+end
+
+-- 用户观察table的查找函数。用tableVarName作为key去查逐层级查找realVar是否匹配
+-- @tableVarName 是用户观察的变量名,已经按层级被解析成table。比如用户输出a.b.c,tableVarName是 a = { b = { c } }
+-- @realVar 是待查询 table
+-- @return 返回查到的table。没查到返回nil
+function this.findTableVar( tableVarName, realVar)
+ if type(tableVarName) ~= "table" or type(realVar) ~= "table" then
+ return nil;
+ end
+
+ local layer = 2;
+ local curVar = realVar;
+ local jumpOutFlag = false;
+ repeat
+ if tableVarName[layer] ~= nil then
+ --这里优先展示数字key,比如a{"1" = "aa", [1] = "bb"} 会展示[1]的值
+ local tmpCurVar = nil;
+ xpcall(function() tmpCurVar = curVar[tonumber(tableVarName[layer])]; end , function() tmpCurVar = nil end );
+ if tmpCurVar == nil then
+ xpcall(function() curVar = curVar[tostring(tableVarName[layer])]; end , function() curVar = nil end );
+ else
+ curVar = tmpCurVar;
+ end
+ layer = layer + 1;
+ if curVar == nil then
+ return nil;
+ end
+ else
+ --找到
+ jumpOutFlag = true;
+ end
+ until(jumpOutFlag == true)
+ return curVar;
+end
+
+-- 根据传入信息生成返回的变量信息
+-- @variableName 变量名
+-- @variableIns 变量实例
+-- @return 包含变量信息的格式化table
+function this.createWatchedVariableInfo(variableName, variableIns)
+ local var = {};
+ var.name = variableName;
+ var.type = tostring(type(variableIns));
+ xpcall(function() var.value = tostring(variableIns) end , function() var.value = tostring(type(variableIns)) .. " [value can't trans to string]" end );
+ var.variablesReference = "0"; --这个地方必须用“0”, 以免variableRefTab[0]出错
+
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = variableIns;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(variableIns);
+ var.value = memberNum .." Members ".. var.value;
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..variableIns.. '"';
+ end
+ return var;
+end
+
+-- 设置 global 变量
+-- @varName 被修改的变量名
+-- @newValue 新的值
+function this.setGlobal(varName, newValue)
+ _G[varName] = newValue;
+ this.printToVSCode("[setVariable success] 已设置 _G.".. varName .. " = " .. tostring(newValue) );
+ return true;
+end
+
+-- 设置 upvalue 变量
+-- @varName 被修改的变量名
+-- @newValue 新的值
+-- @stackId 变量所在stack栈层
+-- @tableVarName 变量名拆分成的数组
+function this.setUpvalue(varName, newValue, stackId, tableVarName)
+ local ret = false;
+ local upTable = this.getUpValueVariable(currentCallStack[stackId - 1 ].func, true);
+ for i, realVar in ipairs(upTable) do
+ if realVar.name == varName then
+ if #tableVarName > 0 and type(realVar) == "table" then
+ --处理a.b.c的table类型
+ local findRes = this.findTableVar(tableVarName, variableRefTab[realVar.variablesReference]);
+ if findRes ~= nil then
+ --命中
+ local setVarRet = debug.setupvalue (currentCallStack[stackId - 1 ].func, i, newValue);
+ if setVarRet == varName then
+ this.printToConsole("[setVariable success1] 已设置 upvalue ".. varName .. " = " .. tostring(newValue) );
+ ret = true;
+ else
+ this.printToConsole("[setVariable error1] 未能设置 upvalue ".. varName .. " = " .. tostring(newValue).." , 返回结果: ".. tostring(setVarRet));
+ end
+ return ret;
+ end
+ else
+ --命中
+ local setVarRet = debug.setupvalue (currentCallStack[stackId - 1 ].func, i, newValue);
+ if setVarRet == varName then
+ this.printToConsole("[setVariable success] 已设置 upvalue ".. varName .. " = " .. tostring(newValue) );
+ ret = true;
+ else
+ this.printToConsole("[setVariable error] 未能设置 upvalue ".. varName .. " = " .. tostring(newValue).." , 返回结果: ".. tostring(setVarRet));
+ end
+ return ret;
+ end
+ end
+ end
+ return ret;
+end
+
+-- 设置local 变量
+-- @varName 被修改的变量名
+-- @newValue 新的值
+-- @tableVarName 变量名拆分成的数组
+function this.setLocal( varName, newValue, tableVarName, stackId)
+ local istackId = tonumber(stackId);
+ local offset = (istackId and istackId - 2) or 0;
+ local layerVarTab, ly = this.getVariable(nil , true, offset);
+ local ret = false;
+ for i, realVar in ipairs(layerVarTab) do
+ if realVar.name == varName then
+ if #tableVarName > 0 and type(realVar) == "table" then
+ --处理a.b.c的table类型
+ local findRes = this.findTableVar(tableVarName, variableRefTab[realVar.variablesReference]);
+ if findRes ~= nil then
+ --命中
+ local setVarRet = debug.setlocal(ly , layerVarTab[i].index, newValue);
+ if setVarRet == varName then
+ this.printToConsole("[setVariable success1] 已设置 local ".. varName .. " = " .. tostring(newValue) );
+ ret = true;
+ else
+ this.printToConsole("[setVariable error1] 未能设置 local ".. varName .. " = " .. tostring(newValue).." , 返回结果: ".. tostring(setVarRet));
+ end
+ return ret;
+ end
+ else
+
+ local setVarRet = debug.setlocal(ly , layerVarTab[i].index, newValue);
+
+ if setVarRet == varName then
+ this.printToConsole("[setVariable success] 已设置 local ".. varName .. " = " .. tostring(newValue) );
+ ret = true;
+ else
+ this.printToConsole("[setVariable error] 未能设置 local ".. varName .. " = " .. tostring(newValue) .." , 返回结果: ".. tostring(setVarRet));
+ end
+ return ret;
+ end
+ end
+ end
+ return ret;
+end
+
+
+-- 设置变量的值
+-- @varName 被修改的变量名
+-- @curStackId 调用栈层级(仅在固定栈层查找)
+-- @newValue 新的值
+-- @limit 限制符, 10000表示仅在局部变量查找 ,20000 global, 30000 upvalue
+function this.setVariableValue (varName, stackId, newValue , limit)
+ this.printToConsole("setVariableValue | varName:" .. tostring(varName) .. " stackId:".. tostring(stackId) .." newValue:" .. tostring(newValue) .." limit:"..tostring(limit) )
+ if tostring(varName) == nil or tostring(varName) == "" then
+ --赋值错误
+ this.printToConsole("[setVariable Error] 被赋值的变量名为空", 2 );
+ this.printToVSCode("[setVariable Error] 被赋值的变量名为空", 2 );
+ return false;
+ end
+
+ --支持a.b.c形式。切割varName
+ local tableVarName = {};
+ if varName:match('%.') then
+ tableVarName = this.stringSplit(varName , '%.');
+ if type(tableVarName) ~= "table" or #tableVarName < 1 then
+ return false;
+ end
+ varName = tableVarName[1];
+ end
+
+ if limit == "local" then
+ local ret = this.setLocal( varName, newValue, tableVarName, stackId);
+ return ret;
+ elseif limit == "upvalue" then
+ local ret = this.setUpvalue(varName, newValue, stackId, tableVarName);
+ return ret
+ elseif limit == "global" then
+ local ret = this.setGlobal(varName, newValue);
+ return ret;
+ else
+ local ret = this.setLocal( varName, newValue, tableVarName, stackId) or this.setUpvalue(varName, newValue, stackId, tableVarName) or this.setGlobal(varName, newValue);
+ this.printToConsole("set Value res :".. tostring(ret));
+ return ret;
+ end
+end
+
+-- 按照local -> upvalue -> _G 顺序查找观察变量
+-- @varName 用户输入的变量名
+-- @stackId 调用栈层级(仅在固定栈层查找)
+-- @isFormatVariable 是否把变量格式化为VSCode接收的形式
+-- @return 查到返回信息,查不到返回nil
+function this.getWatchedVariable( varName , stackId , isFormatVariable )
+ this.printToConsole("getWatchedVariable | varName:" .. tostring(varName) .. " stackId:".. tostring(stackId) .." isFormatVariable:" .. tostring(isFormatVariable) )
+ if tostring(varName) == nil or tostring(varName) == "" then
+ return nil;
+ end
+
+ if type(currentCallStack[stackId - 1]) ~= "table" or type(currentCallStack[stackId - 1].func) ~= "function" then
+ local str = "getWatchedVariable currentCallStack " .. stackId - 1 .. " Error\n" .. this.serializeTable(currentCallStack, "currentCallStack");
+ this.printToVSCode(str, 2);
+ return nil;
+ end
+
+ --orgname 记录原名字. 用来处理a.b.c的形式
+ local orgname = varName;
+ --支持a.b.c形式。切割varName
+ local tableVarName = {};
+ if varName:match('%.') then
+ tableVarName = this.stringSplit(varName , '%.');
+ if type(tableVarName) ~= "table" or #tableVarName < 1 then
+ return nil;
+ end
+ varName = tableVarName[1];
+ end
+ --用来返回,带有查到变量的table
+ local varTab = {};
+ local ly = this.getSpecificFunctionStackLevel(currentCallStack[stackId - 1].func);
+
+ local layerVarTab = this.getVariable(ly, isFormatVariable);
+ local upTable = this.getUpValueVariable(currentCallStack[stackId - 1 ].func, isFormatVariable);
+ local travelTab = {};
+ table.insert(travelTab, layerVarTab);
+ table.insert(travelTab, upTable);
+ for _, layerVarTab in ipairs(travelTab) do
+ for i,realVar in ipairs(layerVarTab) do
+ if realVar.name == varName then
+ if #tableVarName > 0 and type(realVar) == "table" then
+ --处理a.b.c的table类型
+ local findRes = this.findTableVar(tableVarName, variableRefTab[realVar.variablesReference]);
+ if findRes ~= nil then
+ --命中
+ if isFormatVariable then
+ local var = this.createWatchedVariableInfo( orgname , findRes );
+ table.insert(varTab, var);
+ return varTab;
+ else
+ return findRes.value;
+ end
+ end
+ else
+ --命中
+ if isFormatVariable then
+ table.insert(varTab, realVar);
+ return varTab;
+ else
+ return realVar.value;
+ end
+ end
+ end
+ end
+ end
+
+ --在全局变量_G中查找
+ if _G[varName] ~= nil then
+ --命中
+ if #tableVarName > 0 and type(_G[varName]) == "table" then
+ local findRes = this.findTableVar(tableVarName, _G[varName]);
+ if findRes ~= nil then
+ if isFormatVariable then
+ local var = this.createWatchedVariableInfo( orgname , findRes );
+ table.insert(varTab, var);
+ return varTab;
+ else
+ return findRes;
+ end
+ end
+ else
+ if isFormatVariable then
+ local var = this.createWatchedVariableInfo( varName , _G[varName] );
+ table.insert(varTab, var);
+ return varTab;
+ else
+ return _G[varName];
+ end
+ end
+ end
+ this.printToConsole("getWatchedVariable not find variable");
+ return nil;
+end
+
+-- 查询引用变量
+-- @refStr 变量记录id(variableRefTab索引)
+-- @return 格式化的变量信息table
+function this.getVariableRef( refStr )
+ local varRef = tonumber(refStr);
+ local varTab = {};
+
+ if tostring(type(variableRefTab[varRef])) == "table" then
+ for n,v in pairs(variableRefTab[varRef]) do
+ local var = {};
+ if type(n) == "string" then
+ var.name = '"' .. tostring(n) .. '"';
+ else
+ var.name = tostring(n);
+ end
+ var.type = tostring(type(v));
+ xpcall(function() var.value = tostring(v) end , function() var.value = tostring(type(v)) .. " [value can't trans to string]" end );
+ var.variablesReference = "0";
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = v;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(v);
+ var.value = memberNum .." Members ".. ( var.value or '' );
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..v.. '"';
+ end
+ table.insert(varTab, var);
+ end
+ --获取一下mtTable
+ local mtTab = getmetatable(variableRefTab[varRef]);
+ if mtTab ~= nil and type(mtTab) == "table" then
+ local var = {};
+ var.name = "_Metatable_";
+ var.type = tostring(type(mtTab));
+ xpcall(function() var.value = "元表 "..tostring(mtTab); end , function() var.value = "元表 [value can't trans to string]" end );
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = mtTab;
+ variableRefIdx = variableRefIdx + 1;
+ table.insert(varTab, var);
+ end
+ elseif tostring(type(variableRefTab[varRef])) == "function" then
+ --取upvalue
+ varTab = this.getUpValueVariable(variableRefTab[varRef], true);
+ elseif tostring(type(variableRefTab[varRef])) == "userdata" then
+ --取mt table
+ local udMtTable = getmetatable(variableRefTab[varRef]);
+ if udMtTable ~= nil and type(udMtTable) == "table" then
+ local var = {};
+ var.name = "_Metatable_";
+ var.type = tostring(type(udMtTable));
+ xpcall(function() var.value = "元表 "..tostring(udMtTable); end , function() var.value = "元表 [value can't trans to string]" end );
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = udMtTable;
+ variableRefIdx = variableRefIdx + 1;
+ table.insert(varTab, var);
+
+ if traversalUserData and udMtTable.__pairs ~= nil and type(udMtTable.__pairs) == "function" then
+ for n,v in pairs(variableRefTab[varRef]) do
+ local var = {};
+ var.name = tostring(n);
+ var.type = tostring(type(v));
+ xpcall(function() var.value = tostring(v) end , function() var.value = tostring(type(v)) .. " [value can't trans to string]" end );
+ var.variablesReference = "0";
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = v;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(v);
+ var.value = memberNum .." Members ".. ( var.value or '' );
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..v.. '"';
+ end
+ table.insert(varTab, var);
+ end
+ end
+ end
+ end
+ return varTab;
+end
+
+-- 获取全局变量。方法和内存管理中获取全局变量的方法一样
+-- @return 格式化的信息, 若未找到返回空table
+function this.getGlobalVariable( ... )
+ --成本比较高,这里只能遍历_G中的所有变量,并去除系统变量,再返回给客户端
+ local varTab = {};
+ for k,v in pairs(_G) do
+ local var = {};
+ var.name = tostring(k);
+ var.type = tostring(type(v));
+ xpcall(function() var.value = tostring(v) end , function() var.value = tostring(type(v)) .." [value can't trans to string]" end );
+ var.variablesReference = "0";
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = v;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(v);
+ var.value = memberNum .." Members ".. ( var.value or '' );
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..v.. '"';
+ end
+ table.insert(varTab, var);
+ end
+ return varTab;
+end
+
+-- 获取upValues
+-- @isFormatVariable true返回[值] true返回[格式化的数据]
+function this.getUpValueVariable( checkFunc , isFormatVariable)
+ local isGetValue = true;
+ if isFormatVariable == true then
+ isGetValue = false;
+ end
+
+ --通过Debug获取当前函数的Func
+ checkFunc = checkFunc or lastRunFunction.func;
+
+ local varTab = {};
+ if checkFunc == nil then
+ return varTab;
+ end
+ local i = 1
+ repeat
+ local n, v = debug.getupvalue(checkFunc, i)
+ if n then
+
+ local var = {};
+ var.name = n;
+ var.type = tostring(type(v));
+ var.variablesReference = "0";
+
+ if isGetValue == false then
+ xpcall(function() var.value = tostring(v) end , function() var.value = tostring(type(v)) .. " [value can't trans to string]" end );
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = v;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(v);
+ var.value = memberNum .." Members ".. ( var.value or '' );
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..v.. '"';
+ end
+ else
+ var.value = v;
+ end
+
+ table.insert(varTab, var);
+ i = i + 1
+ end
+ until not n
+ return varTab;
+end
+
+-- 获取局部变量 checkLayer是要查询的层级,如果不设置则查询当前层级
+-- @isFormatVariable 是否取值,true:取值的tostring
+function this.getVariable( checkLayer, isFormatVariable , offset)
+ local isGetValue = true;
+ if isFormatVariable == true then
+ isGetValue = false;
+ end
+
+ local ly = 0;
+ if checkLayer ~= nil and type(checkLayer) == "number" then ly = checkLayer + 1;
+ else ly = this.getSpecificFunctionStackLevel(lastRunFunction.func); end
+
+ if ly == 0 then
+ this.printToVSCode("[error]获取层次失败!", 2);
+ return;
+ end
+ local varTab = {};
+ local stacklayer = ly;
+ local k = 1;
+
+ if type(offset) == 'number' then
+ stacklayer = stacklayer + offset;
+ end
+
+ repeat
+ local n, v = debug.getlocal(stacklayer, k)
+ if n == nil then
+ break;
+ end
+
+ --(*temporary)是系统变量,过滤掉。这里假设(*temporary)仅出现在最后
+ if "(*temporary)" ~= tostring(n) then
+ local var = {};
+ var.name = n;
+ var.type = tostring(type(v));
+ var.variablesReference = "0";
+ var.index = k;
+
+ if isGetValue == false then
+ xpcall(function() var.value = tostring(v) end , function() var.value = tostring(type(v)) .. " [value can't trans to string]" end );
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = v;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(v);
+ var.value = memberNum .." Members ".. ( var.value or '' );
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..v.. '"';
+ end
+ else
+ var.value = v;
+ end
+
+ local sameIdx = this.checkSameNameVar(varTab, var);
+ if sameIdx ~= 0 then
+ varTab[sameIdx] = var;
+ else
+ table.insert(varTab, var);
+ end
+ end
+ k = k + 1
+ until n == nil
+ return varTab, stacklayer - 1;
+end
+
+--检查变量列表中的同名变量
+function this.checkSameNameVar(varTab, var)
+ for k , v in pairs(varTab) do
+ if v.name == var.name then
+ return k;
+ end
+ end
+ return 0;
+end
+
+-- 执行表达式
+function this.processExp(msgTable)
+ local retString;
+ local var = {};
+ var.isSuccess = "true";
+ if msgTable ~= nil then
+ local expression = this.trim(tostring(msgTable.Expression));
+ local isCmd = false;
+ if isCmd == false then
+ --兼容旧版p 命令
+ if expression:find("p ", 1, true) == 1 then
+ expression = expression:sub(3);
+ end
+
+ local expressionWithReturn = "return " .. expression;
+ local f = debugger_loadString(expressionWithReturn) or debugger_loadString(expression);
+ --判断结果,如果表达式错误会返回nil
+ if type(f) == "function" then
+ if _VERSION == "Lua 5.1" then
+ setfenv(f , env);
+ else
+ debug.setupvalue(f, 1, env);
+ end
+ --表达式要有错误处理
+ xpcall(function() retString = f() end , function() retString = "输入错误指令。\n + 请检查指令是否正确\n + 指令仅能在[暂停在断点时]输入, 请不要在程序持续运行时输入"; var.isSuccess = false; end)
+ else
+ retString = "指令执行错误。\n + 请检查指令是否正确\n + 可以直接输入表达式,执行函数或变量名,并观察执行结果";
+ var.isSuccess = false;
+ end
+ end
+ end
+
+ var.name = "Exp";
+ var.type = tostring(type(retString));
+ xpcall(function() var.value = tostring(retString) end , function(e) var.value = tostring(type(retString)) .. " [value can't trans to string] ".. e; var.isSuccess = false; end);
+ var.variablesReference = "0";
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ variableRefTab[variableRefIdx] = retString;
+ var.variablesReference = variableRefIdx;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(retString);
+ var.value = memberNum .." Members ".. var.value;
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..retString.. '"';
+ end
+ --string执行完毕后清空env环境
+ this.clearEnv();
+ local retTab = {}
+ table.insert(retTab ,var);
+ return retTab;
+end
+
+--执行变量观察表达式
+function this.processWatchedExp(msgTable)
+ local retString;
+ local expression = "return ".. tostring(msgTable.varName)
+ this.printToConsole("processWatchedExp | expression: " .. expression);
+ local f = debugger_loadString(expression);
+ local var = {};
+ var.isSuccess = "true";
+ --判断结果,如果表达式错误会返回nil
+ if type(f) == "function" then
+ --表达式正确
+ if _VERSION == "Lua 5.1" then
+ setfenv(f , env);
+ else
+ debug.setupvalue(f, 1, env);
+ end
+ xpcall(function() retString = f() end , function() retString = "输入了错误的变量信息"; var.isSuccess = "false"; end)
+ else
+ retString = "未能找到变量的值";
+ var.isSuccess = "false";
+ end
+
+ var.name = msgTable.varName;
+ var.type = tostring(type(retString));
+ xpcall(function() var.value = tostring(retString) end , function() var.value = tostring(type(retString)) .. " [value can't trans to string]"; var.isSuccess = "false"; end );
+ var.variablesReference = "0";
+
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ variableRefTab[variableRefIdx] = retString;
+ var.variablesReference = variableRefIdx;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(retString);
+ var.value = memberNum .." Members ".. var.value;
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..retString.. '"';
+ end
+
+ local retTab = {}
+ table.insert(retTab ,var);
+ return retTab;
+end
+
+
+function tools.getFileSource()
+ local info = debug.getinfo(1, "S")
+ for k,v in pairs(info) do
+ if k == "source" then
+ return v;
+ end
+ end
+end
+
+--序列化并打印table
+function tools.printTable(t, name ,indent)
+ local str = (tools.show(t, name, indent));
+ print(str);
+end
+
+--序列化并返回table
+function tools.serializeTable(t, name, indent)
+ local str = (tools.show(t, name, indent))
+ return str
+end
+
+--[[
+Author: Julio Manuel Fernandez-Diaz
+Date: January 12, 2007
+Modified slightly by RiciLake to avoid the unnecessary table traversal in tablecount()
+Formats tables with cycles recursively to any depth.
+The output is returned as a string.
+References to other tables are shown as values.
+Self references are indicated.
+The string returned is "Lua code", which can be procesed
+(in the case in which indent is composed by spaces or "--").
+Userdata and function keys and values are shown as strings,
+which logically are exactly not equivalent to the original code.
+This routine can serve for pretty formating tables with
+proper indentations, apart from printing them:
+print(table.show(t, "t")) -- a typical use
+Heavily based on "Saving tables with cycles", PIL2, p. 113.
+Arguments:
+t is the table.
+name is the name of the table (optional)
+indent is a first indentation (optional).
+--]]
+function tools.show(t, name, indent)
+ local cart -- a container
+ local autoref -- for self references
+
+ local function isemptytable(t) return next(t) == nil end
+
+ local function basicSerialize (o)
+ local so = tostring(o)
+ if type(o) == "function" then
+ local info = debug.getinfo(o, "S")
+ -- info.name is nil because o is not a calling level
+ if info.what == "C" then
+ return string.format("%q", so .. ", C function")
+ else
+ -- the information is defined through lines
+ return string.format("%q", so .. ", defined in (" ..
+ info.linedefined .. "-" .. info.lastlinedefined ..
+ ")" .. info.source)
+ end
+ elseif type(o) == "number" or type(o) == "boolean" then
+ return so
+ else
+ return string.format("%q", so)
+ end
+ end
+
+ local function addtocart (value, name, indent, saved, field)
+ indent = indent or ""
+ saved = saved or {}
+ field = field or name
+
+ cart = cart .. indent .. field
+
+ if type(value) ~= "table" then
+ cart = cart .. " = " .. basicSerialize(value) .. ";\n"
+ else
+ if saved[value] then
+ cart = cart .. " = {}; -- " .. saved[value]
+ .. " (self reference)\n"
+ autoref = autoref .. name .. " = " .. saved[value] .. ";\n"
+ else
+ saved[value] = name
+ --if tablecount(value) == 0 then
+ if isemptytable(value) then
+ cart = cart .. " = {};\n"
+ else
+ cart = cart .. " = {\n"
+ for k, v in pairs(value) do
+ k = basicSerialize(k)
+ local fname = string.format("%s[%s]", name, k)
+ field = string.format("[%s]", k)
+ -- three spaces between levels
+ addtocart(v, fname, indent .. " ", saved, field)
+ end
+ cart = cart .. indent .. "};\n"
+ end
+ end
+ end
+ end
+
+ name = name or "PRINT_Table"
+ if type(t) ~= "table" then
+ return name .. " = " .. basicSerialize(t)
+ end
+ cart, autoref = "", ""
+ addtocart(t, name, indent)
+ return cart .. autoref
+end
+
+-----------------------------------------------------------------------------
+-- JSON4Lua: JSON encoding / decoding support for the Lua language.
+-- json Module.
+-- Author: Craig Mason-Jones
+-- Homepage: http://github.com/craigmj/json4lua/
+-- Version: 1.0.0
+-- This module is released under the MIT License (MIT).
+-- Please see LICENCE.txt for details.
+--
+-- USAGE:
+-- This module exposes two functions:
+-- json.encode(o)
+-- Returns the table / string / boolean / number / nil / json.null value as a JSON-encoded string.
+-- json.decode(json_string)
+-- Returns a Lua object populated with the data encoded in the JSON string json_string.
+--
+-- REQUIREMENTS:
+-- compat-5.1 if using Lua 5.0
+--
+-- CHANGELOG
+-- 0.9.20 Introduction of local Lua functions for private functions (removed _ function prefix).
+-- Fixed Lua 5.1 compatibility issues.
+-- Introduced json.null to have null values in associative arrays.
+-- json.encode() performance improvement (more than 50%) through table.concat rather than ..
+-- Introduced decode ability to ignore /**/ comments in the JSON string.
+-- 0.9.10 Fix to array encoding / decoding to correctly manage nil/null values in arrays.
+-----------------------------------------------------------------------------
+
+function tools.createJson()
+ -----------------------------------------------------------------------------
+ -- Imports and dependencies
+ -----------------------------------------------------------------------------
+ local math = require('math')
+ local string = require("string")
+ local table = require("table")
+
+ -----------------------------------------------------------------------------
+ -- Module declaration
+ -----------------------------------------------------------------------------
+ local json = {} -- Public namespace
+ local json_private = {} -- Private namespace
+
+ -- Public constants
+ json.EMPTY_ARRAY={}
+ json.EMPTY_OBJECT={}
+
+ -- Public functions
+
+ -- Private functions
+ local decode_scanArray
+ local decode_scanComment
+ local decode_scanConstant
+ local decode_scanNumber
+ local decode_scanObject
+ local decode_scanString
+ local decode_scanWhitespace
+ local encodeString
+ local isArray
+ local isEncodable
+
+ -----------------------------------------------------------------------------
+ -- PUBLIC FUNCTIONS
+ -----------------------------------------------------------------------------
+ --- Encodes an arbitrary Lua object / variable.
+ -- @param v The Lua object / variable to be JSON encoded.
+ -- @return String containing the JSON encoding in internal Lua string format (i.e. not unicode)
+ function json.encode (v)
+ -- Handle nil values
+ if v==nil then
+ return "null"
+ end
+
+ local vtype = type(v)
+
+ -- Handle strings
+ if vtype=='string' then
+ return '"' .. json_private.encodeString(v) .. '"' -- Need to handle encoding in string
+ end
+
+ -- Handle booleans
+ if vtype=='number' or vtype=='boolean' then
+ return tostring(v)
+ end
+
+ -- Handle tables
+ if vtype=='table' then
+ local rval = {}
+ -- Consider arrays separately
+ local bArray, maxCount = isArray(v)
+ if bArray then
+ for i = 1,maxCount do
+ table.insert(rval, json.encode(v[i]))
+ end
+ else -- An object, not an array
+ for i,j in pairs(v) do
+ if isEncodable(i) and isEncodable(j) then
+ table.insert(rval, '"' .. json_private.encodeString(i) .. '":' .. json.encode(j))
+ end
+ end
+ end
+ if bArray then
+ return '[' .. table.concat(rval,',') ..']'
+ else
+ return '{' .. table.concat(rval,',') .. '}'
+ end
+ end
+
+ -- Handle null values
+ if vtype=='function' and v==json.null then
+ return 'null'
+ end
+
+ assert(false,'encode attempt to encode unsupported type ' .. vtype .. ':' .. tostring(v))
+ end
+
+
+ --- Decodes a JSON string and returns the decoded value as a Lua data structure / value.
+ -- @param s The string to scan.
+ -- @param [startPos] Optional starting position where the JSON string is located. Defaults to 1.
+ -- @param Lua object, number The object that was scanned, as a Lua table / string / number / boolean or nil,
+ -- and the position of the first character after
+ -- the scanned JSON object.
+ function json.decode(s, startPos)
+ startPos = startPos and startPos or 1
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=string.len(s), 'Unterminated JSON encoded object found at position in [' .. s .. ']')
+ local curChar = string.sub(s,startPos,startPos)
+ -- Object
+ if curChar=='{' then
+ return decode_scanObject(s,startPos)
+ end
+ -- Array
+ if curChar=='[' then
+ return decode_scanArray(s,startPos)
+ end
+ -- Number
+ if string.find("+-0123456789.e", curChar, 1, true) then
+ return decode_scanNumber(s,startPos)
+ end
+ -- String
+ if curChar==[["]] or curChar==[[']] then
+ return decode_scanString(s,startPos)
+ end
+ if string.sub(s,startPos,startPos+1)=='/*' then
+ return json.decode(s, decode_scanComment(s,startPos))
+ end
+ -- Otherwise, it must be a constant
+ return decode_scanConstant(s,startPos)
+ end
+
+ --- The null function allows one to specify a null value in an associative array (which is otherwise
+ -- discarded if you set the value with 'nil' in Lua. Simply set t = { first=json.null }
+ function json.null()
+ return json.null -- so json.null() will also return null ;-)
+ end
+ -----------------------------------------------------------------------------
+ -- Internal, PRIVATE functions.
+ -- Following a Python-like convention, I have prefixed all these 'PRIVATE'
+ -- functions with an underscore.
+ -----------------------------------------------------------------------------
+
+ --- Scans an array from JSON into a Lua object
+ -- startPos begins at the start of the array.
+ -- Returns the array and the next starting position
+ -- @param s The string being scanned.
+ -- @param startPos The starting position for the scan.
+ -- @return table, int The scanned array as a table, and the position of the next character to scan.
+ function decode_scanArray(s,startPos)
+ local array = {} -- The return value
+ local stringLen = string.len(s)
+ assert(string.sub(s,startPos,startPos)=='[','decode_scanArray called but array does not start at position ' .. startPos .. ' in string:\n'..s )
+ startPos = startPos + 1
+ -- Infinite loop for array elements
+ local index = 1
+ repeat
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=stringLen,'JSON String ended unexpectedly scanning array.')
+ local curChar = string.sub(s,startPos,startPos)
+ if (curChar==']') then
+ return array, startPos+1
+ end
+ if (curChar==',') then
+ startPos = decode_scanWhitespace(s,startPos+1)
+ end
+ assert(startPos<=stringLen, 'JSON String ended unexpectedly scanning array.')
+ local object
+ object, startPos = json.decode(s,startPos)
+ array[index] = object
+ index = index + 1
+ until false
+ end
+
+ --- Scans a comment and discards the comment.
+ -- Returns the position of the next character following the comment.
+ -- @param string s The JSON string to scan.
+ -- @param int startPos The starting position of the comment
+ function decode_scanComment(s, startPos)
+ assert( string.sub(s,startPos,startPos+1)=='/*', "decode_scanComment called but comment does not start at position " .. startPos)
+ local endPos = string.find(s,'*/',startPos+2)
+ assert(endPos~=nil, "Unterminated comment in string at " .. startPos)
+ return endPos+2
+ end
+
+ --- Scans for given constants: true, false or null
+ -- Returns the appropriate Lua type, and the position of the next character to read.
+ -- @param s The string being scanned.
+ -- @param startPos The position in the string at which to start scanning.
+ -- @return object, int The object (true, false or nil) and the position at which the next character should be
+ -- scanned.
+ function decode_scanConstant(s, startPos)
+ local consts = { ["true"] = true, ["false"] = false, ["null"] = nil }
+ local constNames = {"true","false","null"}
+
+ for i,k in pairs(constNames) do
+ if string.sub(s,startPos, startPos + string.len(k) -1 )==k then
+ return consts[k], startPos + string.len(k)
+ end
+ end
+ assert(nil, 'Failed to scan constant from string ' .. s .. ' at starting position ' .. startPos)
+ end
+
+ --- Scans a number from the JSON encoded string.
+ -- (in fact, also is able to scan numeric +- eqns, which is not
+ -- in the JSON spec.)
+ -- Returns the number, and the position of the next character
+ -- after the number.
+ -- @param s The string being scanned.
+ -- @param startPos The position at which to start scanning.
+ -- @return number, int The extracted number and the position of the next character to scan.
+ function decode_scanNumber(s,startPos)
+ local endPos = startPos+1
+ local stringLen = string.len(s)
+ local acceptableChars = "+-0123456789.e"
+ while (string.find(acceptableChars, string.sub(s,endPos,endPos), 1, true)
+ and endPos<=stringLen
+ ) do
+ endPos = endPos + 1
+ end
+ -- local stringValue = 'return ' .. string.sub(s, startPos, endPos - 1)
+ -- local stringEval = loadstring(stringValue)
+ -- assert(stringEval, 'Failed to scan number [ ' .. stringValue .. '] in JSON string at position ' .. startPos .. ' : ' .. endPos)
+ local numberValue = string.sub(s, startPos, endPos - 1)
+ return numberValue, endPos
+ end
+
+ --- Scans a JSON object into a Lua object.
+ -- startPos begins at the start of the object.
+ -- Returns the object and the next starting position.
+ -- @param s The string being scanned.
+ -- @param startPos The starting position of the scan.
+ -- @return table, int The scanned object as a table and the position of the next character to scan.
+ function decode_scanObject(s,startPos)
+ local object = {}
+ local stringLen = string.len(s)
+ local key, value
+ assert(string.sub(s,startPos,startPos)=='{','decode_scanObject called but object does not start at position ' .. startPos .. ' in string:\n' .. s)
+ startPos = startPos + 1
+ repeat
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly while scanning object.')
+ local curChar = string.sub(s,startPos,startPos)
+ if (curChar=='}') then
+ return object,startPos+1
+ end
+ if (curChar==',') then
+ startPos = decode_scanWhitespace(s,startPos+1)
+ end
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly scanning object.')
+ -- Scan the key
+ key, startPos = json.decode(s,startPos)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
+ assert(string.sub(s,startPos,startPos)==':','JSON object key-value assignment mal-formed at ' .. startPos)
+ startPos = decode_scanWhitespace(s,startPos+1)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
+ value, startPos = json.decode(s,startPos)
+ object[key]=value
+ until false -- infinite loop while key-value pairs are found
+ end
+
+ -- START SoniEx2
+ -- Initialize some things used by decode_scanString
+ -- You know, for efficiency
+ local escapeSequences = {
+ ["\\t"] = "\t",
+ ["\\f"] = "\f",
+ ["\\r"] = "\r",
+ ["\\n"] = "\n",
+ ["\\b"] = "\b"
+ }
+ setmetatable(escapeSequences, {__index = function(t,k)
+ -- skip "\" aka strip escape
+ return string.sub(k,2)
+ end})
+ -- END SoniEx2
+
+ --- Scans a JSON string from the opening inverted comma or single quote to the
+ -- end of the string.
+ -- Returns the string extracted as a Lua string,
+ -- and the position of the next non-string character
+ -- (after the closing inverted comma or single quote).
+ -- @param s The string being scanned.
+ -- @param startPos The starting position of the scan.
+ -- @return string, int The extracted string as a Lua string, and the next character to parse.
+ function decode_scanString(s,startPos)
+ assert(startPos, 'decode_scanString(..) called without start position')
+ local startChar = string.sub(s,startPos,startPos)
+ -- START SoniEx2
+ -- PS: I don't think single quotes are valid JSON
+ assert(startChar == [["]] or startChar == [[']],'decode_scanString called for a non-string')
+ --assert(startPos, "String decoding failed: missing closing " .. startChar .. " for string at position " .. oldStart)
+ local t = {}
+ local i,j = startPos,startPos
+ while string.find(s, startChar, j+1) ~= j+1 do
+ local oldj = j
+ i,j = string.find(s, "\\.", j+1)
+ local x,y = string.find(s, startChar, oldj+1)
+ if not i or x < i then
+ i,j = x,y-1
+ end
+ table.insert(t, string.sub(s, oldj+1, i-1))
+ if string.sub(s, i, j) == "\\u" then
+ local a = string.sub(s,j+1,j+4)
+ j = j + 4
+ local n = tonumber(a, 16)
+ assert(n, "String decoding failed: bad Unicode escape " .. a .. " at position " .. i .. " : " .. j)
+ -- math.floor(x/2^y) == lazy right shift
+ -- a % 2^b == bitwise_and(a, (2^b)-1)
+ -- 64 = 2^6
+ -- 4096 = 2^12 (or 2^6 * 2^6)
+ local x
+ if n < 0x80 then
+ x = string.char(n % 0x80)
+ elseif n < 0x800 then
+ -- [110x xxxx] [10xx xxxx]
+ x = string.char(0xC0 + (math.floor(n/64) % 0x20), 0x80 + (n % 0x40))
+ else
+ -- [1110 xxxx] [10xx xxxx] [10xx xxxx]
+ x = string.char(0xE0 + (math.floor(n/4096) % 0x10), 0x80 + (math.floor(n/64) % 0x40), 0x80 + (n % 0x40))
+ end
+ table.insert(t, x)
+ else
+ table.insert(t, escapeSequences[string.sub(s, i, j)])
+ end
+ end
+ table.insert(t,string.sub(j, j+1))
+ assert(string.find(s, startChar, j+1), "String decoding failed: missing closing " .. startChar .. " at position " .. j .. "(for string at position " .. startPos .. ")")
+ return table.concat(t,""), j+2
+ -- END SoniEx2
+ end
+
+ --- Scans a JSON string skipping all whitespace from the current start position.
+ -- Returns the position of the first non-whitespace character, or nil if the whole end of string is reached.
+ -- @param s The string being scanned
+ -- @param startPos The starting position where we should begin removing whitespace.
+ -- @return int The first position where non-whitespace was encountered, or string.len(s)+1 if the end of string
+ -- was reached.
+ function decode_scanWhitespace(s,startPos)
+ local whitespace=" \n\r\t"
+ local stringLen = string.len(s)
+ while ( string.find(whitespace, string.sub(s,startPos,startPos), 1, true) and startPos <= stringLen) do
+ startPos = startPos + 1
+ end
+ return startPos
+ end
+
+ --- Encodes a string to be JSON-compatible.
+ -- This just involves back-quoting inverted commas, back-quotes and newlines, I think ;-)
+ -- @param s The string to return as a JSON encoded (i.e. backquoted string)
+ -- @return The string appropriately escaped.
+
+ local escapeList = {
+ ['"'] = '\\"',
+ ['\\'] = '\\\\',
+ ['/'] = '\\/',
+ ['\b'] = '\\b',
+ ['\f'] = '\\f',
+ ['\n'] = '\\n',
+ ['\r'] = '\\r',
+ ['\t'] = '\\t'
+ }
+
+ function json_private.encodeString(s)
+ local s = tostring(s)
+ return s:gsub(".", function(c) return escapeList[c] end) -- SoniEx2: 5.0 compat
+ end
+
+ -- Determines whether the given Lua type is an array or a table / dictionary.
+ -- We consider any table an array if it has indexes 1..n for its n items, and no
+ -- other data in the table.
+ -- I think this method is currently a little 'flaky', but can't think of a good way around it yet...
+ -- @param t The table to evaluate as an array
+ -- @return boolean, number True if the table can be represented as an array, false otherwise. If true,
+ -- the second returned value is the maximum
+ -- number of indexed elements in the array.
+ function isArray(t)
+ -- Next we count all the elements, ensuring that any non-indexed elements are not-encodable
+ -- (with the possible exception of 'n')
+ if (t == json.EMPTY_ARRAY) then return true, 0 end
+ if (t == json.EMPTY_OBJECT) then return false end
+
+ local maxIndex = 0
+ for k,v in pairs(t) do
+ if (type(k)=='number' and math.floor(k)==k and 1<=k) then -- k,v is an indexed pair
+ if (not isEncodable(v)) then return false end -- All array elements must be encodable
+ maxIndex = math.max(maxIndex,k)
+ else
+ if (k=='n') then
+ if v ~= (t.n or #t) then return false end -- False if n does not hold the number of elements
+ else -- Else of (k=='n')
+ if isEncodable(v) then return false end
+ end -- End of (k~='n')
+ end -- End of k,v not an indexed pair
+ end -- End of loop across all pairs
+ return true, maxIndex
+ end
+
+ --- Determines whether the given Lua object / table / variable can be JSON encoded. The only
+ -- types that are JSON encodable are: string, boolean, number, nil, table and json.null.
+ -- In this implementation, all other types are ignored.
+ -- @param o The object to examine.
+ -- @return boolean True if the object should be JSON encoded, false if it should be ignored.
+ function isEncodable(o)
+ local t = type(o)
+ return (t=='string' or t=='boolean' or t=='number' or t=='nil' or t=='table') or
+ (t=='function' and o==json.null)
+ end
+ return json
+end
+
+-- Sourced from http://lua-users.org/wiki/BaseSixtyFour
+
+-- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss <alexthkloss@web.de>
+-- licensed under the terms of the LGPL2
+
+-- character table string
+local base64CharTable='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+
+-- encoding
+function tools.base64encode(data)
+ return ((data:gsub('.', function(x)
+ local r,b='',x:byte()
+ for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
+ return r;
+ end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
+ if (#x < 6) then return '' end
+ local c=0
+ for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
+ return base64CharTable:sub(c+1,c+1)
+ end)..({ '', '==', '=' })[#data%3+1])
+end
+
+-- decoding
+function tools.base64decode(data)
+ data = string.gsub(data, '[^'..base64CharTable..'=]', '')
+ return (data:gsub('.', function(x)
+ if (x == '=') then return '' end
+ local r,f='',(base64CharTable:find(x)-1)
+ for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
+ return r;
+ end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
+ if (#x ~= 8) then return '' end
+ local c=0
+ for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
+ return string.char(c)
+ end))
+end
+
+-- tools变量
+json = tools.createJson(); --json处理
+this.printToConsole("load LuaPanda success", 1);
+this.replaceCoroutineFuncs()
+return this;
diff --git a/Data/Libraries/LuaPanda/README.txt b/Data/Libraries/LuaPanda/README.txt
new file mode 100644
index 0000000..9aca5bc
--- /dev/null
+++ b/Data/Libraries/LuaPanda/README.txt
@@ -0,0 +1 @@
+https://github.com/Tencent/LuaPanda \ No newline at end of file
diff --git a/Data/Libraries/luaunit/.appveyor/install-lua.cmd b/Data/Libraries/luaunit/.appveyor/install-lua.cmd
new file mode 100644
index 0000000..943bacd
--- /dev/null
+++ b/Data/Libraries/luaunit/.appveyor/install-lua.cmd
@@ -0,0 +1,133 @@
+REM This is a batch file to help with setting up the desired Lua environment.
+REM It is intended to be run as "install" step from within AppVeyor.
+
+REM version numbers and file names for binaries from http://sf.net/p/luabinaries/
+set VER_51=5.1.5
+set VER_52=5.2.4
+set VER_53=5.3.3
+set VER_54=5.4.0
+set ZIP_51=lua-%VER_51%_Win32_bin.zip
+set ZIP_52=lua-%VER_52%_Win32_bin.zip
+set ZIP_53=lua-%VER_53%_Win32_bin.zip
+set ZIP_54=lua-%VER_54%_Win32_bin.zip
+set ZIP_51_64=lua-%VER_51%_Win64_bin.zip
+set ZIP_52_64=lua-%VER_52%_Win64_bin.zip
+set ZIP_53_64=lua-%VER_53%_Win64_bin.zip
+set ZIP_54_64=lua-%VER_54%_Win64_bin.zip
+set ZIP_LUAJIT20=LuaJIT-2.0.5
+set ZIP_LUAJIT21=LuaJIT-2.1.0-beta3
+
+goto %LUAENV%
+goto error
+
+:lua51
+set PRETTY_VERSION='Lua 5.1'
+set LUA_BIN_DIR=lua51
+set LUA_EXE=lua51\lua5.1.exe
+set DL_URL=http://sourceforge.net/projects/luabinaries/files/%VER_51%/Tools%%20Executables/%ZIP_51%/download
+set DL_ZIP=%ZIP_51%
+goto download_and_intall_lua
+
+:lua51_64
+set PRETTY_VERSION='Lua 5.1 - 64 bits'
+set LUA_BIN_DIR=lua51-64
+set LUA_EXE=lua51-64\lua5.1.exe
+set DL_URL=http://sourceforge.net/projects/luabinaries/files/%VER_51%/Tools%%20Executables/%ZIP_51_64%/download
+set DL_ZIP=%ZIP_51_64%
+goto download_and_intall_lua
+
+:lua52
+set PRETTY_VERSION='Lua 5.2'
+set LUA_BIN_DIR=lua52
+set LUA_EXE=lua52\lua52.exe
+set DL_URL=http://sourceforge.net/projects/luabinaries/files/%VER_52%/Tools%%20Executables/%ZIP_52%/download
+set DL_ZIP=%ZIP_52%
+goto download_and_intall_lua
+
+:lua52_64
+set PRETTY_VERSION='Lua 5.2 - 64 bits'
+set LUA_BIN_DIR=lua52-64
+set LUA_EXE=lua52-64\lua52.exe
+set DL_URL=http://sourceforge.net/projects/luabinaries/files/%VER_52%/Tools%%20Executables/%ZIP_52_64%/download
+set DL_ZIP=%ZIP_52_64%
+goto download_and_intall_lua
+
+:lua53
+set PRETTY_VERSION='Lua 5.3'
+set LUA_BIN_DIR=lua53
+set LUA_EXE=lua53\lua53.exe
+set DL_URL=http://sourceforge.net/projects/luabinaries/files/%VER_53%/Tools%%20Executables/%ZIP_53%/download
+set DL_ZIP=%ZIP_53%
+goto download_and_intall_lua
+
+:lua53_64
+set PRETTY_VERSION='Lua 5.3 - 64 bits'
+set LUA_BIN_DIR=lua53-64
+set LUA_EXE=lua53-64\lua53.exe
+set DL_URL=http://sourceforge.net/projects/luabinaries/files/%VER_53%/Tools%%20Executables/%ZIP_53_64%/download
+set DL_ZIP=%ZIP_53_64%
+goto download_and_intall_lua
+
+:lua54
+set PRETTY_VERSION='Lua 5.4'
+set LUA_BIN_DIR=lua54
+set LUA_EXE=lua54\lua54.exe
+set DL_URL=http://sourceforge.net/projects/luabinaries/files/%VER_54%/Tools%%20Executables/%ZIP_54%/download
+set DL_ZIP=%ZIP_54%
+goto download_and_intall_lua
+
+:lua54_64
+set PRETTY_VERSION='Lua 5.4 - 64 bits'
+set LUA_BIN_DIR=lua54-64
+set LUA_EXE=lua54-64\lua54.exe
+set DL_URL=http://sourceforge.net/projects/luabinaries/files/%VER_54%/Tools%%20Executables/%ZIP_54_64%/download
+set DL_ZIP=%ZIP_54_64%
+goto download_and_intall_lua
+
+
+:luajit20
+set PRETTY_VERSION='LuaJIT 2.0'
+set LUA_BIN_DIR=luajit20
+set LUA_EXE=luajit20\luajit.exe
+set DL_ZIP=LuaJIT-2.0.5
+set DL_URL=http://luajit.org/download/%DL_ZIP%.zip
+goto download_and_intall_luajit
+
+
+:luajit21
+set PRETTY_VERSION='LuaJIT 2.1'
+set LUA_BIN_DIR=luajit21
+set LUA_EXE=luajit21\luajit.exe
+set DL_ZIP=LuaJIT-2.1.0-beta3
+set DL_URL=http://luajit.org/download/%DL_ZIP%.zip
+goto download_and_intall_luajit
+
+
+:download_and_intall_lua
+echo Setting up %PRETTY_VERSION% ...
+if NOT EXIST %LUA_EXE% (
+ @echo on
+ echo Fetching %PRETTY_VERSION% from internet
+ curl -fLsS -o %DL_ZIP% %DL_URL%
+ unzip -d %LUA_BIN_DIR% %DL_ZIP%
+) else (
+ echo Using cached version of %PRETTY_VERSION
+)
+set LUA=%LUA_EXE%
+goto :eof
+
+:download_and_intall_luajit
+echo download and install luajit
+if NOT EXIST %LUA_EXE% (
+ REM We need to put the compiling logic into a separate script
+ REM else we hit the limitation on the length of the path variable
+ REM which somehow stops the script
+ call %~dp0install-luajit.cmd
+) else (
+ echo Using cached version of %PRETTY_VERSION%
+)
+set LUA=%LUA_EXE%
+goto :eof
+
+:error
+echo Do not know how to install %LUAENV%
diff --git a/Data/Libraries/luaunit/.appveyor/install-luajit.cmd b/Data/Libraries/luaunit/.appveyor/install-luajit.cmd
new file mode 100644
index 0000000..ca7dbb4
--- /dev/null
+++ b/Data/Libraries/luaunit/.appveyor/install-luajit.cmd
@@ -0,0 +1,25 @@
+REM Do a minimalistic build of LuaJIT using the MinGW compiler
+
+set PATH=C:\MinGW\bin;%PATH%
+
+echo Downloading %PRETTY_VERSION% ...
+curl -fLsS -o %DL_ZIP%.zip %DL_URL%
+
+echo Unzipping %DL_ZIP%
+unzip -q %DL_ZIP%
+
+REM tweak Makefile for a static LuaJIT build (Windows defaults to "dynamic" otherwise)
+sed -i "s/BUILDMODE=.*mixed/BUILDMODE=static/" %DL_ZIP%\src\Makefile
+
+mingw32-make TARGET_SYS=Windows -C %DL_ZIP%\src
+
+echo Installing %PRETTY_VERSION% ...
+REM copy luajit.exe to project dir
+mkdir %APPVEYOR_BUILD_FOLDER%\%LUA_BIN_DIR%
+copy %DL_ZIP%\src\luajit.exe %APPVEYOR_BUILD_FOLDER%\%LUA_BIN_DIR%\
+
+REM clean up (remove source folders and archive)
+rm -rf %DL_ZIP%/*
+rm -f %DL_ZIP%.zip
+
+
diff --git a/Data/Libraries/luaunit/.gitignore b/Data/Libraries/luaunit/.gitignore
new file mode 100644
index 0000000..4884d0f
--- /dev/null
+++ b/Data/Libraries/luaunit/.gitignore
@@ -0,0 +1,65 @@
+
+# ignore temp files
+*.sw?
+*.bak
+*.pyc
+
+#ignore thumbnails created by windows
+Thumbs.db
+
+#Ignore files build by Visual Studio
+*.obj
+*.exe
+*.pdb
+*.user
+*.aps
+*.pch
+*.vspscc
+*_i.c
+*_p.c
+*.ncb
+*.suo
+*.tlb
+*.tlh
+*.cache
+*.ilk
+*.log
+[Bb]in
+[Dd]ebug*/
+*.lib
+*.sbr
+obj/
+[Rr]elease*/
+_ReSharper*/
+
+# LuaCov output (stats and report)
+luacov.*.out
+
+# LuaUnit ignores
+[Tt]est[Rr]esult*
+*.sublime-project
+*.lsln
+*.sublime-workspace
+doc/_build/
+doc/html/
+junit_stdout.txt
+output_junit.xml
+junit_stdout?.txt
+output_junit?.xml
+test/example*.txt
+test/example*.xml
+test/testWithXml*.xml
+test/testWithXml*.txt
+test/unitTests*.xml
+test/unitTests*.txt
+test/legacyExample.txt
+test/legacyExampleError.txt
+test/compat_luaunit_v2x.txt
+test/errFailPass*.txt
+test/errFailPass*.xml
+test/some_lists_comparisons.txt
+
+*.diff
+
+#Emacs
+*~
diff --git a/Data/Libraries/luaunit/.luacheckrc b/Data/Libraries/luaunit/.luacheckrc
new file mode 100644
index 0000000..5c14b7f
--- /dev/null
+++ b/Data/Libraries/luaunit/.luacheckrc
@@ -0,0 +1,26 @@
+--[[
+Luacheck configuration
+(see http://luacheck.readthedocs.io/en/stable/config.html)
+Thanks to Peter Melnichenko for providing an example file for LuaUnit.
+]]
+
+only = {"1"} -- limit checks to the use of global variables
+std = "max"
+self = false
+ignore = {"[Tt]est[%w_]+"}
+
+files = {
+ ["luaunit.lua"] = {
+ globals = {"EXPORT_ASSERT_TO_GLOBALS", "LuaUnit", "os"},
+ },
+ ["test/compat_luaunit_v2x.lua"] = {
+ ignore = {"EXPORT_ASSERT_TO_GLOBALS", "assert[%w_]+", "v", "y"}
+ },
+ ["test/legacy_example_with_luaunit.lua"] = {
+ ignore = {"LuaUnit", "EXPORT_ASSERT_TO_GLOBALS",
+ "assertEquals", "assertNotEquals", "assertTrue", "assertFalse"}
+ },
+ ["test/test_luaunit.lua"] = {
+ ignore = {"TestMock", "TestLuaUnit%a+", "MyTest%w+", "v", "y" }
+ }
+}
diff --git a/Data/Libraries/luaunit/.travis.yml b/Data/Libraries/luaunit/.travis.yml
new file mode 100644
index 0000000..470b223
--- /dev/null
+++ b/Data/Libraries/luaunit/.travis.yml
@@ -0,0 +1,47 @@
+language: c
+sudo: false
+
+os: linux
+
+env:
+ matrix:
+ - LUA=lua5.1 LUANUMBER=double
+ - LUA=lua5.1 LUANUMBER=float
+ - LUA=lua5.2 LUANUMBER=double
+ - LUA=lua5.2 LUANUMBER=float
+ - LUA=lua5.3 LUANUMBER=double
+ - LUA=lua5.3 LUANUMBER=float
+ - LUA=lua5.4 LUANUMBER=double
+ - LUA=luajit2.0
+ - LUA=luajit2.1
+
+matrix:
+ # test Mac OS X, but limit it to a single build
+ include:
+ - os: osx
+ env: LUA=lua5.1 LUANUMBER=double
+
+ allow_failures:
+ - os: osx
+ env: LUA=lua5.1 LUANUMBER=double
+
+before_install:
+ - source .travis/setup_lua.sh
+ - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y libxml2-utils; fi
+
+cache:
+ directories:
+ - $TRAVIS_BUILD_DIR/install
+
+script:
+ - lua -v -lluacov run_unit_tests.lua --shuffle
+ - lua run_functional_tests.lua --coverage
+ - luacheck example_with_luaunit.lua luaunit.lua run_unit_tests.lua run_functional_tests.lua test/
+
+after_success:
+ - luacov-coveralls -v --include %./luaunit.lua
+
+notifications:
+ email:
+ on_success: change
+ on_failure: always
diff --git a/Data/Libraries/luaunit/.travis/emulate_travis.sh b/Data/Libraries/luaunit/.travis/emulate_travis.sh
new file mode 100644
index 0000000..ceef037
--- /dev/null
+++ b/Data/Libraries/luaunit/.travis/emulate_travis.sh
@@ -0,0 +1,16 @@
+echo == Travis emulation mode ==
+rm -rf $HOME/.lua
+
+export LUA=lua5.4
+# export LUA=luajit2.1
+
+export LUANUMBER=double
+
+
+export TRAVIS_BUILD_DIR=`pwd`
+export TRAVIS_OS_NAME=linux
+
+# erase previous builds
+rm -rf $TRAVIS_BUILD_DIR/install
+
+bash ../.travis/setup_lua.sh
diff --git a/Data/Libraries/luaunit/.travis/setup_lua.sh b/Data/Libraries/luaunit/.travis/setup_lua.sh
new file mode 100644
index 0000000..f4eb46f
--- /dev/null
+++ b/Data/Libraries/luaunit/.travis/setup_lua.sh
@@ -0,0 +1,231 @@
+#! /bin/bash
+
+# A script for setting up environment for travis-ci testing.
+# Sets up Lua and Luarocks.
+# LUA must be "lua5.1", "lua5.2" or "luajit".
+# luajit2.0 - master v2.0
+# luajit2.1 - master v2.1
+
+###
+# This script will create the following symbolic links, to refer to the installed lua:
+# $HOME/.lua/lua
+# $HOME/.lua/luajit
+# $HOME/.lua/luac
+# $HOME/.lua/luarocks
+#
+# Building of the targeted lua version is done in:
+# $HOME/install/<lua-version>
+#
+# Lua rocks in installed in
+# $HOME/install/luacoks
+
+set -eufox pipefail
+
+LUAROCKS_VERSION=3.4.0
+LUAROCKS_URL=http://luarocks.org/releases/luarocks-3.4.0.tar.gz
+
+# Note: TRAVIS_BUILD_DIR=/home/travis/build/bluebird75/luaunit/
+LUA_HOME_DIR=$TRAVIS_BUILD_DIR/install/$LUA
+LUAROCK_HOME_DIR=$TRAVIS_BUILD_DIR/install/luarocks
+
+# setup a wide path
+export PATH=$HOME/.lua:${LUAROCK_HOME_DIR}/bin:${PATH}
+
+case $LUA in
+"lua5.1")
+ LUA_SOURCE_URL=http://www.lua.org/ftp/lua-5.1.5.tar.gz
+ LUA_BUILD_DIR=lua-5.1.5
+ LUAJIT="no"
+ LUAROCKS_CONFIGURE_ARGS=--with-lua="$LUA_HOME_DIR"
+ LUAROCKS_CONFIGURE_ARGS2=
+ ;;
+"lua5.2")
+ LUA_SOURCE_URL=http://www.lua.org/ftp/lua-5.2.4.tar.gz
+ LUA_BUILD_DIR=lua-5.2.4
+ LUAJIT="no"
+ LUAROCKS_CONFIGURE_ARGS=--with-lua="$LUA_HOME_DIR"
+ LUAROCKS_CONFIGURE_ARGS2=
+ ;;
+"lua5.3")
+ LUA_SOURCE_URL=http://www.lua.org/ftp/lua-5.3.3.tar.gz
+ LUA_BUILD_DIR=lua-5.3.3
+ LUAJIT="no"
+ LUAROCKS_CONFIGURE_ARGS=--with-lua="$LUA_HOME_DIR"
+ LUAROCKS_CONFIGURE_ARGS2=
+ ;;
+"lua5.4")
+ LUA_SOURCE_URL=http://www.lua.org/ftp/lua-5.4.0.tar.gz
+ LUA_BUILD_DIR=lua-5.4.0
+ LUAJIT="no"
+ LUAROCKS_CONFIGURE_ARGS=--with-lua="$LUA_HOME_DIR"
+ LUAROCKS_CONFIGURE_ARGS2=
+ ;;
+"luajit2.0")
+ LUA_SOURCE_URL=https://luajit.org/download/LuaJIT-2.0.5.tar.gz
+ LUA_BUILD_DIR=LuaJIT-2.0.5
+ LUAJIT="yes"
+ LUAROCKS_CONFIGURE_ARGS=--lua-suffix=jit
+ LUAROCKS_CONFIGURE_ARGS2=--with-lua-include="$LUA_HOME_DIR/include/luajit-2.0"
+ ;;
+"luajit2.1")
+ LUA_SOURCE_URL=https://luajit.org/download/LuaJIT-2.1.0-beta3.tar.gz
+ LUA_BUILD_DIR=LuaJIT-2.1.0-beta3
+ LUAJIT="yes"
+ LUAROCKS_CONFIGURE_ARGS=--lua-suffix=jit
+ LUAROCKS_CONFIGURE_ARGS2=--with-lua-include="$LUA_HOME_DIR/include/luajit-2.1"
+ ;;
+esac
+
+
+# Set the variable PLATFORM to one of the following:
+# - linux
+# - macosx
+
+if [ -z "${PLATFORM:-}" ]; then
+ PLATFORM=$TRAVIS_OS_NAME;
+fi
+
+if [ "$PLATFORM" == "osx" ]; then
+ PLATFORM="macosx";
+fi
+
+# Allow running not on travis
+if [ -z "$PLATFORM" ]; then
+ if [ "$(uname)" == "Linux" ]; then
+ PLATFORM="linux";
+ else
+ PLATFORM="macosx";
+ fi;
+fi
+
+
+mkdir $HOME/.lua
+
+if [ -e $LUA_HOME_DIR ]
+then
+ echo ">> Using cached version of $LUA_HOME_DIR and luarocks"
+ echo "Content:"
+ find $LUA_HOME_DIR -print
+ find $LUAROCK_HOME_DIR -print
+
+ # remove links to other version of lua and luarocks
+ rm -f $HOME/.lua/lua
+ rm -f $HOME/.lua/luajit
+ rm -f $HOME/.lua/luac
+ rm -f $HOME/.lua/luarocks
+
+ # recreating the links
+ if [ "$LUAJIT" == "yes" ]; then
+ ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/luajit
+ ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/lua
+ else
+ ln -s $LUA_HOME_DIR/bin/lua $HOME/.lua/lua
+ ln -s $LUA_HOME_DIR/bin/luac $HOME/.lua/luac
+ fi
+ ln -s $LUAROCK_HOME_DIR/bin/luarocks $HOME/.lua/luarocks
+
+ # installation is ok ?
+ lua -v
+ luarocks --version
+
+else # -e $LUA_HOME_DIR
+
+ echo ">> Compiling lua into $LUA_HOME_DIR"
+
+ mkdir -p "$LUA_HOME_DIR"
+
+ echo ">> Downloading $LUA from $LUA_SOURCE_URL"
+ curl $LUA_SOURCE_URL | tar xz
+ cd $LUA_BUILD_DIR
+
+
+ if [ "$LUAJIT" == "yes" ]; then
+
+ if [ "$LUA" == "luajit2.1" ]; then
+ # force the INSTALL_TNAME to be luajit
+ perl -i -pe 's/INSTALL_TNAME=.+/INSTALL_TNAME= luajit/' Makefile
+ fi
+
+ echo ">> Compiling LuaJIT"
+ make && make install PREFIX="$LUA_HOME_DIR"
+
+ ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/luajit
+ ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/lua
+
+ else # $LUAJIT == "yes"
+
+ # adjust numerical precision if requested with LUANUMBER=float
+ if [ "$LUANUMBER" == "float" ]; then
+ if [ "$LUA" == "lua5.3" -o "$LUA" == "lua5.4" ]; then
+ # for Lua 5.3 we can simply adjust the default float type
+ perl -i -pe "s/#define LUA_FLOAT_TYPE\tLUA_FLOAT_DOUBLE/#define LUA_FLOAT_TYPE\tLUA_FLOAT_FLOAT/" src/luaconf.h
+ else
+ # modify the basic LUA_NUMBER type
+ perl -i -pe 's/#define LUA_NUMBER_DOUBLE/#define LUA_NUMBER_FLOAT/' src/luaconf.h
+ perl -i -pe "s/LUA_NUMBER\tdouble/LUA_NUMBER\tfloat/" src/luaconf.h
+ #perl -i -pe "s/LUAI_UACNUMBER\tdouble/LUAI_UACNUMBER\tfloat/" src/luaconf.h
+ # adjust LUA_NUMBER_SCAN (input format)
+ perl -i -pe 's/"%lf"/"%f"/' src/luaconf.h
+ # adjust LUA_NUMBER_FMT (output format)
+ perl -i -pe 's/"%\.14g"/"%\.7g"/' src/luaconf.h
+ # adjust lua_str2number conversion
+ perl -i -pe 's/strtod\(/strtof\(/' src/luaconf.h
+ # this one is specific to the l_mathop(x) macro of Lua 5.2
+ perl -i -pe 's/\t\t\(x\)/\t\t\(x##f\)/' src/luaconf.h
+ fi
+ fi
+
+ # Build Lua without backwards compatibility for testing
+ perl -i -pe 's/-DLUA_COMPAT_(ALL|5_2)//' src/Makefile
+
+ echo ">> Compiling $LUA"
+ make $PLATFORM
+ make INSTALL_TOP="$LUA_HOME_DIR" install
+
+ ln -s $LUA_HOME_DIR/bin/lua $HOME/.lua/lua
+ ln -s $LUA_HOME_DIR/bin/luac $HOME/.lua/luac
+
+ fi # $LUAJIT == "yes"
+
+ # cleanup LUA build dir
+ rm -rf $LUA_BUILD_DIR
+
+ # lua is OK ?
+ echo ">> lua -v"
+ lua -v
+
+ echo ">> Downloading luarocks"
+ curl --location $LUAROCKS_URL | tar xz
+
+ cd luarocks-$LUAROCKS_VERSION
+
+ echo ">> Compiling luarocks"
+ ./configure $LUAROCKS_CONFIGURE_ARGS $LUAROCKS_CONFIGURE_ARGS2 --prefix="$LUAROCK_HOME_DIR";
+
+ make build && make install
+
+ # cleanup luarocks
+ rm -rf luarocks-$LUAROCKS_VERSION
+
+ ln -s $LUAROCK_HOME_DIR/bin/luarocks $HOME/.lua/luarocks
+ echo ">> luarocks --version"
+ luarocks --version
+ echo ">> luarocks install luacheck"
+ luarocks install luacheck
+ echo ">> luarocks install luacov"
+ luarocks install luacov
+ echo ">> luarocks install luacov-coversall"
+ luarocks install luacov-coveralls
+
+fi # -e $LUA_HOME_DIR
+
+echo "Setting lua path to luarock user tree "
+eval $(luarocks path --bin)
+
+lua -l luacov -v
+
+cd $TRAVIS_BUILD_DIR
+
+# To make travis happy, we must no fail on unassigned variables so reset this option to its default value
+set +u
+
diff --git a/Data/Libraries/luaunit/LICENSE.txt b/Data/Libraries/luaunit/LICENSE.txt
new file mode 100644
index 0000000..6f414b1
--- /dev/null
+++ b/Data/Libraries/luaunit/LICENSE.txt
@@ -0,0 +1,12 @@
+This software is distributed under the BSD License.
+
+Copyright (c) 2005-2018, Philippe Fremy <phil at freehackers dot org>
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Data/Libraries/luaunit/README.md b/Data/Libraries/luaunit/README.md
new file mode 100644
index 0000000..9786ba3
--- /dev/null
+++ b/Data/Libraries/luaunit/README.md
@@ -0,0 +1,267 @@
+[![Build status](https://ci.appveyor.com/api/projects/status/us6uh4e5q597jj54?svg=true&passingText=Windows%20Build%20passing&failingText=Windows%20Build%20failed)](https://ci.appveyor.com/project/bluebird75/luaunit)
+[![Build Status](https://travis-ci.org/bluebird75/luaunit.svg?branch=master)](https://travis-ci.org/bluebird75/luaunit)
+[![Documentation Status](https://readthedocs.org/projects/luaunit/badge/?version=latest)](https://readthedocs.org/projects/luaunit/?badge=latest)
+[![Coverage Status](https://coveralls.io/repos/github/bluebird75/luaunit/badge.svg?branch=master)](https://coveralls.io/github/bluebird75/luaunit?branch=master)
+[![Downloads](https://img.shields.io/badge/downloads-235k-brightgreen.svg)](https://luarocks.org/modules/bluebird75/luaunit)
+[![License](http://img.shields.io/badge/License-BSD-green.svg)](LICENSE.txt)
+[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/2756/badge)](https://bestpractices.coreinfrastructure.org/projects/2756)
+
+## LuaUnit
+by Philippe Fremy
+
+LuaUnit is a popular unit-testing framework for Lua, with an interface typical
+of xUnit libraries (Python unittest, Junit, NUnit, ...). It supports
+several output formats (Text, TAP, JUnit, ...) to be used directly or work with Continuous Integration platforms
+(Jenkins, Hudson, ...).
+
+LuaUnit may be installed as a [rock](https://luarocks.org/modules/bluebird75/luaunit) or directly added to your project.
+For simplicity, LuaUnit is contained into a single-file and has no external dependency.
+
+Tutorial and reference documentation is available on
+[read-the-docs](http://luaunit.readthedocs.org/en/latest/)
+
+LuaUnit may also be used as an assertion library, to validate assertions inside a running program. In addition, it provides
+a pretty stringifier which converts any type into a nicely formatted string (including complex nested or recursive tables).
+
+## More details
+
+LuaUnit provides a wide range of assertions and goes into great efforts to provide the most useful output. For example
+since version 3.3 , comparing lists will provide a detailed difference analysis:
+
+ -- lua test code. Can you spot the difference ?
+ function TestListCompare:test1()
+ local A = { 121221, 122211, 121221, 122211, 121221, 122212, 121212, 122112, 122121, 121212, 122121 }
+ local B = { 121221, 122211, 121221, 122211, 121221, 122212, 121212, 122112, 121221, 121212, 122121 }
+ lu.assertEquals( A, B )
+ end
+
+ $ lua test_some_lists_comparison.lua
+
+ TestListCompare.test1 ... FAIL
+ test/some_lists_comparisons.lua:22: expected:
+
+ List difference analysis:
+ * lists A (actual) and B (expected) have the same size
+ * lists A and B start differing at index 9
+ * lists A and B are equal again from index 10
+ * Common parts:
+ = A[1], B[1]: 121221
+ = A[2], B[2]: 122211
+ = A[3], B[3]: 121221
+ = A[4], B[4]: 122211
+ = A[5], B[5]: 121221
+ = A[6], B[6]: 122212
+ = A[7], B[7]: 121212
+ = A[8], B[8]: 122112
+ * Differing parts:
+ - A[9]: 122121
+ + B[9]: 121221
+ * Common parts at the end of the lists
+ = A[10], B[10]: 121212
+ = A[11], B[11]: 122121
+
+
+The command-line options provide a flexible interface to select tests by name or patterns, control output
+format, set verbosity and more. See [the documentation](http://luaunit.readthedocs.io/en/latest/#command-line-options) .
+
+LuaUnit also provides some dedicated support to scientific computing. See [the documentation](http://luaunit.readthedocs.io/en/latest/#scientific-computing-and-luaunit) .
+
+LuaUnit is very well tested: code coverage is 99.5% . The test suite is run on every version of Lua (Lua 5.1 to 5.4, LuaJIT 2.0 and 2.1 beta)
+and on many OS (Windows Seven, Windows Server 2012, MacOs X and Ubuntu). You can check the continuous build results on [Travis-CI](https://travis-ci.org/bluebird75/luaunit) and [AppVeyor](https://ci.appveyor.com/project/bluebird75/luaunit).
+
+LuaUnit is maintained on GitHub: https://github.com/bluebird75/luaunit . We gladly accept feature requests and even better Pull Requests.
+For more information on LuaUnit development, please check: [Developing LuaUnit](http://luaunit.readthedocs.org/en/latest/#developing-luaunit) .
+
+LuaUnit is released under the BSD license.
+
+The main developer can be reached at *phil.fremy at free.fr* . If you have security issue to report requiring confidentiality, this is the address to use.
+
+## LuaUnit successes
+
+Version 3.2 of LuaUnit has been downloaded more than 235 000 times on [LuaRocks](https://luarocks.org/modules/bluebird75/luaunit)
+
+LuaUnit is used in some very nice technological products. I like to mention:
+
+* [SchedMD/Slurm](https://www.schedmd.com/): Slurm is an open-source cluster resource management and job scheduling
+system that strives to be simple, scalable, portable, fault-tolerant, and interconnect agnostic. On the June 2017 Top 500 computer
+list, Slurm was performing workload management on six of the ten most powerful computers in the world including the number 1 system,
+Sunway TaihuLight with 10,649,600 computing cores. LuaUnit is used by Slurm to validate plugins written in Lua. Thanks Douglas Jacobsen
+to contribute back to LuaUnit. See the [GitHub repository of Slurm](https://github.com/SchedMD/slurm) .
+
+* [MAD by the CERN](http://mad.web.cern.ch/mad/): CERN is the European Organization for Nuclear Research, where physicists and engineers are
+probing the fundamental structure of the universe. MAD is one of the CERN project: MAD aims to be at the forefront of computational physics in
+the field of particle accelerator design and simulation. Its scripting language is de facto the standard to describe particle accelerators, simulate
+beam dynamics and optimize beam optics at CERN. Lua is the main language of MAD-ng, the new generatino of MAD. A fork of LuaUnit is used extensively
+for all MAD calculation and framework validation. Thanks Laurent Deniau for contributing back to LuaUnit. See the [GitHub repository of MAD](https://github.com/MethodicalAcceleratorDesign/MAD) .
+
+## Contributors
+* [NiteHawk](https://github.com/n1tehawk)
+* [AbigailBuccaneer](https://github.com/AbigailBuccaneer)
+* [Juan Julián Merelo Guervós](https://github.com/JJ)
+* [Naoyuki Totani](https://github.com/ntotani)
+* [Jennal](https://github.com/Jennal)
+* [George Zhao](https://github.com/zhaozg)
+* kbuschelman
+* [Victor Seva](https://github.com/linuxmaniac)
+* [Urs Breu](https://github.com/ubreu)
+* Jim Anderson
+* [Douglas Jacobsen](https://github.com/dmjacobsen)
+* [Mayama Takeshi](https://github.com/MayamaTakeshi)
+
+
+## Installation
+
+**LuaRocks**
+
+LuaUnit is available on [LuaRocks](https://luarocks.org/modules/bluebird75/luaunit). To install it, you need at least
+LuaRocks version 2.4.4 (due to old versions of wget being incompatible with GitHub https downloading)
+
+**GitHub**
+
+The simplest way to install LuaUnit is to fetch the GitHub version:
+
+ git clone git@github.com:bluebird75/luaunit.git
+
+Then copy the file luaunit.lua into your project or the Lua libs directory.
+
+The version of the main branch on GitHub is always stable and can be used safely.
+
+### History
+
+#### Version 3.4 - 02 March 2021
+* support for Lua 5.4
+* assertAlmostEquals() works also on tables and nested structures
+* choose test output style with environment variable LUAUNIT_OUTPUT
+* setOutputType() accepts the xml filename as second argument when using the format junit
+* improve printing of table information in case of cycles
+* add ability to skip tests with `skip()` and `skipIf()`
+* detect attempts to exit the test suite before it is finished running
+* add assertErrorMsgContentEquals() to validate exactly any error message
+* filter out some stack entries when printing assertions (useful when embedding LuaUnit inside another test layer) with `STRIP_EXTRA_ENTRIES_IN_STACK_TRACE`
+* add `assertTableContains()` and `assertNotTableContains()` to verify the presence of a given value within a table
+* remove option TABLE_EQUALS_KEYBYCONTENT, it did not make sense
+* bugfix:
+ * assertIs()/assertNotIs() deals better with protected metatables
+ * assertEquals() deals better with tables containing cycles of different structure
+ * fix table length comparison for table returning inconsistent length
+
+
+#### Version 3.3 - 6. March 2018
+* General
+ * when comparing lists with assertEquals(), failure message provides an advanced comparison of the lists
+ * assertErrorMsgEquals() can check for error raised as tables
+ * tests may be finished early with fail(), failIf(), success() or successIf()
+ * improve printing of recursive tables
+ * improvements and fixes to JUnit and TAP output
+ * stricter assertTrue() and assertFalse(): they only succeed with boolean values
+ * add assertEvalToTrue() and assertEvalToFalse() with previous assertTrue()/assertFalse() behavior of coercing to boolean before asserting
+ ** all assertion functions accept an optional extra message, to be printed along the failure
+* New command-line arguments:
+ * can now shuffle tests with --shuffle or -s
+ * possibility to repeat tests (for example to trigger a JIT), with --repeat NUM or -r NUM
+ * more flexible test selection with inclusion (--pattern / -p) or exclusion (--exclude / -x) or combination of both
+* Scientific computing dedicated support (see documentation):
+ * provide the machine epsilon in lu.EPS
+ * new functions: assertNan(), assertInf(), assertPlusInf(), assertMinusInf(), assertPlusZero(), assertMinusZero()
+ * in assertAlmostEquals( a, b, margin ), margin no longer provides a default value of 1E-11, the machine epsilon is used instead
+* Platform and continuous integration support:
+ * validate LuaUnit on MacOs platform (thank to Travis CI)
+ * validate LuaUnit with 32 bits numbers (floats) and 64 bits numbers (double)
+ * add test coverage measurements thank to coveralls.io . Status: 99.76% of the code is verified.
+ * use cache for AppVeyor and Travis builds
+ * support for luarocks doc command
+* General doc improvements (detailed description of all output, more cross-linking between sections)
+
+
+#### Version 3.2 - 12. Jul 2016
+* distinguish between failures (failed assertion) and errors
+* add command-line option to stop on first error or failure
+* support for new versions: Lua 5.3 and LuaJIT (2.0, 2.1 beta)
+* validation of all lua versions on Travis CI and AppVeyor
+* added compatibility layer with forked luaunit v2.x
+* added documentation about development process
+* improved support for table containing keys of type table
+* small bug fixes, several internal improvements
+
+
+#### Version 3.1 - 10 Mar. 2015
+* luaunit no longer pollutes global namespace, unless defining EXPORT_ASSERT_TO_GLOBALS to true
+* fixes and validation of JUnit XML generation
+* strip luaunit internal information from stacktrace
+* general improvements of test results with duration and other details
+* improve printing for tables, with an option to always print table id
+* fix printing of recursive tables
+
+**Important note when upgrading to version 3.1** : assertions functions are
+no longer exported directly to the global namespace. See documentation for upgrade
+paths.
+
+
+#### Version 3.0 - 9. Oct 2014
+
+Since some people have forked LuaUnit and release some 2.x version, I am
+jumping the version number to 3.
+
+- moved to Github
+- full documentation available in text, html and pdf at read-the-docs.org
+- new output format: JUnit
+- much better table assertions
+- new assertions for strings, with patterns and case insensitivity: assertStrContains,
+ assertNotStrContains, assertNotStrIContains, assertStrIContains, assertStrMatches
+- new assertions for floats: assertAlmostEquals, assertNotAlmostEquals
+- type assertions: assertIsString, assertIsNumber, ...
+- error assertions: assertErrorMsgEquals, assertErrorMsgContains, assertErrorMsgMatches
+- improved error messages for several assertions
+- command-line options to select test, control output type and verbosity
+
+
+#### Version 2.0
+Unofficial fork from version 1.3 by rjbcomupting
+- lua 5.2 module style, without global namespace pollution
+- setUp() may be named Setup() or setup()
+- tearDown() may be named Teardown() or teardown()
+- wrapFunction() may be called WrapFunctions() or wrap_functions()
+- run() may also be called Run()
+- table deep comparision (also available in 1.4)
+- control verbosity with setVerbosity() SetVerbosity() and set_verbosity()
+- More assertions:
+ - is<Type>, is_<type>, assert<Type> and assert_<type> (e.g. assert( LuaUnit.isString( getString() ) )
+ - assertNot<Type> and assert_not_<type>
+
+
+#### Version 1.5 - 8. Nov 2012
+- compatibility with Lua 5.1 and 5.2
+- better object model internally
+- a lot more of internal tests
+- several internal bug fixes
+- make it easy to customize the test output
+- running test functions no longer requires a wrapper
+- several level of verbosity
+
+
+#### Version 1.4 - 26. Jul 2012
+- table deep comparison
+- switch from X11 to more popular BSD license
+- add TAP output format for integration into Jenkins
+- official repository now on GitHub
+
+
+#### Version 1.3 - 30. Oct 2007
+- port to lua 5.1
+- iterate over the test classes, methods and functions in the alphabetical order
+- change the default order of expected, actual in assertEquals (adjustable with USE_EXPECTED_ACTUAL_IN_ASSERT_EQUALS).
+
+
+#### Version 1.2 - 13. Jun 2005
+- first public release
+
+
+#### Version 1.1
+- move global variables to internal variables
+- assertion order is configurable between expected/actual or actual/expected
+- new assertion to check that a function call returns an error
+- display the calling stack when an error is spotted
+- two verbosity level, like in python unittest
+
+![stats](https://stats.sylphide-consulting.com/piwik/piwik.php?idsite=37&rec=1)
+
diff --git a/Data/Libraries/luaunit/TODO.txt b/Data/Libraries/luaunit/TODO.txt
new file mode 100644
index 0000000..1b29df8
--- /dev/null
+++ b/Data/Libraries/luaunit/TODO.txt
@@ -0,0 +1,223 @@
+# make all instead of make platform, this would allow to remove platform.sh
+# also avoid setnv_lua.sh if possible
+
+# ensure luarocks package are installed inside insall location
+/home/travis/build/bluebird75/luaunit/install/luarocks/share/lua/5.1/luarocks"
+/home/travis/build/bluebird75/luaunit/install/luarocks/share/lua/5.1/luarocks"
+
+
+TODO Future:
+============
+- run a full modules with a function
+- build lua with ASAN, memory sanitizer and so on on travis before running it
+- ensure that assert string functions like assertStr, strcontains, etc reject incorrect type with a correct error message
+- pretty function formatting: https://github.com/luarocks/luarocks/blob/master/src/luarocks/core/util.lua
+- platform detection:
+- document prettystr
+- validate output with ignored tests (0 failures or some failures)
+- parametrize tests
+- coloured output
+- better error messages for string differences (diffing)
+- print local variables upon assertion error:
+ + debug.get_local( ) will get the local variables in the current context
+ + debug.get_upvalue( ) will get the upvalues in the current context
+- see inspect for better table printing: https://github.com/kikito/inspect.lua
+ + print list part separate from the dict part in a table
+ + print metatables in tables
+- see StackTracePlus for printing more stack information: https://github.com/ignacio/StackTracePlus
+- how does busted deal with nested tables ? functions ?
+- look at serpent to see how to improve nested table printing
+- function should be printed as <function>
+- print table of test test_filterWithPattern and see how to improve readability
+- shuffle should shuffle separately classes and then class methods
+- add assertTableContains and assertTableNotContains to check the presence / absence of value in an array
+- look at serpent to see how to improve nested table printing
+- doc about usage of prettystr & assertion library
+- assertListContainsElements
+- assertListContainsElements
+- checkXXX for every assertXXX
+
+- review and enhance: TestLuaUnitExecution:test_withTableErrorInside
+
+
+Version 3.5 (future):
+============
+
+Planned:
+--------
+- global setup / teardown
+- class setup / teardown
+- report test duration everywhere
+- add date and duration to tap output
+- XML: report system information
+- align the "OK" vertically for text output
+- better detection of screen size
+- move all file:line description to stack trace
+- better deal with one line formatting
+- table_contains():
+ + check with finding table or nested tables
+ + add check for error messages
+- correctly compare tables with same content but different metatable
+
+Already done:
+-------------
+-
+
+Version 3.4:
+============
+TODO:
+- assertAlmostNotEquals shall support tables
+- document the release process to luarocks and update dev manual
+- add test for the runner interface of luaunit
+- update examples
+- dev guide: explain doit.py
+- dev guide: explain CI
+
+Done
+- add a list of environment variables controlling LuaUnit
+- double-check documentation generation
+- move enabling global namespace pollution explanation to a later chapter
+- update doc about TABLE_EQUALS_KEYBYCONTENT
+- update doc about test skipping
+- update documentation about how to run list of test classes
+- update documentation about setOutputType()
+- assertAlmostEquals can check lists and more complex structures
+- can choose test output type through environment variables LUAUNIT_OUTPUT
+- setOutputType() also accepts the xml filename when using the format junit
+- simplify printing of table-info in cycles
+- allow to skip tests
+- fix a bug where assertIs/assertNotIs would not deal with protected metatables
+- fix a bug in dealing with table including cycles of different structure
+- remove option TABLE_EQUALS_KEYBYCONTENT, it did not make sense
+
+
+Version 3.3:
+============
+- make sure that example source code is included in documentation when packaging
+- add annex to documentation with full source code of example
+- add annex with BSD license
+- verify that assertError functions all work with tables, review implementation in detail
+- useRe -> usePattern
+- add success() to terminate test successfully
+- doc: explain that prettystr() is used in assertions
+- check rock installation of luaunit
+- add custom message support
+- build luarocks
+- update contributors
+- update download badge
+- doc about prettystr
+- add fail() to force test failure
+- use caching on travis-ci
+- assertAlmostEqual no longer includes a default margin, margin must always be explicitly specified.
+- verify that lu.EPS by calculation
+- fix include/exclude bug (see https://github.com/bluebird75/luaunit/pull/82 )
+- doc about scientific computing dedicated functions
+- assertions for nan and inf and +/- zero
+- fixes for junit and tap output
+- doc improvements
+- better error messages for list assertions:
+ + expected length of X, got Y
+ + index differing in table 1 and 2
+- more doc about assertTrue/False/... with a table
+- randomized testing
+- can run a tests numerous times (useful for triggering the JIT effect)
+- can include and exclude tests from the test list
+
+Done since 3.1:
+===============
+x provide a luarock package. See: https://rocks.moonscript.org/modules/rjpcomputing/luaunit
+x make a difference between errors and failures
+x lua 5.3
+x travis lua 5.3
+x compatibility with LuaUnit v2.0 of rjbcomputing
+x provide a legacy wrapFunction()
+
+Done since 3.0:
+===============
+x check documentation link glitch to TAP
+x doc: report how to handle global space pollution/restriction
+x doc: adapt all examples to new way of requireing luaunit
+x less global space pollution
+x doc: move description of table printing to an annex
+x validate well-formed XML with a DTD
+x validate test output (TAP, ...) with functional tests
+x test failures, verify that output is correct
+x improve testresult: contain the list of tests, with status of each test
+x strip luaunit stack more intelligently: exclude content of luaunit
+x mention mailing-list in README.md
+x mention version in documentation
+x mention mailing-list
+x mention the new global variable config for displaying table content
+x fix display of tables with recursive references
+x improve display of nested tables in error messages
+x improve display of multiline strings in error messages
+
+x Junit XML Ouptut:
+ x test and fix xml escaping
+ x validate xml with apache and jenkins schemas
+ + xml format:
+ - add proper xml formatting header
+ - report number of failures within <testsuite> element
+ - report duration
+ - add properties describe the environment
+
+Done:
+============
+x add email to report vulnerabilities in private
+x add other types of output
+x assert with matching of the error message
+x finish user documentation
+x switch version 3.0
+x add assertMatch for strings
+x document --name
+x improve junit xml output (one file, choice of filename)
+x display number of non selected tests
+x assertIs with all types
+x mention one file distribution
+x improve TAP output: pre-calculate test numbers, display test summary as comment
+x test error messages of assertStrMatches and all error functions
+x assertNil + assertNotNil
+x readthedocs integration
+x add travis-ci badges to README
+x filter by pattern
+x support --version
+x support --help
+x replace methodInstance with real test name in reports
+x better error messages for wrong command line option, or wrong output type
+x control verbosity and output type with command line
+x display time to run all tests
+x move all assertions together
+x better error display of assertIsXXX functions
+x add assertContains for strings
+x add assertIsNumber, assertIsXXX
+x table assertions
+x sequence asserts
+x compatibilty tests with several version of lua
+x add assertNotEquals
+
+Release TODO:
+=============
+- all tests green in Travis and AppVeyor
+- doc is green in read-the-docs
+- documentation is updated with release content
+- doit.py runtests success
+- tag set on the code
+- upload release to GitHub
+- prepare luarocks and upload to luarocks
+- verify smooth installation of luarocks
+- annonce release on lua mailing-list
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Data/Libraries/luaunit/appveyor.yml b/Data/Libraries/luaunit/appveyor.yml
new file mode 100644
index 0000000..1f932d4
--- /dev/null
+++ b/Data/Libraries/luaunit/appveyor.yml
@@ -0,0 +1,42 @@
+image: Visual Studio 2015
+shallow_clone: true
+
+# create a build matrix to use various Lua and LuaJIT versions
+environment:
+ matrix:
+ - LUAENV: luajit20
+ - LUAENV: luajit21
+ - LUAENV: lua51
+ - LUAENV: lua51_64
+ - LUAENV: lua52
+ - LUAENV: lua52_64
+ - LUAENV: lua53
+ - LUAENV: lua53_64
+ - LUAENV: lua54
+ - LUAENV: lua54_64
+
+
+# install required binaries via batch file (also sets %LUA% path)
+install:
+- cmd: .appveyor\install-lua.cmd
+
+cache:
+ # each directory resulting from the previous download/build is cached
+ - lua51 -> .appveyor\install-lua.cmd
+ - lua51-64 -> .appveyor\install-lua.cmd
+ - lua52 -> .appveyor\install-lua.cmd
+ - lua52-64 -> .appveyor\install-lua.cmd
+ - lua53 -> .appveyor\install-lua.cmd
+ - lua53-64 -> .appveyor\install-lua.cmd
+ - lua54 -> .appveyor\install-lua.cmd
+ - lua54-64 -> .appveyor\install-lua.cmd
+ - luajit20 -> .appveyor\install-lua.cmd
+ - luajit21 -> .appveyor\install-lua.cmd
+
+build: off
+
+test_script:
+- cmd: >-
+ %LUA% -v run_unit_tests.lua --shuffle
+
+ %LUA% run_functional_tests.lua
diff --git a/Data/Libraries/luaunit/doc/Makefile b/Data/Libraries/luaunit/doc/Makefile
new file mode 100644
index 0000000..d4baefa
--- /dev/null
+++ b/Data/Libraries/luaunit/doc/Makefile
@@ -0,0 +1,177 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " xml to make Docutils-native XML files"
+ @echo " pseudoxml to make pseudoxml-XML files for display purposes"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/LuaUnit.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/LuaUnit.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/LuaUnit"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/LuaUnit"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+latexpdfja:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through platex and dvipdfmx..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
+
+xml:
+ $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+ @echo
+ @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+pseudoxml:
+ $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+ @echo
+ @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/Data/Libraries/luaunit/doc/conf.py b/Data/Libraries/luaunit/doc/conf.py
new file mode 100644
index 0000000..ef20a8f
--- /dev/null
+++ b/Data/Libraries/luaunit/doc/conf.py
@@ -0,0 +1,259 @@
+# -*- coding: utf-8 -*-
+#
+# LuaUnit documentation build configuration file, created by
+# sphinx-quickstart on Thu Aug 21 21:45:55 2014.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys
+import os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'LuaUnit'
+copyright = u'2016, Philippe Fremy'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '3.3'
+# The full version, including alpha/beta/rc tags.
+release = '3.3'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = []
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'LuaUnitdoc'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ ('index', 'LuaUnit.tex', u'LuaUnit Documentation',
+ u'Philippe Fremy', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'luaunit', u'LuaUnit Documentation',
+ [u'Philippe Fremy'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'LuaUnit', u'LuaUnit Documentation',
+ u'Philippe Fremy', 'LuaUnit', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
+
diff --git a/Data/Libraries/luaunit/doc/index.rst b/Data/Libraries/luaunit/doc/index.rst
new file mode 100644
index 0000000..a475984
--- /dev/null
+++ b/Data/Libraries/luaunit/doc/index.rst
@@ -0,0 +1,2644 @@
+.. LuaUnit documentation master file, created by
+
+ sphinx-quickstart on Thu Aug 21 21:45:55 2014.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+
+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+Welcome to LuaUnit's documentation!
+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+
+Introduction
+************
+
+LuaUnit is a popular unit-testing framework for Lua, with an interface typical
+of xUnit libraries (Python unittest, Junit, NUnit, ...). It supports
+several output formats (Text, TAP, JUnit, ...) to be used directly or work with Continuous Integration platforms
+(Jenkins, Hudson, ...).
+
+For simplicity, LuaUnit is contained into a single-file and has no external dependency. To start using it,
+just add the file *luaunit.lua* to your project. A `LuaRocks package`_ is also available.
+
+.. _LuaRocks package: https://luarocks.org/modules/bluebird75/luaunit
+
+Tutorial and reference documentation is available on `Read-the-docs`_ .
+
+.. _Read-the-docs: http://luaunit.readthedocs.org/en/latest/
+
+LuaUnit also provides some dedicated support to scientific computing. See the section `Scientific computing and LuaUnit`_
+
+LuaUnit may also be used as an assertion library. In that case, you will call the assertion functions, which generate errors
+when the assertion fails. The error includes a detailed analysis of the failed assertion, like when executing a test suite.
+
+LuaUnit provides another generic usage function: :func:`prettystr` which converts any value to a nicely
+formatted string. It supports in particular tables, nested table and even recursive tables.
+
+
+More details
+************
+
+LuaUnit provides a wide range of assertions and goes into great efforts to provide the most useful output. For example
+since version 3.3 , comparing lists will provide a detailed difference analysis:
+
+.. code-block::
+
+ -- lua test code. Can you spot the difference ?
+ function TestListCompare:test1()
+ local A = { 121221, 122211, 121221, 122211, 121221, 122212, 121212, 122112, 122121, 121212, 122121 }
+ local B = { 121221, 122211, 121221, 122211, 121221, 122212, 121212, 122112, 121221, 121212, 122121 }
+ lu.assertEquals( A, B )
+ end
+
+ $ lua test_some_lists_comparison.lua
+
+ TestListCompare.test1 ... FAIL
+ test/some_lists_comparisons.lua:22: expected:
+
+ List difference analysis:
+ * lists A (actual) and B (expected) have the same size
+ * lists A and B start differing at index 9
+ * lists A and B are equal again from index 10
+ * Common parts:
+ = A[1], B[1]: 121221
+ = A[2], B[2]: 122211
+ = A[3], B[3]: 121221
+ = A[4], B[4]: 122211
+ = A[5], B[5]: 121221
+ = A[6], B[6]: 122212
+ = A[7], B[7]: 121212
+ = A[8], B[8]: 122112
+ * Differing parts:
+ - A[9]: 122121
+ + B[9]: 121221
+ * Common parts at the end of the lists
+ = A[10], B[10]: 121212
+ = A[11], B[11]: 122121
+
+
+The command-line options provide a flexible interface to select tests by name or patterns, control output
+format, set verbosity and more. See `Using the command-line`_ .
+
+LuaUnit is very well tested: code coverage is 99.5% . The test suite is run on every version of Lua (Lua 5.1 to 5.3, LuaJIT 2.0 and 2.1 beta)
+and on many OS (Windows Seven, Windows Server 2012, MacOs X and Ubuntu). You can check the continuous build results on `Travis-CI`_ and `AppVeyor`_ .
+
+.. _Travis-CI: https://travis-ci.org/bluebird75/luaunit
+.. _AppVeyor: https://ci.appveyor.com/project/bluebird75/luaunit/history
+
+LuaUnit is maintained on GitHub: https://github.com/bluebird75/luaunit . We gladly accept feature requests and even better Pull Requests.
+
+LuaUnit is released under the BSD license.
+
+
+Installation
+============
+
+LuaUnit is packed into a single-file. To make start using it, just add the file to your project.
+
+Several installation methods are available.
+
+LuaRocks
+--------
+
+LuaUnit is available as a `LuaRocks package`_ .
+
+.. _LuaRocks package: https://luarocks.org/modules/bluebird75/luaunit
+
+GitHub
+------
+
+The simplest way to install LuaUnit is to fetch the GitHub version:
+
+.. code-block:: bash
+
+ git clone git@github.com:bluebird75/luaunit.git
+
+Then copy the file luaunit.lua into your project or the Lua libs directory.
+
+The version in development on GitHub is always stable and can be used safely.
+
+On Linux, you can also install it into your Lua directories
+
+.. code-block:: bash
+
+ sudo python doit.py install
+
+If that fail, edit the function *install()* in the file *doit.py* to adjust
+the Lua version and installation directory. It uses, by default, Linux paths that depend on the version.
+
+
+Upgrade note
+================
+
+**Important note when upgrading from version below 3.1** : there is a break of backward compatibility in version 3.1, assertions functions are no longer exported directly to the global namespace. See :ref:`luaunit-global-asserts` on how to adjust or restore previous behavior.
+
+
+LuaUnit development
+===================
+
+See `Developing luaunit`_
+
+Version and Changelog
+=====================
+This documentation describes the functionality of LuaUnit v3.2 .
+
+New in version 3.4 - 02 March 2021
+----------------------------------
+* support for Lua 5.4
+* :func:`assertAlmostEquals` works also on tables and nested structures
+* choose test output style with environment variable `LUAUNIT_OUTPUT`
+* :func:`runner:setOutputType()` accepts the xml filename as second argument when using the format *junit*
+* improve printing of table information in case of cycles
+* add ability to skip tests with :func:`skip` and :func:`skipIf`
+* detect attempts to exit the test suite before it is finished running
+* add :func:`assertErrorMsgContentEquals` to validate exactly any error message
+* filter out some stack entries when printing assertions (useful when embedding LuaUnit inside another test layer) with :ref:`strip_extra_entries_in_stack_trace`
+* add :func:`assertTableContains` and :func:`assertNotTableContains` to verify the presence of a given value within a table
+* remove option `TABLE_EQUALS_KEYBYCONTENT`, it did not make sense
+* bugfix:
+ * :func:`assertIs`/:func:`assertNotIs` deals better with protected metatables
+ * :func:`assertEquals` deals better with tables containing cycles of different structure
+ * fix table length comparison for table returning inconsistent length
+
+
+New in version 3.3 - 6. Mar 2018
+--------------------------------
+* General
+ * when comparing lists with :func:`assertEquals`, failure message provides an advanced comparison of the lists
+ * :func:`assertErrorMsgEquals` can check for error raised as tables
+ * tests may be finished early with :func:`fail`, :func:`failIf`, :func:`success` or :func:`successIf`
+ * improve printing of recursive tables
+ * improvements and fixes to JUnit and TAP output
+ * stricter :func:`assertTrue` and :func:`assertFalse`: they only succeed with boolean values
+ * add :func:`assertEvalToTrue` and :func:`assertEvalToFalse` with previous :func:`assertTrue`/:func:`assertFalse` behavior of coercing to boolean before asserting
+ * all assertion functions accept an optional extra message, to be printed along the failure
+* New command-line arguments:
+ * can now shuffle tests with ``--shuffle`` or ``-s``
+ * possibility to repeat tests (for example to trigger a JIT), with ``--repeat NUM`` or ``-r NUM``
+ * more flexible test selection with inclusion (``--pattern`` / ``-p``) or exclusion (``--exclude`` / ``-x``) or combination of both
+* Scientific computing dedicated support (see documentation):
+ * provide the machine epsilon in EPS
+ * new functions: :func:`assertNan`, :func:`assertInf`, :func:`assertPlusInf`, :func:`assertMinusInf`, :func:`assertPlusZero`, :func:`assertMinusZero` and
+ their negative version
+ * in :func:`assertAlmostEquals`, margin no longer provides a default value of 1E-11, the machine epsilon is used instead
+* Platform and continuous integration support:
+ * validate LuaUnit on MacOs platform (thank to Travis CI)
+ * validate LuaUnit with 32 bits numbers (floats) and 64 bits numbers (double)
+ * add test coverage measurements thank to coveralls.io . Status: 99.76% of the code is verified.
+ * use cache for AppVeyor and Travis builds
+ * support for ``luarocks doc`` command
+* General doc improvements (detailed description of all output, more cross-linking between sections)
+
+
+New in version 3.2 - 12. Jul 2016
+---------------------------------
+* Add command-line option to stop on first error or failure. See `Other options`_
+* Distinguish between failures (failed assertion) and errors
+* Support for new versions: Lua 5.3 and LuaJIT (2.0, 2.1 beta)
+* Validation of all lua versions on Travis CI and AppVeyor
+* Add compatibility layer with forked luaunit v2.x
+* Added documentation about development process. See `Developing luaUnit`_
+* Improved support for table containing keys of type table. See :ref:`comparing-table-keys-table`
+* Small bug fixes, several internal improvements
+* Availability of a Luarock package. See `https://luarocks.org/modules/bluebird75/luaunit` .
+
+New in version 3.1 - 10. Mar 2015
+---------------------------------
+* luaunit no longer pollutes global namespace, unless defining EXPORT_ASSERT_TO_GLOBALS to true. See :ref:`luaunit-global-asserts`
+* fixes and validation of JUnit XML generation
+* strip luaunit internal information from stacktrace
+* general improvements of test results with duration and other details
+* improve printing for tables, with an option to always print table id. See :ref:`table-printing`
+* fix printing of recursive tables
+
+**Important note when upgrading to version 3.1** : assertions functions are
+no longer exported directly to the global namespace. See :ref:`luaunit-global-asserts`
+
+New in version 3.0 - 9. Oct 2014
+--------------------------------
+
+Because LuaUnit was forked and released as some 2.x version, version number
+is now jumping to 3.0 .
+
+* full documentation available in text, html and pdf at http://luaunit.read-the-docs.org
+* new output format: JUnit, compatible with Bamboo and other CI platforms. See `Output formats`_
+* much better table assertions
+* new assertions for strings, with patterns and case insensitivity: assertStrContains,
+ assertNotStrContains, assertNotStrIContains, assertStrIContains, assertStrMatches
+* new assertions for floats: assertAlmostEquals, assertNotAlmostEquals
+* type assertions: assertIsString, assertIsNumber, ...
+* error assertions: assertErrorMsgEquals, assertErrorMsgContains, assertErrorMsgMatches
+* improved error messages for several assertions
+* command-line options to select test, control output type and verbosity
+
+
+New in version 1.5 - 8. Nov 2012
+--------------------------------
+* compatibility with Lua 5.1 and 5.2
+* better object model internally
+* a lot more of internal tests
+* several internal bug fixes
+* make it easy to customize the test output
+* running test functions no longer requires a wrapper
+* several level of verbosity
+
+
+New in version 1.4 - 26. Jul 2012
+---------------------------------
+* switch from X11 to more popular BSD license
+* add TAP output format for integration into Jenkins. See `Output formats`_
+* official repository now on GitHub
+
+
+New in version 1.3 - 30. Oct 2007
+---------------------------------
+* port to lua 5.1
+* iterate over the test classes, methods and functions in the alphabetical order
+* change the default order of expected, actual in assertEquals. See `Equality assertions`_
+
+
+Version 1.2 - 13. Jun 2005
+---------------------------------
+* first public release
+
+
+Version 1.1
+------------
+* move global variables to internal variables
+* assertion order is configurable between expected/actual or actual/expected. See `Equality assertions`_
+* new assertion to check that a function call returns an error
+* display the calling stack when an error is spotted
+* two verbosity level, like in python unittest
+
+
+Getting started with LuaUnit
+****************************
+
+This section will guide you through a step by step usage of *LuaUnit* . The full source code
+of the example below is available in the : `source_code_example`_ or in the file *my_test_suite.lua*
+in the doc directory.
+
+Setting up your test script
+===========================
+
+To get started, create your file *my_test_suite.lua* .
+
+The script should import LuaUnit::
+
+ lu = require('luaunit')
+
+The last line executes your script with LuaUnit and exit with the
+proper error code::
+
+ os.exit( lu.LuaUnit.run() )
+
+Now, run your file with::
+
+ lua my_test_suite.lua
+
+It prints something like::
+
+ Ran 0 tests in 0.000 seconds, 0 successes, 0 failures
+ OK
+
+Now, your testing framework is in place, you can start writing tests.
+
+Writing tests
+=============
+
+LuaUnit scans all variables that start with *test* or *Test*.
+If they are functions, or if they are tables that contain
+functions that start with *test* or *Test*, they are run as part of the test suite.
+
+So just write a function whose name starts with test. Inside test functions, use the assertions functions provided by LuaUnit, such
+as :func:`assertEquals`.
+
+Let's see that in practice.
+
+Suppose you want to test the following add function::
+
+ function add(v1,v2)
+ -- add positive numbers
+ -- return 0 if any of the numbers are 0
+ -- error if any of the two numbers are negative
+ if v1 < 0 or v2 < 0 then
+ error('Can only add positive or null numbers, received '..v1..' and '..v2)
+ end
+ if v1 == 0 or v2 == 0 then
+ return 0
+ end
+ return v1+v2
+ end
+
+You write the following tests::
+
+ function testAddPositive()
+ lu.assertEquals(add(1,1),2)
+ end
+
+ function testAddZero()
+ lu.assertEquals(add(1,0),0)
+ lu.assertEquals(add(0,5),0)
+ lu.assertEquals(add(0,0),0)
+ end
+
+
+:func:`assertEquals` is the most commonly used assertion function. It
+verifies that both argument are equals, in the order actual value, expected value.
+
+Rerun your test script (``-v`` is to activate a more verbose output)::
+
+ $ lua my_test_suite.lua -v
+
+It now prints::
+
+ Started on 02/19/17 22:15:53
+ TestAdd.testAddPositive ... Ok
+ TestAdd.testAddZero ... Ok
+ =========================================================
+ Ran 2 tests in 0.003 seconds, 2 successes, 0 failures
+ OK
+
+You always have:
+
+* the date at which the test suite was started
+* the group to which the function belongs (usually, the name of the function table, and *<TestFunctions>* for all direct test functions)
+* the name of the function being executed
+* a report at the end, with number of executed test, number of non selected tests if any, number of failures, number of errors (if any) and duration.
+
+The difference between failures and errors are:
+
+* luaunit assertion functions generate failures
+* any unexpected error during execution generates an error
+* failures or errors during setup() or teardown() always generate errors
+
+
+If we continue with our example, we also want to test that when the function receives negative numbers, it generates an error. Use
+:func:`assertError` or even better, :func:`assertErrorMsgContains` to also validate the content
+of the error message. There are other types or error checking functions, see `Error assertions`_ . Here
+we use :func:`assertErrorMsgContains` . First argument is the expected message, then the function to call
+and the optional arguments::
+
+ function testAddError()
+ lu.assertErrorMsgContains('Can only add positive or null numbers, received 2 and -3', add, 2, -3)
+ end
+
+Now, suppose we also have the following function to test::
+
+ function adder(v)
+ -- return a function that adds v to its argument using add
+ function closure( x ) return x+v end
+ return closure
+ end
+
+We want to test the type of the value returned by adder and its behavior. LuaUnit
+provides assertion for type testing (see `Type assertions`_ ). In this case, we use
+:func:`assertIsFunction`::
+
+ function testAdder()
+ f = adder(3)
+ lu.assertIsFunction( f )
+ lu.assertEquals( f(2), 5 )
+ end
+
+Grouping tests, setup/teardown functionality
+=====================================================
+
+When the number of tests starts to grow, you usually organise them
+into separate groups. You can do that with LuaUnit by putting them
+inside a table (whose name must start with *Test* or *test* ).
+
+For example, assume we have a second function to test::
+
+ function div(v1,v2)
+ -- divide positive numbers
+ -- return 0 if any of the numbers are 0
+ -- error if any of the two numbers are negative
+ if v1 < 0 or v2 < 0 then
+ error('Can only divide positive or null numbers, received '..v1..' and '..v2)
+ end
+ if v1 == 0 or v2 == 0 then
+ return 0
+ end
+ return v1/v2
+ end
+
+We move the tests related to the function add into their own table::
+
+ TestAdd = {}
+ function TestAdd:testAddPositive()
+ lu.assertEquals(add(1,1),2)
+ end
+
+ function TestAdd:testAddZero()
+ lu.assertEquals(add(1,0),0)
+ lu.assertEquals(add(0,5),0)
+ lu.assertEquals(add(0,0),0)
+ end
+
+ function TestAdd:testAddError()
+ lu.assertErrorMsgContains('Can only add positive or null numbers, received 2 and -3', add, 2, -3)
+ end
+
+ function TestAdd:testAdder()
+ f = adder(3)
+ lu.assertIsFunction( f )
+ lu.assertEquals( f(2), 5 )
+ end
+ -- end of table TestAdd
+
+Then we create a second set of tests for div::
+
+ TestDiv = {}
+ function TestDiv:testDivPositive()
+ lu.assertEquals(div(4,2),2)
+ end
+
+ function TestDiv:testDivZero()
+ lu.assertEquals(div(4,0),0)
+ lu.assertEquals(div(0,5),0)
+ lu.assertEquals(div(0,0),0)
+ end
+
+ function TestDiv:testDivError()
+ lu.assertErrorMsgContains('Can only divide positive or null numbers, received 2 and -3', div, 2, -3)
+ end
+ -- end of table TestDiv
+
+Execution of the test suite now looks like this::
+
+ Started on 02/19/17 22:15:53
+ TestAdd.testAddError ... Ok
+ TestAdd.testAddPositive ... Ok
+ TestAdd.testAddZero ... Ok
+ TestAdd.testAdder ... Ok
+ TestDiv.testDivError ... Ok
+ TestDiv.testDivPositive ... Ok
+ TestDiv.testDivZero ... Ok
+ =========================================================
+ Ran 7 tests in 0.006 seconds, 7 successes, 0 failures
+ OK
+
+
+When tests are defined in tables, you can optionally define two special
+functions, *setUp()* and *tearDown()*, which will be executed
+respectively before and after every test.
+
+These function may be used to create specific resources for the
+test being executed and cleanup the test environment.
+
+For a practical example, imagine that we have a *log()* function
+that writes strings to a log file on disk. The file is created
+upon first usage of the function, and the filename is defined
+by calling the function *initLog()*.
+
+The tests for these functions would take advantage of the *setup/teardown*
+functionality to prepare a log filename shared
+by all tests, make sure that all tests start with a non existing
+log file name, and delete the log filename after every test::
+
+ TestLogger = {}
+ function TestLogger:setUp()
+ -- define the fname to use for logging
+ self.fname = 'mytmplog.log'
+ -- make sure the file does not already exists
+ os.remove(self.fname)
+ end
+
+ function TestLogger:testLoggerCreatesFile()
+ initLog(self.fname)
+ log('toto')
+ -- make sure that our log file was created
+ f = io.open(self.fname, 'r')
+ lu.assertNotNil( f )
+ f:close()
+ end
+
+ function TestLogger:tearDown()
+ -- cleanup our log file after all tests
+ os.remove(self.fname)
+ end
+
+.. Note::
+
+ *Errors generated during execution of setUp() or tearDown()
+ functions are considered test failures.*
+
+
+.. Note::
+
+ *For compatibility with luaunit v2 and other lua unit-test frameworks,
+ setUp() and tearDown() may also be named setup(), SetUp(), Setup() and teardown(), TearDown(), Teardown().*
+
+
+Using the command-line
+======================
+
+You can control the LuaUnit execution from the command-line:
+
+**Output format**
+
+Choose the test output format with ``-o`` or ``--output``. Available formats are:
+
+* text: the default output format
+* nil: no output at all
+* tap: TAP format
+* junit: output junit xml
+
+Example of non-verbose text format::
+
+ $ lua doc/my_test_suite.lua
+ .......
+ Ran 7 tests in 0.003 seconds, 7 successes, 0 failures
+ OK
+
+
+Example of TAP format::
+
+ $ lua doc/my_test_suite.lua -o TAP
+ 1..7
+ # Started on 02/19/17 22:15:53
+ # Starting class: TestAdd
+ ok 1 TestAdd.testAddError
+ ok 2 TestAdd.testAddPositive
+ ok 3 TestAdd.testAddZero
+ ok 4 TestAdd.testAdder
+ # Starting class: TestDiv
+ ok 5 TestDiv.testDivError
+ ok 6 TestDiv.testDivPositive
+ ok 7 TestDiv.testDivZero
+ # Ran 7 tests in 0.007 seconds, 7 successes, 0 failures
+
+
+Output formats may also be controlled by the following environment variables:
+* LUAUNIT_OUTPUT: output format to use
+* LUAUNIT_JUNIT_FNAME: for junit output format, name of the xml file
+
+For a more detailed overview of all formats and their verbosity see the section `Output formats`_ .
+
+
+**List of tests to run**
+
+You can list some test names on the command-line to run only those tests.
+The name must be the exact match of either the test table, the test function or the test table
+and the test method. The option may be repeated.
+
+Example::
+
+ -- Run all TestAdd table tests and one test of TestDiv table.
+ $ lua doc/my_test_suite.lua TestAdd TestDiv.testDivError -v
+ Started on 02/19/17 22:15:53
+ TestAdd.testAddError ... Ok
+ TestAdd.testAddPositive ... Ok
+ TestAdd.testAddZero ... Ok
+ TestAdd.testAdder ... Ok
+ TestDiv.testDivError ... Ok
+ =========================================================
+ Ran 5 tests in 0.003 seconds, 5 successes, 0 failures
+ OK
+
+**Including / excluding tests**
+
+The most flexible approach for selecting tests to use the include and exclude functionality.
+With ``--pattern`` or ``-p``, you can provide a lua pattern and only the tests that contain
+the pattern will actually be run.
+
+Example::
+ -- Run all tests of zero testing and error testing
+ -- by using the magic character .
+ $ lua my_test_suite.lua -v -p Err.r -p Z.ro
+
+For our test suite, it gives the following output::
+
+ Started on 02/19/17 22:15:53
+ TestAdd.testAddError ... Ok
+ TestAdd.testAddZero ... Ok
+ TestDiv.testDivError ... Ok
+ TestDiv.testDivZero ... Ok
+ =========================================================
+ Ran 4 tests in 0.003 seconds, 4 successes, 0 failures, 3 non-selected
+ OK
+
+The number of tests ignored by the selection is printed, along
+with the test result. The pattern can be any lua pattern. Be sure to exclude all magic
+characters with % (like -+?*) and protect your pattern from the shell
+interpretation by putting it in quotes.
+
+You can also exclude tests that match some patterns:
+
+Example::
+
+ -- Run all tests except zero testing and except error testing
+ $ lua my_test_suite.lua -v -x Error -x Zero
+
+For our test suite, it gives the following output::
+
+ Started on 02/19/17 22:29:45
+ TestAdd.testAddPositive ... Ok
+ TestAdd.testAdder ... Ok
+ TestDiv.testDivPositive ... Ok
+ =========================================================
+ Ran 3 tests in 0.003 seconds, 3 successes, 0 failures, 4 non-selected
+ OK
+
+You can also combine test selection and test exclusion. See `Flexible test selection`_
+
+Conclusion
+==========
+
+You now know enough of LuaUnit to start writing your test suite. Check
+the reference documentation for a complete list of
+assertions, command-line options and specific behavior.
+
+
+Reference documentation
+***********************
+
+Command-line options
+====================
+
+Usage: lua <your_test_suite.lua> [options] [testname1 [testname2] ...]
+
+**Test names**
+
+When no test names are supplied, all tests are collected.
+
+The syntax for supplying test names can be either: name of the function, name of the table
+or [name of the table].[name of the function]. Only the supplied tests will be executed.
+
+Selecting tests with --pattern and --exclude is usually more flexible. See `Flexible test selection`_
+
+**Options**
+
+--output, -o FORMAT Set output format to FORMAT. Possible values: text, tap, junit, nil . See `Output formats`_
+--name, -n FILENAME For junit format only, mandatory name of xml file. Ignored for other formats.
+--pattern, -p PATTERN Execute all test names matching the Lua PATTERN. May be repeated to include severals patterns. See `Flexible test selection`_
+--exclude, -x PATTERN Exclude all test names matching the Lua PATTERN. May be repeated to exclude severals patterns. See `Flexible test selection`_
+--repeat, -r NUM Repeat all tests NUM times, e.g. to trigger the JIT. See `Other options`_
+--shuffle, -s Shuffle tests before running them. See `Other options`_
+--error, -e Stop on first error. See `Other options`_
+--failure, -f Stop on first failure or error. See `Other options`_
+--verbose, -v Increase verbosity
+--quiet, -q Set verbosity to minimum
+--help, -h Print help
+--version Version information of LuaUnit
+
+
+Output formats
+----------------------
+
+Choose the output format with the syntax ``-o FORMAT`` or ``--output FORMAT`` or the environment variable ``LUAUNIT_OUTPUT``.
+
+Formats available:
+
+* ``text``: the default output format of LuaUnit
+* ``tap``: output compatible with the `Test Anything Protocol`_
+* ``junit``: output compatible with the *JUnit XML* format (used by many CI
+ platforms). The XML is written to the file provided with the ``--name`` or ``-n`` option or the environment variable ``LUAUNIT_JUNIT_FNAME``.
+* ``nil``: no output at all
+
+.. _Test Anything Protocol: http://testanything.org/
+
+For more information on each format, see `Output formats details`_
+
+
+Other options
+--------------
+
+**Stopping on first error or failure**
+
+If ``--failure`` or ``-f`` is passed as an option, LuaUnit will stop on the first failure or error and display the test results.
+
+If ``--error`` or ``-e`` is passed as an option, LuaUnit will stop on the first error (but continue on failures).
+
+**Randomize test order**
+
+If ``--shuffle`` or ``-s`` is passed as an option, LuaUnit will execute tests in random order. The randomisation works on all test functions
+and methods. As a consequence test methods of a given class may be splitted into multiple location, generating several test class creation and destruction.
+
+**Repeat test**
+
+When using luajit, the just-in-time compiler will kick in only after a given function has been executed a sufficient number of times. To make sure
+that the JIT is not introducing any bug, LuaUnit provides a way to repeat a test may times, with ``--repeat`` or ``-r`` followed by a number.
+
+Flexible test selection
+-------------------------
+
+LuaUnit provides very flexible way to select which tests to execute. We will illustrate this with several examples.
+
+In the examples, we use a test suite composed of the following test funcions::
+
+ -- class: TestAdd
+ TestAdd.testAddError
+ TestAdd.testAddPositive
+ TestAdd.testAddZero
+ TestAdd.testAdder
+
+ -- class: TestDiv
+ TestDiv.testDivError
+ TestDiv.testDivPositive
+ TestDiv.testDivZero
+
+
+With ``--pattern`` or ``-p``, you can provide a lua pattern and only the tests that contain
+the pattern will actually be run.
+
+Example::
+
+ -- Run all tests of zero testing and error testing
+ -- by using the magic character .
+ $ lua mytest_suite.lua -v -p Err.r -p Z.ro
+ Started on 02/19/17 22:29:45
+ TestAdd.testAddError ... Ok
+ TestAdd.testAddZero ... Ok
+ TestDiv.testDivError ... Ok
+ TestDiv.testDivZero ... Ok
+ =========================================================
+ Ran 4 tests in 0.004 seconds, 4 successes, 0 failures, 3 non-selected
+ OK
+
+The number of tests ignored by the selection is printed, along
+with the test result. The tests *TestAdd.testAdder testAdd.testPositive and
+testDiv.testDivPositive* have been correctly ignored.
+
+The pattern can be any lua pattern. Be sure to exclude all magic
+characters with % (like ``-+?*``) and protect your pattern from the shell
+interpretation by putting it in quotes.
+
+With ``--exclude`` or ``-x``, you can provide a lua pattern of tests which should
+be excluded from execution.
+
+Example::
+
+ -- Run all tests except zero testing and except error testing
+ $ lua mytest_suite.lua -v -x Error -x Zero
+ Started on 02/19/17 22:29:45
+ TestAdd.testAddPositive ... Ok
+ TestAdd.testAdder ... Ok
+ TestDiv.testDivPositive ... Ok
+ =========================================================
+ Ran 3 tests in 0.003 seconds, 3 successes, 0 failures, 4 non-selected
+ OK
+
+You can also combine test selection and test exclusion. The rules are the following:
+
+* if the first argument encountered is a inclusion pattern, the list of tests start empty
+* if the first argument encountered is an exclusion pattern, the list of tests start with all tests of the suite
+* each subsequent inclusion pattern will add new tests to the list
+* each subsequent exclusion pattern will remove test from the list
+* the final list is the list of tests executed
+
+In pure logic term, inclusion is the equivalent of ``or match(pattern)`` and exclusion is ``and not match(pattern)`` .
+
+Let's look at some practical examples::
+
+ -- Add all tests which include the word Add
+ -- except the test Adder
+ -- and also include the Zero tests
+ $ lua my_test_suite.lua -v --pattern Add --exclude Adder --pattern Zero
+ Started on 02/19/17 22:29:45
+ TestAdd.testAddError ... Ok
+ TestAdd.testAddPositive ... Ok
+ TestAdd.testAddZero ... Ok
+ TestDiv.testDivZero ... Ok
+ =========================================================
+ Ran 4 tests in 0.003 seconds, 4 successes, 0 failures, 3 non-selected
+ OK
+
+
+LuaUnit runner object
+=======================
+
+The various options set on the command-line can be overridden by creating a LuaUnit runner explicitely and calling specific functions on it.
+
+.. function:: LuaUnit.new()
+
+The execution of a LuaUnit test suite is controlled through a runner object. This object is created with `LuaUnit.new()` .
+
+.. code-block:: lua
+
+ lu = require('luaunit')
+
+
+ runner = lu.LuaUnit.new()
+ -- use the runner object...
+ runner.runSuite()
+
+.. function:: runner:setVerbosity( verbosity )
+
+Set the verbosity of the runner. The value is an integer ranging from lu.VERBOSITY_QUIET to lu.VERBOSITY_VERBOSE .
+
+
+.. function:: runner:setQuitOnError( quitOnError )
+
+Set the quit-on-first-error behavior, like the command-line `--xx`. The argument is a boolean value.
+
+
+.. function:: runner:setQuitOnFailuer( quitOnFailure )
+
+Set the quit-on-first-failure-or-error behavior, like the command-line `--xx`. The argument is a boolean value.
+
+
+.. function:: runner:setRepeat( repeatNumber )
+
+Set the number of times a test function is executed, like the command-line `-xx`. The argument is an integer.
+
+
+.. function:: runner:setShuffle( shuffle )
+
+Set whether the test are run in randomized, like the command-line `--shuffle`. The argument is a boolean value.
+
+
+.. function:: runner:setOutputType(type [, junit_fname])
+
+Set the output type of the test suite. See `Output formats`_ for possible values. When setting the format `junit`, it
+is mandatory to set the filename receiving the xml output. This can be done by passing it as second argument of this function.
+
+
+.. function:: runner:runSuite( [arguments] )
+
+This function runs the test suite.
+
+**Arguments**
+
+If no arguments are supplied, it parses the command-line arguments of the script
+and interpret them. If arguments are supplied to the function, they are parsed
+as the command-line. It uses the same syntax.
+
+Test names may be supplied in arguments, to execute
+only these specific tests. Note that when explicit names are provided
+LuaUnit does not require the test names to necessarily start with *test*.
+
+If no test names were supplied, a general test collection process is done
+and the resulting tests are executed.
+
+**Return value**
+
+It returns the number of failures and errors. On
+success 0 is returned, making is suitable for an exit code.
+
+.. code-block:: lua
+
+ lu = require('luaunit')
+
+ runner = lu.LuaUnit.new()
+ os.exit(runner.runSuite())
+
+
+
+Example of using pattern to select tests::
+
+.. code-block:: lua
+
+ lu = require('luaunit')
+
+ runner = lu.LuaUnit.new()
+ -- execute tests matching the 'withXY' pattern
+ os.exit(runner.runSuite('--pattern', 'withXY')
+
+
+Example of explicitly selecting tests::
+
+.. code-block:: lua
+
+ lu = require('luaunit')
+
+ runner = lu.LuaUnit.new()
+ os.exit(runner.runSuite('testABC', 'testDEF'))
+
+
+.. function:: LuaUnit.run( [arguments] )
+
+This function may be called directly from the LuaUnit table. It will
+create internally a LuaUnit runner and pass all arguments to it.
+
+Arguments and return value is the same as :func:`runner:runSuite()`
+
+Example::
+
+.. code-block:: lua
+
+ -- execute tests matching the 'withXY' pattern
+ os.exit(lu.LuaUnit.run('--pattern', 'withXY'))
+
+
+
+.. function:: runner:runSuiteByInstances( listOfNameAndInstances )
+
+This function runs test without performing the global test collection process on the global namespace, the test
+are explicitely provided as argument, along with their names.
+
+Before execution, the function will parse the script command-line, like :func:`funner:runSuite()`.
+
+Input is provided as a list of { name, test_instance } . test_instance can either be a function or a table containing
+test functions starting with the prefix "test".
+
+
+Example of using runSuiteByInstances
+
+.. code-block:: lua
+
+ lu = require('luaunit')
+
+ runner = lu.LuaUnit.new()
+ os.exit(runner.runSuiteByInstances( {'mySpecialTest1', mySpecialTest1}, {'mySpecialTest2', mySpecialTest2} } )
+
+
+Skipping and ending test
+==========================
+
+LuaUnit allows to force test ending in several ways.
+
+**Test skipping**
+
+.. function:: skip( message )
+
+ Stops the ongoing test and mark it as skipped with the given message. This can be used
+ to deactivate a given test.
+
+
+.. function:: skipIf( condition, message )
+
+ If the condition *condition* evaluates to *true*, stops the ongoing test and mark it as skipped with the given message.
+ Else, continue the test execution normally.
+
+ The expected usage is to call the function at the beginning of the test to
+ verify if the conditions are met for executing such tests.
+
+
+.. function:: runOnlyIf( condition, message )
+
+ If condition evaluates to *false*, stops the ongoing test and mark it as skipped with the
+ given message. This is the opposite behavior of :func:`skipIf()` .
+
+ The expected usage is to call the function at the beginning of the test to
+ verify if the conditions are met for executing such tests.
+
+
+Number of skipped tests, if any, are reported at the end of the execution.
+
+
+**Force test failing**
+
+.. function:: fail( message )
+
+ Stops the ongoing test and mark it as failed with the given message.
+
+
+.. function:: failIf( condition, message )
+
+ If the condition *condition* evaluates to *true*, stops the ongoing test and mark it as failed with the given message.
+ Else, continue the test execution normally.
+
+
+**Force test success**
+
+.. function:: success()
+
+ Stops the ongoing test and mark it as successful.
+
+.. function:: successIf( condition )
+
+ If the condition *condition* evaluates to *true*, stops the ongoing test and mark it as successful.
+ Else, continue the test execution normally.
+
+
+Output formats details
+=======================
+
+
+To demonstrate the different output formats, we will take the example of the `Getting started with LuaUnit`_
+section and add the following two failing cases:
+
+.. code-block:: lua
+
+ TestWithFailures = {}
+ -- two failing tests
+
+ function TestWithFailures:testFail1()
+ local a="toto"
+ local b="titi"
+ lu.assertEquals( a, b ) --oops, two values are not equal
+ end
+
+ function TestWithFailures:testFail2()
+ local a=1
+ local b='toto'
+ local c = a + b --oops, can not add string and numbers
+ return c
+ end
+
+
+**Text format**
+
+By default, LuaUnit uses the output format TEXT, with minimum verbosity::
+
+ $ lua my_test_suite.lua
+ .......FE
+ Failed tests:
+ -------------
+ 1) TestWithFailures.testFail1
+ doc\my_test_suite_with_failures.lua:79: expected: "titi"
+ actual: "toto"
+ stack traceback:
+ doc\my_test_suite_with_failures.lua:79: in function 'TestWithFailures.testFail1'
+
+ 2) TestWithFailures.testFail2
+ doc\my_test_suite_with_failures.lua:85: attempt to perform arithmetic on local 'b' (a string value)
+ stack traceback:
+ [C]: in function 'xpcall'
+
+ Ran 9 tests in 0.001 seconds, 7 successes, 1 failure, 1 error
+
+This format is heavily inspired by python unit-test library. One character is printed
+for every test executed, a dot for a successful test, a **F** for a test with failure and
+a **E** for a test with an error.
+
+At the end of the test suite execution, the details of the failures or errors are given, with an
+informative message and a full stack trace.
+
+The last line sums up the number of test executed, successful, failed, in error and not selected if any.
+When all tests are successful, a line with just OK is added::
+
+ $ lua doc\my_test_suite.lua
+ .......
+ Ran 7 tests in 0.002 seconds, 7 successes, 0 failures
+ OK
+
+
+The text format is also available as a more verbose version, by adding the ``--verbose`` flag::
+
+ $ lua doc\my_test_suite_with_failures.lua --verbose
+ Started on 02/20/17 21:47:21
+ TestAdd.testAddError ... Ok
+ TestAdd.testAddPositive ... Ok
+ TestAdd.testAddZero ... Ok
+ TestAdd.testAdder ... Ok
+ TestDiv.testDivError ... Ok
+ TestDiv.testDivPositive ... Ok
+ TestDiv.testDivZero ... Ok
+ TestWithFailures.testFail1 ... FAIL
+ doc\my_test_suite_with_failures.lua:79: expected: "titi"
+ actual: "toto"
+ TestWithFailures.testFail2 ... ERROR
+ doc\my_test_suite_with_failures.lua:85: attempt to perform arithmetic on local 'b' (a string value)
+ =========================================================
+ Failed tests:
+ -------------
+ 1) TestWithFailures.testFail1
+ doc\my_test_suite_with_failures.lua:79: expected: "titi"
+ actual: "toto"
+ stack traceback:
+ doc\my_test_suite_with_failures.lua:79: in function 'TestWithFailures.testFail1'
+
+ 2) TestWithFailures.testFail2
+ doc\my_test_suite_with_failures.lua:85: attempt to perform arithmetic on local 'b' (a string value)
+ stack traceback:
+ [C]: in function 'xpcall'
+
+ Ran 9 tests in 0.008 seconds, 7 successes, 1 failure, 1 error
+
+In this format, you get:
+
+* a first line with date-time at which the test was started
+* one line per test executed
+* the test line is ended by **Ok**, **FAIL**, or **ERROR** in case the test is not successful
+* a summary of the failed tests with all details, like in the compact version.
+
+This format is usually interesting if some tests print debug output, to match the output to the test.
+
+**JUNIT format**
+
+The Junit XML format was introduced by the `Java testing framework JUnit`_ and has been then used by many continuous
+integration platform as an interoperability format between test suites and the platform.
+
+.. _Java testing framework JUnit: http://junit.org/junit4/
+
+To output in the JUnit XML format, you use the format junit with ``--output junit`` and specify the XML filename with ``--name <filename>`` . On
+the standard output, LuaUnit will print information about the test progress in a simple format.
+
+Let's see with a simple example::
+
+ $ lua my_test_suite_with_failures.lua -o junit -n toto.xml
+ # XML output to toto.xml
+ # Started on 02/24/17 09:54:59
+ # Starting class: TestAdd
+ # Starting test: TestAdd.testAddError
+ # Starting test: TestAdd.testAddPositive
+ # Starting test: TestAdd.testAddZero
+ # Starting test: TestAdd.testAdder
+ # Starting class: TestDiv
+ # Starting test: TestDiv.testDivError
+ # Starting test: TestDiv.testDivPositive
+ # Starting test: TestDiv.testDivZero
+ # Starting class: TestWithFailures
+ # Starting test: TestWithFailures.testFail1
+ # Failure: doc/my_test_suite_with_failures.lua:79: expected: "titi"
+ # actual: "toto"
+ # Starting test: TestWithFailures.testFail2
+ # Error: doc/my_test_suite_with_failures.lua:85: attempt to perform arithmetic on local 'b' (a string value)
+ # Ran 9 tests in 0.007 seconds, 7 successes, 1 failure, 1 error
+
+On the standard output, you will see the date-time, the name of the XML file, one line for each test started, a summary
+of the failure or errors when they occurs and the usual one line summary of the test execution: number of tests run, successful, failed,
+in error and number of non selected tests if any.
+
+The XML file generated by this execution is the following::
+
+ <?xml version="1.0" encoding="UTF-8" ?>
+ <testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="9" timestamp="2017-02-24T09:54:59" time="0.007" errors="1" failures="1">
+ <properties>
+ <property name="Lua Version" value="Lua 5.2"/>
+ <property name="LuaUnit Version" value="3.2"/>
+ </properties>
+ <testcase classname="TestAdd" name="TestAdd.testAddError" time="0.001">
+ </testcase>
+ <testcase classname="TestAdd" name="TestAdd.testAddPositive" time="0.001">
+ </testcase>
+ <testcase classname="TestAdd" name="TestAdd.testAddZero" time="0.000">
+ </testcase>
+ <testcase classname="TestAdd" name="TestAdd.testAdder" time="0.000">
+ </testcase>
+ <testcase classname="TestDiv" name="TestDiv.testDivError" time="0.000">
+ </testcase>
+ <testcase classname="TestDiv" name="TestDiv.testDivPositive" time="0.000">
+ </testcase>
+ <testcase classname="TestDiv" name="TestDiv.testDivZero" time="0.001">
+ </testcase>
+ <testcase classname="TestWithFailures" name="TestWithFailures.testFail1" time="0.000">
+ <failure type="doc/my_test_suite_with_failures.lua:79: expected: &quot;titi&quot;
+ actual: &quot;toto&quot;">
+ <![CDATA[stack traceback:
+ doc/my_test_suite_with_failures.lua:79: in function 'TestWithFailures.testFail1']]></failure>
+ </testcase>
+ <testcase classname="TestWithFailures" name="TestWithFailures.testFail2" time="0.000">
+ <error type="doc/my_test_suite_with_failures.lua:85: attempt to perform arithmetic on local &apos;b&apos; (a string value)">
+ <![CDATA[stack traceback:
+ [C]: in function 'xpcall']]></error>
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+ </testsuites>
+
+As you can see, the XML file is quite rich in terms of information. The verbosity level has no effect on junit output, all verbosity give the same output.
+
+Slight inconsistencies exist in the exact XML format in the different continuous integration suites. LuaUnit provides a compatible output which
+is validated against `Jenkins/Hudson schema`_ . If you ever find an problem in the XML formats, please report a bug to us, more testing is always welcome.
+
+.. _Jenkins/Hudson schema: https://github.com/bluebird75/luaunit/blob/LUAUNIT_V3_2_1/junitxml/junit-jenkins.xsd
+
+**TAP format**
+
+The `TAP format`_ for test results has been around since 1988. LuaUnit produces TAP reports compatible with version 12 of
+the specification.
+
+.. _`TAP format`: https://testanything.org/
+
+Example with minimal verbosiy::
+
+ $ lua my_test_suite_with_failures.lua -o tap --quiet
+ 1..9
+ # Started on 02/24/17 22:09:31
+ # Starting class: TestAdd
+ ok 1 TestAdd.testAddError
+ ok 2 TestAdd.testAddPositive
+ ok 3 TestAdd.testAddZero
+ ok 4 TestAdd.testAdder
+ # Starting class: TestDiv
+ ok 5 TestDiv.testDivError
+ ok 6 TestDiv.testDivPositive
+ ok 7 TestDiv.testDivZero
+ # Starting class: TestWithFailures
+ not ok 8 TestWithFailures.testFail1
+ not ok 9 TestWithFailures.testFail2
+ # Ran 9 tests in 0.003 seconds, 7 successes, 1 failure, 1 error
+
+With minimal verbosity, you have one line for each test run, with the status of the test, and one comment line
+when starting the test suite, when starting a new class or when finishing the test.
+
+
+Example with default verbosiy::
+
+ $ lua my_test_suite_with_failures.lua -o tap
+ 1..9
+ # Started on 02/24/17 22:09:31
+ # Starting class: TestAdd
+ ok 1 TestAdd.testAddError
+ ok 2 TestAdd.testAddPositive
+ ok 3 TestAdd.testAddZero
+ ok 4 TestAdd.testAdder
+ # Starting class: TestDiv
+ ok 5 TestDiv.testDivError
+ ok 6 TestDiv.testDivPositive
+ ok 7 TestDiv.testDivZero
+ # Starting class: TestWithFailures
+ not ok 8 TestWithFailures.testFail1
+ doc/my_test_suite_with_failures.lua:79: expected: "titi"
+ actual: "toto"
+ not ok 9 TestWithFailures.testFail2
+ doc/my_test_suite_with_failures.lua:85: attempt to perform arithmetic on local 'b' (a string value)
+ # Ran 9 tests in 0.005 seconds, 7 successes, 1 failure, 1 error
+
+In the default mode, the failure or error message is displayed in the failing test diagnostic part.
+
+Example with full verbosiy::
+
+ $ lua my_test_suite_with_failures.lua -o tap --verbose
+ 1..9
+ # Started on 02/24/17 22:09:31
+ # Starting class: TestAdd
+ ok 1 TestAdd.testAddError
+ ok 2 TestAdd.testAddPositive
+ ok 3 TestAdd.testAddZero
+ ok 4 TestAdd.testAdder
+ # Starting class: TestDiv
+ ok 5 TestDiv.testDivError
+ ok 6 TestDiv.testDivPositive
+ ok 7 TestDiv.testDivZero
+ # Starting class: TestWithFailures
+ not ok 8 TestWithFailures.testFail1
+ doc/my_test_suite_with_failures.lua:79: expected: "titi"
+ actual: "toto"
+ stack traceback:
+ doc/my_test_suite_with_failures.lua:79: in function 'TestWithFailures.testFail1'
+ not ok 9 TestWithFailures.testFail2
+ doc/my_test_suite_with_failures.lua:85: attempt to perform arithmetic on local 'b' (a string value)
+ stack traceback:
+ [C]: in function 'xpcall'
+ # Ran 9 tests in 0.007 seconds, 7 successes, 1 failure, 1 error
+
+With maximum verbosity, the stack trace is also displayed in the test diagnostic.
+
+**NIL format**
+
+With the nil format output, absolutely nothing is displayed while running the tests. Only the
+exit code of the command can tell whether the test was successful or not::
+
+ $ lua my_test_suite_with_failures.lua -o nil --verbose
+ $
+
+This mode is used by LuaUnit for its internal validation.
+
+
+
+Test collection and execution process
+======================================
+
+Test collection
+-------------------
+
+The test collection and execution process is the following:
+
+* If a list of tests is specified on the command-line or as argument to the *runSuite()* or *runSuiteByInstances()*, this
+ the considered list of tests to run.
+* If no list of tests is specified, the global namespace *_G* is searched for names starting by *test* or *Test*. All
+ such names are put into the list of tests to run (provided they reference either a function or a table).
+* All tables are then scanned for table functions starting with *test* or *Test*, which are then added to the list of tests to run
+* From the list of tests to run, include and exclude patterns are applied
+* If shuffling is activated, the list is randomized. Else, it is sorted in alphabetical order.
+
+This constitutes the final list of tests to run.
+
+Test execution
+-------------------
+
+Each test function is run in a protected call. If any luaunit assertion fails (assertEquals, ...), the test is considered as a failure. If
+an error is generated during the test execution, the test is marked as in error. Both errors and failures are reported at the end of the execution.
+
+When executing a table containing tests, the following methods are also considered:
+
+* *setUp()* is called prior to each test execution. Any failure or error during *setUp()* will prevent the test from being executed and will
+ be reported in the test suite.
+* *tearDown()* is called after each test, even if the *setUp()* or the test failed. Any failure or error during *tearDown()* will be reported
+ in the test suite.
+
+
+Assertions functions
+=====================
+We will now list all assertion functions. For every functions, the failure
+message tries to be as informative as possible, by displaying the expectation and value that caused the failure. It
+relies on the :func:`prettystr` for printing nicely formatted values.
+
+All function accept an optional extra message which if provided, is printed along with the failure message.
+
+.. Note:: see :ref:`table-printing` for more information on how LuaUnit prints tables.
+
+Equality assertions
+----------------------
+All equality assertions functions take two arguments, in the order
+*actual value* then *expected value*. Some people are more familiar
+with the order *expected value* then *actual value*. It is possible to configure
+LuaUnit to use the opposite order for all equality assertions, by setting up a module
+variable:
+
+.. code-block:: lua
+
+ lu.ORDER_ACTUAL_EXPECTED=false
+
+The order only matters for the message that is displayed in case of failures. It does
+not influence the test itself.
+
+
+.. function:: assertEquals(actual, expected [, extra_msg] )
+
+ **Alias**: *assert_equals()*
+
+ Assert that two values are equal. This is the most used function for assertion within LuaUnit.
+ The values being compared may be integers, floats, strings, tables, functions or a combination of
+ those. If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+ When comparing floating point numbers, it is better to use :func:`assertAlmostEquals` which supports a margin
+ for the equality verification.
+
+ For tables, the comparison supports nested tables and cyclic structures. To be equal, two tables must
+ have the same keys and the value associated with a key must compare equal with assertEquals() (using a recursive
+ algorithm).
+
+ When displaying the difference between two tables used as lists, LuaUnit performs an analysis of the list content
+ to pinpoint the place where the list actually differs. See the below example:
+
+.. code-block::
+
+ -- lua test code. Can you spot the difference ?
+ function TestListCompare:test1()
+ local A = { 121221, 122211, 121221, 122211, 121221, 122212, 121212, 122112, 122121, 121212, 122121 }
+ local B = { 121221, 122211, 121221, 122211, 121221, 122212, 121212, 122112, 121221, 121212, 122121 }
+ lu.assertEquals( A, B )
+ end
+
+ $ lua test_some_lists_comparison.lua
+
+ TestListCompare.test1 ... FAIL
+ test/some_lists_comparisons.lua:22: expected:
+
+ List difference analysis:
+ * lists A (actual) and B (expected) have the same size
+ * lists A and B start differing at index 9
+ * lists A and B are equal again from index 10
+ * Common parts:
+ = A[1], B[1]: 121221
+ = A[2], B[2]: 122211
+ = A[3], B[3]: 121221
+ = A[4], B[4]: 122211
+ = A[5], B[5]: 121221
+ = A[6], B[6]: 122212
+ = A[7], B[7]: 121212
+ = A[8], B[8]: 122112
+ * Differing parts:
+ - A[9]: 122121
+ + B[9]: 121221
+ * Common parts at the end of the lists
+ = A[10], B[10]: 121212
+ = A[11], B[11]: 122121
+
+
+
+.. Note:: see :ref:`comparing-table-keys-table` for information on comparison of tables containing keys of type table.
+
+ LuaUnit provides other table-related assertions, see :ref:`assert-table` .
+
+
+.. function:: assertNotEquals(actual, expected [, extra_msg])
+
+ **Alias**: *assert_not_equals()*
+
+ Assert that two values are different. The assertion
+ fails if the two values are identical. It behaves exactly like :func:`assertEquals` but checks
+ for the opposite condition.
+
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+Value assertions
+----------------------
+
+LuaUnit contains several flavours of true/false assertions, to be used in different contexts.
+Usually, when asserting for *true* or *false*, you want strict assertions (*nil* should not
+assert to *false*); *assertTrue()* and *assertFalse()* are the functions for this purpose. In some cases though,
+you want Lua coercion rules to apply (e.g. value *1* or string *"hello"* yields *true*) and the right functions to use
+are *assertEvalToTrue()* and *assertEvalToFalse()*. Finally, you have the *assertNotTrue()* and *assertNotFalse()* to verify
+that a value is anything but the boolean *true* or *false*.
+
+The below table sums it up:
+
+ **True assertion family**
+
+============ ============ =================== ================
+Input Value assertTrue() assertEvalToTrue() assertNotTrue()
+============ ============ =================== ================
+*true* OK OK OK
+*false* Fail Fail Fail
+*nil* Fail Fail OK
+*0* Fail OK OK
+*1* Fail OK OK
+*"hello"* Fail OK OK
+============ ============ =================== ================
+
+ **False assertion family**
+
+============ ================ ============= ===================
+Input Value assertNotFalse() assertFalse() assertEvalToFalse()
+============ ================ ============= ===================
+*true* Fail Fail Fail
+*false* OK OK OK
+*nil* Fail OK OK
+*0* Fail Fail Fail
+*1* Fail Fail Fail
+*"hello"* Fail Fail Fail
+============ ================ ============= ===================
+
+.. function:: assertEvalToTrue(value [, extra_msg])
+
+ **Alias**: *assert_eval_to_true()*
+
+ Assert that a given value evals to ``true``. Lua coercion rules are applied
+ so that values like ``0``, ``""``, ``1.17`` **succeed** in this assertion. If provided,
+ extra_msg is a string which will be printed along with the failure message.
+
+ See :func:`assertTrue` for a strict assertion to boolean ``true``.
+
+.. function:: assertEvalToFalse(value [, extra_msg])
+
+ **Alias**: *assert_eval_to_false()*
+
+ Assert that a given value eval to ``false``. Lua coercion rules are applied
+ so that ``nil`` and ``false`` **succeed** in this assertion. If provided, extra_msg
+ is a string which will be printed along with the failure message.
+
+ See :func:`assertFalse` for a strict assertion to boolean ``false``.
+
+.. function:: assertTrue(value [, extra_msg])
+
+ **Alias**: *assert_true()*
+
+ Assert that a given value is strictly ``true``. Lua coercion rules do not apply
+ so that values like ``0``, ``""``, ``1.17`` **fail** in this assertion. If provided,
+ extra_msg is a string which will be printed along with the failure message.
+
+ See :func:`assertEvalToTrue` for an assertion to ``true`` where Lua coercion rules apply.
+
+.. function:: assertFalse(value [, extra_msg])
+
+ **Alias**: *assert_false()*
+
+ Assert that a given value is strictly ``false``. Lua coercion rules do not apply
+ so that ``nil`` **fails** in this assertion. If provided, *extra_msg* is a string
+ which will be printed along with the failure message.
+
+ See :func:`assertEvalToFalse` for an assertion to ``false`` where Lua coertion fules apply.
+
+.. function:: assertNil(value [, extra_msg])
+
+ **Aliases**: *assert_nil()*, *assertIsNil()*, *assert_is_nil()*
+
+ Assert that a given value is *nil* . If provided, *extra_msg* is
+ a string which will be printed along with the failure message.
+
+.. function:: assertNotNil(value [, extra_msg])
+
+ **Aliases**: *assert_not_nil()*, *assertNotIsNil()*, *assert_not_is_nil()*
+
+ Assert that a given value is not *nil* . Lua coercion rules are applied
+ so that values like ``0``, ``""``, ``false`` all validate the assertion.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+.. function:: assertIs(actual, expected [, extra_msg])
+
+ **Alias**: *assert_is()*
+
+ Assert that two variables are identical. For string, numbers, boolean and for nil,
+ this gives the same result as :func:`assertEquals` . For the other types, identity
+ means that the two variables refer to the same object.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+ **Example :**
+
+.. code-block:: lua
+
+ s1='toto'
+ s2='to'..'to'
+ t1={1,2}
+ t2={1,2}
+ v1=nil
+ v2=false
+
+ lu.assertIs(s1,s1) -- ok
+ lu.assertIs(s1,s2) -- ok
+ lu.assertIs(t1,t1) -- ok
+ lu.assertIs(t1,t2) -- fail
+ lu.assertIs(v1,v2) -- fail
+
+.. function:: assertNotIs(actual, expected [, extra_msg])
+
+ **Alias**: *assert_not_is()*
+
+ Assert that two variables are not identical, in the sense that they do not
+ refer to the same value. If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+ See :func:`assertIs` for more details.
+
+
+String assertions
+--------------------------
+
+Assertions related to string and patterns.
+
+.. function:: assertStrContains( str, sub [, isPattern [, extra_msg ]] )
+
+ **Alias**: *assert_str_contains()*
+
+ Assert that the string *str* contains the substring or pattern *sub*.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+ By default, substring is searched in the string. If *isPattern*
+ is provided and is true, *sub* is treated as a pattern which
+ is searched inside the string *str* .
+
+
+.. function:: assertStrIContains( str, sub [, extra_msg] )
+
+ **Alias**: *assert_str_icontains()*
+
+ Assert that the string *str* contains the given substring *sub*, irrespective of the case.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+ Note that unlike :func:`assertStrcontains`, you can not search for a pattern.
+
+
+
+.. function:: assertNotStrContains( str, sub, [isPattern [, extra_msg]] )
+
+ **Alias**: *assert_not_str_contains()*
+
+ Assert that the string *str* does not contain the substring or pattern *sub*.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+ By default, the substring is searched in the string. If *isPattern*
+ is provided and is true, *sub* is treated as a pattern which
+ is searched inside the string *str* .
+
+
+.. function:: assertNotStrIContains( str, sub [, extra_msg] )
+
+ **Alias**: *assert_not_str_icontains()*
+
+ Assert that the string *str* does not contain the substring *sub*, irrespective of the case.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+ Note that unlike :func:`assertNotStrcontains`, you can not search for a pattern.
+
+
+.. function:: assertStrMatches( str, pattern [, start [, final [, extra_msg ]]] )
+
+ **Alias**: *assert_str_matches()*
+
+ Assert that the string *str* matches the full pattern *pattern*.
+
+ If *start* and *final* are not provided or are *nil*, the pattern must match the full string, from start to end. The
+ function allows to specify the expected start and end position of the pattern in the string. If provided,
+ *extra_msg* is a string which will be printed along with the failure message.
+
+
+Error assertions
+--------------------------
+Error related assertions, to verify error generation and error messages.
+
+.. function:: assertError( func, ...)
+
+ **Alias**: *assert_error()*
+
+ Assert that calling functions *func* with the arguments yields an error. If the
+ function does not yield an error, the assertion fails.
+
+ Note that the error message itself is not checked, which means that this function
+ does not distinguish between the legitimate error that you expect and another error
+ that might be triggered by mistake.
+
+ The next functions provide a better approach to error testing, by checking
+ explicitly the error message content.
+
+.. Note::
+
+ When testing LuaUnit, switching from *assertError()* to *assertErrorMsgEquals()*
+ revealed quite a few bugs!
+
+.. function:: assertErrorMsgEquals( expectedMsg, func, ... )
+
+ **Alias**: *assert_error_msg_equals()*
+
+ Assert that calling function *func* will generate exactly the given error message. If the
+ function does not yield an error, or if the error message is not identical, the assertion fails.
+
+ Be careful when using this function that error messages usually contain the file name and
+ line number information of where the error was generated. This is usually inconvenient so we have
+ introduced the :func:`assertErrorMsgContentEquals` . Be sure to check it.
+
+
+.. function:: assertErrorMsgContentEquals( expectedMsg, func, ... )
+
+ **Alias**: *assert_error_msg_content_equals()*
+
+ Assert that calling function *func* will generate exactly the given error message, excluding the
+ file and line information. File and line information may change as your programs evolve so we
+ find this version more convenient than :func:`assertErrorMsgEquals` .
+
+
+
+.. function:: assertErrorMsgContains( partialMsg, func, ... )
+
+ **Alias**: *assert_error_msg_contains()*
+
+ Assert that calling function *func* will generate an error message containing *partialMsg* . If the
+ function does not yield an error, or if the expected message is not contained in the error message, the
+ assertion fails.
+
+
+
+.. function:: assertErrorMsgMatches( expectedPattern, func, ... )
+
+ **Alias**: *assert_error_msg_matches()*
+
+ Assert that calling function *func* will generate an error message matching *expectedPattern* . If the
+ function does not yield an error, or if the error message does not match the provided patternm the
+ assertion fails.
+
+ Note that matching is done from the start to the end of the error message. Be sure to escape magic all magic
+ characters with ``%`` (like ``-+.?*``) .
+
+
+Type assertions
+--------------------------
+
+ The following functions all perform type checking on their argument. If the
+ received value is not of the right type, the failure message will contain
+ the expected type, the received type and the received value to help you
+ identify better the problem.
+
+.. function:: assertIsNumber(value [, extra_msg])
+
+ **Aliases**: *assertNumber()*, *assert_is_number()*, *assert_number()*
+
+ Assert that the argument is a number (integer or float).
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+.. function:: assertIsString(value [, extra_msg])
+
+ **Aliases**: *assertString()*, *assert_is_string()*, *assert_string()*
+
+ Assert that the argument is a string.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+.. function:: assertIsTable(value [, extra_msg])
+
+ **Aliases**: *assertTable()*, *assert_is_table()*, *assert_table()*
+
+ Assert that the argument is a table.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+.. function:: assertIsBoolean(value [, extra_msg])
+
+ **Aliases**: *assertBoolean()*, *assert_is_boolean()*, *assert_boolean()*
+
+ Assert that the argument is a boolean.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+.. function:: assertIsNil(value [, extra_msg])
+
+ **Aliases**: *assertNil()*, *assert_is_nil()*, *assert_nil()*
+
+ Assert that the argument is nil.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+.. function:: assertIsFunction(value [, extra_msg])
+
+ **Aliases**: *assertFunction()*, *assert_is_function()*, *assert_function()*
+
+ Assert that the argument is a function.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+.. function:: assertIsUserdata(value [, extra_msg])
+
+ **Aliases**: *assertUserdata()*, *assert_is_userdata()*, *assert_userdata()*
+
+ Assert that the argument is a userdata.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+.. function:: assertIsCoroutine(value [, extra_msg])
+
+ **Aliases**: *assertCoroutine()*, *assert_is_coroutine()*, *assert_coroutine()*
+
+ Assert that the argument is a coroutine (an object with type *thread* ).
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+.. function:: assertIsThread(value [, extra_msg])
+
+ **Aliases**: *assertIsThread()*, *assertThread()*, *assert_is_thread()*, *assert_thread()*
+
+ Same function as :func:assertIsCoroutine . Since Lua coroutines have the type thread, it's not
+ clear which name is the clearer, so we provide syntax for both names.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+
+.. _assert-table:
+
+Table assertions
+--------------------------
+
+.. function:: assertItemsEquals(actual, expected [, extra_msg])
+
+ **Alias**: *assert_items_equals()*
+
+ Assert that two tables contain the same items, irrespective of their keys.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+ This function is practical for example if you want to compare two lists but
+ where items are not in the same order:
+
+.. code-block:: lua
+
+ lu.assertItemsEquals( {1,2,3}, {3,2,1} ) -- assertion succeeds
+
+..
+
+ The comparison is not recursive on the items: if any of the items are tables,
+ they are compared using table equality (like as in :func:`assertEquals` ), where
+ the key matters.
+
+
+.. code-block:: lua
+
+ lu.assertItemsEquals( {1,{2,3},4}, {4,{3,2,},1} ) -- assertion fails because {2,3} ~= {3,2}
+
+
+
+.. function:: assertTableContains(table, element [, extra_msg])
+
+ **Alias**: *assert_table_contains()*
+
+ Assert that the table contains at least one key with value `element`. Element
+ may be of any type (including table), the recursive equality algorithm of assertEquals()
+ is used for verifying the presence of the element.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+.. code-block:: lua
+
+ lu.assertTableContains( {'a', 'b', 'c', 'd'}, 'b' ) -- assertion succeeds
+ lu.assertTableContains( {1, 2, 3, {4} }, {4} } -- assertion succeeds
+
+
+.. function:: assertNotTableContains(table, element [, extra_msg])
+
+ **Alias**: *assert_not_table_contains()*
+
+ Negative version of :func:`assertTableContains` .
+
+ Assert that the table contains no element with value `element`. Element
+ may be of any type (including table), the recursive equality algorithm of assertEquals()
+ is used for verifying the presence of the element.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+.. code-block:: lua
+
+ lu.assertNotTableContains( {'a', 'b', 'c', 'd'}, 'e' ) -- assertion succeeds
+ lu.assertNotTableContains( {1, 2, 3, {4} }, {5} } -- assertion succeeds
+
+
+
+
+Scientific computing and LuaUnit
+--------------------------------
+
+LuaUnit is used by the CERN for the MAD-NG program, the forefront of computational physics in the field of particle accelerator design and simulation (See MAD_). Thank to the feedback of a scientific computing developer, LuaUnit has been enhanced with some facilities for scientific applications (see all assertions functions below).
+
+.. _MAD: http://mad.web.cern.ch/mad/
+
+The floating point library used by Lua is the one provided by the C compiler which built Lua. It is usually compliant with IEEE-754_ . As such,
+it can yields results such as *plus infinity*, *minus infinity* or *Not a Number* (NaN). The precision of any calculation performed in Lua is
+related to the smallest representable floating point value (typically called *EPS*): 2^-52 for 64 bits floats (type double in the C language) and 2^-23 for 32 bits float
+(type float in C).
+
+.. _IEEE-754: https://en.wikipedia.org/wiki/IEEE_754
+
+.. Note :: Lua may be compiled with numbers represented either as 32 bits floats or 64 bits double (as defined by the macro LUA_FLOAT_TYPE in luaconf.h ). LuaUnit has been validated in both these configurations and in particuluar, the epsilon value *EPS* is adjusted accordingly.
+
+For more information about performing calculations on computers, please read the reference paper `What Every Computer Scientist Should Know About Floating-Point Arithmetic`_
+
+.. _What Every Computer Scientist Should Know About Floating-Point Arithmetic: https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
+
+If your calculation shall be portable to multiple OS or compilers, you may get different calculation errors depending on the OS/compiler. It is therefore important to verify them on every target.
+
+
+.. _MinusZero:
+
+.. Note on minus zero::
+ If you need to deal with value *minus zero*, be very careful because Lua versions are inconsistent on how they treat the syntax *-0* : it creates either
+ a *plus zero* or a *minus zero* . Multiplying or dividing *0* by *-1* also yields inconsistent results. The reliable way to create the *-0*
+ value is : minusZero = -1 / (1/0)
+
+
+.. _EPS:
+
+**EPS** *constant*
+
+The machine epsilon, to be used with :func:`assertAlmostEquals` .
+
+This is either:
+
+* 2^-52 or ~2.22E-16 (with lua number defined as double)
+* 2^-23 or ~1.19E-07 (with lua number defined as float)
+
+
+.. function:: assertNan( value [, extra_msg])
+
+ **Alias**: *assert_nan()*
+
+ Assert that a given number is a *NaN* (Not a Number), according to the definition of IEEE-754_ .
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+
+.. function:: assertNotNan( value [, extra_msg])
+
+ **Alias**: *assert_not_nan()*
+
+ Assert that a given number is NOT a *NaN* (Not a Number), according to the definition of IEEE-754_ .
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+
+.. function:: assertPlusInf( value [, extra_msg])
+
+ **Alias**: *assert_plus_inf()*
+
+ Assert that a given number is *plus infinity*, according to the definition of IEEE-754_ .
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+
+.. function:: assertMinusInf( value [, extra_msg])
+
+ **Alias**: *assert_minus_inf()*
+
+ Assert that a given number is *minus infinity*, according to the definition of IEEE-754_ .
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+
+.. function:: assertInf( value [, extra_msg])
+
+ **Alias**: *assert_inf()*
+
+ Assert that a given number is *infinity* (either positive or negative), according to the definition of IEEE-754_ .
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+
+.. function:: assertNotPlusInf( value [, extra_msg])
+
+ **Alias**: *assert_not_plus_inf()*
+
+ Assert that a given number is NOT *plus infinity*, according to the definition of IEEE-754_ .
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+
+.. function:: assertNotMinusInf( value [, extra_msg])
+
+ **Alias**: *assert_not_minus_inf()*
+
+ Assert that a given number is NOT *minus infinity*, according to the definition of IEEE-754_ .
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+
+.. function:: assertNotInf( value [, extra_msg])
+
+ **Alias**: *assert_not_inf()*
+
+ Assert that a given number is neither *infinity* nor *minus infinity*, according to the definition of IEEE-754_ .
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+
+.. function:: assertPlusZero( value [, extra_msg])
+
+ **Alias**: *assert_plus_zero()*
+
+ Assert that a given number is *+0*, according to the definition of IEEE-754_ . The
+ verification is done by dividing by the provided number and verifying that it yields
+ *infinity* . If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+ Be careful when dealing with *+0* and *-0*, see note above.
+
+
+.. function:: assertMinusZero( value [, extra_msg])
+
+ **Alias**: *assert_minus_zero()*
+
+ Assert that a given number is *-0*, according to the definition of IEEE-754_ . The
+ verification is done by dividing by the provided number and verifying that it yields
+ *minus infinity* . If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+ Be careful when dealing with *+0* and *-0*, see MinusZero_
+
+
+.. function:: assertNotPlusZero( value [, extra_msg])
+
+ **Alias**: *assert_not_plus_zero()*
+
+ Assert that a given number is NOT *+0*, according to the definition of IEEE-754_ .
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+ Be careful when dealing with *+0* and *-0*, see MinusZero_
+
+
+.. function:: assertNotMinusZero( value [, extra_msg])
+
+ **Alias**: *assert_not_minus_zero()*
+
+ Assert that a given number is NOT *-0*, according to the definition of IEEE-754_ .
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+ Be careful when dealing with *+0* and *-0*, see MinusZero_
+
+
+.. function:: assertAlmostEquals( actual, expected [, margin=EPS [, extra_msg]] )
+
+ **Alias**: *assert_almost_equals()*
+
+ Assert that two floating point numbers or tables are equal by the defined margin.
+ If margin is not provided, the machine epsilon *EPS* is used.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+ The function accepts either floating point numbers or tables. Complex structures with
+ nested tables are supported. Comparing tables with assertAlmostEquals works just like :func:`assertEquals`
+ with the difference that values are compared with a margin instead of with direct equality.
+
+ Be careful that depending on the calculation, it might make more sense to measure
+ the absolute error or the relative error (see below):
+
+
+.. function:: assertNotAlmostEquals( actual, expected [, margin=EPS [, extra_msg]] )
+
+ **Alias**: *assert_not_almost_equals()*
+
+ Assert that two floating point numbers are not equal by the defined margin.
+ If margin is not provided, the machine epsilon *EPS* is used.
+ If provided, *extra_msg* is a string which will be printed along with the failure message.
+
+ Be careful that depending on the calculation, it might make more sense to measure
+ the absolute error or the relative error (see below).
+
+**Example of absolute versus relative error**
+
+.. code-block:: lua
+
+ -- convert pi/6 radian to 30 degree
+ pi_div_6_deg_calculated = math.deg(math.pi/6)
+ pi_div_6_deg_expected = 30
+
+ -- convert pi/3 radian to 60 degree
+ pi_div_3_deg_calculated = math.deg(math.pi/3)
+ pi_div_3_deg_expected = 60
+
+ -- check absolute error: it is not constant
+ print( (pi_div_6_deg_expected - pi_div_6_deg_calculated) / lu.EPS ) -- prints: 16
+ print( (pi_div_3_deg_expected - pi_div_3_deg_calculated) / lu.EPS ) -- prints: 32
+
+ -- Better use relative error:
+ print( ( (pi_div_6_deg_expected - pi_div_6_deg_calculated) / pi_div_6_deg_expected) / lu.EPS ) -- prints: 0.53333
+ print( ( (pi_div_3_deg_expected - pi_div_3_deg_calculated) / pi_div_3_deg_expected) / lu.EPS ) -- prints: 0.53333
+
+ -- relative error is constant. Assertion can take the form of:
+ assertAlmostEquals( (pi_div_6_deg_expected - pi_div_6_deg_calculated) / pi_div_6_deg_expected, lu.EPS )
+ assertAlmostEquals( (pi_div_3_deg_expected - pi_div_3_deg_calculated) / pi_div_3_deg_expected, lu.EPS )
+
+
+Pretty printing
+----------------
+
+.. function:: prettystr( value )
+
+ Converts *value* to a nicely formatted string, whatever the type of the value.
+ It supports in particular tables, nested table and even recursive tables.
+
+ You can use it in your code to replace calls to *tostring()* .
+
+**Example of prettystr()**
+
+.. code-block::
+
+ > lu = require('luaunit')
+ > t1 = {1,2,3}
+ > t1['toto'] = 'titi'
+ > t1.f = function () end
+ > t1.fa = (1 == 0)
+ > t1.tr = (1 == 1)
+ > print( lu.prettystr(t1) )
+ {1, 2, 3, f=function: 00635d68, fa=false, toto="titi", tr=true}
+
+
+.. _luaunit-global-asserts:
+
+Enabling global or module-level functions
+=========================================
+
+Versions of LuaUnit before version 3.1 would export all assertions functions to the global namespace. A typical
+lua test file would look like this:
+
+.. code-block:: lua
+
+ require('luaunit')
+
+ TestToto = {} --class
+
+ function TestToto:test1_withFailure()
+ local a = 1
+ assertEquals( a , 1 )
+ -- will fail
+ assertEquals( a , 2 )
+ end
+
+ [...]
+
+However, this is an obsolete practice in Lua. It is now recommended to keep all functions inside the module. Starting
+from version 3.1 LuaUnit follows this practice and the code should be adapted to look like this:
+
+.. code-block:: lua
+
+ -- the imported module must be stored
+ lu = require('luaunit')
+
+ TestToto = {} --class
+
+ function TestToto:test1_withFailure()
+ local a = 1
+ lu.assertEquals( a , 1 )
+ -- will fail
+ lu.assertEquals( a , 2 )
+ end
+
+ [...]
+
+If you prefer the old way, LuaUnit can continue to export assertions functions if you set the following
+global variable **prior** to importing LuaUnit:
+
+.. code-block:: lua
+
+ -- this works
+ EXPORT_ASSERT_TO_GLOBALS = true
+ require('luaunit')
+
+ TestToto = {} --class
+
+ function TestToto:test1_withFailure()
+ local a = 1
+ assertEquals( a , 1 )
+ -- will fail
+ assertEquals( a , 2 )
+ end
+
+ [...]
+
+
+Variables controlling LuaUnit behavior
+=========================================
+
+luaunit.ORDER_ACTUAL_EXPECTED
+------------------------------
+
+This boolean value defines the order of arguments in assertion functions.
+
+For example, in the code `luaunit.assertEquals( a, b )` , LuaUnit will treat by default
+`a` as a calculated value under test (actual value) and `b` as a reference value aginst which `a` is
+compared (expected value). This will show up in the error reported for the test:
+
+.. code-block:: shell
+
+ 1) TestWithFailures.testFail1
+ doc\my_test_suite_with_failures.lua:79: expected: "titi"
+ actual: "toto"
+
+If you prefer the opposite convention, i.e having the expected argument as first
+and actual argument as second, set the *ORDER_ACTUAL_EXPECTED* to *false*.
+
+
+luaunit.PRINT_TABLE_REF_IN_ERROR_MSG
+------------------------------------------
+
+This controls whether table references are always printed along with table or not. See `table-printing`_ for details. The
+default is `false`.
+
+
+.. _strip_extra_entries_in_stack_trace:
+
+luaunit.STRIP_EXTRA_ENTRIES_IN_STACK_TRACE
+------------------------------------------
+
+This controls how many extra entries in a stack-trace are stripped. By default, LuaUnit hides all its internals
+functions to show only user code in the error stack trace. However, if LuaUnit is used as part of another test
+framework, and one wants to also hide this global test framework entries, you can increase the number here. The default
+is *0* .
+
+
+luaunit.VERSION
+------------------------------------------
+
+Current version of LuaUnit as a string.
+
+
+Developing LuaUnit
+******************
+
+Development ecosystem
+======================
+
+LuaUnit is developed on `GitHub`_.
+
+.. _GitHub: https://github.com/bluebird75/luaunit
+
+Bugs or feature requests should be reported using `GitHub issues`_.
+
+.. _GitHub issues: https://github.com/bluebird75/luaunit/issues
+
+LuaUnit is released under the BSD license.
+
+This documentation is available at `Read-the-docs`_.
+
+.. _Read-the-docs: http://luaunit.readthedocs.org/en/latest/
+
+
+Contributing
+=============
+You may contribute to LuaUnit by reporting bugs or wishes, or by contributing code directly with a pull request.
+
+Some issues on GitHub are marked with label *enhancement*. Feel also free to pick up such tasks and implement them.
+
+Changes should be proposed as *Pull Requests* on GitHub.
+
+Thank to our continuous integration setup with Travis-Ci and AppVeyor, all unit-tests and functional tests are run on Linux, Windows and MacOs, with all versions of Lua. So
+any *Pull Request* will show immediately if anything is going unexpected.
+
+
+Running unit-tests
+-------------------
+All proposed changes should pass all unit-tests and if needed, add more unit-tests to cover the bug or the new functionality. Usage is pretty simple:
+
+.. code-block:: shell
+
+ $ lua run_unit_tests.lua
+ ................................................................................
+ ...............................
+ Ran 111 tests in 0.120 seconds
+ OK
+
+
+Running functional tests
+----------------------------
+Functional tests also exist to validate LuaUnit. Their management is slightly more complicated.
+
+The main goal of functional tests is to validate that LuaUnit output has not been altered. Since LuaUnit supports some standard compliant output (TAP, junitxml), this is very important (and it has been broken in the past).
+
+Functional tests perform the following actions:
+
+* Run the 2 suites: example_with_luaunit.lua, test_with_err_fail_pass.lua (with various options to have successe, failure and/or errors)
+* Run every suite with all output format, all verbosity
+* Validate the XML output with jenkins/hudson and junit schema
+* Compare the results with the reference output ( archived in test/ref ), with some tricks to make the comparison possible :
+
+ * adjustment of the file separator to use the same output on Windows and Unix
+ * date and test duration is zeroed so that it does not impact the comparison
+ * adjust the stack trace format which has changed between Lua 5.1, 5.2 and 5.3
+
+* Run some legacy suites or tricky output to manage and verify output: test_with_xml.lua, , compat_luaunit_v2x.lua, legacy_example_with_luaunit.lua
+
+
+For functional tests to run, *diff* must be available on the command line. *xmllint* is needed to perform the xml validation but
+this step is skipped if *xmllint* can not be found.
+
+When functional tests work well, it looks like this:
+
+.. code-block:: shell
+
+ $ lua run_functional_tests.lua
+ ...............
+ Ran 15 tests in 9.676 seconds
+ OK
+
+
+When functional test fail, a diff of the comparison between the reference output and the current output is displayed (it can be quite
+long). The list of faulty files is summed-up at the end.
+
+
+Modifying reference files for functional tests
+-----------------------------------------------
+The script run_functional_tests.lua supports a --update option, with an optional argument.
+
+* *--update* without argument **overwrites all reference output** with the current output. Use only if you know what you are doing, this is usually a very bad idea!
+
+* The following argument overwrite a specific subset of reference files, select the one that fits your change:
+
+ * TestXml: XML output of test_with_xml
+ * ExampleXml: XML output of example_with_luaunit
+ * ExampleTap: TAP output of example_with_luaunit
+ * ExampleText: text output of example_with_luaunit
+ * ExampleNil: nil output of example_with_luaunit
+ * ErrFailPassText: text output of test_with_err_fail_pass
+ * ErrFailPassTap: TAP output of test_with_err_fail_pass
+ * ErrFailPassXml: XML output of test_with_err_fail_pass
+ * StopOnError: errFailPassTextStopOnError-1.txt, -2.txt, -3.txt, -4.txt
+
+
+For example to record a change in the test_with_err_fail_pass output
+
+.. code-block:: shell
+
+ $ lua run_functional_tests.lua --update ErrFailPassXml ErrFailPassTap ErrFailPassText
+
+ >>>>>>> Generating test/ref/errFailPassXmlDefault.txt
+ >>>>>>> Generating test/ref/errFailPassXmlDefault-success.txt
+ >>>>>>> Generating test/ref/errFailPassXmlDefault-failures.txt
+ >>>>>>> Generating test/ref/errFailPassXmlQuiet.txt
+ >>>>>>> Generating test/ref/errFailPassXmlQuiet-success.txt
+ >>>>>>> Generating test/ref/errFailPassXmlQuiet-failures.txt
+ >>>>>>> Generating test/ref/errFailPassXmlVerbose.txt
+ >>>>>>> Generating test/ref/errFailPassXmlVerbose-success.txt
+ >>>>>>> Generating test/ref/errFailPassXmlVerbose-failures.txt
+ >>>>>>> Generating test/ref/errFailPassTapDefault.txt
+ >>>>>>> Generating test/ref/errFailPassTapDefault-success.txt
+ >>>>>>> Generating test/ref/errFailPassTapDefault-failures.txt
+ >>>>>>> Generating test/ref/errFailPassTapQuiet.txt
+ >>>>>>> Generating test/ref/errFailPassTapQuiet-success.txt
+ >>>>>>> Generating test/ref/errFailPassTapQuiet-failures.txt
+ >>>>>>> Generating test/ref/errFailPassTapVerbose.txt
+ >>>>>>> Generating test/ref/errFailPassTapVerbose-success.txt
+ >>>>>>> Generating test/ref/errFailPassTapVerbose-failures.txt
+ >>>>>>> Generating test/ref/errFailPassTextDefault.txt
+ >>>>>>> Generating test/ref/errFailPassTextDefault-success.txt
+ >>>>>>> Generating test/ref/errFailPassTextDefault-failures.txt
+ >>>>>>> Generating test/ref/errFailPassTextQuiet.txt
+ >>>>>>> Generating test/ref/errFailPassTextQuiet-success.txt
+ >>>>>>> Generating test/ref/errFailPassTextQuiet-failures.txt
+ >>>>>>> Generating test/ref/errFailPassTextVerbose.txt
+ >>>>>>> Generating test/ref/errFailPassTextVerbose-success.txt
+ >>>>>>> Generating test/ref/errFailPassTextVerbose-failures.txt
+ $
+
+You can then commit the new files into git.
+
+.. Note :: how to commit updated reference outputs
+
+ When committing those changes into git, please use if possible an
+ intelligent git committing tool to commit only the interesting changes.
+ With SourceTree or SublimeMerge for example, in case of XML changes, I can select only the
+ lines relevant to the change and avoid committing all the updates to test
+ duration and test datestamp.
+
+
+
+Typical failures for functional tests
+---------------------------------------
+
+Functional tests may start failing when:
+
+1. Increasing LuaUnit version
+2. Improving or breaking LuaUnit output
+
+This a good place to start looking if you see failures occurring.
+
+
+Using doit.py
+--------------
+
+The utility *doit.py* is a useful developer tool to repeat common developer commands.
+
+**Running syntax check**
+
+.. code-block:: shell
+
+ doit.py luacheck
+
+Run luacheck on the LuaUnit code.
+
+
+**Running unit-tests**
+
+.. code-block:: shell
+
+ doit.py rununittests
+
+Use it to run all unit tests, on all installed versions of Lua on the sytem.
+
+
+**Running all tests**
+
+.. code-block:: shell
+
+ doit.py runtests
+
+Run luacheck then run unit-tests then run functional tests. Just like the continuous integration.
+
+**Creating documentation**
+
+.. code-block:: shell
+
+ doit.py makedoc
+
+Runs sphinx to generate the html documentation. You must have sphinx installed on your path.
+
+
+**Preparing a release**
+
+.. code-block:: shell
+
+ doit.py buildrock
+
+Create a rock file ready to be uploaded to luarocks, containing a clone of the current git, with documentation generated
+README and LICENSE, tests, and everything else stripped out.
+
+
+.. code-block:: shell
+
+ doit.py packageit
+
+Create a zip and tar.gz archive suitable to be uploaded to github. The archive is composed of a clone
+of the current git content, stripped from everything not related to using luaunit (no CI files, no doit.lu, ...)
+but with full documentation generated.
+
+
+Process of releasing a new version of LuaUnit
+=============================================
+
+The steps are the following:
+
+* update luaunit with the desired functionality, ready for a release
+* update the version number in luaunit.lua
+* update the version number in doit.py
+* check that all tests pass on all supported lua versions
+
+.. code-block:: shell
+
+ doit.py runtests
+
+* update *examples* if needed to reflect new features
+* update index.rst with documentation of new features/behavior
+* update README.md and index.rst with the release information (date and content)
+* generate package for github:
+
+.. code-block:: shell
+
+ doit.py packageit
+
+* verify the content of the packages:
+ * documentation must be properly generated
+ * examples should work
+ * unit-tests should pass
+
+
+
+Annexes
+********
+
+.. _table-printing:
+
+Annex A: More on table printing
+================================
+
+When asserting tables equality, by default, the table content is printed in case of failures. LuaUnit tries to print
+tables in a readable format. It is
+possible to always display the table id along with the content, by setting a module parameter PRINT_TABLE_REF_IN_ERROR_MSG . This
+helps identifying tables:
+
+.. code-block:: lua
+
+ local lu = require('luaunit')
+
+ local t1 = {1,2,3}
+ -- normally, t1 is dispalyed as: "{1,2,3}"
+
+ -- if setting this:
+ lu.PRINT_TABLE_REF_IN_ERROR_MSG = true
+
+ -- display of table t1 becomes: "<table: 0x29ab56> {1,2,3}"
+
+
+.. Note :: table loops
+
+ When displaying table content, it is possible to encounter loops, if for example two table references eachother. In such
+ cases, LuaUnit display the full table content once, along with the table id, and displays only the table id for the looping
+ reference.
+
+**Example:** displaying a table with reference loop
+
+.. code-block:: lua
+
+ local t1 = {}
+ local t2 = {}
+ t1.t2 = t2
+ t1.a = {1,2,3}
+ t2.t1 = t1
+
+ -- when displaying table t1:
+ -- table t1 inside t2 is only displayed by its id because t1 is already being displayed
+ -- table t2 is displayed along with its id because it is part of a loop.
+ -- t1: "<table: 0x29ab56> { a={1,2,3}, t2=<table: 0x27ab23> {t1=<table: 0x29ab56>} }"
+
+
+.. _comparing-table-keys-table:
+
+Annex B: Comparing tables with keys of type table
+==================================================
+
+There are a few programs out there which use tables as keys for other tables. How to compare
+such tables is delicate.
+
+A small code block is worth a thousand pictures :
+
+.. code-block:: lua
+
+ local lu = require('luaunit')
+
+ -- let's define two tables
+ t1 = { 1, 2 }
+ t2 = { 1, 2 }
+ lu.assertEquals( t1, t2 ) -- succeeds
+
+ -- let's define three tables, with the two above tables as keys
+ t3 = { t1='a' }
+ t4 = { t2='a' }
+ t5 = { t2='a' }
+
+
+The difference between t3 and t4 is that they both reference a key with different table references but
+identical table content.
+
+LuaUnit chooses to treat this as two different keys, so t3 and t4 are not considered equal.
+
+.. code-block:: lua
+
+ lu.assertEquals( t3, t4 ) -- fails
+
+
+If using the same table as key, they are now considered equal:
+
+.. code-block:: lua
+
+ lu.assertEquals( t4, t5 ) -- fails
+
+
+.. _Source_code_example:
+
+Annex C: Source code of example
+=================================
+
+Source code of the example used in the `Getting started with LuaUnit`_
+
+.. code-block:: lua
+
+ --
+ -- The examples described in the documentation are below.
+ --
+
+ lu = require('luaunit')
+
+ function add(v1,v2)
+ -- add positive numbers
+ -- return 0 if any of the numbers are 0
+ -- error if any of the two numbers are negative
+ if v1 < 0 or v2 < 0 then
+ error('Can only add positive or null numbers, received '..v1..' and '..v2)
+ end
+ if v1 == 0 or v2 == 0 then
+ return 0
+ end
+ return v1+v2
+ end
+
+ function adder(v)
+ -- return a function that adds v to its argument using add
+ function closure( x ) return x+v end
+ return closure
+ end
+
+ function div(v1,v2)
+ -- divide positive numbers
+ -- return 0 if any of the numbers are 0
+ -- error if any of the two numbers are negative
+ if v1 < 0 or v2 < 0 then
+ error('Can only divide positive or null numbers, received '..v1..' and '..v2)
+ end
+ if v1 == 0 or v2 == 0 then
+ return 0
+ end
+ return v1/v2
+ end
+
+
+
+ TestAdd = {}
+ function TestAdd:testAddPositive()
+ lu.assertEquals(add(1,1),2)
+ end
+
+ function TestAdd:testAddZero()
+ lu.assertEquals(add(1,0),0)
+ lu.assertEquals(add(0,5),0)
+ lu.assertEquals(add(0,0),0)
+ end
+
+ function TestAdd:testAddError()
+ lu.assertErrorMsgContains('Can only add positive or null numbers, received 2 and -3', add, 2, -3)
+ end
+
+ function TestAdd:testAdder()
+ f = adder(3)
+ lu.assertIsFunction( f )
+ lu.assertEquals( f(2), 5 )
+ end
+ -- end of table TestAdd
+
+ TestDiv = {}
+ function TestDiv:testDivPositive()
+ lu.assertEquals(div(4,2),2)
+ end
+
+ function TestDiv:testDivZero()
+ lu.assertEquals(div(4,0),0)
+ lu.assertEquals(div(0,5),0)
+ lu.assertEquals(div(0,0),0)
+ end
+
+ function TestDiv:testDivError()
+ lu.assertErrorMsgContains('Can only divide positive or null numbers, received 2 and -3', div, 2, -3)
+ end
+ -- end of table TestDiv
+
+ --[[
+ --
+ -- Uncomment this section to see how failures are displayed
+ --
+ TestWithFailures = {}
+ -- two failing tests
+
+ function TestWithFailures:testFail1()
+ lu.assertEquals( "toto", "titi")
+ end
+
+ function TestWithFailures:testFail2()
+ local a=1
+ local b='toto'
+ local c = a + b -- oops, can not add string and numbers
+ return c
+ end
+ -- end of table TestWithFailures
+ ]]
+
+
+ --[[
+ TestLogger = {}
+ function TestLogger:setUp()
+ -- define the fname to use for logging
+ self.fname = 'mytmplog.log'
+ -- make sure the file does not already exists
+ os.remove(self.fname)
+ end
+
+ function TestLogger:testLoggerCreatesFile()
+ initLog(self.fname)
+ log('toto')
+ f = io.open(self.fname, 'r')
+ lu.assertNotNil( f )
+ f:close()
+ end
+
+ function TestLogger:tearDown()
+ self.fname = 'mytmplog.log'
+ -- cleanup our log file after all tests
+ os.remove(self.fname)
+ end
+ -- end of table TestLogger
+
+ ]]
+
+ os.exit(lu.LuaUnit.run())
+
+
+
+
+Annex D: BSD License
+====================
+
+ This software is distributed under the BSD License.
+
+ Copyright (c) 2005-2018, Philippe Fremy <phil at freehackers dot org>
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+Index and Search page
+**********************
+
+* :ref:`genindex`
+* :ref:`search`
+
diff --git a/Data/Libraries/luaunit/doc/make.bat b/Data/Libraries/luaunit/doc/make.bat
new file mode 100644
index 0000000..25eb454
--- /dev/null
+++ b/Data/Libraries/luaunit/doc/make.bat
@@ -0,0 +1,241 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. xml to make Docutils-native XML files
+ echo. pseudoxml to make pseudoxml-XML files for display purposes
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+%SPHINXBUILD% 1> nul 2> nul
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.http://sphinx-doc.org/
+ exit /b 1
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\LuaUnit.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\LuaUnit.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "latexpdf" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ cd %BUILDDIR%/latex
+ make all-pdf
+ cd %BUILDDIR%/..
+ echo.
+ echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "latexpdfja" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ cd %BUILDDIR%/latex
+ make all-pdf-ja
+ cd %BUILDDIR%/..
+ echo.
+ echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+if "%1" == "xml" (
+ %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The XML files are in %BUILDDIR%/xml.
+ goto end
+)
+
+if "%1" == "pseudoxml" (
+ %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
+ goto end
+)
+
+:end
diff --git a/Data/Libraries/luaunit/doc/my_test_suite.lua b/Data/Libraries/luaunit/doc/my_test_suite.lua
new file mode 100644
index 0000000..8fec554
--- /dev/null
+++ b/Data/Libraries/luaunit/doc/my_test_suite.lua
@@ -0,0 +1,127 @@
+
+--
+-- The examples described in the documentation are below.
+--
+
+lu = require('luaunit')
+
+function add(v1,v2)
+ -- add positive numbers
+ -- return 0 if any of the numbers are 0
+ -- error if any of the two numbers are negative
+ if v1 < 0 or v2 < 0 then
+ error('Can only add positive or null numbers, received '..v1..' and '..v2)
+ end
+ if v1 == 0 or v2 == 0 then
+ return 0
+ end
+ return v1+v2
+end
+
+function adder(v)
+ -- return a function that adds v to its argument using add
+ function closure( x ) return x+v end
+ return closure
+end
+
+function div(v1,v2)
+ -- divide positive numbers
+ -- return 0 if any of the numbers are 0
+ -- error if any of the two numbers are negative
+ if v1 < 0 or v2 < 0 then
+ error('Can only divide positive or null numbers, received '..v1..' and '..v2)
+ end
+ if v1 == 0 or v2 == 0 then
+ return 0
+ end
+ return v1/v2
+end
+
+
+
+TestAdd = {}
+ function TestAdd:testAddPositive()
+ lu.assertEquals(add(1,1),2)
+ end
+
+ function TestAdd:testAddZero()
+ lu.assertEquals(add(1,0),0)
+ lu.assertEquals(add(0,5),0)
+ lu.assertEquals(add(0,0),0)
+ end
+
+ function TestAdd:testAddError()
+ lu.assertErrorMsgContains('Can only add positive or null numbers, received 2 and -3', add, 2, -3)
+ end
+
+ function TestAdd:testAdder()
+ f = adder(3)
+ lu.assertIsFunction( f )
+ lu.assertEquals( f(2), 5 )
+ end
+-- end of table TestAdd
+
+TestDiv = {}
+ function TestDiv:testDivPositive()
+ lu.assertEquals(div(4,2),2)
+ end
+
+ function TestDiv:testDivZero()
+ lu.assertEquals(div(4,0),0)
+ lu.assertEquals(div(0,5),0)
+ lu.assertEquals(div(0,0),0)
+ end
+
+ function TestDiv:testDivError()
+ lu.assertErrorMsgContains('Can only divide positive or null numbers, received 2 and -3', div, 2, -3)
+ end
+-- end of table TestDiv
+
+--[[
+--
+-- Uncomment this section to see how failures are displayed
+--
+TestWithFailures = {}
+ -- two failing tests
+
+ function TestWithFailures:testFail1()
+ lu.assertEquals( "toto", "titi")
+ end
+
+ function TestWithFailures:testFail2()
+ local a=1
+ local b='toto'
+ local c = a + b -- oops, can not add string and numbers
+ return c
+ end
+-- end of table TestWithFailures
+]]
+
+
+--[[
+TestLogger = {}
+ function TestLogger:setUp()
+ -- define the fname to use for logging
+ self.fname = 'mytmplog.log'
+ -- make sure the file does not already exists
+ os.remove(self.fname)
+ end
+
+ function TestLogger:testLoggerCreatesFile()
+ initLog(self.fname)
+ log('toto')
+ f = io.open(self.fname, 'r')
+ lu.assertNotNil( f )
+ f:close()
+ end
+
+ function TestLogger:tearDown()
+ self.fname = 'mytmplog.log'
+ -- cleanup our log file after all tests
+ os.remove(self.fname)
+ end
+-- end of table TestLogger
+
+]]
+
+os.exit(lu.LuaUnit.run())
diff --git a/Data/Libraries/luaunit/doit.py b/Data/Libraries/luaunit/doit.py
new file mode 100644
index 0000000..41dd38d
--- /dev/null
+++ b/Data/Libraries/luaunit/doit.py
@@ -0,0 +1,237 @@
+# My universal runner for this project, the equivalent of a Makefile
+import subprocess, sys, os, shutil, os.path, glob
+
+VERSION='3.4'
+RELEASE_NAME='luaunit-%s' % VERSION
+ROCK_RELEASE_NAME='rock-%s' % RELEASE_NAME
+RELEASE_DIR='release/' + RELEASE_NAME + '/'
+RELEASE_TAG='LUAUNIT_V' + VERSION.replace('.', '_')
+TARGET_ZIP=RELEASE_NAME + '.zip'
+TARGET_TGZ=RELEASE_NAME + '.tgz'
+REPO_PATH='d:/work/luaunit/luaunit1'
+
+PATH_LUACHECK='d:\\program\\dev\\lua\\luarocks\\systree\\bin\\luacheck.bat'
+
+LUA51='d:/program/dev/lua/lua51/lua51.exe'
+LUA52='d:/program/dev/lua/lua52/lua52.exe'
+LUA53='d:/program/dev/lua/lua53/lua53.exe'
+LUA54='d:/program/dev/lua/lua54/lua54.exe'
+LUAJIT='d:/program/dev/lua/luajit/luajit.exe'
+LUAJIT21='d:/program/dev/lua/luajit21/luajit.exe'
+
+ALL_LUA = (
+ (LUA54, 'Lua 5.4'),
+ (LUA53, 'Lua 5.3'),
+ (LUA52, 'Lua 5.2'),
+ (LUA51, 'Lua 5.1'),
+ (LUAJIT, 'Lua JIT 2.0'),
+ (LUAJIT21, 'Lua JIT 2.1'),
+)
+
+os.environ["nodosfilewarning"] = "1"
+
+def report( s ):
+ print( '[[[[[[[[[[[[[ %s ]]]]]]]]]]]]]' % s )
+
+def run_unit_tests():
+ '''Run unit-tests with all versions of lua'''
+ for lua, luaversion in ALL_LUA:
+ report( 'Running unit-tests tests with %s' % luaversion )
+ retcode = subprocess.call( [lua, 'run_unit_tests.lua', '--shuffle'] )
+ if retcode != 0:
+ report( 'Invalid retcode when running tests: %d' % retcode )
+ sys.exit( retcode )
+
+def run_tests(with_linting=True):
+ '''Run tests with all versions of lua'''
+ run_luacheck()
+ run_unit_tests()
+
+ for lua, luaversion in ALL_LUA:
+ report( 'Running functional tests tests with %s' % luaversion )
+ args = [lua, 'run_functional_tests.lua']
+ if with_linting:
+ args.append('--with-linting')
+ retcode = subprocess.call( args )
+ if retcode != 0:
+ report( 'Invalid retcode when running tests: %d' % retcode )
+ sys.exit( retcode )
+
+ report( 'All tests succeed!' )
+
+def run_luacheck():
+ report('Running luacheck')
+ subprocess.check_call([PATH_LUACHECK, 'example_with_luaunit.lua', 'luaunit.lua', 'run_unit_tests.lua', 'run_functional_tests.lua', 'test/'],
+ shell=True)
+
+def run_example():
+ for lua, luaversion in ALL_LUA:
+ report( 'Running examples with %s' % luaversion )
+ retcode = subprocess.call( [lua, 'example_with_luaunit.lua'] )
+ if retcode != 12:
+ report( 'Invalid retcode when running examples: %d' % retcode )
+ sys.exit( retcode )
+ report( 'All examples ran!' )
+
+
+def pre_packageit_or_buildrock_step1():
+ '''
+ - create a release directory
+ - export the content of the git project but strips
+ * git stuff
+ * CI stuff (travis, appveyor)
+ * doit.py, todo.txt
+ * junitxml directory
+ * rockspec
+ * build documentation and move the html documentation to just doc
+ '''
+ # shutil.rmtree('release', True)
+ try:
+ os.mkdir('release')
+ except OSError:
+ pass
+ subprocess.check_call(['d:/program/utils/Git/bin/git.exe', 'clone', '--no-hardlinks', '--branch', RELEASE_TAG, REPO_PATH, RELEASE_DIR])
+
+ os.chdir( RELEASE_DIR )
+
+ # Release dir cleanup.
+ shutil.rmtree('.git')
+ os.unlink('.gitignore')
+ shutil.rmtree('.travis')
+ os.unlink('.travis.yml')
+ shutil.rmtree('.appveyor')
+ os.unlink('appveyor.yml')
+ os.unlink('doit.py')
+ os.unlink('TODO.txt')
+ shutil.rmtree('junitxml/')
+
+ for p in glob.glob('*.rockspec'):
+ os.unlink(p)
+
+ makedoc()
+ # doc cleanup and simplification
+ os.rename( 'doc', 'olddoc' )
+ shutil.copytree( 'olddoc/html', 'doc')
+ os.unlink('doc/.buildinfo')
+ shutil.copy( 'olddoc/my_test_suite.lua', 'doc')
+ shutil.rmtree('olddoc/')
+
+ run_tests(False)
+ run_example()
+ os.unlink('.luacheckrc') # keep it to run the tests successfully
+
+def packageit():
+ '''Generate zip and targz archives for a release to GitHub
+ '''
+
+ pre_packageit_or_buildrock_step1()
+
+ # Packaging into zip and tgz
+ os.chdir('..')
+ report('Start packaging')
+ shutil.make_archive(RELEASE_NAME, 'zip', root_dir='.', base_dir=RELEASE_NAME )
+ shutil.make_archive(RELEASE_NAME, 'gztar', root_dir='.', base_dir=RELEASE_NAME )
+ report('Zip and tgz ready!')
+
+def buildrock():
+ pre_packageit_or_buildrock_step1()
+
+ # Packaging into source rocks
+ report('Start preparing rock')
+ shutil.move('test/test_luaunit.lua', '.')
+ shutil.rmtree('test')
+ os.mkdir('test')
+ shutil.move('test_luaunit.lua', 'test')
+ shutil.move('run_unit_tests.lua', 'test')
+
+ for p in glob.glob('*.lua'):
+ if p == 'luaunit.lua':
+ continue
+ os.unlink(p)
+ os.unlink('README.md')
+ os.unlink('LICENSE.txt')
+
+ os.chdir('..')
+ shutil.move( RELEASE_NAME, ROCK_RELEASE_NAME )
+ shutil.make_archive( ROCK_RELEASE_NAME, 'zip', root_dir='.', base_dir=ROCK_RELEASE_NAME )
+
+
+def help():
+ print( 'Available actions:')
+ for opt in sorted(OptToFunc.keys()):
+ print( '\t%s' % opt )
+
+def makedoc():
+ os.chdir('doc')
+ if os.path.exists('html'):
+ shutil.rmtree('html')
+ subprocess.check_call(['make.bat', 'html'])
+ shutil.copytree('_build/html', 'html')
+ os.chdir('..')
+
+def rundoctests():
+ lua = LUA52
+ for expretcode, l in (
+ (0, [ '-e', "lu = require('luaunit');os.exit(lu.LuaUnit.run())" ]),
+ (0, [ 'doc/my_test_suite.lua', '-v', 'TestAdd.testAddPositive', 'TestAdd.testAddZero']),
+ (0, [ 'doc/my_test_suite.lua', '-v' ]),
+ (0, [ 'doc/my_test_suite.lua', ]),
+ (0, [ 'doc/my_test_suite.lua', '-o','TAP']),
+ (0, [ 'doc/my_test_suite.lua', 'TestAdd', 'TestDiv.testDivError' , '-v']),
+ (0, [ 'doc/my_test_suite.lua', '-v', '-p', 'Err.r', '-p', 'Z.ro' ]),
+ (0, [ 'doc/my_test_suite.lua', '-v', '--pattern', 'Add', '--exclude', 'Adder', '--pattern', 'Zero' ]),
+ (0, [ 'doc/my_test_suite.lua', '-v', '-x', 'Error', '-x', 'Zero' ]),
+ (2, [ 'doc/my_test_suite_with_failures.lua', '-o', 'text' ]),
+ (2, [ 'doc/my_test_suite_with_failures.lua', '-o', 'text', '--verbose' ]),
+ (2, [ 'doc/my_test_suite_with_failures.lua', '-o', 'tap', '--quiet' ]),
+ (2, [ 'doc/my_test_suite_with_failures.lua', '-o', 'tap' ]),
+ (2, [ 'doc/my_test_suite_with_failures.lua', '-o', 'tap', '--verbose' ]),
+ (2, [ 'doc/my_test_suite_with_failures.lua', '-o', 'nil', '--verbose' ]),
+ ):
+ print( '%s %s' % ('\n$ lua', ' '.join(l).replace('doc/', '') ) )
+ retcode = subprocess.call( [lua] + l )
+ if retcode != expretcode:
+ report( 'Invalid luacheck result' )
+ sys.exit( retcode )
+
+ for expretcode, l in (
+ (2, [ 'doc/my_test_suite_with_failures.lua', '-o', 'junit', '-n', 'toto.xml' ]),
+ ):
+ print( '%s %s' % ('\n$ lua', ' '.join(l).replace('doc/', '') ) )
+ retcode = subprocess.call( [lua] + l )
+ if retcode != expretcode:
+ report( 'Invalid luacheck result' )
+ sys.exit( retcode )
+
+ print( open('toto.xml').read() )
+
+
+OptToFunc = {
+ 'rununittests' : run_unit_tests,
+ 'run_unit_tests': run_unit_tests, # alias
+ 'runtests' : run_tests,
+ 'run_tests' : run_tests, # alis
+ 'luacheck' : run_luacheck,
+ 'runexample' : run_example,
+ 'packageit' : packageit,
+ 'buildrock' : buildrock,
+ 'makedoc' : makedoc,
+ 'rundoctests' : rundoctests,
+ 'help' : help,
+}
+
+if __name__ == '__main__':
+ doingNothing = True
+ for arg in sys.argv[1:]:
+ if arg in OptToFunc:
+ doingNothing = False
+ OptToFunc[arg]()
+ else:
+ print( 'No such action :', arg )
+ sys.exit(-1)
+
+ if doingNothing:
+ help()
+
+
+
diff --git a/Data/Libraries/luaunit/example_with_luaunit.lua b/Data/Libraries/luaunit/example_with_luaunit.lua
new file mode 100644
index 0000000..5e10843
--- /dev/null
+++ b/Data/Libraries/luaunit/example_with_luaunit.lua
@@ -0,0 +1,150 @@
+#!/usr/bin/env lua
+
+
+local lu = require('luaunit')
+
+TestToto = {} --class
+
+ function TestToto:setUp()
+ -- set up tests
+ self.a = 1
+ self.s = 'hop'
+ self.t1 = {1,2,3}
+ self.t2 = {one=1,two=2,three=3}
+ self.t3 = {1,2,three=3}
+ end
+
+ function TestToto:test1_withFailure()
+ -- print( "some stuff test 1" )
+ lu.assertEquals( self.a , 1 )
+ -- will fail
+ lu.assertEquals( self.a , 2 )
+ lu.assertEquals( self.a , 2 )
+ end
+
+ function TestToto:test2_withFailure()
+ -- print( "some stuff test 2" )
+ lu.assertEquals( self.a , 1 )
+ lu.assertEquals( self.s , 'hop' )
+ -- will fail
+ lu.assertEquals( self.s , 'bof' )
+ lu.assertEquals( self.s , 'bof' )
+ end
+
+ function TestToto:test3()
+ -- print( "some stuff test 3" )
+ lu.assertEquals( self.a , 1 )
+ lu.assertEquals( self.s , 'hop' )
+ lu.assertEquals( type(self.a), 'number' )
+ end
+
+ function TestToto:test4()
+ -- print( "some stuff test 4" )
+ lu.assertNotEquals( self.a , 1 )
+ end
+
+ function TestToto:test5()
+ -- print( "some stuff test 5" )
+ lu.assertEvalToTrue( self.a )
+ lu.assertEvalToFalse( self.a ) -- will trigger the failure
+ end
+
+ function TestToto:test6()
+ -- print( "some stuff test 6" )
+ lu.assertTrue( true )
+ lu.assertFalse( false )
+ lu.assertEvalToFalse( nil )
+ lu.assertFalse( nil ) -- trigger the failure assertFalse is strict
+ end
+
+ function TestToto:test7()
+ -- assertEquals( {1,2}, self.t1 )
+ -- assertEquals( {1,2}, self.t2 )
+ lu.assertEquals( {1,2}, self.t3 )
+ end
+
+ function TestToto:test8a()
+ -- failure occurs in a submethod
+ self:funcWithError()
+ end
+
+ function TestToto:test8b()
+ -- failure occurs in a submethod
+ self:funcWithFuncWithError()
+ end
+
+ function TestToto:funcWithFuncWithError()
+ self:funcWithError()
+ end
+
+ function TestToto:funcWithError()
+ error('Bouhouhoum error!')
+ end
+
+ function TestToto:test_skipped()
+ local test_conditions_are_met = false
+ lu.skipIf( not test_conditions_are_met, "Test is skipped because ..." )
+ end
+
+
+-- class TestTiti
+
+TestTiti = {} --class
+ function TestTiti:setUp()
+ -- set up tests
+ self.a = 1
+ self.s = 'hop'
+ -- print( 'TestTiti:setUp' )
+ end
+
+ function TestTiti:tearDown()
+ -- some tearDown() code if necessary
+ -- print( 'TestTiti:tearDown' )
+ end
+
+ function TestTiti:test1_withFailure()
+ -- print( "some stuff test 1" )
+ lu.assertEquals( self.a , 1 )
+ -- will fail
+ lu.assertEquals( self.a , 2 )
+ lu.assertEquals( self.a , 2 )
+ end
+
+ function TestTiti:test2_withFailure()
+ -- print( "some stuff test 2" )
+ lu.assertEquals( self.a , 1 )
+ lu.assertEquals( self.s , 'hop' )
+ -- will fail
+ lu.assertEquals( self.s , 'bof' )
+ lu.assertEquals( self.s , 'bof' )
+ end
+
+ function TestTiti:test3()
+ -- print( "some stuff test 3" )
+ lu.assertEquals( self.a , 1 )
+ lu.assertEquals( self.s , 'hop' )
+ end
+-- class TestTiti
+
+-- simple test functions that were written previously can be integrated
+-- in luaunit too
+function test1_withAssertionError()
+ assert( 1 == 1)
+ -- will fail
+ assert( 1 == 2)
+end
+
+function test2_withAssertionError()
+ assert( 'a' == 'a')
+ -- will fail
+ assert( 'a' == 'b')
+end
+
+function test3()
+ assert( 1 == 1)
+ assert( 'a' == 'a')
+end
+
+local runner = lu.LuaUnit.new()
+runner:setOutputType("text")
+os.exit( runner:runSuite() )
diff --git a/Data/Libraries/luaunit/junitxml/Makefile b/Data/Libraries/luaunit/junitxml/Makefile
new file mode 100644
index 0000000..9679016
--- /dev/null
+++ b/Data/Libraries/luaunit/junitxml/Makefile
@@ -0,0 +1,17 @@
+#
+# junitxml/Makefile
+#
+
+XMLLINT ?= xmllint
+TEST_APACHE = --noout --schema junit-apache-ant.xsd
+TEST_JENKINS = --noout --schema junit-jenkins.xsd
+
+validate-examples: validate-apache validate-jenkins
+
+# This example file is the only one that satisfies the Apache schema
+validate-apache: example-apache-ant.xml
+ $(XMLLINT) $(TEST_APACHE) $<
+
+# The Jenkins schema is more relaxed, and should apply to all .xml files
+validate-jenkins: $(wildcard *.xml)
+ for file in $^; do $(XMLLINT) $(TEST_JENKINS) $$file || exit 1; done
diff --git a/Data/Libraries/luaunit/junitxml/XMLJUnitResultFormatter.java.txt b/Data/Libraries/luaunit/junitxml/XMLJUnitResultFormatter.java.txt
new file mode 100644
index 0000000..5e3d1d7
--- /dev/null
+++ b/Data/Libraries/luaunit/junitxml/XMLJUnitResultFormatter.java.txt
@@ -0,0 +1,301 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Date;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.DOMElementWriter;
+import org.apache.tools.ant.util.DateUtils;
+import org.apache.tools.ant.util.FileUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+
+
+/**
+ * Prints XML output of the test to a specified Writer.
+ *
+ * @see FormatterElement
+ */
+
+public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstants {
+
+ private static final double ONE_SECOND = 1000.0;
+
+ /** constant for unnnamed testsuites/cases */
+ private static final String UNKNOWN = "unknown";
+
+ private static DocumentBuilder getDocumentBuilder() {
+ try {
+ return DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ } catch (Exception exc) {
+ throw new ExceptionInInitializerError(exc);
+ }
+ }
+
+ /**
+ * The XML document.
+ */
+ private Document doc;
+ /**
+ * The wrapper for the whole testsuite.
+ */
+ private Element rootElement;
+ /**
+ * Element for the current test.
+ */
+ private Hashtable testElements = new Hashtable();
+ /**
+ * tests that failed.
+ */
+ private Hashtable failedTests = new Hashtable();
+ /**
+ * Timing helper.
+ */
+ private Hashtable testStarts = new Hashtable();
+ /**
+ * Where to write the log to.
+ */
+ private OutputStream out;
+
+ /** No arg constructor. */
+ public XMLJUnitResultFormatter() {
+ }
+
+ /** {@inheritDoc}. */
+ public void setOutput(OutputStream out) {
+ this.out = out;
+ }
+
+ /** {@inheritDoc}. */
+ public void setSystemOutput(String out) {
+ formatOutput(SYSTEM_OUT, out);
+ }
+
+ /** {@inheritDoc}. */
+ public void setSystemError(String out) {
+ formatOutput(SYSTEM_ERR, out);
+ }
+
+ /**
+ * The whole testsuite started.
+ * @param suite the testsuite.
+ */
+ public void startTestSuite(JUnitTest suite) {
+ doc = getDocumentBuilder().newDocument();
+ rootElement = doc.createElement(TESTSUITE);
+ String n = suite.getName();
+ rootElement.setAttribute(ATTR_NAME, n == null ? UNKNOWN : n);
+
+ //add the timestamp
+ final String timestamp = DateUtils.format(new Date(),
+ DateUtils.ISO8601_DATETIME_PATTERN);
+ rootElement.setAttribute(TIMESTAMP, timestamp);
+ //and the hostname.
+ rootElement.setAttribute(HOSTNAME, getHostname());
+
+ // Output properties
+ Element propsElement = doc.createElement(PROPERTIES);
+ rootElement.appendChild(propsElement);
+ Properties props = suite.getProperties();
+ if (props != null) {
+ Enumeration e = props.propertyNames();
+ while (e.hasMoreElements()) {
+ String name = (String) e.nextElement();
+ Element propElement = doc.createElement(PROPERTY);
+ propElement.setAttribute(ATTR_NAME, name);
+ propElement.setAttribute(ATTR_VALUE, props.getProperty(name));
+ propsElement.appendChild(propElement);
+ }
+ }
+ }
+
+ /**
+ * get the local hostname
+ * @return the name of the local host, or "localhost" if we cannot work it out
+ */
+ private String getHostname() {
+ try {
+ return InetAddress.getLocalHost().getHostName();
+ } catch (UnknownHostException e) {
+ return "localhost";
+ }
+ }
+
+ /**
+ * The whole testsuite ended.
+ * @param suite the testsuite.
+ * @throws BuildException on error.
+ */
+ public void endTestSuite(JUnitTest suite) throws BuildException {
+ rootElement.setAttribute(ATTR_TESTS, "" + suite.runCount());
+ rootElement.setAttribute(ATTR_FAILURES, "" + suite.failureCount());
+ rootElement.setAttribute(ATTR_ERRORS, "" + suite.errorCount());
+ rootElement.setAttribute(
+ ATTR_TIME, "" + (suite.getRunTime() / ONE_SECOND));
+ if (out != null) {
+ Writer wri = null;
+ try {
+ wri = new BufferedWriter(new OutputStreamWriter(out, "UTF8"));
+ wri.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
+ (new DOMElementWriter()).write(rootElement, wri, 0, " ");
+ } catch (IOException exc) {
+ throw new BuildException("Unable to write log file", exc);
+ } finally {
+ if (wri != null) {
+ try {
+ wri.flush();
+ } catch (IOException ex) {
+ // ignore
+ }
+ }
+ if (out != System.out && out != System.err) {
+ FileUtils.close(wri);
+ }
+ }
+ }
+ }
+
+ /**
+ * Interface TestListener.
+ *
+ * <p>A new Test is started.
+ * @param t the test.
+ */
+ public void startTest(Test t) {
+ testStarts.put(t, new Long(System.currentTimeMillis()));
+ }
+
+ /**
+ * Interface TestListener.
+ *
+ * <p>A Test is finished.
+ * @param test the test.
+ */
+ public void endTest(Test test) {
+ // Fix for bug #5637 - if a junit.extensions.TestSetup is
+ // used and throws an exception during setUp then startTest
+ // would never have been called
+ if (!testStarts.containsKey(test)) {
+ startTest(test);
+ }
+
+ Element currentTest = null;
+ if (!failedTests.containsKey(test)) {
+ currentTest = doc.createElement(TESTCASE);
+ String n = JUnitVersionHelper.getTestCaseName(test);
+ currentTest.setAttribute(ATTR_NAME,
+ n == null ? UNKNOWN : n);
+ // a TestSuite can contain Tests from multiple classes,
+ // even tests with the same name - disambiguate them.
+ currentTest.setAttribute(ATTR_CLASSNAME,
+ JUnitVersionHelper.getTestCaseClassName(test));
+ rootElement.appendChild(currentTest);
+ testElements.put(test, currentTest);
+ } else {
+ currentTest = (Element) testElements.get(test);
+ }
+
+ Long l = (Long) testStarts.get(test);
+ currentTest.setAttribute(ATTR_TIME,
+ "" + ((System.currentTimeMillis()
+ - l.longValue()) / ONE_SECOND));
+ }
+
+ /**
+ * Interface TestListener for JUnit &lt;= 3.4.
+ *
+ * <p>A Test failed.
+ * @param test the test.
+ * @param t the exception.
+ */
+ public void addFailure(Test test, Throwable t) {
+ formatError(FAILURE, test, t);
+ }
+
+ /**
+ * Interface TestListener for JUnit &gt; 3.4.
+ *
+ * <p>A Test failed.
+ * @param test the test.
+ * @param t the assertion.
+ */
+ public void addFailure(Test test, AssertionFailedError t) {
+ addFailure(test, (Throwable) t);
+ }
+
+ /**
+ * Interface TestListener.
+ *
+ * <p>An error occurred while running the test.
+ * @param test the test.
+ * @param t the error.
+ */
+ public void addError(Test test, Throwable t) {
+ formatError(ERROR, test, t);
+ }
+
+ private void formatError(String type, Test test, Throwable t) {
+ if (test != null) {
+ endTest(test);
+ failedTests.put(test, test);
+ }
+
+ Element nested = doc.createElement(type);
+ Element currentTest = null;
+ if (test != null) {
+ currentTest = (Element) testElements.get(test);
+ } else {
+ currentTest = rootElement;
+ }
+
+ currentTest.appendChild(nested);
+
+ String message = t.getMessage();
+ if (message != null && message.length() > 0) {
+ nested.setAttribute(ATTR_MESSAGE, t.getMessage());
+ }
+ nested.setAttribute(ATTR_TYPE, t.getClass().getName());
+
+ String strace = JUnitTestRunner.getFilteredTrace(t);
+ Text trace = doc.createTextNode(strace);
+ nested.appendChild(trace);
+ }
+
+ private void formatOutput(String type, String output) {
+ Element nested = doc.createElement(type);
+ rootElement.appendChild(nested);
+ nested.appendChild(doc.createCDATASection(output));
+ }
+
+} // XMLJUnitResultFormatter
diff --git a/Data/Libraries/luaunit/junitxml/example-apache-ant.xml b/Data/Libraries/luaunit/junitxml/example-apache-ant.xml
new file mode 100644
index 0000000..6123da0
--- /dev/null
+++ b/Data/Libraries/luaunit/junitxml/example-apache-ant.xml
@@ -0,0 +1,31 @@
+<testsuites>
+ <testsuite name="testsuite1" tests="21" id="123456" package="???"
+ failures="0" errors="0" time="21.67" timestamp="2015-01-01T12:33:00" hostname="localhost">
+ <properties>
+ <property name="prop1" value="value1"/>
+ </properties>
+ <testcase name="toto"
+ classname="titi" time="33.17" >
+ <!-- Optional -->
+ <!-- <skipped>bla bla</skipped> -->
+ <failure
+ type="typeOfFailure" message="failureMsg">
+ Detailed failure content
+ </failure>
+ </testcase>
+ <!--
+ <system-out>bla bla output bla bla</system-out>
+ <system-err>bla bla error bla bla</system-err>
+ -->
+ <testcase name="toto"
+ classname="titi" time="17.33" >
+ <!-- Optional -->
+ <error
+ type="typeOfError" message="errorMsg">
+ Detailed error content
+ </error>
+ </testcase>
+ <system-out>bla bla output bla bla</system-out>
+ <system-err>bla bla error bla bla</system-err>
+ </testsuite>
+</testsuites> \ No newline at end of file
diff --git a/Data/Libraries/luaunit/junitxml/example-bamboo-1.xml b/Data/Libraries/luaunit/junitxml/example-bamboo-1.xml
new file mode 100644
index 0000000..f0b9933
--- /dev/null
+++ b/Data/Libraries/luaunit/junitxml/example-bamboo-1.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuite errors="0" tests="3" time="0.391" failures="1"
+ name="com.atlassian.bamboo.repository.perforce.PerforceSyncCommandTest">
+ <properties>
+ <property value="Java(TM) 2 Runtime Environment, Standard Edition" name="java.runtime.name"/>
+ <property value="UnicodeBig" name="sun.io.unicode.encoding"/>
+ </properties>
+ <testcase time="0.001" name="testGeneratesCorrectP4CommandLine"/>
+ <testcase time="0" name="testGettersReturnExpectedStuff"/>
+ <testcase time="0.164" name="testUsingPerforceWhenNoFilesHaveChanged">
+ <failure type="junit.framework.AssertionFailedError"
+ message="Should not have any errors. [Perforce client error:, Connect to server failed; ">
+ junit.framework.AssertionFailedError: Should not have any errors. [Perforce client error:, Connect to server
+ failed; check $P4PORT., TCP connect to keg failed., keg: host unknown.] expected:&lt;0&gt; but was:&lt;4&gt;
+ at junit.framework.Assert.fail(Assert.java:47)
+ at junit.framework.Assert.failNotEquals(Assert.java:282)
+ at junit.framework.Assert.assertEquals(Assert.java:64)
+ at junit.framework.Assert.assertEquals(Assert.java:201)
+ at com.atlassian.bamboo.repository.perforce.PerforceSyncCommandTest.testUsingPerforceWhenNoFilesHaveChanged(PerforceSyncCommandTest.java:60)
+ at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+ at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+ at java.lang.reflect.Method.invoke(Method.java:585)
+ at junit.framework.TestCase.runTest(TestCase.java:154)
+ at junit.framework.TestCase.runBare(TestCase.java:127)
+ at junit.framework.TestResult$1.protect(TestResult.java:106)
+ at junit.framework.TestResult.runProtected(TestResult.java:124)
+ at junit.framework.TestResult.run(TestResult.java:109)
+ at junit.framework.TestCase.run(TestCase.java:118)
+ at junit.framework.TestSuite.runTest(TestSuite.java:208)
+ at junit.framework.TestSuite.run(TestSuite.java:203)
+ at sun.reflect.GeneratedMethodAccessor17.invoke(Unknown Source)
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+ at java.lang.reflect.Method.invoke(Method.java:585)
+ at org.apache.maven.surefire.battery.JUnitBattery.executeJUnit(JUnitBattery.java:242)
+ at org.apache.maven.surefire.battery.JUnitBattery.execute(JUnitBattery.java:216)
+ at org.apache.maven.surefire.Surefire.executeBattery(Surefire.java:215)
+ at org.apache.maven.surefire.Surefire.run(Surefire.java:163)
+ at org.apache.maven.surefire.Surefire.run(Surefire.java:87)
+ at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+ at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+ at java.lang.reflect.Method.invoke(Method.java:585)
+ at org.apache.maven.surefire.SurefireBooter.runTestsInProcess(SurefireBooter.java:313)
+ at org.apache.maven.surefire.SurefireBooter.run(SurefireBooter.java:221)
+ at org.apache.maven.test.SurefirePlugin.execute(SurefirePlugin.java:371)
+ at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:412)
+ at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:534)
+ at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:475)
+ at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:454)
+ at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:306)
+ at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:273)
+ at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:140)
+ at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:322)
+ at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:115)
+ at org.apache.maven.cli.MavenCli.main(MavenCli.java:256)
+ at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+ at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+ at java.lang.reflect.Method.invoke(Method.java:585)
+ at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
+ at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
+ at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
+ at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
+ </failure>
+ <system-out>
+ PerforceSyncCommand.command: /usr/local/bin/p4
+ </system-out>
+ </testcase>
+</testsuite> \ No newline at end of file
diff --git a/Data/Libraries/luaunit/junitxml/example-bamboo-2.xml b/Data/Libraries/luaunit/junitxml/example-bamboo-2.xml
new file mode 100644
index 0000000..02f628c
--- /dev/null
+++ b/Data/Libraries/luaunit/junitxml/example-bamboo-2.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuite errors="0" skipped="0" tests="1" time="0.045" failures="0" name="com.atlassian.bamboo.labels.LabelManagerImplTest">
+ <properties>
+ <property value="Java(TM) 2 Runtime Environment, Standard Edition" name="java.runtime.name"/>
+ <property value="/usr/java/jdk1.5.0_07/jre/lib/i386" name="sun.boot.library.path"/>
+ <property value="1.5.0_07-b03" name="java.vm.version"/>
+ <property value="Sun Microsystems Inc." name="java.vm.vendor"/>
+ <property value="http://java.sun.com/" name="java.vendor.url"/>
+ <property value=":" name="path.separator"/>
+ <property value="Java HotSpot(TM) Client VM" name="java.vm.name"/>
+ <property value="sun.io" name="file.encoding.pkg"/>
+ <property value="US" name="user.country"/>
+ <property value="unknown" name="sun.os.patch.level"/>
+ <property value="Java Virtual Machine Specification" name="java.vm.specification.name"/>
+ <property value="/opt/bamboo-data/bamboohome/xml-data/build-dir/BAM-MAIN" name="user.dir"/>
+ <property value="1.5.0_07-b03" name="java.runtime.version"/>
+ <property value="sun.awt.X11GraphicsEnvironment" name="java.awt.graphicsenv"/>
+ <property value="/opt/bamboo-data/bamboohome/xml-data/build-dir/BAM-MAIN/bamboo-core" name="basedir"/>
+ <property value="/usr/java/jdk1.5.0_07/jre/lib/endorsed" name="java.endorsed.dirs"/>
+ <property value="i386" name="os.arch"/>
+ <property value="/tmp" name="java.io.tmpdir"/>
+ <property value="Sun Microsystems Inc." name="java.vm.specification.vendor"/>
+ <property value="Linux" name="os.name"/>
+ <property value="/opt/java/tools/maven2/bin/m2.conf" name="classworlds.conf"/>
+ <property value="ISO-8859-1" name="sun.jnu.encoding"/>
+ <property value="/usr/java/jdk1.5.0_07/jre/lib/i386.." name="java.library.path"/>
+ <property value="Java Platform API Specification" name="java.specification.name"/>
+ <property value="49.0" name="java.class.version"/>
+ <property value="HotSpot Client Compiler" name="sun.management.compiler"/>
+ <property value="2.6.15-1.1833_FC4smp" name="os.version"/>
+ <property value="/home/bamboo" name="user.home"/>
+ <property value="Australia/Sydney" name="user.timezone"/>
+ <property value="sun.print.PSPrinterJob" name="java.awt.printerjob"/>
+ <property value="ISO-8859-1" name="file.encoding"/>
+ <property value="1.5" name="java.specification.version"/>
+ <property value="bamboo" name="user.name"/>
+ <property value="/opt/java/tools/maven2/boot/classworlds-1.1.jar" name="java.class.path"/>
+ <property value="1.0" name="java.vm.specification.version"/>
+ <property value="32" name="sun.arch.data.model"/>
+ <property value="/usr/java/jdk1.5.0_07/jre" name="java.home"/>
+ <property value="Sun Microsystems Inc." name="java.specification.vendor"/>
+ <property value="en" name="user.language"/>
+ <property value="mixed mode, sharing" name="java.vm.info"/>
+ <property value="1.5.0_07" name="java.version"/>
+ <property value="/usr/java/jdk1.5.0_07/jre/lib/ext" name="java.ext.dirs"/>
+ <property value="Sun Microsystems Inc." name="java.vendor"/>
+ <property value="/opt/java/tools/maven2" name="maven.home"/>
+ <property value="/home/bamboo/.m2/repository" name="localRepository"/>
+ <property value="/" name="file.separator"/>
+ <property value="http://java.sun.com/cgi-bin/bugreport.cgi" name="java.vendor.url.bug"/>
+ <property value="little" name="sun.cpu.endian"/>
+ <property value="UnicodeLittle" name="sun.io.unicode.encoding"/>
+ <property value="" name="sun.cpu.isalist"/>
+ </properties>
+ <testcase time="0.045" name="testBAM1436"/>
+</testsuite> \ No newline at end of file
diff --git a/Data/Libraries/luaunit/junitxml/example-jenkins.xml b/Data/Libraries/luaunit/junitxml/example-jenkins.xml
new file mode 100644
index 0000000..6690664
--- /dev/null
+++ b/Data/Libraries/luaunit/junitxml/example-jenkins.xml
@@ -0,0 +1,29 @@
+<testsuites
+ name="suite1" time="33.17" tests="21" failures="22" disabled="6" errors="3">
+ <testsuite name="testsuite1" tests="???"
+ failures="0" disabled="0" errors="0" time="33.17" skipped="0" timestamp="2015-01-01T12:33:00" hostname="localhost" id="???" package="???">
+ <properties>
+ <property name="prop1" value="value1"/>
+ </properties>
+ <testcase name="toto"
+ classname="titi" time="33.17" status="???" assertions="???">
+ <!-- Optional -->
+ <skipped>bla bla</skipped>
+ <failure
+ type="typeOfFailure" message="failureMsg">
+ Detailed failure content
+ </failure>
+ </testcase>
+ <testcase name="toto"
+ classname="titi" time="33.17" status="???" assertions="???">
+ <!-- Optional -->
+ <error
+ type="typeOfError" message="errorMsg">
+ Detailed error content
+ </error>
+ </testcase>
+ <system-out>bla bla output bla bla</system-out>
+ <system-err>bla bla error bla bla</system-err>
+ </testsuite>
+ <!-- more testsuites -->
+</testsuites> \ No newline at end of file
diff --git a/Data/Libraries/luaunit/junitxml/junit-apache-ant.xsd b/Data/Libraries/luaunit/junitxml/junit-apache-ant.xsd
new file mode 100644
index 0000000..71bdf60
--- /dev/null
+++ b/Data/Libraries/luaunit/junitxml/junit-apache-ant.xsd
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">JUnit test result schema for the Apache Ant JUnit and JUnitReport tasks
+Copyright © 2011, Windy Road Technology Pty. Limited
+The Apache Ant JUnit XML Schema is distributed under the terms of the GNU Lesser General Public License (LGPL) http://www.gnu.org/licenses/lgpl.html
+Permission to waive conditions of this license may be requested from Windy Road Support (http://windyroad.org/support).</xs:documentation>
+ </xs:annotation>
+ <xs:element name="testsuite" type="testsuite"/>
+ <xs:simpleType name="ISO8601_DATETIME_PATTERN">
+ <xs:restriction base="xs:dateTime">
+ <xs:pattern value="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:element name="testsuites">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">Contains an aggregation of testsuite results</xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="testsuite" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:extension base="testsuite">
+ <xs:attribute name="package" type="xs:token" use="required">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">Derived from testsuite/@name in the non-aggregated documents</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="id" type="xs:int" use="required">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">Starts at '0' for the first testsuite and is incremented by 1 for each following testsuite</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:complexType name="testsuite">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">Contains the results of exexuting a testsuite</xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="properties">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">Properties (e.g., environment settings) set during test execution</xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="property" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" use="required">
+ <xs:simpleType>
+ <xs:restriction base="xs:token">
+ <xs:minLength value="1"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="value" type="xs:string" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="testcase" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:choice minOccurs="0">
+ <xs:element name="error">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">Indicates that the test errored. An errored test is one that had an unanticipated problem. e.g., an unchecked throwable; or a problem with the implementation of the test. Contains as a text node relevant data for the error, e.g., a stack trace</xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="pre-string">
+ <xs:attribute name="message" type="xs:string">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">The error message. e.g., if a java exception is thrown, the return value of getMessage()</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="type" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">The type of error that occured. e.g., if a java execption is thrown the full class name of the exception.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="failure">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">Indicates that the test failed. A failure is a test which the code has explicitly failed by using the mechanisms for that purpose. e.g., via an assertEquals. Contains as a text node relevant data for the failure, e.g., a stack trace</xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="pre-string">
+ <xs:attribute name="message" type="xs:string">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">The message specified in the assert</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="type" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">The type of the assert.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ <xs:attribute name="name" type="xs:token" use="required">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">Name of the test method</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="classname" type="xs:token" use="required">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">Full class name for the class the test method is in.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="time" type="xs:decimal" use="required">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">Time taken (in seconds) to execute the test</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="system-out">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">Data that was written to standard out while the test was executed</xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="pre-string">
+ <xs:whiteSpace value="preserve"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="system-err">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">Data that was written to standard error while the test was executed</xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="pre-string">
+ <xs:whiteSpace value="preserve"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" use="required">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">Full class name of the test for non-aggregated testsuite documents. Class name without the package for aggregated testsuites documents</xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:token">
+ <xs:minLength value="1"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="timestamp" type="ISO8601_DATETIME_PATTERN" use="required">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">when the test was executed. Timezone may not be specified.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="hostname" use="required">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">Host on which the tests were executed. 'localhost' should be used if the hostname cannot be determined.</xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:token">
+ <xs:minLength value="1"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="tests" type="xs:int" use="required">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">The total number of tests in the suite</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="failures" type="xs:int" use="required">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">The total number of tests in the suite that failed. A failure is a test which the code has explicitly failed by using the mechanisms for that purpose. e.g., via an assertEquals</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="errors" type="xs:int" use="required">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">The total number of tests in the suite that errorrd. An errored test is one that had an unanticipated problem. e.g., an unchecked throwable; or a problem with the implementation of the test.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="time" type="xs:decimal" use="required">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">Time taken (in seconds) to execute the tests in the suite</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:simpleType name="pre-string">
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="preserve"/>
+ </xs:restriction>
+ </xs:simpleType>
+</xs:schema> \ No newline at end of file
diff --git a/Data/Libraries/luaunit/junitxml/junit-jenkins.xsd b/Data/Libraries/luaunit/junitxml/junit-jenkins.xsd
new file mode 100644
index 0000000..a1d5ab0
--- /dev/null
+++ b/Data/Libraries/luaunit/junitxml/junit-jenkins.xsd
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+ <xs:element name="failure">
+ <xs:complexType mixed="true">
+ <xs:attribute name="type" type="xs:string" use="optional"/>
+ <xs:attribute name="message" type="xs:string" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="error">
+ <xs:complexType mixed="true">
+ <xs:attribute name="type" type="xs:string" use="optional"/>
+ <xs:attribute name="message" type="xs:string" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="properties">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="property" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="property">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="value" type="xs:string" use="required"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="skipped" type="xs:string"/>
+ <xs:element name="system-err" type="xs:string"/>
+ <xs:element name="system-out" type="xs:string"/>
+
+ <xs:element name="testcase">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="skipped" minOccurs="0" maxOccurs="1"/>
+ <xs:element ref="error" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element ref="failure" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element ref="system-out" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element ref="system-err" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="assertions" type="xs:string" use="optional"/>
+ <xs:attribute name="time" type="xs:string" use="optional"/>
+ <xs:attribute name="classname" type="xs:string" use="optional"/>
+ <xs:attribute name="status" type="xs:string" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="testsuite">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="properties" minOccurs="0" maxOccurs="1"/>
+ <xs:element ref="testcase" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element ref="system-out" minOccurs="0" maxOccurs="1"/>
+ <xs:element ref="system-err" minOccurs="0" maxOccurs="1"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="tests" type="xs:string" use="required"/>
+ <xs:attribute name="failures" type="xs:string" use="optional"/>
+ <xs:attribute name="errors" type="xs:string" use="optional"/>
+ <xs:attribute name="time" type="xs:string" use="optional"/>
+ <xs:attribute name="disabled" type="xs:string" use="optional"/>
+ <xs:attribute name="skipped" type="xs:string" use="optional"/>
+ <xs:attribute name="timestamp" type="xs:string" use="optional"/>
+ <xs:attribute name="hostname" type="xs:string" use="optional"/>
+ <xs:attribute name="id" type="xs:string" use="optional"/>
+ <xs:attribute name="package" type="xs:string" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="testsuites">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="testsuite" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="optional"/>
+ <xs:attribute name="time" type="xs:string" use="optional"/>
+ <xs:attribute name="tests" type="xs:string" use="optional"/>
+ <xs:attribute name="failures" type="xs:string" use="optional"/>
+ <xs:attribute name="disabled" type="xs:string" use="optional"/>
+ <xs:attribute name="errors" type="xs:string" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+
+
+</xs:schema> \ No newline at end of file
diff --git a/Data/Libraries/luaunit/junitxml/notes-junit-compatibility.txt b/Data/Libraries/luaunit/junitxml/notes-junit-compatibility.txt
new file mode 100644
index 0000000..ab92cff
--- /dev/null
+++ b/Data/Libraries/luaunit/junitxml/notes-junit-compatibility.txt
@@ -0,0 +1,34 @@
+Our source information:
+https://github.com/windyroad/JUnit-Schema
+* http://stackoverflow.com/questions/4922867/junit-xml-format-specification-that-hudson-supports
+(Jenkins)
+* https://github.com/jenkinsci/xunit-plugin/tree/master/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd
+* http://help.catchsoftware.com/display/ET/JUnit+Format
+* http://llg.cubic.org/docs/junit/
+* https://confluence.atlassian.com/bamboo/junit-parsing-in-bamboo-289277357.html
+* http://nose2.readthedocs.io/en/latest/plugins/junitxml.html
+* https://pzolee.blogs.balabit.com/2012/11/jenkins-vs-junit-xml-format/
+* https://www.relishapp.com/cucumber/cucumber/docs/formatters/junit-output-formatter
+* http://stackoverflow.com/questions/11241781/python-unittests-in-jenkins
+* https://github.com/xmlrunner/unittest-xml-reporting/tree/master/
+
+
+
+Notes:
+======
+Ant xml schema is much more restrictive than jenkins.
+
+Non allowed fields in ant, allowed in jenkins:
+
+testsuites:
+- apache ant forbids all attributes.
+
+testsuite:
+- apache ant forbids attributes: disabled, skipped
+- apache ant allows elements system-out and system-err, that are in testcase for jenkins
+
+testcase:
+- apache ant forbids attributes: assertions, status
+- apache ant forbids elements: skipped, system-out, system-err
+
+
diff --git a/Data/Libraries/luaunit/luaunit-3.4-1.rockspec b/Data/Libraries/luaunit/luaunit-3.4-1.rockspec
new file mode 100644
index 0000000..f26f4ee
--- /dev/null
+++ b/Data/Libraries/luaunit/luaunit-3.4-1.rockspec
@@ -0,0 +1,48 @@
+package = "LuaUnit"
+version = "3.4-1"
+source =
+{
+ url = 'https://github.com/bluebird75/luaunit/releases/download/LUAUNIT_V3_4/rock-luaunit-3.4.zip'
+}
+
+description =
+{
+ summary = "A unit testing framework for Lua",
+ detailed =
+ [[
+ LuaUnit is a popular unit-testing framework for Lua, with an interface typical
+ of xUnit libraries (Python unittest, Junit, NUnit, ...). It supports
+ several output formats (Text, TAP, JUnit, ...) to be used directly or work with Continuous Integration platforms
+ (Jenkins, Hudson, ...).
+
+ For simplicity, LuaUnit is contained into a single-file and has no external dependency.
+
+ Tutorial and reference documentation is available on
+ [read-the-docs](http://luaunit.readthedocs.org/en/latest/)
+
+ LuaUnit may also be used as an assertion library, to validate assertions inside a running program. In addition, it provides
+ a pretty stringifier which converts any type into a nicely formatted string (including complex nested or recursive tables).
+
+ To install LuaUnit from LuaRocks, you need at least LuaRocks version 2.4.4 (due to old versions of wget being incompatible
+ with GitHub https downloading)
+
+ ]],
+ homepage = "http://github.com/bluebird75/luaunit",
+ license = "BSD",
+ maintainer = 'Philippe Fremy <phil dot fremy at free dot fr>',
+}
+
+dependencies =
+{
+ "lua >= 5.1", "lua < 5.5"
+}
+
+build =
+{
+ type = "builtin",
+ modules =
+ {
+ luaunit = "luaunit.lua"
+ },
+ copy_directories = { "doc", "test" }
+}
diff --git a/Data/Libraries/luaunit/luaunit.lua b/Data/Libraries/luaunit/luaunit.lua
new file mode 100644
index 0000000..4741478
--- /dev/null
+++ b/Data/Libraries/luaunit/luaunit.lua
@@ -0,0 +1,3453 @@
+--[[
+ luaunit.lua
+
+Description: A unit testing framework
+Homepage: https://github.com/bluebird75/luaunit
+Development by Philippe Fremy <phil@freehackers.org>
+Based on initial work of Ryu, Gwang (http://www.gpgstudy.com/gpgiki/LuaUnit)
+License: BSD License, see LICENSE.txt
+]]--
+
+require("math")
+local M={}
+
+-- private exported functions (for testing)
+M.private = {}
+
+M.VERSION='3.4'
+M._VERSION=M.VERSION -- For LuaUnit v2 compatibility
+
+-- a version which distinguish between regular Lua and LuaJit
+M._LUAVERSION = (jit and jit.version) or _VERSION
+
+--[[ Some people like assertEquals( actual, expected ) and some people prefer
+assertEquals( expected, actual ).
+]]--
+M.ORDER_ACTUAL_EXPECTED = true
+M.PRINT_TABLE_REF_IN_ERROR_MSG = false
+M.LINE_LENGTH = 80
+M.TABLE_DIFF_ANALYSIS_THRESHOLD = 10 -- display deep analysis for more than 10 items
+M.LIST_DIFF_ANALYSIS_THRESHOLD = 10 -- display deep analysis for more than 10 items
+
+-- this setting allow to remove entries from the stack-trace, for
+-- example to hide a call to a framework which would be calling luaunit
+M.STRIP_EXTRA_ENTRIES_IN_STACK_TRACE = 0
+
+--[[ EPS is meant to help with Lua's floating point math in simple corner
+cases like almostEquals(1.1-0.1, 1), which may not work as-is (e.g. on numbers
+with rational binary representation) if the user doesn't provide some explicit
+error margin.
+
+The default margin used by almostEquals() in such cases is EPS; and since
+Lua may be compiled with different numeric precisions (single vs. double), we
+try to select a useful default for it dynamically. Note: If the initial value
+is not acceptable, it can be changed by the user to better suit specific needs.
+
+See also: https://en.wikipedia.org/wiki/Machine_epsilon
+]]
+M.EPS = 2^-52 -- = machine epsilon for "double", ~2.22E-16
+if math.abs(1.1 - 1 - 0.1) > M.EPS then
+ -- rounding error is above EPS, assume single precision
+ M.EPS = 2^-23 -- = machine epsilon for "float", ~1.19E-07
+end
+
+-- set this to false to debug luaunit
+local STRIP_LUAUNIT_FROM_STACKTRACE = true
+
+M.VERBOSITY_DEFAULT = 10
+M.VERBOSITY_LOW = 1
+M.VERBOSITY_QUIET = 0
+M.VERBOSITY_VERBOSE = 20
+M.DEFAULT_DEEP_ANALYSIS = nil
+M.FORCE_DEEP_ANALYSIS = true
+M.DISABLE_DEEP_ANALYSIS = false
+
+-- set EXPORT_ASSERT_TO_GLOBALS to have all asserts visible as global values
+-- EXPORT_ASSERT_TO_GLOBALS = true
+
+-- we need to keep a copy of the script args before it is overriden
+local cmdline_argv = rawget(_G, "arg")
+
+M.FAILURE_PREFIX = 'LuaUnit test FAILURE: ' -- prefix string for failed tests
+M.SUCCESS_PREFIX = 'LuaUnit test SUCCESS: ' -- prefix string for successful tests finished early
+M.SKIP_PREFIX = 'LuaUnit test SKIP: ' -- prefix string for skipped tests
+
+
+
+M.USAGE=[[Usage: lua <your_test_suite.lua> [options] [testname1 [testname2] ... ]
+Options:
+ -h, --help: Print this help
+ --version: Print version information
+ -v, --verbose: Increase verbosity
+ -q, --quiet: Set verbosity to minimum
+ -e, --error: Stop on first error
+ -f, --failure: Stop on first failure or error
+ -s, --shuffle: Shuffle tests before running them
+ -o, --output OUTPUT: Set output type to OUTPUT
+ Possible values: text, tap, junit, nil
+ -n, --name NAME: For junit only, mandatory name of xml file
+ -r, --repeat NUM: Execute all tests NUM times, e.g. to trig the JIT
+ -p, --pattern PATTERN: Execute all test names matching the Lua PATTERN
+ May be repeated to include several patterns
+ Make sure you escape magic chars like +? with %
+ -x, --exclude PATTERN: Exclude all test names matching the Lua PATTERN
+ May be repeated to exclude several patterns
+ Make sure you escape magic chars like +? with %
+ testname1, testname2, ... : tests to run in the form of testFunction,
+ TestClass or TestClass.testMethod
+
+You may also control LuaUnit options with the following environment variables:
+* LUAUNIT_OUTPUT: same as --output
+* LUAUNIT_JUNIT_FNAME: same as --name ]]
+
+----------------------------------------------------------------
+--
+-- general utility functions
+--
+----------------------------------------------------------------
+
+--[[ Note on catching exit
+
+I have seen the case where running a big suite of test cases and one of them would
+perform a os.exit(0), making the outside world think that the full test suite was executed
+successfully.
+
+This is an attempt to mitigate this problem: we override os.exit() to now let a test
+exit the framework while we are running. When we are not running, it behaves normally.
+]]
+
+M.oldOsExit = os.exit
+os.exit = function(...)
+ if M.LuaUnit and #M.LuaUnit.instances ~= 0 then
+ local msg = [[You are trying to exit but there is still a running instance of LuaUnit.
+LuaUnit expects to run until the end before exiting with a complete status of successful/failed tests.
+
+To force exit LuaUnit while running, please call before os.exit (assuming lu is the luaunit module loaded):
+
+ lu.unregisterCurrentSuite()
+
+]]
+ M.private.error_fmt(2, msg)
+ end
+ M.oldOsExit(...)
+end
+
+local function pcall_or_abort(func, ...)
+ -- unpack is a global function for Lua 5.1, otherwise use table.unpack
+ local unpack = rawget(_G, "unpack") or table.unpack
+ local result = {pcall(func, ...)}
+ if not result[1] then
+ -- an error occurred
+ print(result[2]) -- error message
+ print()
+ print(M.USAGE)
+ os.exit(-1)
+ end
+ return unpack(result, 2)
+end
+
+local crossTypeOrdering = {
+ number = 1, boolean = 2, string = 3, table = 4, other = 5
+}
+local crossTypeComparison = {
+ number = function(a, b) return a < b end,
+ string = function(a, b) return a < b end,
+ other = function(a, b) return tostring(a) < tostring(b) end,
+}
+
+local function crossTypeSort(a, b)
+ local type_a, type_b = type(a), type(b)
+ if type_a == type_b then
+ local func = crossTypeComparison[type_a] or crossTypeComparison.other
+ return func(a, b)
+ end
+ type_a = crossTypeOrdering[type_a] or crossTypeOrdering.other
+ type_b = crossTypeOrdering[type_b] or crossTypeOrdering.other
+ return type_a < type_b
+end
+
+local function __genSortedIndex( t )
+ -- Returns a sequence consisting of t's keys, sorted.
+ local sortedIndex = {}
+
+ for key,_ in pairs(t) do
+ table.insert(sortedIndex, key)
+ end
+
+ table.sort(sortedIndex, crossTypeSort)
+ return sortedIndex
+end
+M.private.__genSortedIndex = __genSortedIndex
+
+local function sortedNext(state, control)
+ -- Equivalent of the next() function of table iteration, but returns the
+ -- keys in sorted order (see __genSortedIndex and crossTypeSort).
+ -- The state is a temporary variable during iteration and contains the
+ -- sorted key table (state.sortedIdx). It also stores the last index (into
+ -- the keys) used by the iteration, to find the next one quickly.
+ local key
+
+ --print("sortedNext: control = "..tostring(control) )
+ if control == nil then
+ -- start of iteration
+ state.count = #state.sortedIdx
+ state.lastIdx = 1
+ key = state.sortedIdx[1]
+ return key, state.t[key]
+ end
+
+ -- normally, we expect the control variable to match the last key used
+ if control ~= state.sortedIdx[state.lastIdx] then
+ -- strange, we have to find the next value by ourselves
+ -- the key table is sorted in crossTypeSort() order! -> use bisection
+ local lower, upper = 1, state.count
+ repeat
+ state.lastIdx = math.modf((lower + upper) / 2)
+ key = state.sortedIdx[state.lastIdx]
+ if key == control then
+ break -- key found (and thus prev index)
+ end
+ if crossTypeSort(key, control) then
+ -- key < control, continue search "right" (towards upper bound)
+ lower = state.lastIdx + 1
+ else
+ -- key > control, continue search "left" (towards lower bound)
+ upper = state.lastIdx - 1
+ end
+ until lower > upper
+ if lower > upper then -- only true if the key wasn't found, ...
+ state.lastIdx = state.count -- ... so ensure no match in code below
+ end
+ end
+
+ -- proceed by retrieving the next value (or nil) from the sorted keys
+ state.lastIdx = state.lastIdx + 1
+ key = state.sortedIdx[state.lastIdx]
+ if key then
+ return key, state.t[key]
+ end
+
+ -- getting here means returning `nil`, which will end the iteration
+end
+
+local function sortedPairs(tbl)
+ -- Equivalent of the pairs() function on tables. Allows to iterate in
+ -- sorted order. As required by "generic for" loops, this will return the
+ -- iterator (function), an "invariant state", and the initial control value.
+ -- (see http://www.lua.org/pil/7.2.html)
+ return sortedNext, {t = tbl, sortedIdx = __genSortedIndex(tbl)}, nil
+end
+M.private.sortedPairs = sortedPairs
+
+-- seed the random with a strongly varying seed
+math.randomseed(math.floor(os.clock()*1E11))
+
+local function randomizeTable( t )
+ -- randomize the item orders of the table t
+ for i = #t, 2, -1 do
+ local j = math.random(i)
+ if i ~= j then
+ t[i], t[j] = t[j], t[i]
+ end
+ end
+end
+M.private.randomizeTable = randomizeTable
+
+local function strsplit(delimiter, text)
+-- Split text into a list consisting of the strings in text, separated
+-- by strings matching delimiter (which may _NOT_ be a pattern).
+-- Example: strsplit(", ", "Anna, Bob, Charlie, Dolores")
+ if delimiter == "" or delimiter == nil then -- this would result in endless loops
+ error("delimiter is nil or empty string!")
+ end
+ if text == nil then
+ return nil
+ end
+
+ local list, pos, first, last = {}, 1
+ while true do
+ first, last = text:find(delimiter, pos, true)
+ if first then -- found?
+ table.insert(list, text:sub(pos, first - 1))
+ pos = last + 1
+ else
+ table.insert(list, text:sub(pos))
+ break
+ end
+ end
+ return list
+end
+M.private.strsplit = strsplit
+
+local function hasNewLine( s )
+ -- return true if s has a newline
+ return (string.find(s, '\n', 1, true) ~= nil)
+end
+M.private.hasNewLine = hasNewLine
+
+local function prefixString( prefix, s )
+ -- Prefix all the lines of s with prefix
+ return prefix .. string.gsub(s, '\n', '\n' .. prefix)
+end
+M.private.prefixString = prefixString
+
+local function strMatch(s, pattern, start, final )
+ -- return true if s matches completely the pattern from index start to index end
+ -- return false in every other cases
+ -- if start is nil, matches from the beginning of the string
+ -- if final is nil, matches to the end of the string
+ start = start or 1
+ final = final or string.len(s)
+
+ local foundStart, foundEnd = string.find(s, pattern, start, false)
+ return foundStart == start and foundEnd == final
+end
+M.private.strMatch = strMatch
+
+local function patternFilter(patterns, expr)
+ -- Run `expr` through the inclusion and exclusion rules defined in patterns
+ -- and return true if expr shall be included, false for excluded.
+ -- Inclusion pattern are defined as normal patterns, exclusions
+ -- patterns start with `!` and are followed by a normal pattern
+
+ -- result: nil = UNKNOWN (not matched yet), true = ACCEPT, false = REJECT
+ -- default: true if no explicit "include" is found, set to false otherwise
+ local default, result = true, nil
+
+ if patterns ~= nil then
+ for _, pattern in ipairs(patterns) do
+ local exclude = pattern:sub(1,1) == '!'
+ if exclude then
+ pattern = pattern:sub(2)
+ else
+ -- at least one include pattern specified, a match is required
+ default = false
+ end
+ -- print('pattern: ',pattern)
+ -- print('exclude: ',exclude)
+ -- print('default: ',default)
+
+ if string.find(expr, pattern) then
+ -- set result to false when excluding, true otherwise
+ result = not exclude
+ end
+ end
+ end
+
+ if result ~= nil then
+ return result
+ end
+ return default
+end
+M.private.patternFilter = patternFilter
+
+local function xmlEscape( s )
+ -- Return s escaped for XML attributes
+ -- escapes table:
+ -- " &quot;
+ -- ' &apos;
+ -- < &lt;
+ -- > &gt;
+ -- & &amp;
+
+ return string.gsub( s, '.', {
+ ['&'] = "&amp;",
+ ['"'] = "&quot;",
+ ["'"] = "&apos;",
+ ['<'] = "&lt;",
+ ['>'] = "&gt;",
+ } )
+end
+M.private.xmlEscape = xmlEscape
+
+local function xmlCDataEscape( s )
+ -- Return s escaped for CData section, escapes: "]]>"
+ return string.gsub( s, ']]>', ']]&gt;' )
+end
+M.private.xmlCDataEscape = xmlCDataEscape
+
+
+local function lstrip( s )
+ --[[Return s with all leading white spaces and tabs removed]]
+ local idx = 0
+ while idx < s:len() do
+ idx = idx + 1
+ local c = s:sub(idx,idx)
+ if c ~= ' ' and c ~= '\t' then
+ break
+ end
+ end
+ return s:sub(idx)
+end
+M.private.lstrip = lstrip
+
+local function extractFileLineInfo( s )
+ --[[ From a string in the form "(leading spaces) dir1/dir2\dir3\file.lua:linenb: msg"
+
+ Return the "file.lua:linenb" information
+ ]]
+ local s2 = lstrip(s)
+ local firstColon = s2:find(':', 1, true)
+ if firstColon == nil then
+ -- string is not in the format file:line:
+ return s
+ end
+ local secondColon = s2:find(':', firstColon+1, true)
+ if secondColon == nil then
+ -- string is not in the format file:line:
+ return s
+ end
+
+ return s2:sub(1, secondColon-1)
+end
+M.private.extractFileLineInfo = extractFileLineInfo
+
+
+local function stripLuaunitTrace2( stackTrace, errMsg )
+ --[[
+ -- Example of a traceback:
+ <<stack traceback:
+ example_with_luaunit.lua:130: in function 'test2_withFailure'
+ ./luaunit.lua:1449: in function <./luaunit.lua:1449>
+ [C]: in function 'xpcall'
+ ./luaunit.lua:1449: in function 'protectedCall'
+ ./luaunit.lua:1508: in function 'execOneFunction'
+ ./luaunit.lua:1596: in function 'runSuiteByInstances'
+ ./luaunit.lua:1660: in function 'runSuiteByNames'
+ ./luaunit.lua:1736: in function 'runSuite'
+ example_with_luaunit.lua:140: in main chunk
+ [C]: in ?>>
+ error message: <<example_with_luaunit.lua:130: expected 2, got 1>>
+
+ Other example:
+ <<stack traceback:
+ ./luaunit.lua:545: in function 'assertEquals'
+ example_with_luaunit.lua:58: in function 'TestToto.test7'
+ ./luaunit.lua:1517: in function <./luaunit.lua:1517>
+ [C]: in function 'xpcall'
+ ./luaunit.lua:1517: in function 'protectedCall'
+ ./luaunit.lua:1578: in function 'execOneFunction'
+ ./luaunit.lua:1677: in function 'runSuiteByInstances'
+ ./luaunit.lua:1730: in function 'runSuiteByNames'
+ ./luaunit.lua:1806: in function 'runSuite'
+ example_with_luaunit.lua:140: in main chunk
+ [C]: in ?>>
+ error message: <<example_with_luaunit.lua:58: expected 2, got 1>>
+
+ <<stack traceback:
+ luaunit2/example_with_luaunit.lua:124: in function 'test1_withFailure'
+ luaunit2/luaunit.lua:1532: in function <luaunit2/luaunit.lua:1532>
+ [C]: in function 'xpcall'
+ luaunit2/luaunit.lua:1532: in function 'protectedCall'
+ luaunit2/luaunit.lua:1591: in function 'execOneFunction'
+ luaunit2/luaunit.lua:1679: in function 'runSuiteByInstances'
+ luaunit2/luaunit.lua:1743: in function 'runSuiteByNames'
+ luaunit2/luaunit.lua:1819: in function 'runSuite'
+ luaunit2/example_with_luaunit.lua:140: in main chunk
+ [C]: in ?>>
+ error message: <<luaunit2/example_with_luaunit.lua:124: expected 2, got 1>>
+
+
+ -- first line is "stack traceback": KEEP
+ -- next line may be luaunit line: REMOVE
+ -- next lines are call in the program under testOk: REMOVE
+ -- next lines are calls from luaunit to call the program under test: KEEP
+
+ -- Strategy:
+ -- keep first line
+ -- remove lines that are part of luaunit
+ -- kepp lines until we hit a luaunit line
+
+ The strategy for stripping is:
+ * keep first line "stack traceback:"
+ * part1:
+ * analyse all lines of the stack from bottom to top of the stack (first line to last line)
+ * extract the "file:line:" part of the line
+ * compare it with the "file:line" part of the error message
+ * if it does not match strip the line
+ * if it matches, keep the line and move to part 2
+ * part2:
+ * anything NOT starting with luaunit.lua is the interesting part of the stack trace
+ * anything starting again with luaunit.lua is part of the test launcher and should be stripped out
+ ]]
+
+ local function isLuaunitInternalLine( s )
+ -- return true if line of stack trace comes from inside luaunit
+ return s:find('[/\\]luaunit%.lua:%d+: ') ~= nil
+ end
+
+ -- print( '<<'..stackTrace..'>>' )
+
+ local t = strsplit( '\n', stackTrace )
+ -- print( prettystr(t) )
+
+ local idx = 2
+
+ local errMsgFileLine = extractFileLineInfo(errMsg)
+ -- print('emfi="'..errMsgFileLine..'"')
+
+ -- remove lines that are still part of luaunit
+ while t[idx] and extractFileLineInfo(t[idx]) ~= errMsgFileLine do
+ -- print('Removing : '..t[idx] )
+ table.remove(t, idx)
+ end
+
+ -- keep lines until we hit luaunit again
+ while t[idx] and (not isLuaunitInternalLine(t[idx])) do
+ -- print('Keeping : '..t[idx] )
+ idx = idx + 1
+ end
+
+ -- remove remaining luaunit lines
+ while t[idx] do
+ -- print('Removing2 : '..t[idx] )
+ table.remove(t, idx)
+ end
+
+ -- print( prettystr(t) )
+ return table.concat( t, '\n')
+
+end
+M.private.stripLuaunitTrace2 = stripLuaunitTrace2
+
+
+local function prettystr_sub(v, indentLevel, printTableRefs, cycleDetectTable )
+ local type_v = type(v)
+ if "string" == type_v then
+ -- use clever delimiters according to content:
+ -- enclose with single quotes if string contains ", but no '
+ if v:find('"', 1, true) and not v:find("'", 1, true) then
+ return "'" .. v .. "'"
+ end
+ -- use double quotes otherwise, escape embedded "
+ return '"' .. v:gsub('"', '\\"') .. '"'
+
+ elseif "table" == type_v then
+ --if v.__class__ then
+ -- return string.gsub( tostring(v), 'table', v.__class__ )
+ --end
+ return M.private._table_tostring(v, indentLevel, printTableRefs, cycleDetectTable)
+
+ elseif "number" == type_v then
+ -- eliminate differences in formatting between various Lua versions
+ if v ~= v then
+ return "#NaN" -- "not a number"
+ end
+ if v == math.huge then
+ return "#Inf" -- "infinite"
+ end
+ if v == -math.huge then
+ return "-#Inf"
+ end
+ if _VERSION == "Lua 5.3" then
+ local i = math.tointeger(v)
+ if i then
+ return tostring(i)
+ end
+ end
+ end
+
+ return tostring(v)
+end
+
+local function prettystr( v )
+ --[[ Pretty string conversion, to display the full content of a variable of any type.
+
+ * string are enclosed with " by default, or with ' if string contains a "
+ * tables are expanded to show their full content, with indentation in case of nested tables
+ ]]--
+ local cycleDetectTable = {}
+ local s = prettystr_sub(v, 1, M.PRINT_TABLE_REF_IN_ERROR_MSG, cycleDetectTable)
+ if cycleDetectTable.detected and not M.PRINT_TABLE_REF_IN_ERROR_MSG then
+ -- some table contain recursive references,
+ -- so we must recompute the value by including all table references
+ -- else the result looks like crap
+ cycleDetectTable = {}
+ s = prettystr_sub(v, 1, true, cycleDetectTable)
+ end
+ return s
+end
+M.prettystr = prettystr
+
+function M.adjust_err_msg_with_iter( err_msg, iter_msg )
+ --[[ Adjust the error message err_msg: trim the FAILURE_PREFIX or SUCCESS_PREFIX information if needed,
+ add the iteration message if any and return the result.
+
+ err_msg: string, error message captured with pcall
+ iter_msg: a string describing the current iteration ("iteration N") or nil
+ if there is no iteration in this test.
+
+ Returns: (new_err_msg, test_status)
+ new_err_msg: string, adjusted error message, or nil in case of success
+ test_status: M.NodeStatus.FAIL, SUCCESS or ERROR according to the information
+ contained in the error message.
+ ]]
+ if iter_msg then
+ iter_msg = iter_msg..', '
+ else
+ iter_msg = ''
+ end
+
+ local RE_FILE_LINE = '.*:%d+: '
+
+ -- error message is not necessarily a string,
+ -- so convert the value to string with prettystr()
+ if type( err_msg ) ~= 'string' then
+ err_msg = prettystr( err_msg )
+ end
+
+ if (err_msg:find( M.SUCCESS_PREFIX ) == 1) or err_msg:match( '('..RE_FILE_LINE..')' .. M.SUCCESS_PREFIX .. ".*" ) then
+ -- test finished early with success()
+ return nil, M.NodeStatus.SUCCESS
+ end
+
+ if (err_msg:find( M.SKIP_PREFIX ) == 1) or (err_msg:match( '('..RE_FILE_LINE..')' .. M.SKIP_PREFIX .. ".*" ) ~= nil) then
+ -- substitute prefix by iteration message
+ err_msg = err_msg:gsub('.*'..M.SKIP_PREFIX, iter_msg, 1)
+ -- print("failure detected")
+ return err_msg, M.NodeStatus.SKIP
+ end
+
+ if (err_msg:find( M.FAILURE_PREFIX ) == 1) or (err_msg:match( '('..RE_FILE_LINE..')' .. M.FAILURE_PREFIX .. ".*" ) ~= nil) then
+ -- substitute prefix by iteration message
+ err_msg = err_msg:gsub(M.FAILURE_PREFIX, iter_msg, 1)
+ -- print("failure detected")
+ return err_msg, M.NodeStatus.FAIL
+ end
+
+
+
+ -- print("error detected")
+ -- regular error, not a failure
+ if iter_msg then
+ local match
+ -- "./test\\test_luaunit.lua:2241: some error msg
+ match = err_msg:match( '(.*:%d+: ).*' )
+ if match then
+ err_msg = err_msg:gsub( match, match .. iter_msg )
+ else
+ -- no file:line: infromation, just add the iteration info at the beginning of the line
+ err_msg = iter_msg .. err_msg
+ end
+ end
+ return err_msg, M.NodeStatus.ERROR
+end
+
+local function tryMismatchFormatting( table_a, table_b, doDeepAnalysis, margin )
+ --[[
+ Prepares a nice error message when comparing tables, performing a deeper
+ analysis.
+
+ Arguments:
+ * table_a, table_b: tables to be compared
+ * doDeepAnalysis:
+ M.DEFAULT_DEEP_ANALYSIS: (the default if not specified) perform deep analysis only for big lists and big dictionnaries
+ M.FORCE_DEEP_ANALYSIS : always perform deep analysis
+ M.DISABLE_DEEP_ANALYSIS: never perform deep analysis
+ * margin: supplied only for almost equality
+
+ Returns: {success, result}
+ * success: false if deep analysis could not be performed
+ in this case, just use standard assertion message
+ * result: if success is true, a multi-line string with deep analysis of the two lists
+ ]]
+
+ -- check if table_a & table_b are suitable for deep analysis
+ if type(table_a) ~= 'table' or type(table_b) ~= 'table' then
+ return false
+ end
+
+ if doDeepAnalysis == M.DISABLE_DEEP_ANALYSIS then
+ return false
+ end
+
+ local len_a, len_b, isPureList = #table_a, #table_b, true
+
+ for k1, v1 in pairs(table_a) do
+ if type(k1) ~= 'number' or k1 > len_a then
+ -- this table a mapping
+ isPureList = false
+ break
+ end
+ end
+
+ if isPureList then
+ for k2, v2 in pairs(table_b) do
+ if type(k2) ~= 'number' or k2 > len_b then
+ -- this table a mapping
+ isPureList = false
+ break
+ end
+ end
+ end
+
+ if isPureList and math.min(len_a, len_b) < M.LIST_DIFF_ANALYSIS_THRESHOLD then
+ if not (doDeepAnalysis == M.FORCE_DEEP_ANALYSIS) then
+ return false
+ end
+ end
+
+ if isPureList then
+ return M.private.mismatchFormattingPureList( table_a, table_b, margin )
+ else
+ -- only work on mapping for the moment
+ -- return M.private.mismatchFormattingMapping( table_a, table_b, doDeepAnalysis )
+ return false
+ end
+end
+M.private.tryMismatchFormatting = tryMismatchFormatting
+
+local function getTaTbDescr()
+ if not M.ORDER_ACTUAL_EXPECTED then
+ return 'expected', 'actual'
+ end
+ return 'actual', 'expected'
+end
+
+local function extendWithStrFmt( res, ... )
+ table.insert( res, string.format( ... ) )
+end
+
+local function mismatchFormattingMapping( table_a, table_b, doDeepAnalysis )
+ --[[
+ Prepares a nice error message when comparing tables which are not pure lists, performing a deeper
+ analysis.
+
+ Returns: {success, result}
+ * success: false if deep analysis could not be performed
+ in this case, just use standard assertion message
+ * result: if success is true, a multi-line string with deep analysis of the two lists
+ ]]
+
+ -- disable for the moment
+ --[[
+ local result = {}
+ local descrTa, descrTb = getTaTbDescr()
+
+ local keysCommon = {}
+ local keysOnlyTa = {}
+ local keysOnlyTb = {}
+ local keysDiffTaTb = {}
+
+ local k, v
+
+ for k,v in pairs( table_a ) do
+ if is_equal( v, table_b[k] ) then
+ table.insert( keysCommon, k )
+ else
+ if table_b[k] == nil then
+ table.insert( keysOnlyTa, k )
+ else
+ table.insert( keysDiffTaTb, k )
+ end
+ end
+ end
+
+ for k,v in pairs( table_b ) do
+ if not is_equal( v, table_a[k] ) and table_a[k] == nil then
+ table.insert( keysOnlyTb, k )
+ end
+ end
+
+ local len_a = #keysCommon + #keysDiffTaTb + #keysOnlyTa
+ local len_b = #keysCommon + #keysDiffTaTb + #keysOnlyTb
+ local limited_display = (len_a < 5 or len_b < 5)
+
+ if math.min(len_a, len_b) < M.TABLE_DIFF_ANALYSIS_THRESHOLD then
+ return false
+ end
+
+ if not limited_display then
+ if len_a == len_b then
+ extendWithStrFmt( result, 'Table A (%s) and B (%s) both have %d items', descrTa, descrTb, len_a )
+ else
+ extendWithStrFmt( result, 'Table A (%s) has %d items and table B (%s) has %d items', descrTa, len_a, descrTb, len_b )
+ end
+
+ if #keysCommon == 0 and #keysDiffTaTb == 0 then
+ table.insert( result, 'Table A and B have no keys in common, they are totally different')
+ else
+ local s_other = 'other '
+ if #keysCommon then
+ extendWithStrFmt( result, 'Table A and B have %d identical items', #keysCommon )
+ else
+ table.insert( result, 'Table A and B have no identical items' )
+ s_other = ''
+ end
+
+ if #keysDiffTaTb ~= 0 then
+ result[#result] = string.format( '%s and %d items differing present in both tables', result[#result], #keysDiffTaTb)
+ else
+ result[#result] = string.format( '%s and no %sitems differing present in both tables', result[#result], s_other, #keysDiffTaTb)
+ end
+ end
+
+ extendWithStrFmt( result, 'Table A has %d keys not present in table B and table B has %d keys not present in table A', #keysOnlyTa, #keysOnlyTb )
+ end
+
+ local function keytostring(k)
+ if "string" == type(k) and k:match("^[_%a][_%w]*$") then
+ return k
+ end
+ return prettystr(k)
+ end
+
+ if #keysDiffTaTb ~= 0 then
+ table.insert( result, 'Items differing in A and B:')
+ for k,v in sortedPairs( keysDiffTaTb ) do
+ extendWithStrFmt( result, ' - A[%s]: %s', keytostring(v), prettystr(table_a[v]) )
+ extendWithStrFmt( result, ' + B[%s]: %s', keytostring(v), prettystr(table_b[v]) )
+ end
+ end
+
+ if #keysOnlyTa ~= 0 then
+ table.insert( result, 'Items only in table A:' )
+ for k,v in sortedPairs( keysOnlyTa ) do
+ extendWithStrFmt( result, ' - A[%s]: %s', keytostring(v), prettystr(table_a[v]) )
+ end
+ end
+
+ if #keysOnlyTb ~= 0 then
+ table.insert( result, 'Items only in table B:' )
+ for k,v in sortedPairs( keysOnlyTb ) do
+ extendWithStrFmt( result, ' + B[%s]: %s', keytostring(v), prettystr(table_b[v]) )
+ end
+ end
+
+ if #keysCommon ~= 0 then
+ table.insert( result, 'Items common to A and B:')
+ for k,v in sortedPairs( keysCommon ) do
+ extendWithStrFmt( result, ' = A and B [%s]: %s', keytostring(v), prettystr(table_a[v]) )
+ end
+ end
+
+ return true, table.concat( result, '\n')
+ ]]
+end
+M.private.mismatchFormattingMapping = mismatchFormattingMapping
+
+local function mismatchFormattingPureList( table_a, table_b, margin )
+ --[[
+ Prepares a nice error message when comparing tables which are lists, performing a deeper
+ analysis.
+
+ margin is supplied only for almost equality
+
+ Returns: {success, result}
+ * success: false if deep analysis could not be performed
+ in this case, just use standard assertion message
+ * result: if success is true, a multi-line string with deep analysis of the two lists
+ ]]
+ local result, descrTa, descrTb = {}, getTaTbDescr()
+
+ local len_a, len_b, refa, refb = #table_a, #table_b, '', ''
+ if M.PRINT_TABLE_REF_IN_ERROR_MSG then
+ refa, refb = string.format( '<%s> ', M.private.table_ref(table_a)), string.format('<%s> ', M.private.table_ref(table_b) )
+ end
+ local longest, shortest = math.max(len_a, len_b), math.min(len_a, len_b)
+ local deltalv = longest - shortest
+
+ local commonUntil = shortest
+ for i = 1, shortest do
+ if not M.private.is_table_equals(table_a[i], table_b[i], margin) then
+ commonUntil = i - 1
+ break
+ end
+ end
+
+ local commonBackTo = shortest - 1
+ for i = 0, shortest - 1 do
+ if not M.private.is_table_equals(table_a[len_a-i], table_b[len_b-i], margin) then
+ commonBackTo = i - 1
+ break
+ end
+ end
+
+
+ table.insert( result, 'List difference analysis:' )
+ if len_a == len_b then
+ -- TODO: handle expected/actual naming
+ extendWithStrFmt( result, '* lists %sA (%s) and %sB (%s) have the same size', refa, descrTa, refb, descrTb )
+ else
+ extendWithStrFmt( result, '* list sizes differ: list %sA (%s) has %d items, list %sB (%s) has %d items', refa, descrTa, len_a, refb, descrTb, len_b )
+ end
+
+ extendWithStrFmt( result, '* lists A and B start differing at index %d', commonUntil+1 )
+ if commonBackTo >= 0 then
+ if deltalv > 0 then
+ extendWithStrFmt( result, '* lists A and B are equal again from index %d for A, %d for B', len_a-commonBackTo, len_b-commonBackTo )
+ else
+ extendWithStrFmt( result, '* lists A and B are equal again from index %d', len_a-commonBackTo )
+ end
+ end
+
+ local function insertABValue(ai, bi)
+ bi = bi or ai
+ if M.private.is_table_equals( table_a[ai], table_b[bi], margin) then
+ return extendWithStrFmt( result, ' = A[%d], B[%d]: %s', ai, bi, prettystr(table_a[ai]) )
+ else
+ extendWithStrFmt( result, ' - A[%d]: %s', ai, prettystr(table_a[ai]))
+ extendWithStrFmt( result, ' + B[%d]: %s', bi, prettystr(table_b[bi]))
+ end
+ end
+
+ -- common parts to list A & B, at the beginning
+ if commonUntil > 0 then
+ table.insert( result, '* Common parts:' )
+ for i = 1, commonUntil do
+ insertABValue( i )
+ end
+ end
+
+ -- diffing parts to list A & B
+ if commonUntil < shortest - commonBackTo - 1 then
+ table.insert( result, '* Differing parts:' )
+ for i = commonUntil + 1, shortest - commonBackTo - 1 do
+ insertABValue( i )
+ end
+ end
+
+ -- display indexes of one list, with no match on other list
+ if shortest - commonBackTo <= longest - commonBackTo - 1 then
+ table.insert( result, '* Present only in one list:' )
+ for i = shortest - commonBackTo, longest - commonBackTo - 1 do
+ if len_a > len_b then
+ extendWithStrFmt( result, ' - A[%d]: %s', i, prettystr(table_a[i]) )
+ -- table.insert( result, '+ (no matching B index)')
+ else
+ -- table.insert( result, '- no matching A index')
+ extendWithStrFmt( result, ' + B[%d]: %s', i, prettystr(table_b[i]) )
+ end
+ end
+ end
+
+ -- common parts to list A & B, at the end
+ if commonBackTo >= 0 then
+ table.insert( result, '* Common parts at the end of the lists' )
+ for i = longest - commonBackTo, longest do
+ if len_a > len_b then
+ insertABValue( i, i-deltalv )
+ else
+ insertABValue( i-deltalv, i )
+ end
+ end
+ end
+
+ return true, table.concat( result, '\n')
+end
+M.private.mismatchFormattingPureList = mismatchFormattingPureList
+
+local function prettystrPairs(value1, value2, suffix_a, suffix_b)
+ --[[
+ This function helps with the recurring task of constructing the "expected
+ vs. actual" error messages. It takes two arbitrary values and formats
+ corresponding strings with prettystr().
+
+ To keep the (possibly complex) output more readable in case the resulting
+ strings contain line breaks, they get automatically prefixed with additional
+ newlines. Both suffixes are optional (default to empty strings), and get
+ appended to the "value1" string. "suffix_a" is used if line breaks were
+ encountered, "suffix_b" otherwise.
+
+ Returns the two formatted strings (including padding/newlines).
+ ]]
+ local str1, str2 = prettystr(value1), prettystr(value2)
+ if hasNewLine(str1) or hasNewLine(str2) then
+ -- line break(s) detected, add padding
+ return "\n" .. str1 .. (suffix_a or ""), "\n" .. str2
+ end
+ return str1 .. (suffix_b or ""), str2
+end
+M.private.prettystrPairs = prettystrPairs
+
+local UNKNOWN_REF = 'table 00-unknown ref'
+local ref_generator = { value=1, [UNKNOWN_REF]=0 }
+
+local function table_ref( t )
+ -- return the default tostring() for tables, with the table ID, even if the table has a metatable
+ -- with the __tostring converter
+ local ref = ''
+ local mt = getmetatable( t )
+ if mt == nil then
+ ref = tostring(t)
+ else
+ local success, result
+ success, result = pcall(setmetatable, t, nil)
+ if not success then
+ -- protected table, if __tostring is defined, we can
+ -- not get the reference. And we can not know in advance.
+ ref = tostring(t)
+ if not ref:match( 'table: 0?x?[%x]+' ) then
+ return UNKNOWN_REF
+ end
+ else
+ ref = tostring(t)
+ setmetatable( t, mt )
+ end
+ end
+ -- strip the "table: " part
+ ref = ref:sub(8)
+ if ref ~= UNKNOWN_REF and ref_generator[ref] == nil then
+ -- Create a new reference number
+ ref_generator[ref] = ref_generator.value
+ ref_generator.value = ref_generator.value+1
+ end
+ if M.PRINT_TABLE_REF_IN_ERROR_MSG then
+ return string.format('table %02d-%s', ref_generator[ref], ref)
+ else
+ return string.format('table %02d', ref_generator[ref])
+ end
+end
+M.private.table_ref = table_ref
+
+local TABLE_TOSTRING_SEP = ", "
+local TABLE_TOSTRING_SEP_LEN = string.len(TABLE_TOSTRING_SEP)
+
+local function _table_tostring( tbl, indentLevel, printTableRefs, cycleDetectTable )
+ printTableRefs = printTableRefs or M.PRINT_TABLE_REF_IN_ERROR_MSG
+ cycleDetectTable = cycleDetectTable or {}
+ cycleDetectTable[tbl] = true
+
+ local result, dispOnMultLines = {}, false
+
+ -- like prettystr but do not enclose with "" if the string is just alphanumerical
+ -- this is better for displaying table keys who are often simple strings
+ local function keytostring(k)
+ if "string" == type(k) and k:match("^[_%a][_%w]*$") then
+ return k
+ end
+ return prettystr_sub(k, indentLevel+1, printTableRefs, cycleDetectTable)
+ end
+
+ local mt = getmetatable( tbl )
+
+ if mt and mt.__tostring then
+ -- if table has a __tostring() function in its metatable, use it to display the table
+ -- else, compute a regular table
+ result = tostring(tbl)
+ if type(result) ~= 'string' then
+ return string.format( '<invalid tostring() result: "%s" >', prettystr(result) )
+ end
+ result = strsplit( '\n', result )
+ return M.private._table_tostring_format_multiline_string( result, indentLevel )
+
+ else
+ -- no metatable, compute the table representation
+
+ local entry, count, seq_index = nil, 0, 1
+ for k, v in sortedPairs( tbl ) do
+
+ -- key part
+ if k == seq_index then
+ -- for the sequential part of tables, we'll skip the "<key>=" output
+ entry = ''
+ seq_index = seq_index + 1
+ elseif cycleDetectTable[k] then
+ -- recursion in the key detected
+ cycleDetectTable.detected = true
+ entry = "<"..table_ref(k)..">="
+ else
+ entry = keytostring(k) .. "="
+ end
+
+ -- value part
+ if cycleDetectTable[v] then
+ -- recursion in the value detected!
+ cycleDetectTable.detected = true
+ entry = entry .. "<"..table_ref(v)..">"
+ else
+ entry = entry ..
+ prettystr_sub( v, indentLevel+1, printTableRefs, cycleDetectTable )
+ end
+ count = count + 1
+ result[count] = entry
+ end
+ return M.private._table_tostring_format_result( tbl, result, indentLevel, printTableRefs )
+ end
+
+end
+M.private._table_tostring = _table_tostring -- prettystr_sub() needs it
+
+local function _table_tostring_format_multiline_string( tbl_str, indentLevel )
+ local indentString = '\n'..string.rep(" ", indentLevel - 1)
+ return table.concat( tbl_str, indentString )
+
+end
+M.private._table_tostring_format_multiline_string = _table_tostring_format_multiline_string
+
+
+local function _table_tostring_format_result( tbl, result, indentLevel, printTableRefs )
+ -- final function called in _table_to_string() to format the resulting list of
+ -- string describing the table.
+
+ local dispOnMultLines = false
+
+ -- set dispOnMultLines to true if the maximum LINE_LENGTH would be exceeded with the values
+ local totalLength = 0
+ for k, v in ipairs( result ) do
+ totalLength = totalLength + string.len( v )
+ if totalLength >= M.LINE_LENGTH then
+ dispOnMultLines = true
+ break
+ end
+ end
+
+ -- set dispOnMultLines to true if the max LINE_LENGTH would be exceeded
+ -- with the values and the separators.
+ if not dispOnMultLines then
+ -- adjust with length of separator(s):
+ -- two items need 1 sep, three items two seps, ... plus len of '{}'
+ if #result > 0 then
+ totalLength = totalLength + TABLE_TOSTRING_SEP_LEN * (#result - 1)
+ end
+ dispOnMultLines = (totalLength + 2 >= M.LINE_LENGTH)
+ end
+
+ -- now reformat the result table (currently holding element strings)
+ if dispOnMultLines then
+ local indentString = string.rep(" ", indentLevel - 1)
+ result = {
+ "{\n ",
+ indentString,
+ table.concat(result, ",\n " .. indentString),
+ "\n",
+ indentString,
+ "}"
+ }
+ else
+ result = {"{", table.concat(result, TABLE_TOSTRING_SEP), "}"}
+ end
+ if printTableRefs then
+ table.insert(result, 1, "<"..table_ref(tbl).."> ") -- prepend table ref
+ end
+ return table.concat(result)
+end
+M.private._table_tostring_format_result = _table_tostring_format_result -- prettystr_sub() needs it
+
+local function table_findkeyof(t, element)
+ -- Return the key k of the given element in table t, so that t[k] == element
+ -- (or `nil` if element is not present within t). Note that we use our
+ -- 'general' is_equal comparison for matching, so this function should
+ -- handle table-type elements gracefully and consistently.
+ if type(t) == "table" then
+ for k, v in pairs(t) do
+ if M.private.is_table_equals(v, element) then
+ return k
+ end
+ end
+ end
+ return nil
+end
+
+local function _is_table_items_equals(actual, expected )
+ local type_a, type_e = type(actual), type(expected)
+
+ if type_a ~= type_e then
+ return false
+
+ elseif (type_a == 'table') --[[and (type_e == 'table')]] then
+ for k, v in pairs(actual) do
+ if table_findkeyof(expected, v) == nil then
+ return false -- v not contained in expected
+ end
+ end
+ for k, v in pairs(expected) do
+ if table_findkeyof(actual, v) == nil then
+ return false -- v not contained in actual
+ end
+ end
+ return true
+
+ elseif actual ~= expected then
+ return false
+ end
+
+ return true
+end
+
+--[[
+This is a specialized metatable to help with the bookkeeping of recursions
+in _is_table_equals(). It provides an __index table that implements utility
+functions for easier management of the table. The "cached" method queries
+the state of a specific (actual,expected) pair; and the "store" method sets
+this state to the given value. The state of pairs not "seen" / visited is
+assumed to be `nil`.
+]]
+local _recursion_cache_MT = {
+ __index = {
+ -- Return the cached value for an (actual,expected) pair (or `nil`)
+ cached = function(t, actual, expected)
+ local subtable = t[actual] or {}
+ return subtable[expected]
+ end,
+
+ -- Store cached value for a specific (actual,expected) pair.
+ -- Returns the value, so it's easy to use for a "tailcall" (return ...).
+ store = function(t, actual, expected, value, asymmetric)
+ local subtable = t[actual]
+ if not subtable then
+ subtable = {}
+ t[actual] = subtable
+ end
+ subtable[expected] = value
+
+ -- Unless explicitly marked "asymmetric": Consider the recursion
+ -- on (expected,actual) to be equivalent to (actual,expected) by
+ -- default, and thus cache the value for both.
+ if not asymmetric then
+ t:store(expected, actual, value, true)
+ end
+
+ return value
+ end
+ }
+}
+
+local function _is_table_equals(actual, expected, cycleDetectTable, marginForAlmostEqual)
+ --[[Returns true if both table are equal.
+
+ If argument marginForAlmostEqual is suppied, number comparison is done using alomstEqual instead
+ of strict equality.
+
+ cycleDetectTable is an internal argument used during recursion on tables.
+ ]]
+ --print('_is_table_equals( \n '..prettystr(actual)..'\n , '..prettystr(expected)..
+ -- '\n , '..prettystr(cycleDetectTable)..'\n , '..prettystr(marginForAlmostEqual)..' )')
+
+ local type_a, type_e = type(actual), type(expected)
+
+ if type_a ~= type_e then
+ return false -- different types won't match
+ end
+
+ if type_a == 'number' then
+ if marginForAlmostEqual ~= nil then
+ return M.almostEquals(actual, expected, marginForAlmostEqual)
+ else
+ return actual == expected
+ end
+ elseif type_a ~= 'table' then
+ -- other types compare directly
+ return actual == expected
+ end
+
+ cycleDetectTable = cycleDetectTable or { actual={}, expected={} }
+ if cycleDetectTable.actual[ actual ] then
+ -- oh, we hit a cycle in actual
+ if cycleDetectTable.expected[ expected ] then
+ -- uh, we hit a cycle at the same time in expected
+ -- so the two tables have similar structure
+ return true
+ end
+
+ -- cycle was hit only in actual, the structure differs from expected
+ return false
+ end
+
+ if cycleDetectTable.expected[ expected ] then
+ -- no cycle in actual, but cycle in expected
+ -- the structure differ
+ return false
+ end
+
+ -- at this point, no table cycle detected, we are
+ -- seeing this table for the first time
+
+ -- mark the cycle detection
+ cycleDetectTable.actual[ actual ] = true
+ cycleDetectTable.expected[ expected ] = true
+
+
+ local actualKeysMatched = {}
+ for k, v in pairs(actual) do
+ actualKeysMatched[k] = true -- Keep track of matched keys
+ if not _is_table_equals(v, expected[k], cycleDetectTable, marginForAlmostEqual) then
+ -- table differs on this key
+ -- clear the cycle detection before returning
+ cycleDetectTable.actual[ actual ] = nil
+ cycleDetectTable.expected[ expected ] = nil
+ return false
+ end
+ end
+
+ for k, v in pairs(expected) do
+ if not actualKeysMatched[k] then
+ -- Found a key that we did not see in "actual" -> mismatch
+ -- clear the cycle detection before returning
+ cycleDetectTable.actual[ actual ] = nil
+ cycleDetectTable.expected[ expected ] = nil
+ return false
+ end
+ -- Otherwise actual[k] was already matched against v = expected[k].
+ end
+
+ -- all key match, we have a match !
+ cycleDetectTable.actual[ actual ] = nil
+ cycleDetectTable.expected[ expected ] = nil
+ return true
+end
+M.private._is_table_equals = _is_table_equals
+
+local function failure(main_msg, extra_msg_or_nil, level)
+ -- raise an error indicating a test failure
+ -- for error() compatibility we adjust "level" here (by +1), to report the
+ -- calling context
+ local msg
+ if type(extra_msg_or_nil) == 'string' and extra_msg_or_nil:len() > 0 then
+ msg = extra_msg_or_nil .. '\n' .. main_msg
+ else
+ msg = main_msg
+ end
+ error(M.FAILURE_PREFIX .. msg, (level or 1) + 1 + M.STRIP_EXTRA_ENTRIES_IN_STACK_TRACE)
+end
+
+local function is_table_equals(actual, expected, marginForAlmostEqual)
+ return _is_table_equals(actual, expected, nil, marginForAlmostEqual)
+end
+M.private.is_table_equals = is_table_equals
+
+local function fail_fmt(level, extra_msg_or_nil, ...)
+ -- failure with printf-style formatted message and given error level
+ failure(string.format(...), extra_msg_or_nil, (level or 1) + 1)
+end
+M.private.fail_fmt = fail_fmt
+
+local function error_fmt(level, ...)
+ -- printf-style error()
+ error(string.format(...), (level or 1) + 1 + M.STRIP_EXTRA_ENTRIES_IN_STACK_TRACE)
+end
+M.private.error_fmt = error_fmt
+
+----------------------------------------------------------------
+--
+-- assertions
+--
+----------------------------------------------------------------
+
+local function errorMsgEquality(actual, expected, doDeepAnalysis, margin)
+ -- margin is supplied only for almost equal verification
+
+ if not M.ORDER_ACTUAL_EXPECTED then
+ expected, actual = actual, expected
+ end
+ if type(expected) == 'string' or type(expected) == 'table' then
+ local strExpected, strActual = prettystrPairs(expected, actual)
+ local result = string.format("expected: %s\nactual: %s", strExpected, strActual)
+ if margin then
+ result = result .. '\nwere not equal by the margin of: '..prettystr(margin)
+ end
+
+ -- extend with mismatch analysis if possible:
+ local success, mismatchResult
+ success, mismatchResult = tryMismatchFormatting( actual, expected, doDeepAnalysis, margin )
+ if success then
+ result = table.concat( { result, mismatchResult }, '\n' )
+ end
+ return result
+ end
+ return string.format("expected: %s, actual: %s",
+ prettystr(expected), prettystr(actual))
+end
+
+function M.assertError(f, ...)
+ -- assert that calling f with the arguments will raise an error
+ -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error
+ if pcall( f, ... ) then
+ failure( "Expected an error when calling function but no error generated", nil, 2 )
+ end
+end
+
+function M.fail( msg )
+ -- stops a test due to a failure
+ failure( msg, nil, 2 )
+end
+
+function M.failIf( cond, msg )
+ -- Fails a test with "msg" if condition is true
+ if cond then
+ failure( msg, nil, 2 )
+ end
+end
+
+function M.skip(msg)
+ -- skip a running test
+ error_fmt(2, M.SKIP_PREFIX .. msg)
+end
+
+function M.skipIf( cond, msg )
+ -- skip a running test if condition is met
+ if cond then
+ error_fmt(2, M.SKIP_PREFIX .. msg)
+ end
+end
+
+function M.runOnlyIf( cond, msg )
+ -- continue a running test if condition is met, else skip it
+ if not cond then
+ error_fmt(2, M.SKIP_PREFIX .. prettystr(msg))
+ end
+end
+
+function M.success()
+ -- stops a test with a success
+ error_fmt(2, M.SUCCESS_PREFIX)
+end
+
+function M.successIf( cond )
+ -- stops a test with a success if condition is met
+ if cond then
+ error_fmt(2, M.SUCCESS_PREFIX)
+ end
+end
+
+
+------------------------------------------------------------------
+-- Equality assertions
+------------------------------------------------------------------
+
+function M.assertEquals(actual, expected, extra_msg_or_nil, doDeepAnalysis)
+ if type(actual) == 'table' and type(expected) == 'table' then
+ if not is_table_equals(actual, expected) then
+ failure( errorMsgEquality(actual, expected, doDeepAnalysis), extra_msg_or_nil, 2 )
+ end
+ elseif type(actual) ~= type(expected) then
+ failure( errorMsgEquality(actual, expected), extra_msg_or_nil, 2 )
+ elseif actual ~= expected then
+ failure( errorMsgEquality(actual, expected), extra_msg_or_nil, 2 )
+ end
+end
+
+function M.almostEquals( actual, expected, margin )
+ if type(actual) ~= 'number' or type(expected) ~= 'number' or type(margin) ~= 'number' then
+ error_fmt(3, 'almostEquals: must supply only number arguments.\nArguments supplied: %s, %s, %s',
+ prettystr(actual), prettystr(expected), prettystr(margin))
+ end
+ if margin < 0 then
+ error_fmt(3, 'almostEquals: margin must not be negative, current value is ' .. margin)
+ end
+ return math.abs(expected - actual) <= margin
+end
+
+function M.assertAlmostEquals( actual, expected, margin, extra_msg_or_nil )
+ -- check that two floats are close by margin
+ margin = margin or M.EPS
+ if type(margin) ~= 'number' then
+ error_fmt(2, 'almostEquals: margin must be a number, not %s', prettystr(margin))
+ end
+
+ if type(actual) == 'table' and type(expected) == 'table' then
+ -- handle almost equals for table
+ if not is_table_equals(actual, expected, margin) then
+ failure( errorMsgEquality(actual, expected, nil, margin), extra_msg_or_nil, 2 )
+ end
+ elseif type(actual) == 'number' and type(expected) == 'number' and type(margin) == 'number' then
+ if not M.almostEquals(actual, expected, margin) then
+ if not M.ORDER_ACTUAL_EXPECTED then
+ expected, actual = actual, expected
+ end
+ local delta = math.abs(actual - expected)
+ fail_fmt(2, extra_msg_or_nil, 'Values are not almost equal\n' ..
+ 'Actual: %s, expected: %s, delta %s above margin of %s',
+ actual, expected, delta, margin)
+ end
+ else
+ error_fmt(3, 'almostEquals: must supply only number or table arguments.\nArguments supplied: %s, %s, %s',
+ prettystr(actual), prettystr(expected), prettystr(margin))
+ end
+end
+
+function M.assertNotEquals(actual, expected, extra_msg_or_nil)
+ if type(actual) ~= type(expected) then
+ return
+ end
+
+ if type(actual) == 'table' and type(expected) == 'table' then
+ if not is_table_equals(actual, expected) then
+ return
+ end
+ elseif actual ~= expected then
+ return
+ end
+ fail_fmt(2, extra_msg_or_nil, 'Received the not expected value: %s', prettystr(actual))
+end
+
+function M.assertNotAlmostEquals( actual, expected, margin, extra_msg_or_nil )
+ -- check that two floats are not close by margin
+ margin = margin or M.EPS
+ if M.almostEquals(actual, expected, margin) then
+ if not M.ORDER_ACTUAL_EXPECTED then
+ expected, actual = actual, expected
+ end
+ local delta = math.abs(actual - expected)
+ fail_fmt(2, extra_msg_or_nil, 'Values are almost equal\nActual: %s, expected: %s' ..
+ ', delta %s below margin of %s',
+ actual, expected, delta, margin)
+ end
+end
+
+function M.assertItemsEquals(actual, expected, extra_msg_or_nil)
+ -- checks that the items of table expected
+ -- are contained in table actual. Warning, this function
+ -- is at least O(n^2)
+ if not _is_table_items_equals(actual, expected ) then
+ expected, actual = prettystrPairs(expected, actual)
+ fail_fmt(2, extra_msg_or_nil, 'Content of the tables are not identical:\nExpected: %s\nActual: %s',
+ expected, actual)
+ end
+end
+
+------------------------------------------------------------------
+-- String assertion
+------------------------------------------------------------------
+
+function M.assertStrContains( str, sub, isPattern, extra_msg_or_nil )
+ -- this relies on lua string.find function
+ -- a string always contains the empty string
+ -- assert( type(str) == 'string', 'Argument 1 of assertStrContains() should be a string.' ) )
+ -- assert( type(sub) == 'string', 'Argument 2 of assertStrContains() should be a string.' ) )
+ if not string.find(str, sub, 1, not isPattern) then
+ sub, str = prettystrPairs(sub, str, '\n')
+ fail_fmt(2, extra_msg_or_nil, 'Could not find %s %s in string %s',
+ isPattern and 'pattern' or 'substring', sub, str)
+ end
+end
+
+function M.assertStrIContains( str, sub, extra_msg_or_nil )
+ -- this relies on lua string.find function
+ -- a string always contains the empty string
+ if not string.find(str:lower(), sub:lower(), 1, true) then
+ sub, str = prettystrPairs(sub, str, '\n')
+ fail_fmt(2, extra_msg_or_nil, 'Could not find (case insensitively) substring %s in string %s',
+ sub, str)
+ end
+end
+
+function M.assertNotStrContains( str, sub, isPattern, extra_msg_or_nil )
+ -- this relies on lua string.find function
+ -- a string always contains the empty string
+ if string.find(str, sub, 1, not isPattern) then
+ sub, str = prettystrPairs(sub, str, '\n')
+ fail_fmt(2, extra_msg_or_nil, 'Found the not expected %s %s in string %s',
+ isPattern and 'pattern' or 'substring', sub, str)
+ end
+end
+
+function M.assertNotStrIContains( str, sub, extra_msg_or_nil )
+ -- this relies on lua string.find function
+ -- a string always contains the empty string
+ if string.find(str:lower(), sub:lower(), 1, true) then
+ sub, str = prettystrPairs(sub, str, '\n')
+ fail_fmt(2, extra_msg_or_nil, 'Found (case insensitively) the not expected substring %s in string %s',
+ sub, str)
+ end
+end
+
+function M.assertStrMatches( str, pattern, start, final, extra_msg_or_nil )
+ -- Verify a full match for the string
+ if not strMatch( str, pattern, start, final ) then
+ pattern, str = prettystrPairs(pattern, str, '\n')
+ fail_fmt(2, extra_msg_or_nil, 'Could not match pattern %s with string %s',
+ pattern, str)
+ end
+end
+
+local function _assertErrorMsgEquals( stripFileAndLine, expectedMsg, func, ... )
+ local no_error, error_msg = pcall( func, ... )
+ if no_error then
+ failure( 'No error generated when calling function but expected error: '..M.prettystr(expectedMsg), nil, 3 )
+ end
+ if type(expectedMsg) == "string" and type(error_msg) ~= "string" then
+ -- table are converted to string automatically
+ error_msg = tostring(error_msg)
+ end
+ local differ = false
+ if stripFileAndLine then
+ if error_msg:gsub("^.+:%d+: ", "") ~= expectedMsg then
+ differ = true
+ end
+ else
+ if error_msg ~= expectedMsg then
+ local tr = type(error_msg)
+ local te = type(expectedMsg)
+ if te == 'table' then
+ if tr ~= 'table' then
+ differ = true
+ else
+ local ok = pcall(M.assertItemsEquals, error_msg, expectedMsg)
+ if not ok then
+ differ = true
+ end
+ end
+ else
+ differ = true
+ end
+ end
+ end
+
+ if differ then
+ error_msg, expectedMsg = prettystrPairs(error_msg, expectedMsg)
+ fail_fmt(3, nil, 'Error message expected: %s\nError message received: %s\n',
+ expectedMsg, error_msg)
+ end
+end
+
+function M.assertErrorMsgEquals( expectedMsg, func, ... )
+ -- assert that calling f with the arguments will raise an error
+ -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error
+ _assertErrorMsgEquals(false, expectedMsg, func, ...)
+end
+
+function M.assertErrorMsgContentEquals(expectedMsg, func, ...)
+ _assertErrorMsgEquals(true, expectedMsg, func, ...)
+end
+
+function M.assertErrorMsgContains( partialMsg, func, ... )
+ -- assert that calling f with the arguments will raise an error
+ -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error
+ local no_error, error_msg = pcall( func, ... )
+ if no_error then
+ failure( 'No error generated when calling function but expected error containing: '..prettystr(partialMsg), nil, 2 )
+ end
+ if type(error_msg) ~= "string" then
+ error_msg = tostring(error_msg)
+ end
+ if not string.find( error_msg, partialMsg, nil, true ) then
+ error_msg, partialMsg = prettystrPairs(error_msg, partialMsg)
+ fail_fmt(2, nil, 'Error message does not contain: %s\nError message received: %s\n',
+ partialMsg, error_msg)
+ end
+end
+
+function M.assertErrorMsgMatches( expectedMsg, func, ... )
+ -- assert that calling f with the arguments will raise an error
+ -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error
+ local no_error, error_msg = pcall( func, ... )
+ if no_error then
+ failure( 'No error generated when calling function but expected error matching: "'..expectedMsg..'"', nil, 2 )
+ end
+ if type(error_msg) ~= "string" then
+ error_msg = tostring(error_msg)
+ end
+ if not strMatch( error_msg, expectedMsg ) then
+ expectedMsg, error_msg = prettystrPairs(expectedMsg, error_msg)
+ fail_fmt(2, nil, 'Error message does not match pattern: %s\nError message received: %s\n',
+ expectedMsg, error_msg)
+ end
+end
+
+------------------------------------------------------------------
+-- Type assertions
+------------------------------------------------------------------
+
+function M.assertEvalToTrue(value, extra_msg_or_nil)
+ if not value then
+ failure("expected: a value evaluating to true, actual: " ..prettystr(value), extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertEvalToFalse(value, extra_msg_or_nil)
+ if value then
+ failure("expected: false or nil, actual: " ..prettystr(value), extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertIsTrue(value, extra_msg_or_nil)
+ if value ~= true then
+ failure("expected: true, actual: " ..prettystr(value), extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertNotIsTrue(value, extra_msg_or_nil)
+ if value == true then
+ failure("expected: not true, actual: " ..prettystr(value), extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertIsFalse(value, extra_msg_or_nil)
+ if value ~= false then
+ failure("expected: false, actual: " ..prettystr(value), extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertNotIsFalse(value, extra_msg_or_nil)
+ if value == false then
+ failure("expected: not false, actual: " ..prettystr(value), extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertIsNil(value, extra_msg_or_nil)
+ if value ~= nil then
+ failure("expected: nil, actual: " ..prettystr(value), extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertNotIsNil(value, extra_msg_or_nil)
+ if value == nil then
+ failure("expected: not nil, actual: nil", extra_msg_or_nil, 2)
+ end
+end
+
+--[[
+Add type assertion functions to the module table M. Each of these functions
+takes a single parameter "value", and checks that its Lua type matches the
+expected string (derived from the function name):
+
+M.assertIsXxx(value) -> ensure that type(value) conforms to "xxx"
+]]
+for _, funcName in ipairs(
+ {'assertIsNumber', 'assertIsString', 'assertIsTable', 'assertIsBoolean',
+ 'assertIsFunction', 'assertIsUserdata', 'assertIsThread'}
+) do
+ local typeExpected = funcName:match("^assertIs([A-Z]%a*)$")
+ -- Lua type() always returns lowercase, also make sure the match() succeeded
+ typeExpected = typeExpected and typeExpected:lower()
+ or error("bad function name '"..funcName.."' for type assertion")
+
+ M[funcName] = function(value, extra_msg_or_nil)
+ if type(value) ~= typeExpected then
+ if type(value) == 'nil' then
+ fail_fmt(2, extra_msg_or_nil, 'expected: a %s value, actual: nil',
+ typeExpected, type(value), prettystrPairs(value))
+ else
+ fail_fmt(2, extra_msg_or_nil, 'expected: a %s value, actual: type %s, value %s',
+ typeExpected, type(value), prettystrPairs(value))
+ end
+ end
+ end
+end
+
+--[[
+Add shortcuts for verifying type of a variable, without failure (luaunit v2 compatibility)
+M.isXxx(value) -> returns true if type(value) conforms to "xxx"
+]]
+for _, typeExpected in ipairs(
+ {'Number', 'String', 'Table', 'Boolean',
+ 'Function', 'Userdata', 'Thread', 'Nil' }
+) do
+ local typeExpectedLower = typeExpected:lower()
+ local isType = function(value)
+ return (type(value) == typeExpectedLower)
+ end
+ M['is'..typeExpected] = isType
+ M['is_'..typeExpectedLower] = isType
+end
+
+--[[
+Add non-type assertion functions to the module table M. Each of these functions
+takes a single parameter "value", and checks that its Lua type differs from the
+expected string (derived from the function name):
+
+M.assertNotIsXxx(value) -> ensure that type(value) is not "xxx"
+]]
+for _, funcName in ipairs(
+ {'assertNotIsNumber', 'assertNotIsString', 'assertNotIsTable', 'assertNotIsBoolean',
+ 'assertNotIsFunction', 'assertNotIsUserdata', 'assertNotIsThread'}
+) do
+ local typeUnexpected = funcName:match("^assertNotIs([A-Z]%a*)$")
+ -- Lua type() always returns lowercase, also make sure the match() succeeded
+ typeUnexpected = typeUnexpected and typeUnexpected:lower()
+ or error("bad function name '"..funcName.."' for type assertion")
+
+ M[funcName] = function(value, extra_msg_or_nil)
+ if type(value) == typeUnexpected then
+ fail_fmt(2, extra_msg_or_nil, 'expected: not a %s type, actual: value %s',
+ typeUnexpected, prettystrPairs(value))
+ end
+ end
+end
+
+function M.assertIs(actual, expected, extra_msg_or_nil)
+ if actual ~= expected then
+ if not M.ORDER_ACTUAL_EXPECTED then
+ actual, expected = expected, actual
+ end
+ local old_print_table_ref_in_error_msg = M.PRINT_TABLE_REF_IN_ERROR_MSG
+ M.PRINT_TABLE_REF_IN_ERROR_MSG = true
+ expected, actual = prettystrPairs(expected, actual, '\n', '')
+ M.PRINT_TABLE_REF_IN_ERROR_MSG = old_print_table_ref_in_error_msg
+ fail_fmt(2, extra_msg_or_nil, 'expected and actual object should not be different\nExpected: %s\nReceived: %s',
+ expected, actual)
+ end
+end
+
+function M.assertNotIs(actual, expected, extra_msg_or_nil)
+ if actual == expected then
+ local old_print_table_ref_in_error_msg = M.PRINT_TABLE_REF_IN_ERROR_MSG
+ M.PRINT_TABLE_REF_IN_ERROR_MSG = true
+ local s_expected
+ if not M.ORDER_ACTUAL_EXPECTED then
+ s_expected = prettystrPairs(actual)
+ else
+ s_expected = prettystrPairs(expected)
+ end
+ M.PRINT_TABLE_REF_IN_ERROR_MSG = old_print_table_ref_in_error_msg
+ fail_fmt(2, extra_msg_or_nil, 'expected and actual object should be different: %s', s_expected )
+ end
+end
+
+
+------------------------------------------------------------------
+-- Scientific assertions
+------------------------------------------------------------------
+
+
+function M.assertIsNaN(value, extra_msg_or_nil)
+ if type(value) ~= "number" or value == value then
+ failure("expected: NaN, actual: " ..prettystr(value), extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertNotIsNaN(value, extra_msg_or_nil)
+ if type(value) == "number" and value ~= value then
+ failure("expected: not NaN, actual: NaN", extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertIsInf(value, extra_msg_or_nil)
+ if type(value) ~= "number" or math.abs(value) ~= math.huge then
+ failure("expected: #Inf, actual: " ..prettystr(value), extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertIsPlusInf(value, extra_msg_or_nil)
+ if type(value) ~= "number" or value ~= math.huge then
+ failure("expected: #Inf, actual: " ..prettystr(value), extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertIsMinusInf(value, extra_msg_or_nil)
+ if type(value) ~= "number" or value ~= -math.huge then
+ failure("expected: -#Inf, actual: " ..prettystr(value), extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertNotIsPlusInf(value, extra_msg_or_nil)
+ if type(value) == "number" and value == math.huge then
+ failure("expected: not #Inf, actual: #Inf", extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertNotIsMinusInf(value, extra_msg_or_nil)
+ if type(value) == "number" and value == -math.huge then
+ failure("expected: not -#Inf, actual: -#Inf", extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertNotIsInf(value, extra_msg_or_nil)
+ if type(value) == "number" and math.abs(value) == math.huge then
+ failure("expected: not infinity, actual: " .. prettystr(value), extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertIsPlusZero(value, extra_msg_or_nil)
+ if type(value) ~= 'number' or value ~= 0 then
+ failure("expected: +0.0, actual: " ..prettystr(value), extra_msg_or_nil, 2)
+ else if (1/value == -math.huge) then
+ -- more precise error diagnosis
+ failure("expected: +0.0, actual: -0.0", extra_msg_or_nil, 2)
+ else if (1/value ~= math.huge) then
+ -- strange, case should have already been covered
+ failure("expected: +0.0, actual: " ..prettystr(value), extra_msg_or_nil, 2)
+ end
+ end
+ end
+end
+
+function M.assertIsMinusZero(value, extra_msg_or_nil)
+ if type(value) ~= 'number' or value ~= 0 then
+ failure("expected: -0.0, actual: " ..prettystr(value), extra_msg_or_nil, 2)
+ else if (1/value == math.huge) then
+ -- more precise error diagnosis
+ failure("expected: -0.0, actual: +0.0", extra_msg_or_nil, 2)
+ else if (1/value ~= -math.huge) then
+ -- strange, case should have already been covered
+ failure("expected: -0.0, actual: " ..prettystr(value), extra_msg_or_nil, 2)
+ end
+ end
+ end
+end
+
+function M.assertNotIsPlusZero(value, extra_msg_or_nil)
+ if type(value) == 'number' and (1/value == math.huge) then
+ failure("expected: not +0.0, actual: +0.0", extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertNotIsMinusZero(value, extra_msg_or_nil)
+ if type(value) == 'number' and (1/value == -math.huge) then
+ failure("expected: not -0.0, actual: -0.0", extra_msg_or_nil, 2)
+ end
+end
+
+function M.assertTableContains(t, expected, extra_msg_or_nil)
+ -- checks that table t contains the expected element
+ if table_findkeyof(t, expected) == nil then
+ t, expected = prettystrPairs(t, expected)
+ fail_fmt(2, extra_msg_or_nil, 'Table %s does NOT contain the expected element %s',
+ t, expected)
+ end
+end
+
+function M.assertNotTableContains(t, expected, extra_msg_or_nil)
+ -- checks that table t doesn't contain the expected element
+ local k = table_findkeyof(t, expected)
+ if k ~= nil then
+ t, expected = prettystrPairs(t, expected)
+ fail_fmt(2, extra_msg_or_nil, 'Table %s DOES contain the unwanted element %s (at key %s)',
+ t, expected, prettystr(k))
+ end
+end
+
+----------------------------------------------------------------
+-- Compatibility layer
+----------------------------------------------------------------
+
+-- for compatibility with LuaUnit v2.x
+function M.wrapFunctions()
+ -- In LuaUnit version <= 2.1 , this function was necessary to include
+ -- a test function inside the global test suite. Nowadays, the functions
+ -- are simply run directly as part of the test discovery process.
+ -- so just do nothing !
+ io.stderr:write[[Use of WrapFunctions() is no longer needed.
+Just prefix your test function names with "test" or "Test" and they
+will be picked up and run by LuaUnit.
+]]
+end
+
+local list_of_funcs = {
+ -- { official function name , alias }
+
+ -- general assertions
+ { 'assertEquals' , 'assert_equals' },
+ { 'assertItemsEquals' , 'assert_items_equals' },
+ { 'assertNotEquals' , 'assert_not_equals' },
+ { 'assertAlmostEquals' , 'assert_almost_equals' },
+ { 'assertNotAlmostEquals' , 'assert_not_almost_equals' },
+ { 'assertEvalToTrue' , 'assert_eval_to_true' },
+ { 'assertEvalToFalse' , 'assert_eval_to_false' },
+ { 'assertStrContains' , 'assert_str_contains' },
+ { 'assertStrIContains' , 'assert_str_icontains' },
+ { 'assertNotStrContains' , 'assert_not_str_contains' },
+ { 'assertNotStrIContains' , 'assert_not_str_icontains' },
+ { 'assertStrMatches' , 'assert_str_matches' },
+ { 'assertError' , 'assert_error' },
+ { 'assertErrorMsgEquals' , 'assert_error_msg_equals' },
+ { 'assertErrorMsgContains' , 'assert_error_msg_contains' },
+ { 'assertErrorMsgMatches' , 'assert_error_msg_matches' },
+ { 'assertErrorMsgContentEquals', 'assert_error_msg_content_equals' },
+ { 'assertIs' , 'assert_is' },
+ { 'assertNotIs' , 'assert_not_is' },
+ { 'assertTableContains' , 'assert_table_contains' },
+ { 'assertNotTableContains' , 'assert_not_table_contains' },
+ { 'wrapFunctions' , 'WrapFunctions' },
+ { 'wrapFunctions' , 'wrap_functions' },
+
+ -- type assertions: assertIsXXX -> assert_is_xxx
+ { 'assertIsNumber' , 'assert_is_number' },
+ { 'assertIsString' , 'assert_is_string' },
+ { 'assertIsTable' , 'assert_is_table' },
+ { 'assertIsBoolean' , 'assert_is_boolean' },
+ { 'assertIsNil' , 'assert_is_nil' },
+ { 'assertIsTrue' , 'assert_is_true' },
+ { 'assertIsFalse' , 'assert_is_false' },
+ { 'assertIsNaN' , 'assert_is_nan' },
+ { 'assertIsInf' , 'assert_is_inf' },
+ { 'assertIsPlusInf' , 'assert_is_plus_inf' },
+ { 'assertIsMinusInf' , 'assert_is_minus_inf' },
+ { 'assertIsPlusZero' , 'assert_is_plus_zero' },
+ { 'assertIsMinusZero' , 'assert_is_minus_zero' },
+ { 'assertIsFunction' , 'assert_is_function' },
+ { 'assertIsThread' , 'assert_is_thread' },
+ { 'assertIsUserdata' , 'assert_is_userdata' },
+
+ -- type assertions: assertIsXXX -> assertXxx
+ { 'assertIsNumber' , 'assertNumber' },
+ { 'assertIsString' , 'assertString' },
+ { 'assertIsTable' , 'assertTable' },
+ { 'assertIsBoolean' , 'assertBoolean' },
+ { 'assertIsNil' , 'assertNil' },
+ { 'assertIsTrue' , 'assertTrue' },
+ { 'assertIsFalse' , 'assertFalse' },
+ { 'assertIsNaN' , 'assertNaN' },
+ { 'assertIsInf' , 'assertInf' },
+ { 'assertIsPlusInf' , 'assertPlusInf' },
+ { 'assertIsMinusInf' , 'assertMinusInf' },
+ { 'assertIsPlusZero' , 'assertPlusZero' },
+ { 'assertIsMinusZero' , 'assertMinusZero'},
+ { 'assertIsFunction' , 'assertFunction' },
+ { 'assertIsThread' , 'assertThread' },
+ { 'assertIsUserdata' , 'assertUserdata' },
+
+ -- type assertions: assertIsXXX -> assert_xxx (luaunit v2 compat)
+ { 'assertIsNumber' , 'assert_number' },
+ { 'assertIsString' , 'assert_string' },
+ { 'assertIsTable' , 'assert_table' },
+ { 'assertIsBoolean' , 'assert_boolean' },
+ { 'assertIsNil' , 'assert_nil' },
+ { 'assertIsTrue' , 'assert_true' },
+ { 'assertIsFalse' , 'assert_false' },
+ { 'assertIsNaN' , 'assert_nan' },
+ { 'assertIsInf' , 'assert_inf' },
+ { 'assertIsPlusInf' , 'assert_plus_inf' },
+ { 'assertIsMinusInf' , 'assert_minus_inf' },
+ { 'assertIsPlusZero' , 'assert_plus_zero' },
+ { 'assertIsMinusZero' , 'assert_minus_zero' },
+ { 'assertIsFunction' , 'assert_function' },
+ { 'assertIsThread' , 'assert_thread' },
+ { 'assertIsUserdata' , 'assert_userdata' },
+
+ -- type assertions: assertNotIsXXX -> assert_not_is_xxx
+ { 'assertNotIsNumber' , 'assert_not_is_number' },
+ { 'assertNotIsString' , 'assert_not_is_string' },
+ { 'assertNotIsTable' , 'assert_not_is_table' },
+ { 'assertNotIsBoolean' , 'assert_not_is_boolean' },
+ { 'assertNotIsNil' , 'assert_not_is_nil' },
+ { 'assertNotIsTrue' , 'assert_not_is_true' },
+ { 'assertNotIsFalse' , 'assert_not_is_false' },
+ { 'assertNotIsNaN' , 'assert_not_is_nan' },
+ { 'assertNotIsInf' , 'assert_not_is_inf' },
+ { 'assertNotIsPlusInf' , 'assert_not_plus_inf' },
+ { 'assertNotIsMinusInf' , 'assert_not_minus_inf' },
+ { 'assertNotIsPlusZero' , 'assert_not_plus_zero' },
+ { 'assertNotIsMinusZero' , 'assert_not_minus_zero' },
+ { 'assertNotIsFunction' , 'assert_not_is_function' },
+ { 'assertNotIsThread' , 'assert_not_is_thread' },
+ { 'assertNotIsUserdata' , 'assert_not_is_userdata' },
+
+ -- type assertions: assertNotIsXXX -> assertNotXxx (luaunit v2 compat)
+ { 'assertNotIsNumber' , 'assertNotNumber' },
+ { 'assertNotIsString' , 'assertNotString' },
+ { 'assertNotIsTable' , 'assertNotTable' },
+ { 'assertNotIsBoolean' , 'assertNotBoolean' },
+ { 'assertNotIsNil' , 'assertNotNil' },
+ { 'assertNotIsTrue' , 'assertNotTrue' },
+ { 'assertNotIsFalse' , 'assertNotFalse' },
+ { 'assertNotIsNaN' , 'assertNotNaN' },
+ { 'assertNotIsInf' , 'assertNotInf' },
+ { 'assertNotIsPlusInf' , 'assertNotPlusInf' },
+ { 'assertNotIsMinusInf' , 'assertNotMinusInf' },
+ { 'assertNotIsPlusZero' , 'assertNotPlusZero' },
+ { 'assertNotIsMinusZero' , 'assertNotMinusZero' },
+ { 'assertNotIsFunction' , 'assertNotFunction' },
+ { 'assertNotIsThread' , 'assertNotThread' },
+ { 'assertNotIsUserdata' , 'assertNotUserdata' },
+
+ -- type assertions: assertNotIsXXX -> assert_not_xxx
+ { 'assertNotIsNumber' , 'assert_not_number' },
+ { 'assertNotIsString' , 'assert_not_string' },
+ { 'assertNotIsTable' , 'assert_not_table' },
+ { 'assertNotIsBoolean' , 'assert_not_boolean' },
+ { 'assertNotIsNil' , 'assert_not_nil' },
+ { 'assertNotIsTrue' , 'assert_not_true' },
+ { 'assertNotIsFalse' , 'assert_not_false' },
+ { 'assertNotIsNaN' , 'assert_not_nan' },
+ { 'assertNotIsInf' , 'assert_not_inf' },
+ { 'assertNotIsPlusInf' , 'assert_not_plus_inf' },
+ { 'assertNotIsMinusInf' , 'assert_not_minus_inf' },
+ { 'assertNotIsPlusZero' , 'assert_not_plus_zero' },
+ { 'assertNotIsMinusZero' , 'assert_not_minus_zero' },
+ { 'assertNotIsFunction' , 'assert_not_function' },
+ { 'assertNotIsThread' , 'assert_not_thread' },
+ { 'assertNotIsUserdata' , 'assert_not_userdata' },
+
+ -- all assertions with Coroutine duplicate Thread assertions
+ { 'assertIsThread' , 'assertIsCoroutine' },
+ { 'assertIsThread' , 'assertCoroutine' },
+ { 'assertIsThread' , 'assert_is_coroutine' },
+ { 'assertIsThread' , 'assert_coroutine' },
+ { 'assertNotIsThread' , 'assertNotIsCoroutine' },
+ { 'assertNotIsThread' , 'assertNotCoroutine' },
+ { 'assertNotIsThread' , 'assert_not_is_coroutine' },
+ { 'assertNotIsThread' , 'assert_not_coroutine' },
+}
+
+-- Create all aliases in M
+for _,v in ipairs( list_of_funcs ) do
+ local funcname, alias = v[1], v[2]
+ M[alias] = M[funcname]
+
+ if EXPORT_ASSERT_TO_GLOBALS then
+ _G[funcname] = M[funcname]
+ _G[alias] = M[funcname]
+ end
+end
+
+----------------------------------------------------------------
+--
+-- Outputters
+--
+----------------------------------------------------------------
+
+-- A common "base" class for outputters
+-- For concepts involved (class inheritance) see http://www.lua.org/pil/16.2.html
+
+local genericOutput = { __class__ = 'genericOutput' } -- class
+local genericOutput_MT = { __index = genericOutput } -- metatable
+M.genericOutput = genericOutput -- publish, so that custom classes may derive from it
+
+function genericOutput.new(runner, default_verbosity)
+ -- runner is the "parent" object controlling the output, usually a LuaUnit instance
+ local t = { runner = runner }
+ if runner then
+ t.result = runner.result
+ t.verbosity = runner.verbosity or default_verbosity
+ t.fname = runner.fname
+ else
+ t.verbosity = default_verbosity
+ end
+ return setmetatable( t, genericOutput_MT)
+end
+
+-- abstract ("empty") methods
+function genericOutput:startSuite()
+ -- Called once, when the suite is started
+end
+
+function genericOutput:startClass(className)
+ -- Called each time a new test class is started
+end
+
+function genericOutput:startTest(testName)
+ -- called each time a new test is started, right before the setUp()
+ -- the current test status node is already created and available in: self.result.currentNode
+end
+
+function genericOutput:updateStatus(node)
+ -- called with status failed or error as soon as the error/failure is encountered
+ -- this method is NOT called for a successful test because a test is marked as successful by default
+ -- and does not need to be updated
+end
+
+function genericOutput:endTest(node)
+ -- called when the test is finished, after the tearDown() method
+end
+
+function genericOutput:endClass()
+ -- called when executing the class is finished, before moving on to the next class of at the end of the test execution
+end
+
+function genericOutput:endSuite()
+ -- called at the end of the test suite execution
+end
+
+
+----------------------------------------------------------------
+-- class TapOutput
+----------------------------------------------------------------
+
+local TapOutput = genericOutput.new() -- derived class
+local TapOutput_MT = { __index = TapOutput } -- metatable
+TapOutput.__class__ = 'TapOutput'
+
+ -- For a good reference for TAP format, check: http://testanything.org/tap-specification.html
+
+ function TapOutput.new(runner)
+ local t = genericOutput.new(runner, M.VERBOSITY_LOW)
+ return setmetatable( t, TapOutput_MT)
+ end
+ function TapOutput:startSuite()
+ print("1.."..self.result.selectedCount)
+ print('# Started on '..self.result.startDate)
+ end
+ function TapOutput:startClass(className)
+ if className ~= '[TestFunctions]' then
+ print('# Starting class: '..className)
+ end
+ end
+
+ function TapOutput:updateStatus( node )
+ if node:isSkipped() then
+ io.stdout:write("ok ", self.result.currentTestNumber, "\t# SKIP ", node.msg, "\n" )
+ return
+ end
+
+ io.stdout:write("not ok ", self.result.currentTestNumber, "\t", node.testName, "\n")
+ if self.verbosity > M.VERBOSITY_LOW then
+ print( prefixString( '# ', node.msg ) )
+ end
+ if (node:isFailure() or node:isError()) and self.verbosity > M.VERBOSITY_DEFAULT then
+ print( prefixString( '# ', node.stackTrace ) )
+ end
+ end
+
+ function TapOutput:endTest( node )
+ if node:isSuccess() then
+ io.stdout:write("ok ", self.result.currentTestNumber, "\t", node.testName, "\n")
+ end
+ end
+
+ function TapOutput:endSuite()
+ print( '# '..M.LuaUnit.statusLine( self.result ) )
+ return self.result.notSuccessCount
+ end
+
+
+-- class TapOutput end
+
+----------------------------------------------------------------
+-- class JUnitOutput
+----------------------------------------------------------------
+
+-- See directory junitxml for more information about the junit format
+local JUnitOutput = genericOutput.new() -- derived class
+local JUnitOutput_MT = { __index = JUnitOutput } -- metatable
+JUnitOutput.__class__ = 'JUnitOutput'
+
+ function JUnitOutput.new(runner)
+ local t = genericOutput.new(runner, M.VERBOSITY_LOW)
+ t.testList = {}
+ return setmetatable( t, JUnitOutput_MT )
+ end
+
+ function JUnitOutput:startSuite()
+ -- open xml file early to deal with errors
+ if self.fname == nil then
+ error('With Junit, an output filename must be supplied with --name!')
+ end
+ if string.sub(self.fname,-4) ~= '.xml' then
+ self.fname = self.fname..'.xml'
+ end
+ self.fd = io.open(self.fname, "w")
+ if self.fd == nil then
+ error("Could not open file for writing: "..self.fname)
+ end
+
+ print('# XML output to '..self.fname)
+ print('# Started on '..self.result.startDate)
+ end
+ function JUnitOutput:startClass(className)
+ if className ~= '[TestFunctions]' then
+ print('# Starting class: '..className)
+ end
+ end
+ function JUnitOutput:startTest(testName)
+ print('# Starting test: '..testName)
+ end
+
+ function JUnitOutput:updateStatus( node )
+ if node:isFailure() then
+ print( '# Failure: ' .. prefixString( '# ', node.msg ):sub(4, nil) )
+ -- print('# ' .. node.stackTrace)
+ elseif node:isError() then
+ print( '# Error: ' .. prefixString( '# ' , node.msg ):sub(4, nil) )
+ -- print('# ' .. node.stackTrace)
+ end
+ end
+
+ function JUnitOutput:endSuite()
+ print( '# '..M.LuaUnit.statusLine(self.result))
+
+ -- XML file writing
+ self.fd:write('<?xml version="1.0" encoding="UTF-8" ?>\n')
+ self.fd:write('<testsuites>\n')
+ self.fd:write(string.format(
+ ' <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="%d" timestamp="%s" time="%0.3f" errors="%d" failures="%d" skipped="%d">\n',
+ self.result.runCount, self.result.startIsodate, self.result.duration, self.result.errorCount, self.result.failureCount, self.result.skippedCount ))
+ self.fd:write(" <properties>\n")
+ self.fd:write(string.format(' <property name="Lua Version" value="%s"/>\n', _VERSION ) )
+ self.fd:write(string.format(' <property name="LuaUnit Version" value="%s"/>\n', M.VERSION) )
+ -- XXX please include system name and version if possible
+ self.fd:write(" </properties>\n")
+
+ for i,node in ipairs(self.result.allTests) do
+ self.fd:write(string.format(' <testcase classname="%s" name="%s" time="%0.3f">\n',
+ node.className, node.testName, node.duration ) )
+ if node:isNotSuccess() then
+ self.fd:write(node:statusXML())
+ end
+ self.fd:write(' </testcase>\n')
+ end
+
+ -- Next two lines are needed to validate junit ANT xsd, but really not useful in general:
+ self.fd:write(' <system-out/>\n')
+ self.fd:write(' <system-err/>\n')
+
+ self.fd:write(' </testsuite>\n')
+ self.fd:write('</testsuites>\n')
+ self.fd:close()
+ return self.result.notSuccessCount
+ end
+
+
+-- class TapOutput end
+
+----------------------------------------------------------------
+-- class TextOutput
+----------------------------------------------------------------
+
+--[[ Example of other unit-tests suite text output
+
+-- Python Non verbose:
+
+For each test: . or F or E
+
+If some failed tests:
+ ==============
+ ERROR / FAILURE: TestName (testfile.testclass)
+ ---------
+ Stack trace
+
+
+then --------------
+then "Ran x tests in 0.000s"
+then OK or FAILED (failures=1, error=1)
+
+-- Python Verbose:
+testname (filename.classname) ... ok
+testname (filename.classname) ... FAIL
+testname (filename.classname) ... ERROR
+
+then --------------
+then "Ran x tests in 0.000s"
+then OK or FAILED (failures=1, error=1)
+
+-- Ruby:
+Started
+ .
+ Finished in 0.002695 seconds.
+
+ 1 tests, 2 assertions, 0 failures, 0 errors
+
+-- Ruby:
+>> ruby tc_simple_number2.rb
+Loaded suite tc_simple_number2
+Started
+F..
+Finished in 0.038617 seconds.
+
+ 1) Failure:
+test_failure(TestSimpleNumber) [tc_simple_number2.rb:16]:
+Adding doesn't work.
+<3> expected but was
+<4>.
+
+3 tests, 4 assertions, 1 failures, 0 errors
+
+-- Java Junit
+.......F.
+Time: 0,003
+There was 1 failure:
+1) testCapacity(junit.samples.VectorTest)junit.framework.AssertionFailedError
+ at junit.samples.VectorTest.testCapacity(VectorTest.java:87)
+ at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+ at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
+
+FAILURES!!!
+Tests run: 8, Failures: 1, Errors: 0
+
+
+-- Maven
+
+# mvn test
+-------------------------------------------------------
+ T E S T S
+-------------------------------------------------------
+Running math.AdditionTest
+Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed:
+0.03 sec <<< FAILURE!
+
+Results :
+
+Failed tests:
+ testLireSymbole(math.AdditionTest)
+
+Tests run: 2, Failures: 1, Errors: 0, Skipped: 0
+
+
+-- LuaUnit
+---- non verbose
+* display . or F or E when running tests
+---- verbose
+* display test name + ok/fail
+----
+* blank line
+* number) ERROR or FAILURE: TestName
+ Stack trace
+* blank line
+* number) ERROR or FAILURE: TestName
+ Stack trace
+
+then --------------
+then "Ran x tests in 0.000s (%d not selected, %d skipped)"
+then OK or FAILED (failures=1, error=1)
+
+
+]]
+
+local TextOutput = genericOutput.new() -- derived class
+local TextOutput_MT = { __index = TextOutput } -- metatable
+TextOutput.__class__ = 'TextOutput'
+
+ function TextOutput.new(runner)
+ local t = genericOutput.new(runner, M.VERBOSITY_DEFAULT)
+ t.errorList = {}
+ return setmetatable( t, TextOutput_MT )
+ end
+
+ function TextOutput:startSuite()
+ if self.verbosity > M.VERBOSITY_DEFAULT then
+ print( 'Started on '.. self.result.startDate )
+ end
+ end
+
+ function TextOutput:startTest(testName)
+ if self.verbosity > M.VERBOSITY_DEFAULT then
+ io.stdout:write( " ", self.result.currentNode.testName, " ... " )
+ end
+ end
+
+ function TextOutput:endTest( node )
+ if node:isSuccess() then
+ if self.verbosity > M.VERBOSITY_DEFAULT then
+ io.stdout:write("Ok\n")
+ else
+ io.stdout:write(".")
+ io.stdout:flush()
+ end
+ else
+ if self.verbosity > M.VERBOSITY_DEFAULT then
+ print( node.status )
+ print( node.msg )
+ --[[
+ -- find out when to do this:
+ if self.verbosity > M.VERBOSITY_DEFAULT then
+ print( node.stackTrace )
+ end
+ ]]
+ else
+ -- write only the first character of status E, F or S
+ io.stdout:write(string.sub(node.status, 1, 1))
+ io.stdout:flush()
+ end
+ end
+ end
+
+ function TextOutput:displayOneFailedTest( index, fail )
+ print(index..") "..fail.testName )
+ print( fail.msg )
+ print( fail.stackTrace )
+ print()
+ end
+
+ function TextOutput:displayErroredTests()
+ if #self.result.errorTests ~= 0 then
+ print("Tests with errors:")
+ print("------------------")
+ for i, v in ipairs(self.result.errorTests) do
+ self:displayOneFailedTest(i, v)
+ end
+ end
+ end
+
+ function TextOutput:displayFailedTests()
+ if #self.result.failedTests ~= 0 then
+ print("Failed tests:")
+ print("-------------")
+ for i, v in ipairs(self.result.failedTests) do
+ self:displayOneFailedTest(i, v)
+ end
+ end
+ end
+
+ function TextOutput:endSuite()
+ if self.verbosity > M.VERBOSITY_DEFAULT then
+ print("=========================================================")
+ else
+ print()
+ end
+ self:displayErroredTests()
+ self:displayFailedTests()
+ print( M.LuaUnit.statusLine( self.result ) )
+ if self.result.notSuccessCount == 0 then
+ print('OK')
+ end
+ end
+
+-- class TextOutput end
+
+
+----------------------------------------------------------------
+-- class NilOutput
+----------------------------------------------------------------
+
+local function nopCallable()
+ --print(42)
+ return nopCallable
+end
+
+local NilOutput = { __class__ = 'NilOuptut' } -- class
+local NilOutput_MT = { __index = nopCallable } -- metatable
+
+function NilOutput.new(runner)
+ return setmetatable( { __class__ = 'NilOutput' }, NilOutput_MT )
+end
+
+----------------------------------------------------------------
+--
+-- class LuaUnit
+--
+----------------------------------------------------------------
+
+M.LuaUnit = {
+ outputType = TextOutput,
+ verbosity = M.VERBOSITY_DEFAULT,
+ __class__ = 'LuaUnit',
+ instances = {}
+}
+local LuaUnit_MT = { __index = M.LuaUnit }
+
+if EXPORT_ASSERT_TO_GLOBALS then
+ LuaUnit = M.LuaUnit
+end
+
+ function M.LuaUnit.new()
+ local newInstance = setmetatable( {}, LuaUnit_MT )
+ return newInstance
+ end
+
+ -----------------[[ Utility methods ]]---------------------
+
+ function M.LuaUnit.asFunction(aObject)
+ -- return "aObject" if it is a function, and nil otherwise
+ if 'function' == type(aObject) then
+ return aObject
+ end
+ end
+
+ function M.LuaUnit.splitClassMethod(someName)
+ --[[
+ Return a pair of className, methodName strings for a name in the form
+ "class.method". If no class part (or separator) is found, will return
+ nil, someName instead (the latter being unchanged).
+
+ This convention thus also replaces the older isClassMethod() test:
+ You just have to check for a non-nil className (return) value.
+ ]]
+ local separator = string.find(someName, '.', 1, true)
+ if separator then
+ return someName:sub(1, separator - 1), someName:sub(separator + 1)
+ end
+ return nil, someName
+ end
+
+ function M.LuaUnit.isMethodTestName( s )
+ -- return true is the name matches the name of a test method
+ -- default rule is that is starts with 'Test' or with 'test'
+ return string.sub(s, 1, 4):lower() == 'test'
+ end
+
+ function M.LuaUnit.isTestName( s )
+ -- return true is the name matches the name of a test
+ -- default rule is that is starts with 'Test' or with 'test'
+ return string.sub(s, 1, 4):lower() == 'test'
+ end
+
+ function M.LuaUnit.collectTests()
+ -- return a list of all test names in the global namespace
+ -- that match LuaUnit.isTestName
+
+ local testNames = {}
+ for k, _ in pairs(_G) do
+ if type(k) == "string" and M.LuaUnit.isTestName( k ) then
+ table.insert( testNames , k )
+ end
+ end
+ table.sort( testNames )
+ return testNames
+ end
+
+ function M.LuaUnit.parseCmdLine( cmdLine )
+ -- parse the command line
+ -- Supported command line parameters:
+ -- --verbose, -v: increase verbosity
+ -- --quiet, -q: silence output
+ -- --error, -e: treat errors as fatal (quit program)
+ -- --output, -o, + name: select output type
+ -- --pattern, -p, + pattern: run test matching pattern, may be repeated
+ -- --exclude, -x, + pattern: run test not matching pattern, may be repeated
+ -- --shuffle, -s, : shuffle tests before reunning them
+ -- --name, -n, + fname: name of output file for junit, default to stdout
+ -- --repeat, -r, + num: number of times to execute each test
+ -- [testnames, ...]: run selected test names
+ --
+ -- Returns a table with the following fields:
+ -- verbosity: nil, M.VERBOSITY_DEFAULT, M.VERBOSITY_QUIET, M.VERBOSITY_VERBOSE
+ -- output: nil, 'tap', 'junit', 'text', 'nil'
+ -- testNames: nil or a list of test names to run
+ -- exeRepeat: num or 1
+ -- pattern: nil or a list of patterns
+ -- exclude: nil or a list of patterns
+
+ local result, state = {}, nil
+ local SET_OUTPUT = 1
+ local SET_PATTERN = 2
+ local SET_EXCLUDE = 3
+ local SET_FNAME = 4
+ local SET_REPEAT = 5
+
+ if cmdLine == nil then
+ return result
+ end
+
+ local function parseOption( option )
+ if option == '--help' or option == '-h' then
+ result['help'] = true
+ return
+ elseif option == '--version' then
+ result['version'] = true
+ return
+ elseif option == '--verbose' or option == '-v' then
+ result['verbosity'] = M.VERBOSITY_VERBOSE
+ return
+ elseif option == '--quiet' or option == '-q' then
+ result['verbosity'] = M.VERBOSITY_QUIET
+ return
+ elseif option == '--error' or option == '-e' then
+ result['quitOnError'] = true
+ return
+ elseif option == '--failure' or option == '-f' then
+ result['quitOnFailure'] = true
+ return
+ elseif option == '--shuffle' or option == '-s' then
+ result['shuffle'] = true
+ return
+ elseif option == '--output' or option == '-o' then
+ state = SET_OUTPUT
+ return state
+ elseif option == '--name' or option == '-n' then
+ state = SET_FNAME
+ return state
+ elseif option == '--repeat' or option == '-r' then
+ state = SET_REPEAT
+ return state
+ elseif option == '--pattern' or option == '-p' then
+ state = SET_PATTERN
+ return state
+ elseif option == '--exclude' or option == '-x' then
+ state = SET_EXCLUDE
+ return state
+ end
+ error('Unknown option: '..option,3)
+ end
+
+ local function setArg( cmdArg, state )
+ if state == SET_OUTPUT then
+ result['output'] = cmdArg
+ return
+ elseif state == SET_FNAME then
+ result['fname'] = cmdArg
+ return
+ elseif state == SET_REPEAT then
+ result['exeRepeat'] = tonumber(cmdArg)
+ or error('Malformed -r argument: '..cmdArg)
+ return
+ elseif state == SET_PATTERN then
+ if result['pattern'] then
+ table.insert( result['pattern'], cmdArg )
+ else
+ result['pattern'] = { cmdArg }
+ end
+ return
+ elseif state == SET_EXCLUDE then
+ local notArg = '!'..cmdArg
+ if result['pattern'] then
+ table.insert( result['pattern'], notArg )
+ else
+ result['pattern'] = { notArg }
+ end
+ return
+ end
+ error('Unknown parse state: '.. state)
+ end
+
+
+ for i, cmdArg in ipairs(cmdLine) do
+ if state ~= nil then
+ setArg( cmdArg, state, result )
+ state = nil
+ else
+ if cmdArg:sub(1,1) == '-' then
+ state = parseOption( cmdArg )
+ else
+ if result['testNames'] then
+ table.insert( result['testNames'], cmdArg )
+ else
+ result['testNames'] = { cmdArg }
+ end
+ end
+ end
+ end
+
+ if result['help'] then
+ M.LuaUnit.help()
+ end
+
+ if result['version'] then
+ M.LuaUnit.version()
+ end
+
+ if state ~= nil then
+ error('Missing argument after '..cmdLine[ #cmdLine ],2 )
+ end
+
+ return result
+ end
+
+ function M.LuaUnit.help()
+ print(M.USAGE)
+ os.exit(0)
+ end
+
+ function M.LuaUnit.version()
+ print('LuaUnit v'..M.VERSION..' by Philippe Fremy <phil@freehackers.org>')
+ os.exit(0)
+ end
+
+----------------------------------------------------------------
+-- class NodeStatus
+----------------------------------------------------------------
+
+ local NodeStatus = { __class__ = 'NodeStatus' } -- class
+ local NodeStatus_MT = { __index = NodeStatus } -- metatable
+ M.NodeStatus = NodeStatus
+
+ -- values of status
+ NodeStatus.SUCCESS = 'SUCCESS'
+ NodeStatus.SKIP = 'SKIP'
+ NodeStatus.FAIL = 'FAIL'
+ NodeStatus.ERROR = 'ERROR'
+
+ function NodeStatus.new( number, testName, className )
+ -- default constructor, test are PASS by default
+ local t = { number = number, testName = testName, className = className }
+ setmetatable( t, NodeStatus_MT )
+ t:success()
+ return t
+ end
+
+ function NodeStatus:success()
+ self.status = self.SUCCESS
+ -- useless because lua does this for us, but it helps me remembering the relevant field names
+ self.msg = nil
+ self.stackTrace = nil
+ end
+
+ function NodeStatus:skip(msg)
+ self.status = self.SKIP
+ self.msg = msg
+ self.stackTrace = nil
+ end
+
+ function NodeStatus:fail(msg, stackTrace)
+ self.status = self.FAIL
+ self.msg = msg
+ self.stackTrace = stackTrace
+ end
+
+ function NodeStatus:error(msg, stackTrace)
+ self.status = self.ERROR
+ self.msg = msg
+ self.stackTrace = stackTrace
+ end
+
+ function NodeStatus:isSuccess()
+ return self.status == NodeStatus.SUCCESS
+ end
+
+ function NodeStatus:isNotSuccess()
+ -- Return true if node is either failure or error or skip
+ return (self.status == NodeStatus.FAIL or self.status == NodeStatus.ERROR or self.status == NodeStatus.SKIP)
+ end
+
+ function NodeStatus:isSkipped()
+ return self.status == NodeStatus.SKIP
+ end
+
+ function NodeStatus:isFailure()
+ return self.status == NodeStatus.FAIL
+ end
+
+ function NodeStatus:isError()
+ return self.status == NodeStatus.ERROR
+ end
+
+ function NodeStatus:statusXML()
+ if self:isError() then
+ return table.concat(
+ {' <error type="', xmlEscape(self.msg), '">\n',
+ ' <![CDATA[', xmlCDataEscape(self.stackTrace),
+ ']]></error>\n'})
+ elseif self:isFailure() then
+ return table.concat(
+ {' <failure type="', xmlEscape(self.msg), '">\n',
+ ' <![CDATA[', xmlCDataEscape(self.stackTrace),
+ ']]></failure>\n'})
+ elseif self:isSkipped() then
+ return table.concat({' <skipped>', xmlEscape(self.msg),'</skipped>\n' } )
+ end
+ return ' <passed/>\n' -- (not XSD-compliant! normally shouldn't get here)
+ end
+
+ --------------[[ Output methods ]]-------------------------
+
+ local function conditional_plural(number, singular)
+ -- returns a grammatically well-formed string "%d <singular/plural>"
+ local suffix = ''
+ if number ~= 1 then -- use plural
+ suffix = (singular:sub(-2) == 'ss') and 'es' or 's'
+ end
+ return string.format('%d %s%s', number, singular, suffix)
+ end
+
+ function M.LuaUnit.statusLine(result)
+ -- return status line string according to results
+ local s = {
+ string.format('Ran %d tests in %0.3f seconds',
+ result.runCount, result.duration),
+ conditional_plural(result.successCount, 'success'),
+ }
+ if result.notSuccessCount > 0 then
+ if result.failureCount > 0 then
+ table.insert(s, conditional_plural(result.failureCount, 'failure'))
+ end
+ if result.errorCount > 0 then
+ table.insert(s, conditional_plural(result.errorCount, 'error'))
+ end
+ else
+ table.insert(s, '0 failures')
+ end
+ if result.skippedCount > 0 then
+ table.insert(s, string.format("%d skipped", result.skippedCount))
+ end
+ if result.nonSelectedCount > 0 then
+ table.insert(s, string.format("%d non-selected", result.nonSelectedCount))
+ end
+ return table.concat(s, ', ')
+ end
+
+ function M.LuaUnit:startSuite(selectedCount, nonSelectedCount)
+ self.result = {
+ selectedCount = selectedCount,
+ nonSelectedCount = nonSelectedCount,
+ successCount = 0,
+ runCount = 0,
+ currentTestNumber = 0,
+ currentClassName = "",
+ currentNode = nil,
+ suiteStarted = true,
+ startTime = os.clock(),
+ startDate = os.date(os.getenv('LUAUNIT_DATEFMT')),
+ startIsodate = os.date('%Y-%m-%dT%H:%M:%S'),
+ patternIncludeFilter = self.patternIncludeFilter,
+
+ -- list of test node status
+ allTests = {},
+ failedTests = {},
+ errorTests = {},
+ skippedTests = {},
+
+ failureCount = 0,
+ errorCount = 0,
+ notSuccessCount = 0,
+ skippedCount = 0,
+ }
+
+ self.outputType = self.outputType or TextOutput
+ self.output = self.outputType.new(self)
+ self.output:startSuite()
+ end
+
+ function M.LuaUnit:startClass( className, classInstance )
+ self.result.currentClassName = className
+ self.output:startClass( className )
+ self:setupClass( className, classInstance )
+ end
+
+ function M.LuaUnit:startTest( testName )
+ self.result.currentTestNumber = self.result.currentTestNumber + 1
+ self.result.runCount = self.result.runCount + 1
+ self.result.currentNode = NodeStatus.new(
+ self.result.currentTestNumber,
+ testName,
+ self.result.currentClassName
+ )
+ self.result.currentNode.startTime = os.clock()
+ table.insert( self.result.allTests, self.result.currentNode )
+ self.output:startTest( testName )
+ end
+
+ function M.LuaUnit:updateStatus( err )
+ -- "err" is expected to be a table / result from protectedCall()
+ if err.status == NodeStatus.SUCCESS then
+ return
+ end
+
+ local node = self.result.currentNode
+
+ --[[ As a first approach, we will report only one error or one failure for one test.
+
+ However, we can have the case where the test is in failure, and the teardown is in error.
+ In such case, it's a good idea to report both a failure and an error in the test suite. This is
+ what Python unittest does for example. However, it mixes up counts so need to be handled carefully: for
+ example, there could be more (failures + errors) count that tests. What happens to the current node ?
+
+ We will do this more intelligent version later.
+ ]]
+
+ -- if the node is already in failure/error, just don't report the new error (see above)
+ if node.status ~= NodeStatus.SUCCESS then
+ return
+ end
+
+ if err.status == NodeStatus.FAIL then
+ node:fail( err.msg, err.trace )
+ table.insert( self.result.failedTests, node )
+ elseif err.status == NodeStatus.ERROR then
+ node:error( err.msg, err.trace )
+ table.insert( self.result.errorTests, node )
+ elseif err.status == NodeStatus.SKIP then
+ node:skip( err.msg )
+ table.insert( self.result.skippedTests, node )
+ else
+ error('No such status: ' .. prettystr(err.status))
+ end
+
+ self.output:updateStatus( node )
+ end
+
+ function M.LuaUnit:endTest()
+ local node = self.result.currentNode
+ -- print( 'endTest() '..prettystr(node))
+ -- print( 'endTest() '..prettystr(node:isNotSuccess()))
+ node.duration = os.clock() - node.startTime
+ node.startTime = nil
+ self.output:endTest( node )
+
+ if node:isSuccess() then
+ self.result.successCount = self.result.successCount + 1
+ elseif node:isError() then
+ if self.quitOnError or self.quitOnFailure then
+ -- Runtime error - abort test execution as requested by
+ -- "--error" option. This is done by setting a special
+ -- flag that gets handled in internalRunSuiteByInstances().
+ print("\nERROR during LuaUnit test execution:\n" .. node.msg)
+ self.result.aborted = true
+ end
+ elseif node:isFailure() then
+ if self.quitOnFailure then
+ -- Failure - abort test execution as requested by
+ -- "--failure" option. This is done by setting a special
+ -- flag that gets handled in internalRunSuiteByInstances().
+ print("\nFailure during LuaUnit test execution:\n" .. node.msg)
+ self.result.aborted = true
+ end
+ elseif node:isSkipped() then
+ self.result.runCount = self.result.runCount - 1
+ else
+ error('No such node status: ' .. prettystr(node.status))
+ end
+ self.result.currentNode = nil
+ end
+
+ function M.LuaUnit:endClass()
+ self:teardownClass( self.lastClassName, self.lastClassInstance )
+ self.output:endClass()
+ end
+
+ function M.LuaUnit:endSuite()
+ if self.result.suiteStarted == false then
+ error('LuaUnit:endSuite() -- suite was already ended' )
+ end
+ self.result.duration = os.clock()-self.result.startTime
+ self.result.suiteStarted = false
+
+ -- Expose test counts for outputter's endSuite(). This could be managed
+ -- internally instead by using the length of the lists of failed tests
+ -- but unit tests rely on these fields being present.
+ self.result.failureCount = #self.result.failedTests
+ self.result.errorCount = #self.result.errorTests
+ self.result.notSuccessCount = self.result.failureCount + self.result.errorCount
+ self.result.skippedCount = #self.result.skippedTests
+
+ self.output:endSuite()
+ end
+
+ function M.LuaUnit:setOutputType(outputType, fname)
+ -- Configures LuaUnit runner output
+ -- outputType is one of: NIL, TAP, JUNIT, TEXT
+ -- when outputType is junit, the additional argument fname is used to set the name of junit output file
+ -- for other formats, fname is ignored
+ if outputType:upper() == "NIL" then
+ self.outputType = NilOutput
+ return
+ end
+ if outputType:upper() == "TAP" then
+ self.outputType = TapOutput
+ return
+ end
+ if outputType:upper() == "JUNIT" then
+ self.outputType = JUnitOutput
+ if fname then
+ self.fname = fname
+ end
+ return
+ end
+ if outputType:upper() == "TEXT" then
+ self.outputType = TextOutput
+ return
+ end
+ error( 'No such format: '..outputType,2)
+ end
+
+ --------------[[ Runner ]]-----------------
+
+ function M.LuaUnit:protectedCall(classInstance, methodInstance, prettyFuncName)
+ -- if classInstance is nil, this is just a function call
+ -- else, it's method of a class being called.
+
+ local function err_handler(e)
+ -- transform error into a table, adding the traceback information
+ return {
+ status = NodeStatus.ERROR,
+ msg = e,
+ trace = string.sub(debug.traceback("", 1), 2)
+ }
+ end
+
+ local ok, err
+ if classInstance then
+ -- stupid Lua < 5.2 does not allow xpcall with arguments so let's use a workaround
+ ok, err = xpcall( function () methodInstance(classInstance) end, err_handler )
+ else
+ ok, err = xpcall( function () methodInstance() end, err_handler )
+ end
+ if ok then
+ return {status = NodeStatus.SUCCESS}
+ end
+ -- print('ok="'..prettystr(ok)..'" err="'..prettystr(err)..'"')
+
+ local iter_msg
+ iter_msg = self.exeRepeat and 'iteration '..self.currentCount
+
+ err.msg, err.status = M.adjust_err_msg_with_iter( err.msg, iter_msg )
+
+ if err.status == NodeStatus.SUCCESS or err.status == NodeStatus.SKIP then
+ err.trace = nil
+ return err
+ end
+
+ -- reformat / improve the stack trace
+ if prettyFuncName then -- we do have the real method name
+ err.trace = err.trace:gsub("in (%a+) 'methodInstance'", "in %1 '"..prettyFuncName.."'")
+ end
+ if STRIP_LUAUNIT_FROM_STACKTRACE then
+ err.trace = stripLuaunitTrace2(err.trace, err.msg)
+ end
+
+ return err -- return the error "object" (table)
+ end
+
+
+ function M.LuaUnit:execOneFunction(className, methodName, classInstance, methodInstance)
+ -- When executing a test function, className and classInstance must be nil
+ -- When executing a class method, all parameters must be set
+
+ if type(methodInstance) ~= 'function' then
+ self:unregisterSuite()
+ error( tostring(methodName)..' must be a function, not '..type(methodInstance))
+ end
+
+ local prettyFuncName
+ if className == nil then
+ className = '[TestFunctions]'
+ prettyFuncName = methodName
+ else
+ prettyFuncName = className..'.'..methodName
+ end
+
+ if self.lastClassName ~= className then
+ if self.lastClassName ~= nil then
+ self:endClass()
+ end
+ self:startClass( className, classInstance )
+ self.lastClassName = className
+ self.lastClassInstance = classInstance
+ end
+
+ self:startTest(prettyFuncName)
+
+ local node = self.result.currentNode
+ for iter_n = 1, self.exeRepeat or 1 do
+ if node:isNotSuccess() then
+ break
+ end
+ self.currentCount = iter_n
+
+ -- run setUp first (if any)
+ if classInstance then
+ local func = self.asFunction( classInstance.setUp ) or
+ self.asFunction( classInstance.Setup ) or
+ self.asFunction( classInstance.setup ) or
+ self.asFunction( classInstance.SetUp )
+ if func then
+ self:updateStatus(self:protectedCall(classInstance, func, className..'.setUp'))
+ end
+ end
+
+ -- run testMethod()
+ if node:isSuccess() then
+ self:updateStatus(self:protectedCall(classInstance, methodInstance, prettyFuncName))
+ end
+
+ -- lastly, run tearDown (if any)
+ if classInstance then
+ local func = self.asFunction( classInstance.tearDown ) or
+ self.asFunction( classInstance.TearDown ) or
+ self.asFunction( classInstance.teardown ) or
+ self.asFunction( classInstance.Teardown )
+ if func then
+ self:updateStatus(self:protectedCall(classInstance, func, className..'.tearDown'))
+ end
+ end
+ end
+
+ self:endTest()
+ end
+
+ function M.LuaUnit.expandOneClass( result, className, classInstance )
+ --[[
+ Input: a list of { name, instance }, a class name, a class instance
+ Ouptut: modify result to add all test method instance in the form:
+ { className.methodName, classInstance }
+ ]]
+ for methodName, methodInstance in sortedPairs(classInstance) do
+ if M.LuaUnit.asFunction(methodInstance) and M.LuaUnit.isMethodTestName( methodName ) then
+ table.insert( result, { className..'.'..methodName, classInstance } )
+ end
+ end
+ end
+
+ function M.LuaUnit.expandClasses( listOfNameAndInst )
+ --[[
+ -- expand all classes (provided as {className, classInstance}) to a list of {className.methodName, classInstance}
+ -- functions and methods remain untouched
+
+ Input: a list of { name, instance }
+
+ Output:
+ * { function name, function instance } : do nothing
+ * { class.method name, class instance }: do nothing
+ * { class name, class instance } : add all method names in the form of (className.methodName, classInstance)
+ ]]
+ local result = {}
+
+ for i,v in ipairs( listOfNameAndInst ) do
+ local name, instance = v[1], v[2]
+ if M.LuaUnit.asFunction(instance) then
+ table.insert( result, { name, instance } )
+ else
+ if type(instance) ~= 'table' then
+ error( 'Instance must be a table or a function, not a '..type(instance)..' with value '..prettystr(instance))
+ end
+ local className, methodName = M.LuaUnit.splitClassMethod( name )
+ if className then
+ local methodInstance = instance[methodName]
+ if methodInstance == nil then
+ error( "Could not find method in class "..tostring(className).." for method "..tostring(methodName) )
+ end
+ table.insert( result, { name, instance } )
+ else
+ M.LuaUnit.expandOneClass( result, name, instance )
+ end
+ end
+ end
+
+ return result
+ end
+
+ function M.LuaUnit.applyPatternFilter( patternIncFilter, listOfNameAndInst )
+ local included, excluded = {}, {}
+ for i, v in ipairs( listOfNameAndInst ) do
+ -- local name, instance = v[1], v[2]
+ if patternFilter( patternIncFilter, v[1] ) then
+ table.insert( included, v )
+ else
+ table.insert( excluded, v )
+ end
+ end
+ return included, excluded
+ end
+
+ local function getKeyInListWithGlobalFallback( key, listOfNameAndInst )
+ local result = nil
+ for i,v in ipairs( listOfNameAndInst ) do
+ if(listOfNameAndInst[i][1] == key) then
+ result = listOfNameAndInst[i][2]
+ break
+ end
+ end
+ if(not M.LuaUnit.asFunction( result ) ) then
+ result = _G[key]
+ end
+ return result
+ end
+
+ function M.LuaUnit:setupSuite( listOfNameAndInst )
+ local setupSuite = getKeyInListWithGlobalFallback("setupSuite", listOfNameAndInst)
+ if self.asFunction( setupSuite ) then
+ self:updateStatus( self:protectedCall( nil, setupSuite, 'setupSuite' ) )
+ end
+ end
+
+ function M.LuaUnit:teardownSuite(listOfNameAndInst)
+ local teardownSuite = getKeyInListWithGlobalFallback("teardownSuite", listOfNameAndInst)
+ if self.asFunction( teardownSuite ) then
+ self:updateStatus( self:protectedCall( nil, teardownSuite, 'teardownSuite') )
+ end
+ end
+
+ function M.LuaUnit:setupClass( className, instance )
+ if type( instance ) == 'table' and self.asFunction( instance.setupClass ) then
+ self:updateStatus( self:protectedCall( instance, instance.setupClass, className..'.setupClass' ) )
+ end
+ end
+
+ function M.LuaUnit:teardownClass( className, instance )
+ if type( instance ) == 'table' and self.asFunction( instance.teardownClass ) then
+ self:updateStatus( self:protectedCall( instance, instance.teardownClass, className..'.teardownClass' ) )
+ end
+ end
+
+ function M.LuaUnit:internalRunSuiteByInstances( listOfNameAndInst )
+ --[[ Run an explicit list of tests. Each item of the list must be one of:
+ * { function name, function instance }
+ * { class name, class instance }
+ * { class.method name, class instance }
+
+ This function is internal to LuaUnit. The official API to perform this action is runSuiteByInstances()
+ ]]
+
+ local expandedList = self.expandClasses( listOfNameAndInst )
+ if self.shuffle then
+ randomizeTable( expandedList )
+ end
+ local filteredList, filteredOutList = self.applyPatternFilter(
+ self.patternIncludeFilter, expandedList )
+
+ self:startSuite( #filteredList, #filteredOutList )
+ self:setupSuite( listOfNameAndInst )
+
+ for i,v in ipairs( filteredList ) do
+ local name, instance = v[1], v[2]
+ if M.LuaUnit.asFunction(instance) then
+ self:execOneFunction( nil, name, nil, instance )
+ else
+ -- expandClasses() should have already taken care of sanitizing the input
+ assert( type(instance) == 'table' )
+ local className, methodName = M.LuaUnit.splitClassMethod( name )
+ assert( className ~= nil )
+ local methodInstance = instance[methodName]
+ assert(methodInstance ~= nil)
+ self:execOneFunction( className, methodName, instance, methodInstance )
+ end
+ if self.result.aborted then
+ break -- "--error" or "--failure" option triggered
+ end
+ end
+
+ if self.lastClassName ~= nil then
+ self:endClass()
+ end
+
+ self:teardownSuite( listOfNameAndInst )
+ self:endSuite()
+
+ if self.result.aborted then
+ print("LuaUnit ABORTED (as requested by --error or --failure option)")
+ self:unregisterSuite()
+ os.exit(-2)
+ end
+ end
+
+ function M.LuaUnit:internalRunSuiteByNames( listOfName )
+ --[[ Run LuaUnit with a list of generic names, coming either from command-line or from global
+ namespace analysis. Convert the list into a list of (name, valid instances (table or function))
+ and calls internalRunSuiteByInstances.
+ ]]
+
+ local instanceName, instance
+ local listOfNameAndInst = {}
+
+ for i,name in ipairs( listOfName ) do
+ local className, methodName = M.LuaUnit.splitClassMethod( name )
+ if className then
+ instanceName = className
+ instance = _G[instanceName]
+
+ if instance == nil then
+ self:unregisterSuite()
+ error( "No such name in global space: "..instanceName )
+ end
+
+ if type(instance) ~= 'table' then
+ self:unregisterSuite()
+ error( 'Instance of '..instanceName..' must be a table, not '..type(instance))
+ end
+
+ local methodInstance = instance[methodName]
+ if methodInstance == nil then
+ self:unregisterSuite()
+ error( "Could not find method in class "..tostring(className).." for method "..tostring(methodName) )
+ end
+
+ else
+ -- for functions and classes
+ instanceName = name
+ instance = _G[instanceName]
+ end
+
+ if instance == nil then
+ self:unregisterSuite()
+ error( "No such name in global space: "..instanceName )
+ end
+
+ if (type(instance) ~= 'table' and type(instance) ~= 'function') then
+ self:unregisterSuite()
+ error( 'Name must match a function or a table: '..instanceName )
+ end
+
+ table.insert( listOfNameAndInst, { name, instance } )
+ end
+
+ self:internalRunSuiteByInstances( listOfNameAndInst )
+ end
+
+ function M.LuaUnit.run(...)
+ -- Run some specific test classes.
+ -- If no arguments are passed, run the class names specified on the
+ -- command line. If no class name is specified on the command line
+ -- run all classes whose name starts with 'Test'
+ --
+ -- If arguments are passed, they must be strings of the class names
+ -- that you want to run or generic command line arguments (-o, -p, -v, ...)
+ local runner = M.LuaUnit.new()
+ return runner:runSuite(...)
+ end
+
+ function M.LuaUnit:registerSuite()
+ -- register the current instance into our global array of instances
+ -- print('-> Register suite')
+ M.LuaUnit.instances[ #M.LuaUnit.instances+1 ] = self
+ end
+
+ function M.unregisterCurrentSuite()
+ -- force unregister the last registered suite
+ table.remove(M.LuaUnit.instances, #M.LuaUnit.instances)
+ end
+
+ function M.LuaUnit:unregisterSuite()
+ -- print('<- Unregister suite')
+ -- remove our current instqances from the global array of instances
+ local instanceIdx = nil
+ for i, instance in ipairs(M.LuaUnit.instances) do
+ if instance == self then
+ instanceIdx = i
+ break
+ end
+ end
+
+ if instanceIdx ~= nil then
+ table.remove(M.LuaUnit.instances, instanceIdx)
+ -- print('Unregister done')
+ end
+
+ end
+
+ function M.LuaUnit:initFromArguments( ... )
+ --[[Parses all arguments from either command-line or direct call and set internal
+ flags of LuaUnit runner according to it.
+
+ Return the list of names which were possibly passed on the command-line or as arguments
+ ]]
+ local args = {...}
+ if type(args[1]) == 'table' and args[1].__class__ == 'LuaUnit' then
+ -- run was called with the syntax M.LuaUnit:runSuite()
+ -- we support both M.LuaUnit.run() and M.LuaUnit:run()
+ -- strip out the first argument self to make it a command-line argument list
+ table.remove(args,1)
+ end
+
+ if #args == 0 then
+ args = cmdline_argv
+ end
+
+ local options = pcall_or_abort( M.LuaUnit.parseCmdLine, args )
+
+ -- We expect these option fields to be either `nil` or contain
+ -- valid values, so it's safe to always copy them directly.
+ self.verbosity = options.verbosity
+ self.quitOnError = options.quitOnError
+ self.quitOnFailure = options.quitOnFailure
+
+ self.exeRepeat = options.exeRepeat
+ self.patternIncludeFilter = options.pattern
+ self.shuffle = options.shuffle
+
+ options.output = options.output or os.getenv('LUAUNIT_OUTPUT')
+ options.fname = options.fname or os.getenv('LUAUNIT_JUNIT_FNAME')
+
+ if options.output then
+ if options.output:lower() == 'junit' and options.fname == nil then
+ print('With junit output, a filename must be supplied with -n or --name')
+ os.exit(-1)
+ end
+ pcall_or_abort(self.setOutputType, self, options.output, options.fname)
+ end
+
+ return options.testNames
+ end
+
+ function M.LuaUnit:runSuite( ... )
+ testNames = self:initFromArguments(...)
+ self:registerSuite()
+ self:internalRunSuiteByNames( testNames or M.LuaUnit.collectTests() )
+ self:unregisterSuite()
+ return self.result.notSuccessCount
+ end
+
+ function M.LuaUnit:runSuiteByInstances( listOfNameAndInst, commandLineArguments )
+ --[[
+ Run all test functions or tables provided as input.
+
+ Input: a list of { name, instance }
+ instance can either be a function or a table containing test functions starting with the prefix "test"
+
+ return the number of failures and errors, 0 meaning success
+ ]]
+ -- parse the command-line arguments
+ testNames = self:initFromArguments( commandLineArguments )
+ self:registerSuite()
+ self:internalRunSuiteByInstances( listOfNameAndInst )
+ self:unregisterSuite()
+ return self.result.notSuccessCount
+ end
+
+
+
+-- class LuaUnit
+
+-- For compatbility with LuaUnit v2
+M.run = M.LuaUnit.run
+M.Run = M.LuaUnit.run
+
+function M:setVerbosity( verbosity )
+ -- set the verbosity value (as integer)
+ M.LuaUnit.verbosity = verbosity
+end
+M.set_verbosity = M.setVerbosity
+M.SetVerbosity = M.setVerbosity
+
+
+return M
+
diff --git a/Data/Libraries/luaunit/run_functional_tests.lua b/Data/Libraries/luaunit/run_functional_tests.lua
new file mode 100644
index 0000000..59127c5
--- /dev/null
+++ b/Data/Libraries/luaunit/run_functional_tests.lua
@@ -0,0 +1,820 @@
+#!/usr/bin/env lua
+
+require('os')
+local lu = require('luaunit')
+
+
+local function report( ... )
+ print('>>>>>>>', string.format(...))
+end
+
+local function error_fmt( ... )
+ error(string.format(...), 2) -- (level 2 = report chunk calling error_fmt)
+end
+
+local IS_UNIX = ( package.config:sub(1,1) == '/' )
+local LUA='"'..arg[-1]..'"'
+
+
+-- Escape a string so it can safely be used as a Lua pattern without triggering
+-- special semantics. This means prepending any "magic" character ^$()%.[]*+-?
+-- with a percent sign. Note: We DON'T expect embedded NUL chars, and thus
+-- won't escape those (%z) for Lua 5.1.
+local LUA_MAGIC_CHARS = "[%^%$%(%)%%%.%[%]%*%+%-%?]"
+local function escape_lua_pattern(s)
+ return s:gsub(LUA_MAGIC_CHARS, "%%%1") -- substitute with '%' + matched char
+end
+
+local function string_gsub(s, orig, repl)
+ -- replace occurrence of string orig by string repl
+ -- just like string.gsub, but with no pattern matching
+ -- print( 'gsub_input '..s..' '..orig..' '..repl)
+ return s:gsub( escape_lua_pattern(orig), repl )
+end
+
+function testStringSub()
+ lu.assertEquals( string_gsub('aa a % b cc', 'a % b', 'a + b'), 'aa a + b cc' )
+ lu.assertEquals( string_gsub('aa: ?cc', ': ?', 'xx?'), 'aaxx?cc' )
+ lu.assertEquals( string_gsub('aa b: cc b: ee', 'b:', 'xx'), 'aa xx cc xx ee' )
+end
+
+local function osExec( ... )
+ -- execute a command with os.execute and return true if exit code is 0
+ -- false in any other conditions
+
+ local cmd = string.format(...)
+ if not(IS_UNIX) and cmd:sub(1, 1) == '"' then
+ -- In case we're running on Windows, and if the command starts with a
+ -- quote: It's reasonable (or even necessary in some cases) to enclose
+ -- the entire command string in another pair of quotes. (This is needed
+ -- to preserve other quotes, due to how os.execute makes use of cmd.exe)
+ -- see e.g. http://lua-users.org/lists/lua-l/2014-06/msg00551.html
+ cmd = '"' .. cmd .. '"'
+ end
+
+ -- print('osExec('..cmd..')')
+ local exitSuccess, exitReason, exitCode = os.execute( cmd )
+ -- print('\n', exitSuccess, exitReason, exitCode)
+
+ if exitReason == nil and exitCode == nil then
+ -- Lua 5.1 returns only the exit code
+ exitReason = 'exit'
+ if IS_UNIX then
+ -- in C: exitCode = (exitSuccess >> 8) & 0xFF
+ -- poor approximation that works:
+ exitCode = (exitSuccess / 256)
+ else
+ -- Windows, life is simple
+ exitCode = exitSuccess
+ end
+ end
+
+ -- Use heuristics to determine negative exit codes,
+ -- assuming that those are in the range -8 to -1:
+ if exitCode >= 248 then exitCode = exitCode - 256 end
+
+ -- Lua 5.2+ has a weird way of dealing with exit code -1, at least on Windows
+ if exitReason == 'No error' then
+ exitReason = 'exit'
+ exitCode = -1
+ end
+
+ if exitReason ~= 'exit' or exitCode ~= 0 then
+ -- print('return false '..tostring(exitCode))
+ return false, exitCode
+ end
+
+ -- print('return true')
+ return true, exitCode
+end
+
+local function osExpectedCodeExec( refExitCode, ... )
+ local cmd = string.format(...)
+ local ret, exitCode = osExec( cmd )
+ if refExitCode and (exitCode ~= refExitCode) then
+ error_fmt('Expected exit code %d, but got %d for: %s', refExitCode, exitCode, cmd)
+ end
+ return ret
+end
+
+local HAS_XMLLINT
+do
+ local xmllint_output_fname = 'test/has_xmllint.txt'
+ HAS_XMLLINT = osExec('xmllint --version 2> '..xmllint_output_fname)
+ if not HAS_XMLLINT then
+ report('WARNING: xmllint absent, can not validate xml validity')
+ end
+ os.remove(xmllint_output_fname)
+end
+
+local function adjustFile( fileOut, fileIn, pattern, mayBeAbsent, verbose )
+ --[[ Adjust the content of fileOut by copying lines matching pattern from fileIn
+
+ fileIn lines are read and the first line matching pattern is analysed. The first pattern
+ capture is memorized.
+
+ fileOut lines are then read, and the first line matching pattern is modified, by applying
+ the first capture of fileIn. fileOut is then rewritten.
+
+ In most cases, pattern2 may be nil in which case, pattern is used when matching in fileout.
+ ]]
+ if verbose then
+ print('Using reference file: '..fileIn)
+ end
+ local source, idxStart, idxEnd, capture = nil
+ for line in io.lines(fileIn) do
+ idxStart, idxEnd, capture = line:find( pattern )
+ if idxStart ~= nil then
+ if capture == nil then
+ error_fmt('Must specify a capture for pattern %s in function adjustFile()', pattern)
+ end
+ source = capture
+ break
+ end
+ end
+
+ if source == nil then
+ if mayBeAbsent then
+ return -- no capture, just return
+ end
+ error_fmt('No line in file %s matching pattern "%s"', fileIn, pattern)
+ end
+
+ if verbose then
+ print('Captured in source: '.. source )
+ print('Modifying file: '..fileOut)
+ end
+
+ local dest, linesOut = nil, {}
+ for line in io.lines(fileOut) do
+ idxStart, idxEnd, capture = line:find( pattern )
+ while idxStart ~= nil do
+ if capture == nil then
+ print('missing pattern for outfile!')
+ end
+ dest = capture
+ if verbose then
+ print('Modifying line: '..line )
+ end
+ line = string_gsub(line, dest, source)
+ -- line = line:sub(1,idxStart-1)..source..line:sub(idxEnd+1)
+ -- string.gsub( line, dest, source )
+ if verbose then
+ print('Result : '..line )
+ end
+ idxStart, idxEnd, capture = line:find( pattern, idxEnd )
+ end
+ table.insert( linesOut, line )
+ end
+
+ if dest == nil then
+ if mayBeAbsent then
+ return -- capture but nothing to adjust, just return
+ end
+ error_fmt('No line in file %s matching pattern "%s"', fileOut, pattern)
+ end
+
+ local f = io.open( fileOut, 'w')
+ f:write(table.concat(linesOut, '\n'), '\n')
+ f:close()
+end
+
+local function check_tap_output( fileToRun, options, output, refOutput, refExitCode, envOptions, outputArg )
+ -- remove output
+ envOptions = envOptions or ''
+ outputArg = outputArg or ''
+
+ -- by default, if nothing is provided, we set output explicitely
+ -- but we leave the option for the caller to provide either environment and/or output arguments
+ if envOptions == '' and outputArg == '' then
+ outputArg = '--output TAP'
+ end
+
+ if envOptions ~= '' then
+ envOptions = '/usr/bin/env ' .. envOptions
+ end
+
+ osExpectedCodeExec(refExitCode, '%s %s %s %s %s > %s',
+ envOptions, LUA, fileToRun, outputArg, options, output)
+
+ adjustFile( output, refOutput, '# Started on (.*)')
+ adjustFile( output, refOutput, '# Ran %d+ tests in (%d+.%d*).*')
+ if _VERSION ~= 'Lua 5.2' and _VERSION ~= 'Lua 5.1' then
+ -- For Lua 5.3: stack trace uses "method" instead of "function"
+ adjustFile( output, refOutput, '.*%.lua:%d+: in (%S*) .*', true )
+ end
+
+ if not osExec([[diff -NPw -u -I " *\.[/\\]luaunit.lua:[0123456789]\+:.*" %s %s]], refOutput, output) then
+ error('TAP Output mismatch for file : '..output)
+ end
+ -- report('TAP Output ok: '..output)
+ return 0
+end
+
+
+local function check_text_output( fileToRun, options, output, refOutput, refExitCode )
+ -- remove output
+ osExpectedCodeExec(refExitCode, '%s %s --output text %s > %s',
+ LUA, fileToRun, options, output)
+
+ if options:find( '--verbose' ) then
+ adjustFile( output, refOutput, 'Started on (.*)')
+ end
+ adjustFile( output, refOutput, 'Ran .* tests in (%d.%d*) seconds' )
+ adjustFile( output, refOutput, 'Ran .* tests in (%d.%d*) seconds' )
+ adjustFile( output, refOutput, 'thread: (0?x?[%x]+)', true )
+ adjustFile( output, refOutput, 'function: (0?x?[%x]+)', true )
+ adjustFile( output, refOutput, '<table (01%-0?x?[%x]+)>', true )
+ adjustFile( output, refOutput, '<table (02%-0?x?[%x]+)>', true )
+ if _VERSION ~= 'Lua 5.2' and _VERSION ~= 'Lua 5.1' then
+ -- For Lua 5.3: stack trace uses "method" instead of "function"
+ adjustFile( output, refOutput, '.*%.lua:%d+: in (%S*) .*', true )
+ end
+
+ if not osExec([[diff -NPw -u -I " *\.[/\\]luaunit.lua:[0123456789]\+:.*" %s %s]], refOutput, output) then
+ error('Text Output mismatch for file : '..output)
+ end
+ -- report('Text Output ok: '..output)
+ return 0
+end
+
+local function check_nil_output( fileToRun, options, output, refOutput, refExitCode )
+ -- remove output
+ osExpectedCodeExec(refExitCode, '%s %s --output nil %s > %s',
+ LUA, fileToRun, options, output)
+
+ if not osExec([[diff -NPw -u -I " *\.[/\\]luaunit.lua:[0123456789]\+:.*" %s %s]], refOutput, output) then
+ error('NIL Output mismatch for file : '..output)
+ end
+ -- report('NIL Output ok: '..output)
+ return 0
+end
+
+local function check_xml_output( fileToRun, options, output, xmlOutput, xmlLintOutput, refOutput, refXmlOutput, refExitCode, envOptions, outputArg )
+ local retcode = 0
+
+ envOptions = envOptions or ''
+ outputArg = outputArg or ''
+
+ -- by default, if nothing is provided, we set output explicitely
+ -- but we leave the option for the caller to provide either environment and/or output arguments
+ if envOptions == '' and outputArg == '' then
+ outputArg = '--output junit --name '..xmlOutput
+ end
+
+ if envOptions ~= '' then
+ envOptions = '/usr/bin/env ' .. envOptions
+ end
+
+ -- remove output
+ osExpectedCodeExec(refExitCode, '%s %s %s %s %s > %s',
+ envOptions, LUA, fileToRun, outputArg, options, output)
+
+ adjustFile( output, refOutput, '# XML output to (.*)')
+ adjustFile( output, refOutput, '# Started on (.*)')
+ adjustFile( output, refOutput, '# Ran %d+ tests in (%d+.%d*).*')
+ adjustFile( xmlOutput, refXmlOutput, '.*<testsuite.*(timestamp=".-" time=".-").*')
+ adjustFile( xmlOutput, refXmlOutput, '.*<testcase .*(time=".-").*' )
+ -- For Lua 5.1 / 5.2 compatibility
+ adjustFile( xmlOutput, refXmlOutput, '.*<property name="Lua Version" value="(Lua 5%..)"/>')
+
+ if _VERSION ~= 'Lua 5.2' and _VERSION ~= 'Lua 5.1' then
+ -- For Lua 5.3: stack trace uses "method" instead of "function"
+ -- For Lua 5.4: stack trace uses "method" or "upvalue" instead of "function"
+ adjustFile( output, refOutput, '.*%.lua:%d+: in (%S*) .*', true )
+ adjustFile( xmlOutput, refXmlOutput, '.*%.lua:%d+: in (%S*) .*', true )
+ end
+
+ if HAS_XMLLINT then
+ -- General xmllint validation
+ if osExec('xmllint --noout %s > %s', xmlOutput, xmlLintOutput) then
+ -- report('XMLLint validation ok: file %s', xmlLintOutput)
+ else
+ error_fmt('XMLLint reported errors : file %s', xmlLintOutput)
+ retcode = retcode + 1
+ end
+
+ -- we used to validate against apache and/maven xsd but the way it handles skipped test
+ -- is just too specific. I prefer the jenkins way.
+
+ -- Validation against jenkins/hudson schema
+ if osExec('xmllint --noout --schema junitxml/junit-jenkins.xsd %s 2> %s', xmlOutput, xmlLintOutput) then
+ -- report('XMLLint validation ok: file %s', xmlLintOutput)
+ else
+ error_fmt('XMLLint reported errors against jenkins schema: file %s', xmlLintOutput)
+ retcode = retcode + 1
+ end
+ end
+
+ -- ignore change in line numbers for luaunit
+ if not osExec([[diff -NPw -u -I " *\.[/\\]luaunit.lua:[0123456789]\+:.*" %s %s]], refXmlOutput, xmlOutput) then
+ error('XML content mismatch for file : '..xmlOutput)
+ retcode = retcode + 1
+ end
+
+ if not osExec([[diff -NPw -u -I " *\.[/\\]luaunit.lua:[0123456789]\+:.*" %s %s]], refOutput, output) then
+ error('XML Output mismatch for file : '..output)
+ retcode = retcode + 1
+ end
+
+ --[[
+ if retcode == 0 then
+ report('XML Output ok: '..output)
+ end
+ --]]
+
+ return retcode
+end
+
+-- check tap output
+
+function testTapDefault()
+ lu.assertEquals( 0,
+ check_tap_output('example_with_luaunit.lua', '',
+ 'test/exampleTapDefault.txt',
+ 'test/ref/exampleTapDefault.txt', 12) )
+ lu.assertEquals( 0,
+ check_tap_output('test/test_with_err_fail_pass.lua', '',
+ 'test/errFailPassTapDefault.txt',
+ 'test/ref/errFailPassTapDefault.txt', 10 ) )
+ lu.assertEquals( 0,
+ check_tap_output('test/test_with_err_fail_pass.lua', '-p Succ',
+ 'test/errFailPassTapDefault-success.txt',
+ 'test/ref/errFailPassTapDefault-success.txt', 0 ) )
+ lu.assertEquals( 0,
+ check_tap_output('test/test_with_err_fail_pass.lua', '-p Succ -p Fail',
+ 'test/errFailPassTapDefault-failures.txt',
+ 'test/ref/errFailPassTapDefault-failures.txt', 5 ) )
+ if IS_UNIX then
+ -- It is non-trivial to set the environment for new command execution
+ -- on Windows, so we'll only attempt it on UNIX. These systems should
+ -- all have /usr/bin/env
+ lu.assertEquals( 0,
+ check_tap_output('test/test_with_err_fail_pass.lua', '-p Succ -p Fail',
+ 'test/errFailPassTapDefault-failures.txt',
+ 'test/ref/errFailPassTapDefault-failures.txt', 5,
+ 'LUAUNIT_OUTPUT=TAP' ) )
+
+ -- force an alternate file format, check that command-line option prevails
+ lu.assertEquals( 0,
+ check_tap_output('test/test_with_err_fail_pass.lua', '-p Succ -p Fail',
+ 'test/errFailPassTapDefault-failures.txt',
+ 'test/ref/errFailPassTapDefault-failures.txt', 5,
+ 'LUAUNIT_OUTPUT=TEXT', '--output tap' ) )
+ end
+end
+
+function testTapVerbose()
+ lu.assertEquals( 0,
+ check_tap_output('example_with_luaunit.lua', '--verbose',
+ 'test/exampleTapVerbose.txt',
+ 'test/ref/exampleTapVerbose.txt', 12 ) )
+ lu.assertEquals( 0,
+ check_tap_output('test/test_with_err_fail_pass.lua', '--verbose',
+ 'test/errFailPassTapVerbose.txt',
+ 'test/ref/errFailPassTapVerbose.txt', 10 ) )
+ lu.assertEquals( 0,
+ check_tap_output('test/test_with_err_fail_pass.lua', '--verbose -p Succ',
+ 'test/errFailPassTapVerbose-success.txt',
+ 'test/ref/errFailPassTapVerbose-success.txt', 0 ) )
+ lu.assertEquals( 0,
+ check_tap_output('test/test_with_err_fail_pass.lua', '--verbose -p Succ -p Fail',
+ 'test/errFailPassTapVerbose-failures.txt',
+ 'test/ref/errFailPassTapVerbose-failures.txt', 5 ) )
+end
+
+function testTapQuiet()
+ lu.assertEquals( 0,
+ check_tap_output('example_with_luaunit.lua', '--quiet', 'test/exampleTapQuiet.txt', 'test/ref/exampleTapQuiet.txt', 12 ) )
+ lu.assertEquals( 0,
+ check_tap_output('test/test_with_err_fail_pass.lua', '--quiet',
+ 'test/errFailPassTapQuiet.txt',
+ 'test/ref/errFailPassTapQuiet.txt', 10 ) )
+ lu.assertEquals( 0,
+ check_tap_output('test/test_with_err_fail_pass.lua', '--quiet -p Succ',
+ 'test/errFailPassTapQuiet-success.txt',
+ 'test/ref/errFailPassTapQuiet-success.txt', 0 ) )
+ lu.assertEquals( 0,
+ check_tap_output('test/test_with_err_fail_pass.lua', '--quiet -p Succ -p Fail',
+ 'test/errFailPassTapQuiet-failures.txt',
+ 'test/ref/errFailPassTapQuiet-failures.txt', 5 ) )
+end
+
+-- check text output
+
+function testTextDefault()
+ lu.assertEquals( 0,
+ check_text_output('example_with_luaunit.lua', '',
+ 'test/exampleTextDefault.txt',
+ 'test/ref/exampleTextDefault.txt', 12 ) )
+ lu.assertEquals( 0,
+ check_text_output('test/test_with_err_fail_pass.lua', '',
+ 'test/errFailPassTextDefault.txt',
+ 'test/ref/errFailPassTextDefault.txt', 10 ) )
+ lu.assertEquals( 0,
+ check_text_output('test/test_with_err_fail_pass.lua', '-p Succ',
+ 'test/errFailPassTextDefault-success.txt',
+ 'test/ref/errFailPassTextDefault-success.txt', 0 ) )
+ lu.assertEquals( 0,
+ check_text_output('test/test_with_err_fail_pass.lua', '-p Succ -p Fail',
+ 'test/errFailPassTextDefault-failures.txt',
+ 'test/ref/errFailPassTextDefault-failures.txt', 5 ) )
+end
+
+function testTextVerbose()
+ lu.assertEquals( 0,
+ check_text_output('example_with_luaunit.lua', '--verbose', 'test/exampleTextVerbose.txt', 'test/ref/exampleTextVerbose.txt', 12 ) )
+ lu.assertEquals( 0,
+ check_text_output('test/test_with_err_fail_pass.lua', '--verbose',
+ 'test/errFailPassTextVerbose.txt',
+ 'test/ref/errFailPassTextVerbose.txt', 10 ) )
+ lu.assertEquals( 0,
+ check_text_output('test/test_with_err_fail_pass.lua', '--verbose -p Succ',
+ 'test/errFailPassTextVerbose-success.txt',
+ 'test/ref/errFailPassTextVerbose-success.txt', 0 ) )
+ lu.assertEquals( 0,
+ check_text_output('test/test_with_err_fail_pass.lua', '--verbose -p Succ -p Fail',
+ 'test/errFailPassTextVerbose-failures.txt',
+ 'test/ref/errFailPassTextVerbose-failures.txt', 5 ) )
+end
+
+function testTextQuiet()
+ lu.assertEquals( 0,
+ check_text_output('example_with_luaunit.lua', '--quiet',
+ 'test/exampleTextQuiet.txt',
+ 'test/ref/exampleTextQuiet.txt', 12 ) )
+ lu.assertEquals( 0,
+ check_text_output('test/test_with_err_fail_pass.lua', '--quiet',
+ 'test/errFailPassTextQuiet.txt',
+ 'test/ref/errFailPassTextQuiet.txt', 10 ) )
+ lu.assertEquals( 0,
+ check_text_output('test/test_with_err_fail_pass.lua', '--quiet -p Succ',
+ 'test/errFailPassTextQuiet-success.txt',
+ 'test/ref/errFailPassTextQuiet-success.txt', 0 ) )
+ lu.assertEquals( 0,
+ check_text_output('test/test_with_err_fail_pass.lua', '--quiet -p Succ -p Fail',
+ 'test/errFailPassTextQuiet-failures.txt',
+ 'test/ref/errFailPassTextQuiet-failures.txt', 5 ) )
+end
+
+-- check nil output
+
+function testNilDefault()
+ lu.assertEquals( 0,
+ check_nil_output('example_with_luaunit.lua', '', 'test/exampleNilDefault.txt', 'test/ref/exampleNilDefault.txt', 12 ) )
+ lu.assertEquals( 0,
+ check_nil_output('test/test_with_err_fail_pass.lua', '',
+ 'test/errFailPassNilDefault.txt',
+ 'test/ref/errFailPassNilDefault.txt', 10 ) )
+ lu.assertEquals( 0,
+ check_nil_output('test/test_with_err_fail_pass.lua', ' -p Succ',
+ 'test/errFailPassNilDefault-success.txt',
+ 'test/ref/errFailPassNilDefault-success.txt', 0 ) )
+ lu.assertEquals( 0,
+ check_nil_output('test/test_with_err_fail_pass.lua', ' -p Succ -p Fail',
+ 'test/errFailPassNilDefault-failures.txt',
+ 'test/ref/errFailPassNilDefault-failures.txt', 5 ) )
+end
+
+-- check xml output
+
+function testXmlDefault()
+ lu.assertEquals( 0,
+ check_xml_output('example_with_luaunit.lua', '',
+ 'test/exampleXmlDefault.txt', 'test/exampleXmlDefault.xml', 'test/exampleXmllintDefault.xml',
+ 'test/ref/exampleXmlDefault.txt', 'test/ref/exampleXmlDefault.xml', 12 ) )
+ lu.assertEquals( 0,
+ check_xml_output('test/test_with_err_fail_pass.lua', '',
+ 'test/errFailPassXmlDefault.txt', 'test/errFailPassXmlDefault.xml', 'test/errFailPassXmllintDefault.xml',
+ 'test/ref/errFailPassXmlDefault.txt', 'test/ref/errFailPassXmlDefault.xml', 10 ) )
+ lu.assertEquals( 0,
+ check_xml_output('test/test_with_err_fail_pass.lua', '-p Succ',
+ 'test/errFailPassXmlDefault-success.txt', 'test/errFailPassXmlDefault-success.xml', 'test/errFailPassXmllintDefault.xml',
+ 'test/ref/errFailPassXmlDefault-success.txt', 'test/ref/errFailPassXmlDefault-success.xml', 0 ) )
+ lu.assertEquals( 0,
+ check_xml_output('test/test_with_err_fail_pass.lua', '-p Succ -p Fail',
+ 'test/errFailPassXmlDefault-failures.txt', 'test/errFailPassXmlDefault-failures.xml', 'test/errFailPassXmllintDefault.xml',
+ 'test/ref/errFailPassXmlDefault-failures.txt', 'test/ref/errFailPassXmlDefault-failures.xml', 5 ) )
+
+ -- disable this test not working !
+ if IS_UNIX and false then
+ -- It is non-trivial to set the environment for new command execution
+ -- on Windows, so we'll only attempt it on UNIX. These systems should
+ -- all have /usr/bin/env
+ lu.assertEquals( 0,
+ check_xml_output('test/test_with_err_fail_pass.lua', '-p Succ -p Fail',
+ 'test/errFailPassXmlDefault-failures.txt', 'test/errFailPassXmlDefault-failures.xml', 'test/errFailPassXmllintDefault.xml',
+ 'test/ref/errFailPassXmlDefault-failures.txt', 'test/ref/errFailPassXmlDefault-failures.xml', 5,
+ 'LUAUNIT_OUTPUT=JUNIT LUAUNIT_JUNIT_FNAME=test/ref/errFailPassXmlDefault-failures.xml', '' ) )
+ end
+
+end
+
+function testXmlVerbose()
+ lu.assertEquals( 0,
+ check_xml_output('example_with_luaunit.lua', '--verbose',
+ 'test/exampleXmlVerbose.txt', 'test/exampleXmlVerbose.xml', 'test/exampleXmllintVerbose.xml',
+ 'test/ref/exampleXmlVerbose.txt', 'test/ref/exampleXmlVerbose.xml', 12 ) )
+ lu.assertEquals( 0,
+ check_xml_output('test/test_with_err_fail_pass.lua', '--verbose ',
+ 'test/errFailPassXmlVerbose.txt', 'test/errFailPassXmlVerbose.xml', 'test/errFailPassXmllintVerbose.xml',
+ 'test/ref/errFailPassXmlVerbose.txt', 'test/ref/errFailPassXmlVerbose.xml', 10 ) )
+ lu.assertEquals( 0,
+ check_xml_output('test/test_with_err_fail_pass.lua', '--verbose -p Succ',
+ 'test/errFailPassXmlVerbose-success.txt', 'test/errFailPassXmlVerbose-success.xml', 'test/errFailPassXmllintVerbose.xml',
+ 'test/ref/errFailPassXmlVerbose-success.txt', 'test/ref/errFailPassXmlVerbose-success.xml', 0 ) )
+ lu.assertEquals( 0,
+ check_xml_output('test/test_with_err_fail_pass.lua', '--verbose -p Succ -p Fail',
+ 'test/errFailPassXmlVerbose-failures.txt', 'test/errFailPassXmlVerbose-failures.xml', 'test/errFailPassXmllintVerbose.xml',
+ 'test/ref/errFailPassXmlVerbose-failures.txt', 'test/ref/errFailPassXmlVerbose-failures.xml', 5 ) )
+end
+
+function testXmlQuiet()
+ lu.assertEquals( 0,
+ check_xml_output('example_with_luaunit.lua', '--quiet', 'test/exampleXmlQuiet.txt', 'test/exampleXmlQuiet.xml',
+ 'test/exampleXmllintQuiet.xml', 'test/ref/exampleXmlQuiet.txt', 'test/ref/exampleXmlQuiet.xml', 12 ) )
+ lu.assertEquals( 0,
+ check_xml_output('test/test_with_err_fail_pass.lua', '--quiet ',
+ 'test/errFailPassXmlQuiet.txt', 'test/errFailPassXmlQuiet.xml', 'test/errFailPassXmllintQuiet.xml',
+ 'test/ref/errFailPassXmlQuiet.txt', 'test/ref/errFailPassXmlQuiet.xml', 10 ) )
+ lu.assertEquals( 0,
+ check_xml_output('test/test_with_err_fail_pass.lua', '--quiet -p Succ',
+ 'test/errFailPassXmlQuiet-success.txt', 'test/errFailPassXmlQuiet-success.xml', 'test/errFailPassXmllintQuiet.xml',
+ 'test/ref/errFailPassXmlQuiet-success.txt', 'test/ref/errFailPassXmlQuiet-success.xml', 0 ) )
+ lu.assertEquals( 0,
+ check_xml_output('test/test_with_err_fail_pass.lua', '--quiet -p Succ -p Fail',
+ 'test/errFailPassXmlQuiet-failures.txt', 'test/errFailPassXmlQuiet-failures.xml', 'test/errFailPassXmllintQuiet.xml',
+ 'test/ref/errFailPassXmlQuiet-failures.txt', 'test/ref/errFailPassXmlQuiet-failures.xml', 5 ) )
+end
+
+function testTestWithXmlDefault()
+ lu.assertEquals( 0,
+ check_xml_output('test/test_with_xml.lua', '', 'test/testWithXmlDefault.txt', 'test/testWithXmlDefault.xml',
+ 'test/testWithXmlLintDefault.txt', 'test/ref/testWithXmlDefault.txt', 'test/ref/testWithXmlDefault.xml', 2 ) )
+end
+
+function testTestWithXmlVerbose()
+ lu.assertEquals( 0,
+ check_xml_output('test/test_with_xml.lua', '--verbose', 'test/testWithXmlVerbose.txt', 'test/testWithXmlVerbose.xml',
+ 'test/testWithXmlLintVerbose.txt', 'test/ref/testWithXmlVerbose.txt', 'test/ref/testWithXmlVerbose.xml', 2 ) )
+end
+
+function testTestWithXmlQuiet()
+ lu.assertEquals( 0,
+ check_xml_output('test/test_with_xml.lua', '--quiet', 'test/testWithXmlQuiet.txt', 'test/testWithXmlQuiet.xml',
+ 'test/testWithXmlLintQuiet.txt', 'test/ref/testWithXmlQuiet.txt', 'test/ref/testWithXmlQuiet.xml', 2 ) )
+end
+
+function testListComparison()
+ -- run test/some_lists_comparisons and check exit status
+ lu.assertEquals( 0,
+ check_text_output('test/some_lists_comparisons.lua', '--verbose',
+ 'test/some_lists_comparisons.txt',
+ 'test/ref/some_lists_comparisons.txt', 11 ) )
+end
+
+function testLegacyLuaunitUsage()
+ -- run test/legacy_example_usage and check exit status (expecting 12 failures)
+ osExpectedCodeExec(12, '%s %s --output text > %s', LUA,
+ "test/legacy_example_with_luaunit.lua", "test/legacyExample.txt")
+end
+
+function testLuaunitV2Usage()
+ osExpectedCodeExec(0, '%s %s --output text 1> %s 2>&1', LUA,
+ "test/compat_luaunit_v2x.lua", "test/compat_luaunit_v2x.txt")
+end
+
+function testBasicLuaunitOptions()
+ osExpectedCodeExec(0, '%s example_with_luaunit.lua --help > test/null.txt', LUA)
+ osExpectedCodeExec(0, '%s example_with_luaunit.lua --version > test/null.txt', LUA)
+ -- test invalid syntax
+ osExpectedCodeExec(-1, '%s example_with_luaunit.lua --foobar > test/null.txt', LUA) -- invalid option
+ osExpectedCodeExec(-1, '%s example_with_luaunit.lua --output foobar > test/null.txt', LUA) -- invalid format
+ osExpectedCodeExec(-1, '%s example_with_luaunit.lua --output junit > test/null.txt', LUA) -- missing output name
+ os.remove('test/null.txt')
+end
+
+function testStopOnError()
+ lu.assertEquals( 0,
+ check_text_output('test/test_with_err_fail_pass.lua', '--quiet -p Succ --error --failure',
+ 'test/errFailPassTextStopOnError-1.txt',
+ 'test/ref/errFailPassTextStopOnError-1.txt', 0 ) )
+ lu.assertEquals( 0,
+ check_text_output('test/test_with_err_fail_pass.lua', '--quiet -p TestSome --error',
+ 'test/errFailPassTextStopOnError-2.txt',
+ 'test/ref/errFailPassTextStopOnError-2.txt', -2 ) )
+ lu.assertEquals( 0,
+ check_text_output('test/test_with_err_fail_pass.lua', '--quiet -p TestAnoth --failure',
+ 'test/errFailPassTextStopOnError-3.txt',
+ 'test/ref/errFailPassTextStopOnError-3.txt', -2 ) )
+ lu.assertEquals( 0,
+ check_text_output('test/test_with_err_fail_pass.lua', '--quiet -p TestSome --failure',
+ 'test/errFailPassTextStopOnError-4.txt',
+ 'test/ref/errFailPassTextStopOnError-4.txt', -2 ) )
+end
+
+local filesToGenerateExampleXml = {
+ { 'example_with_luaunit.lua', '', '--output junit --name test/ref/exampleXmlDefault.xml', 'test/ref/exampleXmlDefault.txt' },
+ { 'example_with_luaunit.lua', '--quiet', '--output junit --name test/ref/exampleXmlQuiet.xml', 'test/ref/exampleXmlQuiet.txt' },
+ { 'example_with_luaunit.lua', '--verbose', '--output junit --name test/ref/exampleXmlVerbose.xml', 'test/ref/exampleXmlVerbose.txt' },
+}
+
+local filesToGenerateExampleTap = {
+ { 'example_with_luaunit.lua', '', '--output tap', 'test/ref/exampleTapDefault.txt' },
+ { 'example_with_luaunit.lua', '--quiet', '--output tap', 'test/ref/exampleTapQuiet.txt' },
+ { 'example_with_luaunit.lua', '--verbose', '--output tap', 'test/ref/exampleTapVerbose.txt' },
+}
+
+local filesToGenerateExampleText = {
+ { 'example_with_luaunit.lua', '', '--output text', 'test/ref/exampleTextDefault.txt' },
+ { 'example_with_luaunit.lua', '--quiet', '--output text', 'test/ref/exampleTextQuiet.txt' },
+ { 'example_with_luaunit.lua', '--verbose', '--output text', 'test/ref/exampleTextVerbose.txt' },
+}
+
+local filesToGenerateExampleNil = {
+ { 'example_with_luaunit.lua', '', '--output nil', 'test/ref/exampleNilDefault.txt' },
+}
+
+local filesToGenerateErrFailPassXml = {
+ { 'test/test_with_err_fail_pass.lua', '',
+ '--output junit --name test/ref/errFailPassXmlDefault.xml',
+ 'test/ref/errFailPassXmlDefault.txt' },
+ { 'test/test_with_err_fail_pass.lua', '',
+ '-p Succ --output junit --name test/ref/errFailPassXmlDefault-success.xml',
+ 'test/ref/errFailPassXmlDefault-success.txt' },
+ { 'test/test_with_err_fail_pass.lua', '',
+ '-p Succ -p Fail --output junit --name test/ref/errFailPassXmlDefault-failures.xml',
+ 'test/ref/errFailPassXmlDefault-failures.txt' },
+ { 'test/test_with_err_fail_pass.lua', '', '--quiet --output junit --name test/ref/errFailPassXmlQuiet.xml',
+ 'test/ref/errFailPassXmlQuiet.txt' },
+ { 'test/test_with_err_fail_pass.lua', '',
+ '-p Succ --quiet --output junit --name test/ref/errFailPassXmlQuiet-success.xml',
+ 'test/ref/errFailPassXmlQuiet-success.txt' },
+ { 'test/test_with_err_fail_pass.lua', '',
+ '-p Succ -p Fail --quiet --output junit --name test/ref/errFailPassXmlQuiet-failures.xml',
+ 'test/ref/errFailPassXmlQuiet-failures.txt' },
+ { 'test/test_with_err_fail_pass.lua', '', '--verbose --output junit --name test/ref/errFailPassXmlVerbose.xml', 'test/ref/errFailPassXmlVerbose.txt' },
+ { 'test/test_with_err_fail_pass.lua', '',
+ '-p Succ --verbose --output junit --name test/ref/errFailPassXmlVerbose-success.xml',
+ 'test/ref/errFailPassXmlVerbose-success.txt' },
+ { 'test/test_with_err_fail_pass.lua', '',
+ '-p Succ -p Fail --verbose --output junit --name test/ref/errFailPassXmlVerbose-failures.xml',
+ 'test/ref/errFailPassXmlVerbose-failures.txt' },
+}
+
+local filesToGenerateErrFailPassTap = {
+ { 'test/test_with_err_fail_pass.lua', '', '--output tap', 'test/ref/errFailPassTapDefault.txt' },
+ { 'test/test_with_err_fail_pass.lua', '-p Succ', '--output tap', 'test/ref/errFailPassTapDefault-success.txt' },
+ { 'test/test_with_err_fail_pass.lua', '-p Succ -p Fail', '--output tap', 'test/ref/errFailPassTapDefault-failures.txt' },
+
+ { 'test/test_with_err_fail_pass.lua', '--quiet', '--output tap', 'test/ref/errFailPassTapQuiet.txt' },
+ { 'test/test_with_err_fail_pass.lua', '-p Succ --quiet',
+ '--output tap', 'test/ref/errFailPassTapQuiet-success.txt' },
+ { 'test/test_with_err_fail_pass.lua', '-p Succ -p Fail --quiet',
+ '--output tap', 'test/ref/errFailPassTapQuiet-failures.txt' },
+
+ { 'test/test_with_err_fail_pass.lua', '--verbose', '--output tap', 'test/ref/errFailPassTapVerbose.txt' },
+ { 'test/test_with_err_fail_pass.lua', '-p Succ --verbose',
+ '--output tap', 'test/ref/errFailPassTapVerbose-success.txt' },
+ { 'test/test_with_err_fail_pass.lua', '-p Succ -p Fail --verbose',
+ '--output tap', 'test/ref/errFailPassTapVerbose-failures.txt' },
+}
+
+local filesToGenerateErrFailPassText = {
+ { 'test/test_with_err_fail_pass.lua', '', '--output text', 'test/ref/errFailPassTextDefault.txt' },
+ { 'test/test_with_err_fail_pass.lua', '-p Succ', '--output text', 'test/ref/errFailPassTextDefault-success.txt' },
+ { 'test/test_with_err_fail_pass.lua', '-p Succ -p Fail', '--output text', 'test/ref/errFailPassTextDefault-failures.txt' },
+ { 'test/test_with_err_fail_pass.lua', '--quiet', '--output text', 'test/ref/errFailPassTextQuiet.txt' },
+ { 'test/test_with_err_fail_pass.lua', '-p Succ --quiet',
+ '--output text', 'test/ref/errFailPassTextQuiet-success.txt' },
+ { 'test/test_with_err_fail_pass.lua', '-p Succ -p Fail --quiet',
+ '--output text', 'test/ref/errFailPassTextQuiet-failures.txt' },
+ { 'test/test_with_err_fail_pass.lua', '--verbose', '--output text', 'test/ref/errFailPassTextVerbose.txt' },
+ { 'test/test_with_err_fail_pass.lua', '-p Succ --verbose',
+ '--output text', 'test/ref/errFailPassTextVerbose-success.txt' },
+ { 'test/test_with_err_fail_pass.lua', '-p Succ -p Fail --verbose',
+ '--output text', 'test/ref/errFailPassTextVerbose-failures.txt' },
+}
+
+local filesToGenerateTestXml = {
+ { 'test/test_with_xml.lua', '', '--output junit --name test/ref/testWithXmlDefault.xml', 'test/ref/testWithXmlDefault.txt' },
+ { 'test/test_with_xml.lua', '--verbose', '--output junit --name test/ref/testWithXmlVerbose.xml', 'test/ref/testWithXmlVerbose.txt' },
+ { 'test/test_with_xml.lua', '--quiet', '--output junit --name test/ref/testWithXmlQuiet.xml', 'test/ref/testWithXmlQuiet.txt' },
+}
+
+local filesToGenerateStopOnError = {
+ { 'test/test_with_err_fail_pass.lua', '', '--output text --quiet -p Succ --error --failure',
+ 'test/ref/errFailPassTextStopOnError-1.txt'},
+ { 'test/test_with_err_fail_pass.lua', '', '--output text --quiet -p TestSome --error',
+ 'test/ref/errFailPassTextStopOnError-2.txt'},
+ { 'test/test_with_err_fail_pass.lua', '', '--output text --quiet -p TestAnoth --failure',
+ 'test/ref/errFailPassTextStopOnError-3.txt'},
+ { 'test/test_with_err_fail_pass.lua', '', '--output text --quiet -p TestSome --failure',
+ 'test/ref/errFailPassTextStopOnError-4.txt'},
+}
+
+local filesToGenerateListsComp = {
+ { 'test/some_lists_comparisons.lua', '', '--output text --verbose',
+ 'test/ref/some_lists_comparisons.txt'},
+}
+
+local function table_join(...)
+ local args = {...}
+ local ret = {}
+ for i,t in ipairs(args) do
+ for _,v in ipairs(t) do
+ table.insert( ret, v)
+ end
+ end
+ return ret
+end
+
+local filesSetIndex = {
+ ErrFailPassText=filesToGenerateErrFailPassText,
+ ErrFailPassTap=filesToGenerateErrFailPassTap,
+ ErrFailPassXml=filesToGenerateErrFailPassXml,
+ ErrFail = table_join( filesToGenerateErrFailPassText,
+ filesToGenerateErrFailPassTap,
+ filesToGenerateErrFailPassXml ),
+ ExampleNil=filesToGenerateExampleNil,
+ ExampleText=filesToGenerateExampleText,
+ ExampleTap=filesToGenerateExampleTap,
+ ExampleXml=filesToGenerateExampleXml,
+ Example = table_join( filesToGenerateExampleNil,
+ filesToGenerateExampleText,
+ filesToGenerateExampleTap,
+ filesToGenerateExampleXml ),
+ TestXml=filesToGenerateTestXml,
+ StopOnError=filesToGenerateStopOnError,
+ ListsComp=filesToGenerateListsComp,
+}
+
+local function updateRefFiles( filesToGenerate )
+ local ret
+
+ for _,v in ipairs(filesToGenerate) do
+ report('Generating '..v[4])
+ ret = osExec( '%s %s %s %s > %s', LUA, v[1], v[2], v[3], v[4] )
+ --[[
+ -- exitcode != 0 is not an error for us ...
+ if ret == false then
+ error('Error while generating '..prettystr(v) )
+ os.exit(1)
+ end
+ ]]
+ -- neutralize all testcase time values in ref xml output
+ local refXmlName = string.match(v[3], "--name (test/ref/.*%.xml)$")
+ if refXmlName then
+ adjustFile( refXmlName, refXmlName, '.*<testcase .*(time=".-").*' )
+ end
+ end
+end
+
+
+local function main()
+ if arg[1] == '--coverage' then
+ LUA = LUA .." -lluacov" -- run tests with LuaCov active
+ table.remove(arg, 1)
+ end
+
+ if arg[1] ~= '--with-linting' then
+ HAS_XMLLINT = false
+ else
+ table.remove(arg, 1)
+ end
+
+ if arg[1] == '--update' then
+ if #arg == 1 then
+ -- generate all files
+ -- print('Generating all files' )
+ for _,v in pairs(filesSetIndex) do
+ -- print('Generating '..v )
+ updateRefFiles( v )
+ end
+ else
+ -- generate subset of files
+ for i = 2, #arg do
+ local fileSet = filesSetIndex[ arg[i] ]
+ if fileSet == nil then
+ local validTarget = ''
+ for k,_ in pairs(filesSetIndex) do
+ validTarget = validTarget .. ' '.. k
+ end
+ error_fmt('Unable to generate files for target %s\nPossible targets: %s\n',
+ arg[i], validTarget)
+ end
+ -- print('Generating '..arg[i])
+ updateRefFiles( fileSet )
+ end
+ end
+ os.exit(0)
+ end
+
+ os.exit( lu.LuaUnit.run() )
+ -- body
+end
+
+main()
+
+-- TODO check output of run_unit_tests
+-- TODO check return values of execution
diff --git a/Data/Libraries/luaunit/run_unit_tests.lua b/Data/Libraries/luaunit/run_unit_tests.lua
new file mode 100644
index 0000000..b5dcd70
--- /dev/null
+++ b/Data/Libraries/luaunit/run_unit_tests.lua
@@ -0,0 +1,30 @@
+#!/usr/bin/env lua
+if (os.getenv("_DEBUG")) then
+ local json = require 'json'
+ local debuggee = require 'vscode-debuggee'
+
+ local startResult, breakerType = debuggee.start(json)
+ print('debuggee start ->', startResult, breakerType)
+end
+
+
+local no_error, err_msg
+no_error, err_msg = pcall( require, 'test.test_luaunit')
+if not no_error then
+ if nil == err_msg:find( "module 'test.test_luaunit' not found" ) then
+ -- module found but error loading it
+ -- display the error by reproducing it
+ require('test.test_luaunit')
+ end
+
+ -- run_unit_tests shall also work when called directly from the test directory
+ require('test_luaunit')
+
+ -- we must disable this test, not working in this case because it expects
+ -- the stack trace to start with test/test_luaunit.lua
+ TestLuaUnitUtilities.test_FailFmt = nil
+end
+local lu = require('luaunit')
+
+lu.LuaUnit.verbosity = 2
+os.exit( lu.LuaUnit.run() )
diff --git a/Data/Libraries/luaunit/test/check_lua_calc_error.lua b/Data/Libraries/luaunit/test/check_lua_calc_error.lua
new file mode 100644
index 0000000..448be72
--- /dev/null
+++ b/Data/Libraries/luaunit/test/check_lua_calc_error.lua
@@ -0,0 +1,23 @@
+
+local lu = require('luaunit')
+
+print( lu.EPS )
+
+local pi_div_6_deg_expected, pi_div_6_deg_calculated, pi_div_3_deg_expected, pi_div_3_deg_calculated
+
+pi_div_6_deg_calculated = math.deg(math.pi/6)
+pi_div_6_deg_expected = 30
+
+pi_div_3_deg_calculated = math.deg(math.pi/3)
+pi_div_3_deg_expected = 60
+
+print( (pi_div_6_deg_expected - pi_div_6_deg_calculated) / lu.EPS ) -- prints: 16
+print( (pi_div_3_deg_expected - pi_div_3_deg_calculated) / lu.EPS ) -- prints: 32
+
+-- Better use relative error:
+print( ( (pi_div_6_deg_expected - pi_div_6_deg_calculated) / pi_div_6_deg_expected) / lu.EPS ) -- prints: 0.53333
+print( ( (pi_div_3_deg_expected - pi_div_3_deg_calculated) / pi_div_3_deg_expected) / lu.EPS ) -- prints: 0.53333
+
+-- relative error is constant. Assertion can take the form of:
+lu.assertAlmostEquals( (pi_div_6_deg_expected - pi_div_6_deg_calculated) / pi_div_6_deg_expected, 0, lu.EPS )
+lu.assertAlmostEquals( (pi_div_3_deg_expected - pi_div_3_deg_calculated) / pi_div_3_deg_expected, 0, lu.EPS ) \ No newline at end of file
diff --git a/Data/Libraries/luaunit/test/compat_luaunit_v2x.lua b/Data/Libraries/luaunit/test/compat_luaunit_v2x.lua
new file mode 100644
index 0000000..2fc7ef8
--- /dev/null
+++ b/Data/Libraries/luaunit/test/compat_luaunit_v2x.lua
@@ -0,0 +1,175 @@
+EXPORT_ASSERT_TO_GLOBALS = true
+local lu = require('luaunit')
+
+--[[
+Use Luaunit in the v2.1 fashion and check that it still works.
+Exercise every luaunit v2.1 function and have it executed successfully.
+
+Coverage:
+x Made LuaUnit:run() method able to be called with 'run' or 'Run'.
+x Made LuaUnit.wrapFunctions() function able to be called with 'wrapFunctions' or 'WrapFunctions' or 'wrap_functions'.
+x Moved wrapFunctions to the LuaUnit module table (e.g. local LuaUnit = require( "luaunit" ); LuaUnit.wrapFunctions( ... ) )
+x Added LuaUnit.is<Type> and LuaUnit.is_<type> helper functions. (e.g. assert( LuaUnit.isString( getString() ) )
+x Added assert<Type> and assert_<type>
+x Added assertNot<Type> and assert_not_<type>
+x Added _VERSION variable to hold the LuaUnit version
+x Added LuaUnit:setVerbosity(lvl) method to the LuaUnit. Alias: LuaUnit:SetVerbosity() and LuaUnit:set_verbosity().
+x Added table deep compare
+x check that wrapFunctions works
+x Made "testable" classes able to start with 'test' or 'Test' for their name.
+x Made "testable" methods able to start with 'test' or 'Test' for their name.
+x Made testClass:setUp() methods able to be named with 'setUp' or 'Setup' or 'setup'.
+x Made testClass:tearDown() methods able to be named with 'tearDown' or 'TearDown' or 'teardown'.
+]]
+
+
+TestLuaUnitV2Compat = {}
+
+function TestLuaUnitV2Compat:testRunAliases()
+ -- some old function
+ assertFunction( lu.run )
+ assertEquals( lu.Run, lu.run )
+end
+
+function TestLuaUnitV2Compat:testWrapFunctionsAliases()
+ assertFunction( lu.wrapFunctions )
+ assertEquals( lu.wrapFunctions, lu.WrapFunctions )
+ assertEquals( lu.wrapFunctions, lu.wrap_functions )
+end
+
+local function typeAsserter( goodType, badType, goodAsserter, badAsserter )
+ goodAsserter( goodType )
+ if badAsserter ~= nil then
+ badAsserter( badType )
+ end
+end
+
+function TestLuaUnitV2Compat:testAssertType()
+ local f = function (v) return v+1 end
+ local t = coroutine.create( function(v) local y=v+1 end )
+ local typesToVerify = {
+ -- list of: { goodType, badType, goodAsserter, badAsserter }
+ { true, "toto", assertBoolean, assertNotBoolean },
+ { true, "toto", assert_boolean, assert_not_boolean },
+ { 1 , "toto", assertNumber, assertNotNumber },
+ { 1 , "toto", assert_number, assert_not_number },
+ { "q" , 1 , assertString, assertNotString },
+ { "q" , 1 , assert_string, assert_not_string },
+ { nil , 1 , assertNil, assertNotNil },
+ { nil , 1 , assert_nil, assert_not_nil },
+ { {1,2}, "toto", assertTable, assertNotTable },
+ { {1,2}, "toto", assert_table, assert_not_table },
+ { f , "toto", assertFunction, assertNotFunction },
+ { f , "toto", assert_function,assert_not_function },
+ { t , "toto", assertThread, assertNotThread },
+ { t , "toto", assert_thread, assert_not_thread },
+
+ }
+
+ for _,v in ipairs( typesToVerify ) do
+ local goodType, badType, goodAsserter, badAsserter = v[1], v[2], v[3], v[4]
+ typeAsserter( goodType, badType, goodAsserter, badAsserter )
+ end
+
+ assertNotUserdata( "toto" )
+
+
+ local typesToVerify2 = {
+ { true, "toto", lu.isBoolean },
+ { true, "toto", lu.is_boolean },
+ { 1, "toto", lu.isNumber },
+ { 1, "toto", lu.is_number },
+ { "t", 1, lu.isString },
+ { "t", 1, lu.is_string },
+ { nil, "toto", lu.isNil },
+ { nil, "toto", lu.is_nil },
+ { {1,2},"toto", lu.isTable },
+ { {1,2},"toto", lu.is_table },
+ { f, "toto", lu.isFunction },
+ { f, "toto", lu.is_function },
+ { t, "toto", lu.isThread },
+ { t, "toto", lu.is_thread },
+ }
+
+ for _,v in ipairs( typesToVerify2 ) do
+ local goodType, badType, goodTypeVerifier = v[1], v[2], v[3]
+ if (v[3] == nil) then
+ print('Missing function at index '.._)
+ assertNotNil( v[3] )
+ end
+ assertTrue ( goodTypeVerifier( goodType ) )
+ assertFalse( goodTypeVerifier( badType ) )
+ end
+
+end
+
+function TestLuaUnitV2Compat:testHasVersionKey()
+ assertNotNil( lu.VERSION )
+ assertString( lu.VERSION )
+ assertNotNil( lu._VERSION )
+ assertTrue( lu.is_string( lu._VERSION ) )
+end
+
+function TestLuaUnitV2Compat:testTableEquality()
+ local t1 = {1,2}
+ local t2 = t1
+ local t3 = {1,2}
+ local t4 = {1,2,3}
+
+ assertEquals( t1, t1 )
+ assertEquals( t1, t2 )
+ -- new in LuaUnit v2.0 , deep table compare
+ assertEquals( t1, t3 )
+ assertError( assertEquals, t1, t4 )
+end
+
+-- Setup
+local called = {}
+
+function test_w1() called.w1 = true end
+function test_w2() called.w2 = true end
+function test_w3() called.w3 = true end
+
+TestSomeFuncs = lu.wrapFunctions( 'test_w1', 'test_w2', 'test_w3' )
+
+TestWithCap = {}
+function TestWithCap:setup() called.setup = true end
+function TestWithCap:Test1() called.t1 = true end
+function TestWithCap:test2() called.t2 = true end
+function TestWithCap:teardown() called.teardown = true end
+
+testWithoutCap = {}
+function testWithoutCap:Setup() called.Setup = true end
+function testWithoutCap:Test3() called.t3 = true end
+function testWithoutCap:test4() called.t4 = true end
+function testWithoutCap:tearDown() called.tearDown = true end
+
+TestWithUnderscore = {}
+function TestWithUnderscore:setUp() called.setUp = true end
+function TestWithUnderscore:Test1() called.t1 = true end
+function TestWithUnderscore:test2() called.t2 = true end
+function TestWithUnderscore:TearDown() called.TearDown = true end
+
+-- Run
+lu:setVerbosity( 1 )
+lu:set_verbosity( 1 )
+lu:SetVerbosity( 1 )
+
+local results = lu.run()
+
+-- Verif
+assert( called.w1 == true )
+assert( called.w2 == true )
+assert( called.w3 == true )
+assert( called.t1 == true )
+assert( called.t2 == true )
+assert( called.t3 == true )
+assert( called.t4 == true )
+assert( called.setup == true )
+assert( called.setUp == true )
+assert( called.Setup == true )
+assert( called.teardown == true )
+assert( called.tearDown == true )
+assert( called.TearDown == true )
+
+os.exit( results )
diff --git a/Data/Libraries/luaunit/test/legacy_example_with_luaunit.lua b/Data/Libraries/luaunit/test/legacy_example_with_luaunit.lua
new file mode 100644
index 0000000..c73a6d3
--- /dev/null
+++ b/Data/Libraries/luaunit/test/legacy_example_with_luaunit.lua
@@ -0,0 +1,140 @@
+EXPORT_ASSERT_TO_GLOBALS = true
+require('luaunit')
+
+TestToto = {} --class
+
+ function TestToto:setUp()
+ -- set up tests
+ self.a = 1
+ self.s = 'hop'
+ self.t1 = {1,2,3}
+ self.t2 = {one=1,two=2,three=3}
+ self.t3 = {1,2,three=3}
+ end
+
+ function TestToto:test1_withFailure()
+ print( "some stuff test 1" )
+ assertEquals( self.a , 1 )
+ -- will fail
+ assertEquals( self.a , 2 )
+ assertEquals( self.a , 2 )
+ end
+
+ function TestToto:test2_withFailure()
+ print( "some stuff test 2" )
+ assertEquals( self.a , 1 )
+ assertEquals( self.s , 'hop' )
+ -- will fail
+ assertEquals( self.s , 'bof' )
+ assertEquals( self.s , 'bof' )
+ end
+
+ function TestToto:test3()
+ print( "some stuff test 3" )
+ assertEquals( self.a , 1 )
+ assertEquals( self.s , 'hop' )
+ assertEquals( type(self.a), 'number' )
+ end
+
+ function TestToto:test4()
+ print( "some stuff test 4" )
+ assertNotEquals( self.a , 1 )
+ end
+
+ function TestToto:test5()
+ print( "some stuff test 5" )
+ assertTrue( self.a )
+ assertFalse( self.a )
+ end
+
+ function TestToto:test6()
+ print( "some stuff test 6" )
+ assertTrue( false )
+ end
+
+ function TestToto:test7()
+ -- assertEquals( {1,2}, self.t1 )
+ -- assertEquals( {1,2}, self.t2 )
+ assertEquals( {1,2}, self.t3 )
+ end
+
+ function TestToto:test8a()
+ -- failure occurs in a submethod
+ self:funcWithError()
+ end
+
+ function TestToto:test8b()
+ -- failure occurs in a submethod
+ self:funcWithFuncWithError()
+ end
+
+ function TestToto:funcWithFuncWithError()
+ self:funcWithError()
+ end
+
+ function TestToto:funcWithError()
+ error('Bouhouhoum error!')
+ end
+
+
+-- class TestToto
+
+TestTiti = {} --class
+ function TestTiti:setUp()
+ -- set up tests
+ self.a = 1
+ self.s = 'hop'
+ print( 'TestTiti:setUp' )
+ end
+
+ function TestTiti:tearDown()
+ -- some tearDown() code if necessary
+ print( 'TestTiti:tearDown' )
+ end
+
+ function TestTiti:test1_withFailure()
+ print( "some stuff test 1" )
+ assertEquals( self.a , 1 )
+ -- will fail
+ assertEquals( self.a , 2 )
+ assertEquals( self.a , 2 )
+ end
+
+ function TestTiti:test2_withFailure()
+ print( "some stuff test 2" )
+ assertEquals( self.a , 1 )
+ assertEquals( self.s , 'hop' )
+ -- will fail
+ assertEquals( self.s , 'bof' )
+ assertEquals( self.s , 'bof' )
+ end
+
+ function TestTiti:test3()
+ print( "some stuff test 3" )
+ assertEquals( self.a , 1 )
+ assertEquals( self.s , 'hop' )
+ end
+-- class TestTiti
+
+-- simple test functions that were written previously can be integrated
+-- in luaunit too
+function test1_withFailure()
+ assert( 1 == 1)
+ -- will fail
+ assert( 1 == 2)
+end
+
+function test2_withFailure()
+ assert( 'a' == 'a')
+ -- will fail
+ assert( 'a' == 'b')
+end
+
+function test3()
+ assert( 1 == 1)
+ assert( 'a' == 'a')
+end
+
+local lu = LuaUnit.new()
+lu:setOutputType("tap")
+os.exit( lu:runSuite() )
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassNilDefault-failures.txt b/Data/Libraries/luaunit/test/ref/errFailPassNilDefault-failures.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassNilDefault-failures.txt
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassNilDefault-success.txt b/Data/Libraries/luaunit/test/ref/errFailPassNilDefault-success.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassNilDefault-success.txt
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassNilDefault.txt b/Data/Libraries/luaunit/test/ref/errFailPassNilDefault.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassNilDefault.txt
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTapDefault-failures.txt b/Data/Libraries/luaunit/test/ref/errFailPassTapDefault-failures.txt
new file mode 100644
index 0000000..2979151
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTapDefault-failures.txt
@@ -0,0 +1,20 @@
+1..10
+# Started on 03/22/16 21:58:32
+# Starting class: TestAnotherThing
+ok 1 TestAnotherThing.test1_Success1
+ok 2 TestAnotherThing.test1_Success2
+not ok 3 TestAnotherThing.test3_Fail1
+# test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+not ok 4 TestAnotherThing.test3_Fail2
+# test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+# Starting class: TestSomething
+ok 5 TestSomething.test1_Success1
+ok 6 TestSomething.test1_Success2
+not ok 7 TestSomething.test2_Fail1
+# test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+not ok 8 TestSomething.test2_Fail2
+# test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+not ok 9 testFuncFail1
+# test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+ok 10 testFuncSuccess1
+# Ran 10 tests in 0.000 seconds, 5 successes, 5 failures, 5 non-selected
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTapDefault-success.txt b/Data/Libraries/luaunit/test/ref/errFailPassTapDefault-success.txt
new file mode 100644
index 0000000..8dd71e7
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTapDefault-success.txt
@@ -0,0 +1,10 @@
+1..5
+# Started on 03/22/16 21:58:32
+# Starting class: TestAnotherThing
+ok 1 TestAnotherThing.test1_Success1
+ok 2 TestAnotherThing.test1_Success2
+# Starting class: TestSomething
+ok 3 TestSomething.test1_Success1
+ok 4 TestSomething.test1_Success2
+ok 5 testFuncSuccess1
+# Ran 5 tests in 0.000 seconds, 5 successes, 0 failures, 10 non-selected
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTapDefault.txt b/Data/Libraries/luaunit/test/ref/errFailPassTapDefault.txt
new file mode 100644
index 0000000..08c0558
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTapDefault.txt
@@ -0,0 +1,30 @@
+1..15
+# Started on 03/22/16 21:58:32
+# Starting class: TestAnotherThing
+ok 1 TestAnotherThing.test1_Success1
+ok 2 TestAnotherThing.test1_Success2
+not ok 3 TestAnotherThing.test2_Err1
+# test/test_with_err_fail_pass.lua:41: attempt to perform arithmetic on a table value
+not ok 4 TestAnotherThing.test2_Err2
+# test/test_with_err_fail_pass.lua:45: attempt to perform arithmetic on a table value
+not ok 5 TestAnotherThing.test3_Fail1
+# test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+not ok 6 TestAnotherThing.test3_Fail2
+# test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+# Starting class: TestSomething
+ok 7 TestSomething.test1_Success1
+ok 8 TestSomething.test1_Success2
+not ok 9 TestSomething.test2_Fail1
+# test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+not ok 10 TestSomething.test2_Fail2
+# test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+not ok 11 TestSomething.test3_Err1
+# test/test_with_err_fail_pass.lua:23: attempt to perform arithmetic on a table value
+not ok 12 TestSomething.test3_Err2
+# test/test_with_err_fail_pass.lua:27: attempt to perform arithmetic on a table value
+not ok 13 testFuncErr1
+# test/test_with_err_fail_pass.lua:66: attempt to perform arithmetic on a table value
+not ok 14 testFuncFail1
+# test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+ok 15 testFuncSuccess1
+# Ran 15 tests in 0.003 seconds, 5 successes, 5 failures, 5 errors
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTapQuiet-failures.txt b/Data/Libraries/luaunit/test/ref/errFailPassTapQuiet-failures.txt
new file mode 100644
index 0000000..75be7c0
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTapQuiet-failures.txt
@@ -0,0 +1,15 @@
+1..10
+# Started on 03/22/16 21:58:32
+# Starting class: TestAnotherThing
+ok 1 TestAnotherThing.test1_Success1
+ok 2 TestAnotherThing.test1_Success2
+not ok 3 TestAnotherThing.test3_Fail1
+not ok 4 TestAnotherThing.test3_Fail2
+# Starting class: TestSomething
+ok 5 TestSomething.test1_Success1
+ok 6 TestSomething.test1_Success2
+not ok 7 TestSomething.test2_Fail1
+not ok 8 TestSomething.test2_Fail2
+not ok 9 testFuncFail1
+ok 10 testFuncSuccess1
+# Ran 10 tests in 0.002 seconds, 5 successes, 5 failures, 5 non-selected
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTapQuiet-success.txt b/Data/Libraries/luaunit/test/ref/errFailPassTapQuiet-success.txt
new file mode 100644
index 0000000..8dd71e7
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTapQuiet-success.txt
@@ -0,0 +1,10 @@
+1..5
+# Started on 03/22/16 21:58:32
+# Starting class: TestAnotherThing
+ok 1 TestAnotherThing.test1_Success1
+ok 2 TestAnotherThing.test1_Success2
+# Starting class: TestSomething
+ok 3 TestSomething.test1_Success1
+ok 4 TestSomething.test1_Success2
+ok 5 testFuncSuccess1
+# Ran 5 tests in 0.000 seconds, 5 successes, 0 failures, 10 non-selected
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTapQuiet.txt b/Data/Libraries/luaunit/test/ref/errFailPassTapQuiet.txt
new file mode 100644
index 0000000..dc38b42
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTapQuiet.txt
@@ -0,0 +1,20 @@
+1..15
+# Started on 03/22/16 21:58:32
+# Starting class: TestAnotherThing
+ok 1 TestAnotherThing.test1_Success1
+ok 2 TestAnotherThing.test1_Success2
+not ok 3 TestAnotherThing.test2_Err1
+not ok 4 TestAnotherThing.test2_Err2
+not ok 5 TestAnotherThing.test3_Fail1
+not ok 6 TestAnotherThing.test3_Fail2
+# Starting class: TestSomething
+ok 7 TestSomething.test1_Success1
+ok 8 TestSomething.test1_Success2
+not ok 9 TestSomething.test2_Fail1
+not ok 10 TestSomething.test2_Fail2
+not ok 11 TestSomething.test3_Err1
+not ok 12 TestSomething.test3_Err2
+not ok 13 testFuncErr1
+not ok 14 testFuncFail1
+ok 15 testFuncSuccess1
+# Ran 15 tests in 0.002 seconds, 5 successes, 5 failures, 5 errors
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTapVerbose-failures.txt b/Data/Libraries/luaunit/test/ref/errFailPassTapVerbose-failures.txt
new file mode 100644
index 0000000..cdb5060
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTapVerbose-failures.txt
@@ -0,0 +1,30 @@
+1..10
+# Started on 03/22/16 21:58:32
+# Starting class: TestAnotherThing
+ok 1 TestAnotherThing.test1_Success1
+ok 2 TestAnotherThing.test1_Success2
+not ok 3 TestAnotherThing.test3_Fail1
+# test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+# stack traceback:
+# test/test_with_err_fail_pass.lua:49: in function 'TestAnotherThing.test3_Fail1'
+not ok 4 TestAnotherThing.test3_Fail2
+# test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+# stack traceback:
+# test/test_with_err_fail_pass.lua:53: in function 'TestAnotherThing.test3_Fail2'
+# Starting class: TestSomething
+ok 5 TestSomething.test1_Success1
+ok 6 TestSomething.test1_Success2
+not ok 7 TestSomething.test2_Fail1
+# test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+# stack traceback:
+# test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1'
+not ok 8 TestSomething.test2_Fail2
+# test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+# stack traceback:
+# test/test_with_err_fail_pass.lua:19: in function 'TestSomething.test2_Fail2'
+not ok 9 testFuncFail1
+# test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+# stack traceback:
+# test/test_with_err_fail_pass.lua:62: in function 'testFuncFail1'
+ok 10 testFuncSuccess1
+# Ran 10 tests in 0.000 seconds, 5 successes, 5 failures, 5 non-selected
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTapVerbose-success.txt b/Data/Libraries/luaunit/test/ref/errFailPassTapVerbose-success.txt
new file mode 100644
index 0000000..8dd71e7
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTapVerbose-success.txt
@@ -0,0 +1,10 @@
+1..5
+# Started on 03/22/16 21:58:32
+# Starting class: TestAnotherThing
+ok 1 TestAnotherThing.test1_Success1
+ok 2 TestAnotherThing.test1_Success2
+# Starting class: TestSomething
+ok 3 TestSomething.test1_Success1
+ok 4 TestSomething.test1_Success2
+ok 5 testFuncSuccess1
+# Ran 5 tests in 0.000 seconds, 5 successes, 0 failures, 10 non-selected
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTapVerbose.txt b/Data/Libraries/luaunit/test/ref/errFailPassTapVerbose.txt
new file mode 100644
index 0000000..c3380b7
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTapVerbose.txt
@@ -0,0 +1,50 @@
+1..15
+# Started on 03/22/16 21:58:32
+# Starting class: TestAnotherThing
+ok 1 TestAnotherThing.test1_Success1
+ok 2 TestAnotherThing.test1_Success2
+not ok 3 TestAnotherThing.test2_Err1
+# test/test_with_err_fail_pass.lua:41: attempt to perform arithmetic on a table value
+# stack traceback:
+# test/test_with_err_fail_pass.lua:41: in function 'TestAnotherThing.test2_Err1'
+not ok 4 TestAnotherThing.test2_Err2
+# test/test_with_err_fail_pass.lua:45: attempt to perform arithmetic on a table value
+# stack traceback:
+# test/test_with_err_fail_pass.lua:45: in function 'TestAnotherThing.test2_Err2'
+not ok 5 TestAnotherThing.test3_Fail1
+# test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+# stack traceback:
+# test/test_with_err_fail_pass.lua:49: in function 'TestAnotherThing.test3_Fail1'
+not ok 6 TestAnotherThing.test3_Fail2
+# test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+# stack traceback:
+# test/test_with_err_fail_pass.lua:53: in function 'TestAnotherThing.test3_Fail2'
+# Starting class: TestSomething
+ok 7 TestSomething.test1_Success1
+ok 8 TestSomething.test1_Success2
+not ok 9 TestSomething.test2_Fail1
+# test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+# stack traceback:
+# test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1'
+not ok 10 TestSomething.test2_Fail2
+# test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+# stack traceback:
+# test/test_with_err_fail_pass.lua:19: in function 'TestSomething.test2_Fail2'
+not ok 11 TestSomething.test3_Err1
+# test/test_with_err_fail_pass.lua:23: attempt to perform arithmetic on a table value
+# stack traceback:
+# test/test_with_err_fail_pass.lua:23: in function 'TestSomething.test3_Err1'
+not ok 12 TestSomething.test3_Err2
+# test/test_with_err_fail_pass.lua:27: attempt to perform arithmetic on a table value
+# stack traceback:
+# test/test_with_err_fail_pass.lua:27: in function 'TestSomething.test3_Err2'
+not ok 13 testFuncErr1
+# test/test_with_err_fail_pass.lua:66: attempt to perform arithmetic on a table value
+# stack traceback:
+# test/test_with_err_fail_pass.lua:66: in function 'testFuncErr1'
+not ok 14 testFuncFail1
+# test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+# stack traceback:
+# test/test_with_err_fail_pass.lua:62: in function 'testFuncFail1'
+ok 15 testFuncSuccess1
+# Ran 15 tests in 0.000 seconds, 5 successes, 5 failures, 5 errors
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTextDefault-failures.txt b/Data/Libraries/luaunit/test/ref/errFailPassTextDefault-failures.txt
new file mode 100644
index 0000000..08bdc7c
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTextDefault-failures.txt
@@ -0,0 +1,29 @@
+..FF..FFF.
+Failed tests:
+-------------
+1) TestAnotherThing.test3_Fail1
+test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+stack traceback:
+ test/test_with_err_fail_pass.lua:49: in function 'TestAnotherThing.test3_Fail1'
+
+2) TestAnotherThing.test3_Fail2
+test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:53: in function 'TestAnotherThing.test3_Fail2'
+
+3) TestSomething.test2_Fail1
+test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+stack traceback:
+ test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1'
+
+4) TestSomething.test2_Fail2
+test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:19: in function 'TestSomething.test2_Fail2'
+
+5) testFuncFail1
+test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:62: in function 'testFuncFail1'
+
+Ran 10 tests in 0.001 seconds, 5 successes, 5 failures, 5 non-selected
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTextDefault-success.txt b/Data/Libraries/luaunit/test/ref/errFailPassTextDefault-success.txt
new file mode 100644
index 0000000..56ab148
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTextDefault-success.txt
@@ -0,0 +1,3 @@
+.....
+Ran 5 tests in 0.000 seconds, 5 successes, 0 failures, 10 non-selected
+OK
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTextDefault.txt b/Data/Libraries/luaunit/test/ref/errFailPassTextDefault.txt
new file mode 100644
index 0000000..cf1115c
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTextDefault.txt
@@ -0,0 +1,56 @@
+..EEFF..FFEEEF.
+Tests with errors:
+------------------
+1) TestAnotherThing.test2_Err1
+test/test_with_err_fail_pass.lua:41: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:41: in function 'TestAnotherThing.test2_Err1'
+
+2) TestAnotherThing.test2_Err2
+test/test_with_err_fail_pass.lua:45: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:45: in function 'TestAnotherThing.test2_Err2'
+
+3) TestSomething.test3_Err1
+test/test_with_err_fail_pass.lua:23: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:23: in function 'TestSomething.test3_Err1'
+
+4) TestSomething.test3_Err2
+test/test_with_err_fail_pass.lua:27: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:27: in function 'TestSomething.test3_Err2'
+
+5) testFuncErr1
+test/test_with_err_fail_pass.lua:66: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:66: in function 'testFuncErr1'
+
+Failed tests:
+-------------
+1) TestAnotherThing.test3_Fail1
+test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+stack traceback:
+ test/test_with_err_fail_pass.lua:49: in function 'TestAnotherThing.test3_Fail1'
+
+2) TestAnotherThing.test3_Fail2
+test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:53: in function 'TestAnotherThing.test3_Fail2'
+
+3) TestSomething.test2_Fail1
+test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+stack traceback:
+ test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1'
+
+4) TestSomething.test2_Fail2
+test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:19: in function 'TestSomething.test2_Fail2'
+
+5) testFuncFail1
+test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:62: in function 'testFuncFail1'
+
+Ran 15 tests in 0.002 seconds, 5 successes, 5 failures, 5 errors
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTextQuiet-failures.txt b/Data/Libraries/luaunit/test/ref/errFailPassTextQuiet-failures.txt
new file mode 100644
index 0000000..08bdc7c
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTextQuiet-failures.txt
@@ -0,0 +1,29 @@
+..FF..FFF.
+Failed tests:
+-------------
+1) TestAnotherThing.test3_Fail1
+test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+stack traceback:
+ test/test_with_err_fail_pass.lua:49: in function 'TestAnotherThing.test3_Fail1'
+
+2) TestAnotherThing.test3_Fail2
+test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:53: in function 'TestAnotherThing.test3_Fail2'
+
+3) TestSomething.test2_Fail1
+test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+stack traceback:
+ test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1'
+
+4) TestSomething.test2_Fail2
+test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:19: in function 'TestSomething.test2_Fail2'
+
+5) testFuncFail1
+test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:62: in function 'testFuncFail1'
+
+Ran 10 tests in 0.001 seconds, 5 successes, 5 failures, 5 non-selected
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTextQuiet-success.txt b/Data/Libraries/luaunit/test/ref/errFailPassTextQuiet-success.txt
new file mode 100644
index 0000000..56ab148
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTextQuiet-success.txt
@@ -0,0 +1,3 @@
+.....
+Ran 5 tests in 0.000 seconds, 5 successes, 0 failures, 10 non-selected
+OK
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTextQuiet.txt b/Data/Libraries/luaunit/test/ref/errFailPassTextQuiet.txt
new file mode 100644
index 0000000..cf1115c
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTextQuiet.txt
@@ -0,0 +1,56 @@
+..EEFF..FFEEEF.
+Tests with errors:
+------------------
+1) TestAnotherThing.test2_Err1
+test/test_with_err_fail_pass.lua:41: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:41: in function 'TestAnotherThing.test2_Err1'
+
+2) TestAnotherThing.test2_Err2
+test/test_with_err_fail_pass.lua:45: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:45: in function 'TestAnotherThing.test2_Err2'
+
+3) TestSomething.test3_Err1
+test/test_with_err_fail_pass.lua:23: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:23: in function 'TestSomething.test3_Err1'
+
+4) TestSomething.test3_Err2
+test/test_with_err_fail_pass.lua:27: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:27: in function 'TestSomething.test3_Err2'
+
+5) testFuncErr1
+test/test_with_err_fail_pass.lua:66: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:66: in function 'testFuncErr1'
+
+Failed tests:
+-------------
+1) TestAnotherThing.test3_Fail1
+test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+stack traceback:
+ test/test_with_err_fail_pass.lua:49: in function 'TestAnotherThing.test3_Fail1'
+
+2) TestAnotherThing.test3_Fail2
+test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:53: in function 'TestAnotherThing.test3_Fail2'
+
+3) TestSomething.test2_Fail1
+test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+stack traceback:
+ test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1'
+
+4) TestSomething.test2_Fail2
+test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:19: in function 'TestSomething.test2_Fail2'
+
+5) testFuncFail1
+test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:62: in function 'testFuncFail1'
+
+Ran 15 tests in 0.002 seconds, 5 successes, 5 failures, 5 errors
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-1.txt b/Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-1.txt
new file mode 100644
index 0000000..56ab148
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-1.txt
@@ -0,0 +1,3 @@
+.....
+Ran 5 tests in 0.000 seconds, 5 successes, 0 failures, 10 non-selected
+OK
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-2.txt b/Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-2.txt
new file mode 100644
index 0000000..4e1c177
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-2.txt
@@ -0,0 +1,25 @@
+..FFE
+ERROR during LuaUnit test execution:
+test/test_with_err_fail_pass.lua:23: attempt to perform arithmetic on a table value
+
+Tests with errors:
+------------------
+1) TestSomething.test3_Err1
+test/test_with_err_fail_pass.lua:23: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:23: in function 'TestSomething.test3_Err1'
+
+Failed tests:
+-------------
+1) TestSomething.test2_Fail1
+test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+stack traceback:
+ test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1'
+
+2) TestSomething.test2_Fail2
+test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:19: in function 'TestSomething.test2_Fail2'
+
+Ran 5 tests in 0.000 seconds, 2 successes, 2 failures, 1 error, 9 non-selected
+LuaUnit ABORTED (as requested by --error or --failure option)
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-3.txt b/Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-3.txt
new file mode 100644
index 0000000..9672c6d
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-3.txt
@@ -0,0 +1,13 @@
+..E
+ERROR during LuaUnit test execution:
+test/test_with_err_fail_pass.lua:41: attempt to perform arithmetic on a table value
+
+Tests with errors:
+------------------
+1) TestAnotherThing.test2_Err1
+test/test_with_err_fail_pass.lua:41: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:41: in function 'TestAnotherThing.test2_Err1'
+
+Ran 3 tests in 0.000 seconds, 2 successes, 1 error, 9 non-selected
+LuaUnit ABORTED (as requested by --error or --failure option)
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-4.txt b/Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-4.txt
new file mode 100644
index 0000000..78178fd
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTextStopOnError-4.txt
@@ -0,0 +1,13 @@
+..F
+Failure during LuaUnit test execution:
+test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+
+Failed tests:
+-------------
+1) TestSomething.test2_Fail1
+test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+stack traceback:
+ test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1'
+
+Ran 3 tests in 0.000 seconds, 2 successes, 1 failure, 9 non-selected
+LuaUnit ABORTED (as requested by --error or --failure option)
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTextVerbose-failures.txt b/Data/Libraries/luaunit/test/ref/errFailPassTextVerbose-failures.txt
new file mode 100644
index 0000000..af48612
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTextVerbose-failures.txt
@@ -0,0 +1,45 @@
+Started on 03/22/16 21:29:18
+ TestAnotherThing.test1_Success1 ... Ok
+ TestAnotherThing.test1_Success2 ... Ok
+ TestAnotherThing.test3_Fail1 ... FAIL
+test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+ TestAnotherThing.test3_Fail2 ... FAIL
+test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+ TestSomething.test1_Success1 ... Ok
+ TestSomething.test1_Success2 ... Ok
+ TestSomething.test2_Fail1 ... FAIL
+test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+ TestSomething.test2_Fail2 ... FAIL
+test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+ testFuncFail1 ... FAIL
+test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+ testFuncSuccess1 ... Ok
+=========================================================
+Failed tests:
+-------------
+1) TestAnotherThing.test3_Fail1
+test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+stack traceback:
+ test/test_with_err_fail_pass.lua:49: in function 'TestAnotherThing.test3_Fail1'
+
+2) TestAnotherThing.test3_Fail2
+test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:53: in function 'TestAnotherThing.test3_Fail2'
+
+3) TestSomething.test2_Fail1
+test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+stack traceback:
+ test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1'
+
+4) TestSomething.test2_Fail2
+test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:19: in function 'TestSomething.test2_Fail2'
+
+5) testFuncFail1
+test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:62: in function 'testFuncFail1'
+
+Ran 10 tests in 0.001 seconds, 5 successes, 5 failures, 5 non-selected
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTextVerbose-success.txt b/Data/Libraries/luaunit/test/ref/errFailPassTextVerbose-success.txt
new file mode 100644
index 0000000..605df07
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTextVerbose-success.txt
@@ -0,0 +1,9 @@
+Started on 03/22/16 21:29:18
+ TestAnotherThing.test1_Success1 ... Ok
+ TestAnotherThing.test1_Success2 ... Ok
+ TestSomething.test1_Success1 ... Ok
+ TestSomething.test1_Success2 ... Ok
+ testFuncSuccess1 ... Ok
+=========================================================
+Ran 5 tests in 0.000 seconds, 5 successes, 0 failures, 10 non-selected
+OK
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassTextVerbose.txt b/Data/Libraries/luaunit/test/ref/errFailPassTextVerbose.txt
new file mode 100644
index 0000000..7ebe9e3
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassTextVerbose.txt
@@ -0,0 +1,82 @@
+Started on 03/22/16 21:29:18
+ TestAnotherThing.test1_Success1 ... Ok
+ TestAnotherThing.test1_Success2 ... Ok
+ TestAnotherThing.test2_Err1 ... ERROR
+test/test_with_err_fail_pass.lua:41: attempt to perform arithmetic on a table value
+ TestAnotherThing.test2_Err2 ... ERROR
+test/test_with_err_fail_pass.lua:45: attempt to perform arithmetic on a table value
+ TestAnotherThing.test3_Fail1 ... FAIL
+test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+ TestAnotherThing.test3_Fail2 ... FAIL
+test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+ TestSomething.test1_Success1 ... Ok
+ TestSomething.test1_Success2 ... Ok
+ TestSomething.test2_Fail1 ... FAIL
+test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+ TestSomething.test2_Fail2 ... FAIL
+test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+ TestSomething.test3_Err1 ... ERROR
+test/test_with_err_fail_pass.lua:23: attempt to perform arithmetic on a table value
+ TestSomething.test3_Err2 ... ERROR
+test/test_with_err_fail_pass.lua:27: attempt to perform arithmetic on a table value
+ testFuncErr1 ... ERROR
+test/test_with_err_fail_pass.lua:66: attempt to perform arithmetic on a table value
+ testFuncFail1 ... FAIL
+test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+ testFuncSuccess1 ... Ok
+=========================================================
+Tests with errors:
+------------------
+1) TestAnotherThing.test2_Err1
+test/test_with_err_fail_pass.lua:41: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:41: in function 'TestAnotherThing.test2_Err1'
+
+2) TestAnotherThing.test2_Err2
+test/test_with_err_fail_pass.lua:45: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:45: in function 'TestAnotherThing.test2_Err2'
+
+3) TestSomething.test3_Err1
+test/test_with_err_fail_pass.lua:23: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:23: in function 'TestSomething.test3_Err1'
+
+4) TestSomething.test3_Err2
+test/test_with_err_fail_pass.lua:27: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:27: in function 'TestSomething.test3_Err2'
+
+5) testFuncErr1
+test/test_with_err_fail_pass.lua:66: attempt to perform arithmetic on a table value
+stack traceback:
+ test/test_with_err_fail_pass.lua:66: in function 'testFuncErr1'
+
+Failed tests:
+-------------
+1) TestAnotherThing.test3_Fail1
+test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+stack traceback:
+ test/test_with_err_fail_pass.lua:49: in function 'TestAnotherThing.test3_Fail1'
+
+2) TestAnotherThing.test3_Fail2
+test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:53: in function 'TestAnotherThing.test3_Fail2'
+
+3) TestSomething.test2_Fail1
+test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+stack traceback:
+ test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1'
+
+4) TestSomething.test2_Fail2
+test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:19: in function 'TestSomething.test2_Fail2'
+
+5) testFuncFail1
+test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+stack traceback:
+ test/test_with_err_fail_pass.lua:62: in function 'testFuncFail1'
+
+Ran 15 tests in 0.001 seconds, 5 successes, 5 failures, 5 errors
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-failures.txt b/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-failures.txt
new file mode 100644
index 0000000..db2925d
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-failures.txt
@@ -0,0 +1,20 @@
+# XML output to test/ref/errFailPassXmlDefault-failures.xml
+# Started on 04/30/19 20:22:52
+# Starting class: TestAnotherThing
+# Starting test: TestAnotherThing.test1_Success1
+# Starting test: TestAnotherThing.test1_Success2
+# Starting test: TestAnotherThing.test3_Fail1
+# Failure: test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+# Starting test: TestAnotherThing.test3_Fail2
+# Failure: test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+# Starting class: TestSomething
+# Starting test: TestSomething.test1_Success1
+# Starting test: TestSomething.test1_Success2
+# Starting test: TestSomething.test2_Fail1
+# Failure: test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+# Starting test: TestSomething.test2_Fail2
+# Failure: test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+# Starting test: testFuncFail1
+# Failure: test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+# Starting test: testFuncSuccess1
+# Ran 10 tests in 0.000 seconds, 5 successes, 5 failures, 5 non-selected
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-failures.xml b/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-failures.xml
new file mode 100644
index 0000000..0ddd0e0
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-failures.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="10" timestamp="2019-04-30T20:22:52" time="0.000" errors="0" failures="5" skipped="0">
+ <properties>
+ <property name="Lua Version" value="Lua 5.4"/>
+ <property name="LuaUnit Version" value="3.4"/>
+ </properties>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test3_Fail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:49: in function 'TestAnotherThing.test3_Fail1']]></failure>
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test3_Fail2" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:53: in function 'TestAnotherThing.test3_Fail2']]></failure>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test2_Fail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1']]></failure>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test2_Fail2" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:19: in function 'TestSomething.test2_Fail2']]></failure>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncFail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:62: in function 'testFuncFail1']]></failure>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncSuccess1" time="0.000">
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-success.txt b/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-success.txt
new file mode 100644
index 0000000..03927e4
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-success.txt
@@ -0,0 +1,10 @@
+# XML output to test/ref/errFailPassXmlDefault-success.xml
+# Started on 04/30/19 20:22:52
+# Starting class: TestAnotherThing
+# Starting test: TestAnotherThing.test1_Success1
+# Starting test: TestAnotherThing.test1_Success2
+# Starting class: TestSomething
+# Starting test: TestSomething.test1_Success1
+# Starting test: TestSomething.test1_Success2
+# Starting test: testFuncSuccess1
+# Ran 5 tests in 0.000 seconds, 5 successes, 0 failures, 10 non-selected
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-success.xml b/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-success.xml
new file mode 100644
index 0000000..22763a5
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault-success.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="5" timestamp="2019-04-30T20:22:52" time="0.000" errors="0" failures="0" skipped="0">
+ <properties>
+ <property name="Lua Version" value="Lua 5.4"/>
+ <property name="LuaUnit Version" value="3.4"/>
+ </properties>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncSuccess1" time="0.000">
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault.txt b/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault.txt
new file mode 100644
index 0000000..0e4c49e
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault.txt
@@ -0,0 +1,30 @@
+# XML output to test/ref/errFailPassXmlDefault.xml
+# Started on 04/30/19 20:22:52
+# Starting class: TestAnotherThing
+# Starting test: TestAnotherThing.test1_Success1
+# Starting test: TestAnotherThing.test1_Success2
+# Starting test: TestAnotherThing.test2_Err1
+# Error: test/test_with_err_fail_pass.lua:41: attempt to perform arithmetic on a table value
+# Starting test: TestAnotherThing.test2_Err2
+# Error: test/test_with_err_fail_pass.lua:45: attempt to perform arithmetic on a table value
+# Starting test: TestAnotherThing.test3_Fail1
+# Failure: test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+# Starting test: TestAnotherThing.test3_Fail2
+# Failure: test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+# Starting class: TestSomething
+# Starting test: TestSomething.test1_Success1
+# Starting test: TestSomething.test1_Success2
+# Starting test: TestSomething.test2_Fail1
+# Failure: test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+# Starting test: TestSomething.test2_Fail2
+# Failure: test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+# Starting test: TestSomething.test3_Err1
+# Error: test/test_with_err_fail_pass.lua:23: attempt to perform arithmetic on a table value
+# Starting test: TestSomething.test3_Err2
+# Error: test/test_with_err_fail_pass.lua:27: attempt to perform arithmetic on a table value
+# Starting test: testFuncErr1
+# Error: test/test_with_err_fail_pass.lua:66: attempt to perform arithmetic on a table value
+# Starting test: testFuncFail1
+# Failure: test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+# Starting test: testFuncSuccess1
+# Ran 15 tests in 0.004 seconds, 5 successes, 5 failures, 5 errors
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault.xml b/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault.xml
new file mode 100644
index 0000000..9292bcb
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlDefault.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="15" timestamp="2019-04-30T20:22:52" time="0.004" errors="5" failures="5" skipped="0">
+ <properties>
+ <property name="Lua Version" value="Lua 5.4"/>
+ <property name="LuaUnit Version" value="3.4"/>
+ </properties>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test2_Err1" time="0.000">
+ <error type="test/test_with_err_fail_pass.lua:41: attempt to perform arithmetic on a table value">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:41: in function 'TestAnotherThing.test2_Err1']]></error>
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test2_Err2" time="0.000">
+ <error type="test/test_with_err_fail_pass.lua:45: attempt to perform arithmetic on a table value">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:45: in function 'TestAnotherThing.test2_Err2']]></error>
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test3_Fail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:49: in function 'TestAnotherThing.test3_Fail1']]></failure>
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test3_Fail2" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:53: in function 'TestAnotherThing.test3_Fail2']]></failure>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test2_Fail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1']]></failure>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test2_Fail2" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:19: in function 'TestSomething.test2_Fail2']]></failure>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test3_Err1" time="0.000">
+ <error type="test/test_with_err_fail_pass.lua:23: attempt to perform arithmetic on a table value">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:23: in function 'TestSomething.test3_Err1']]></error>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test3_Err2" time="0.000">
+ <error type="test/test_with_err_fail_pass.lua:27: attempt to perform arithmetic on a table value">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:27: in function 'TestSomething.test3_Err2']]></error>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncErr1" time="0.000">
+ <error type="test/test_with_err_fail_pass.lua:66: attempt to perform arithmetic on a table value">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:66: in function 'testFuncErr1']]></error>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncFail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:62: in function 'testFuncFail1']]></failure>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncSuccess1" time="0.000">
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-failures.txt b/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-failures.txt
new file mode 100644
index 0000000..b3ce2f9
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-failures.txt
@@ -0,0 +1,20 @@
+# XML output to test/ref/errFailPassXmlQuiet-failures.xml
+# Started on 04/30/19 20:22:53
+# Starting class: TestAnotherThing
+# Starting test: TestAnotherThing.test1_Success1
+# Starting test: TestAnotherThing.test1_Success2
+# Starting test: TestAnotherThing.test3_Fail1
+# Failure: test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+# Starting test: TestAnotherThing.test3_Fail2
+# Failure: test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+# Starting class: TestSomething
+# Starting test: TestSomething.test1_Success1
+# Starting test: TestSomething.test1_Success2
+# Starting test: TestSomething.test2_Fail1
+# Failure: test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+# Starting test: TestSomething.test2_Fail2
+# Failure: test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+# Starting test: testFuncFail1
+# Failure: test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+# Starting test: testFuncSuccess1
+# Ran 10 tests in 0.000 seconds, 5 successes, 5 failures, 5 non-selected
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-failures.xml b/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-failures.xml
new file mode 100644
index 0000000..9ff97d5
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-failures.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="10" timestamp="2019-04-30T20:22:53" time="0.000" errors="0" failures="5" skipped="0">
+ <properties>
+ <property name="Lua Version" value="Lua 5.4"/>
+ <property name="LuaUnit Version" value="3.4"/>
+ </properties>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test3_Fail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:49: in function 'TestAnotherThing.test3_Fail1']]></failure>
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test3_Fail2" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:53: in function 'TestAnotherThing.test3_Fail2']]></failure>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test2_Fail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1']]></failure>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test2_Fail2" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:19: in function 'TestSomething.test2_Fail2']]></failure>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncFail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:62: in function 'testFuncFail1']]></failure>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncSuccess1" time="0.000">
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-success.txt b/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-success.txt
new file mode 100644
index 0000000..92cc7b6
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-success.txt
@@ -0,0 +1,10 @@
+# XML output to test/ref/errFailPassXmlQuiet-success.xml
+# Started on 04/30/19 20:22:52
+# Starting class: TestAnotherThing
+# Starting test: TestAnotherThing.test1_Success1
+# Starting test: TestAnotherThing.test1_Success2
+# Starting class: TestSomething
+# Starting test: TestSomething.test1_Success1
+# Starting test: TestSomething.test1_Success2
+# Starting test: testFuncSuccess1
+# Ran 5 tests in 0.000 seconds, 5 successes, 0 failures, 10 non-selected
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-success.xml b/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-success.xml
new file mode 100644
index 0000000..22763a5
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet-success.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="5" timestamp="2019-04-30T20:22:52" time="0.000" errors="0" failures="0" skipped="0">
+ <properties>
+ <property name="Lua Version" value="Lua 5.4"/>
+ <property name="LuaUnit Version" value="3.4"/>
+ </properties>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncSuccess1" time="0.000">
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet.txt b/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet.txt
new file mode 100644
index 0000000..1ce973f
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet.txt
@@ -0,0 +1,30 @@
+# XML output to test/ref/errFailPassXmlQuiet.xml
+# Started on 04/30/19 20:22:52
+# Starting class: TestAnotherThing
+# Starting test: TestAnotherThing.test1_Success1
+# Starting test: TestAnotherThing.test1_Success2
+# Starting test: TestAnotherThing.test2_Err1
+# Error: test/test_with_err_fail_pass.lua:41: attempt to perform arithmetic on a table value
+# Starting test: TestAnotherThing.test2_Err2
+# Error: test/test_with_err_fail_pass.lua:45: attempt to perform arithmetic on a table value
+# Starting test: TestAnotherThing.test3_Fail1
+# Failure: test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+# Starting test: TestAnotherThing.test3_Fail2
+# Failure: test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+# Starting class: TestSomething
+# Starting test: TestSomething.test1_Success1
+# Starting test: TestSomething.test1_Success2
+# Starting test: TestSomething.test2_Fail1
+# Failure: test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+# Starting test: TestSomething.test2_Fail2
+# Failure: test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+# Starting test: TestSomething.test3_Err1
+# Error: test/test_with_err_fail_pass.lua:23: attempt to perform arithmetic on a table value
+# Starting test: TestSomething.test3_Err2
+# Error: test/test_with_err_fail_pass.lua:27: attempt to perform arithmetic on a table value
+# Starting test: testFuncErr1
+# Error: test/test_with_err_fail_pass.lua:66: attempt to perform arithmetic on a table value
+# Starting test: testFuncFail1
+# Failure: test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+# Starting test: testFuncSuccess1
+# Ran 15 tests in 0.000 seconds, 5 successes, 5 failures, 5 errors
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet.xml b/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet.xml
new file mode 100644
index 0000000..a878300
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlQuiet.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="15" timestamp="2019-04-30T20:22:52" time="0.000" errors="5" failures="5" skipped="0">
+ <properties>
+ <property name="Lua Version" value="Lua 5.4"/>
+ <property name="LuaUnit Version" value="3.4"/>
+ </properties>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test2_Err1" time="0.000">
+ <error type="test/test_with_err_fail_pass.lua:41: attempt to perform arithmetic on a table value">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:41: in function 'TestAnotherThing.test2_Err1']]></error>
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test2_Err2" time="0.000">
+ <error type="test/test_with_err_fail_pass.lua:45: attempt to perform arithmetic on a table value">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:45: in function 'TestAnotherThing.test2_Err2']]></error>
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test3_Fail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:49: in function 'TestAnotherThing.test3_Fail1']]></failure>
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test3_Fail2" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:53: in function 'TestAnotherThing.test3_Fail2']]></failure>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test2_Fail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1']]></failure>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test2_Fail2" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:19: in function 'TestSomething.test2_Fail2']]></failure>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test3_Err1" time="0.000">
+ <error type="test/test_with_err_fail_pass.lua:23: attempt to perform arithmetic on a table value">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:23: in function 'TestSomething.test3_Err1']]></error>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test3_Err2" time="0.000">
+ <error type="test/test_with_err_fail_pass.lua:27: attempt to perform arithmetic on a table value">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:27: in function 'TestSomething.test3_Err2']]></error>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncErr1" time="0.000">
+ <error type="test/test_with_err_fail_pass.lua:66: attempt to perform arithmetic on a table value">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:66: in function 'testFuncErr1']]></error>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncFail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:62: in function 'testFuncFail1']]></failure>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncSuccess1" time="0.000">
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-failures.txt b/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-failures.txt
new file mode 100644
index 0000000..cab05c6
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-failures.txt
@@ -0,0 +1,20 @@
+# XML output to test/ref/errFailPassXmlVerbose-failures.xml
+# Started on 04/30/19 20:22:53
+# Starting class: TestAnotherThing
+# Starting test: TestAnotherThing.test1_Success1
+# Starting test: TestAnotherThing.test1_Success2
+# Starting test: TestAnotherThing.test3_Fail1
+# Failure: test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+# Starting test: TestAnotherThing.test3_Fail2
+# Failure: test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+# Starting class: TestSomething
+# Starting test: TestSomething.test1_Success1
+# Starting test: TestSomething.test1_Success2
+# Starting test: TestSomething.test2_Fail1
+# Failure: test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+# Starting test: TestSomething.test2_Fail2
+# Failure: test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+# Starting test: testFuncFail1
+# Failure: test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+# Starting test: testFuncSuccess1
+# Ran 10 tests in 0.000 seconds, 5 successes, 5 failures, 5 non-selected
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-failures.xml b/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-failures.xml
new file mode 100644
index 0000000..9ff97d5
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-failures.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="10" timestamp="2019-04-30T20:22:53" time="0.000" errors="0" failures="5" skipped="0">
+ <properties>
+ <property name="Lua Version" value="Lua 5.4"/>
+ <property name="LuaUnit Version" value="3.4"/>
+ </properties>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test3_Fail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:49: in function 'TestAnotherThing.test3_Fail1']]></failure>
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test3_Fail2" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:53: in function 'TestAnotherThing.test3_Fail2']]></failure>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test2_Fail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1']]></failure>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test2_Fail2" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:19: in function 'TestSomething.test2_Fail2']]></failure>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncFail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:62: in function 'testFuncFail1']]></failure>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncSuccess1" time="0.000">
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-success.txt b/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-success.txt
new file mode 100644
index 0000000..41f49ff
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-success.txt
@@ -0,0 +1,10 @@
+# XML output to test/ref/errFailPassXmlVerbose-success.xml
+# Started on 04/30/19 20:22:53
+# Starting class: TestAnotherThing
+# Starting test: TestAnotherThing.test1_Success1
+# Starting test: TestAnotherThing.test1_Success2
+# Starting class: TestSomething
+# Starting test: TestSomething.test1_Success1
+# Starting test: TestSomething.test1_Success2
+# Starting test: testFuncSuccess1
+# Ran 5 tests in 0.000 seconds, 5 successes, 0 failures, 10 non-selected
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-success.xml b/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-success.xml
new file mode 100644
index 0000000..3f10177
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose-success.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="5" timestamp="2019-04-30T20:22:53" time="0.000" errors="0" failures="0" skipped="0">
+ <properties>
+ <property name="Lua Version" value="Lua 5.4"/>
+ <property name="LuaUnit Version" value="3.4"/>
+ </properties>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncSuccess1" time="0.000">
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose.txt b/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose.txt
new file mode 100644
index 0000000..9ff66b8
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose.txt
@@ -0,0 +1,30 @@
+# XML output to test/ref/errFailPassXmlVerbose.xml
+# Started on 04/30/19 20:22:53
+# Starting class: TestAnotherThing
+# Starting test: TestAnotherThing.test1_Success1
+# Starting test: TestAnotherThing.test1_Success2
+# Starting test: TestAnotherThing.test2_Err1
+# Error: test/test_with_err_fail_pass.lua:41: attempt to perform arithmetic on a table value
+# Starting test: TestAnotherThing.test2_Err2
+# Error: test/test_with_err_fail_pass.lua:45: attempt to perform arithmetic on a table value
+# Starting test: TestAnotherThing.test3_Fail1
+# Failure: test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2
+# Starting test: TestAnotherThing.test3_Fail2
+# Failure: test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3
+# Starting class: TestSomething
+# Starting test: TestSomething.test1_Success1
+# Starting test: TestSomething.test1_Success2
+# Starting test: TestSomething.test2_Fail1
+# Failure: test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2
+# Starting test: TestSomething.test2_Fail2
+# Failure: test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3
+# Starting test: TestSomething.test3_Err1
+# Error: test/test_with_err_fail_pass.lua:23: attempt to perform arithmetic on a table value
+# Starting test: TestSomething.test3_Err2
+# Error: test/test_with_err_fail_pass.lua:27: attempt to perform arithmetic on a table value
+# Starting test: testFuncErr1
+# Error: test/test_with_err_fail_pass.lua:66: attempt to perform arithmetic on a table value
+# Starting test: testFuncFail1
+# Failure: test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3
+# Starting test: testFuncSuccess1
+# Ran 15 tests in 0.000 seconds, 5 successes, 5 failures, 5 errors
diff --git a/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose.xml b/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose.xml
new file mode 100644
index 0000000..dc36ba1
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errFailPassXmlVerbose.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="15" timestamp="2019-04-30T20:22:53" time="0.000" errors="5" failures="5" skipped="0">
+ <properties>
+ <property name="Lua Version" value="Lua 5.4"/>
+ <property name="LuaUnit Version" value="3.4"/>
+ </properties>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test2_Err1" time="0.000">
+ <error type="test/test_with_err_fail_pass.lua:41: attempt to perform arithmetic on a table value">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:41: in function 'TestAnotherThing.test2_Err1']]></error>
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test2_Err2" time="0.000">
+ <error type="test/test_with_err_fail_pass.lua:45: attempt to perform arithmetic on a table value">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:45: in function 'TestAnotherThing.test2_Err2']]></error>
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test3_Fail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:49: expected: 0, actual: 2">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:49: in function 'TestAnotherThing.test3_Fail1']]></failure>
+ </testcase>
+ <testcase classname="TestAnotherThing" name="TestAnotherThing.test3_Fail2" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:53: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:53: in function 'TestAnotherThing.test3_Fail2']]></failure>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success1" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test1_Success2" time="0.000">
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test2_Fail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:15: expected: 0, actual: 2">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:15: in function 'TestSomething.test2_Fail1']]></failure>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test2_Fail2" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:19: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:19: in function 'TestSomething.test2_Fail2']]></failure>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test3_Err1" time="0.000">
+ <error type="test/test_with_err_fail_pass.lua:23: attempt to perform arithmetic on a table value">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:23: in function 'TestSomething.test3_Err1']]></error>
+ </testcase>
+ <testcase classname="TestSomething" name="TestSomething.test3_Err2" time="0.000">
+ <error type="test/test_with_err_fail_pass.lua:27: attempt to perform arithmetic on a table value">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:27: in function 'TestSomething.test3_Err2']]></error>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncErr1" time="0.000">
+ <error type="test/test_with_err_fail_pass.lua:66: attempt to perform arithmetic on a table value">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:66: in function 'testFuncErr1']]></error>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncFail1" time="0.000">
+ <failure type="test/test_with_err_fail_pass.lua:62: expected: 0, actual: 3">
+ <![CDATA[stack traceback:
+ test/test_with_err_fail_pass.lua:62: in function 'testFuncFail1']]></failure>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="testFuncSuccess1" time="0.000">
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
diff --git a/Data/Libraries/luaunit/test/ref/errPassFailTapQuiet.txt b/Data/Libraries/luaunit/test/ref/errPassFailTapQuiet.txt
new file mode 100644
index 0000000..fb5196c
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/errPassFailTapQuiet.txt
@@ -0,0 +1,20 @@
+1..15
+# Started on 03/22/16 21:54:40
+# Starting class: TestAnotherThing
+ok 1 TestAnotherThing.test1_Success1
+ok 2 TestAnotherThing.test1_Success2
+not ok 3 TestAnotherThing.test2_Err1
+not ok 4 TestAnotherThing.test2_Err2
+not ok 5 TestAnotherThing.test3_Fail1
+not ok 6 TestAnotherThing.test3_Fail2
+# Starting class: TestSomething
+ok 7 TestSomething.test1_Success1
+ok 8 TestSomething.test1_Success2
+not ok 9 TestSomething.test2_Fail1
+not ok 10 TestSomething.test2_Fail2
+not ok 11 TestSomething.test3_Err1
+not ok 12 TestSomething.test3_Err2
+not ok 13 testFuncErr1
+not ok 14 testFuncFail1
+ok 15 testFuncSuccess1
+# Ran 15 tests in 0.000 seconds, 5 successes, 5 failures, 5 errors
diff --git a/Data/Libraries/luaunit/test/ref/exampleNilDefault.txt b/Data/Libraries/luaunit/test/ref/exampleNilDefault.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/exampleNilDefault.txt
diff --git a/Data/Libraries/luaunit/test/ref/exampleTapDefault.txt b/Data/Libraries/luaunit/test/ref/exampleTapDefault.txt
new file mode 100644
index 0000000..0ae668d
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/exampleTapDefault.txt
@@ -0,0 +1,36 @@
+1..16
+# Started on 04/28/19 21:02:44
+# Starting class: TestTiti
+not ok 1 TestTiti.test1_withFailure
+# example_with_luaunit.lua:109: expected: 2, actual: 1
+not ok 2 TestTiti.test2_withFailure
+# example_with_luaunit.lua:118: expected: "bof"
+# actual: "hop"
+ok 3 TestTiti.test3
+# Starting class: TestToto
+not ok 4 TestToto.test1_withFailure
+# example_with_luaunit.lua:21: expected: 2, actual: 1
+not ok 5 TestToto.test2_withFailure
+# example_with_luaunit.lua:30: expected: "bof"
+# actual: "hop"
+ok 6 TestToto.test3
+not ok 7 TestToto.test4
+# example_with_luaunit.lua:43: Received the not expected value: 1
+not ok 8 TestToto.test5
+# example_with_luaunit.lua:49: expected: false or nil, actual: 1
+not ok 9 TestToto.test6
+# example_with_luaunit.lua:57: expected: false, actual: nil
+not ok 10 TestToto.test7
+# example_with_luaunit.lua:63: expected: {1, 2, three=3}
+# actual: {1, 2}
+not ok 11 TestToto.test8a
+# example_with_luaunit.lua:81: Bouhouhoum error!
+not ok 12 TestToto.test8b
+# example_with_luaunit.lua:81: Bouhouhoum error!
+ok 13 # SKIP Test is skipped because ...
+not ok 14 test1_withAssertionError
+# example_with_luaunit.lua:134: assertion failed!
+not ok 15 test2_withAssertionError
+# example_with_luaunit.lua:140: assertion failed!
+ok 16 test3
+# Ran 15 tests in 0.000 seconds, 3 successes, 8 failures, 4 errors, 1 skipped
diff --git a/Data/Libraries/luaunit/test/ref/exampleTapQuiet.txt b/Data/Libraries/luaunit/test/ref/exampleTapQuiet.txt
new file mode 100644
index 0000000..5cd7c62
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/exampleTapQuiet.txt
@@ -0,0 +1,21 @@
+1..16
+# Started on 04/28/19 21:02:44
+# Starting class: TestTiti
+not ok 1 TestTiti.test1_withFailure
+not ok 2 TestTiti.test2_withFailure
+ok 3 TestTiti.test3
+# Starting class: TestToto
+not ok 4 TestToto.test1_withFailure
+not ok 5 TestToto.test2_withFailure
+ok 6 TestToto.test3
+not ok 7 TestToto.test4
+not ok 8 TestToto.test5
+not ok 9 TestToto.test6
+not ok 10 TestToto.test7
+not ok 11 TestToto.test8a
+not ok 12 TestToto.test8b
+ok 13 # SKIP Test is skipped because ...
+not ok 14 test1_withAssertionError
+not ok 15 test2_withAssertionError
+ok 16 test3
+# Ran 15 tests in 0.000 seconds, 3 successes, 8 failures, 4 errors, 1 skipped
diff --git a/Data/Libraries/luaunit/test/ref/exampleTapVerbose.txt b/Data/Libraries/luaunit/test/ref/exampleTapVerbose.txt
new file mode 100644
index 0000000..23e3917
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/exampleTapVerbose.txt
@@ -0,0 +1,63 @@
+1..16
+# Started on 04/28/19 21:02:44
+# Starting class: TestTiti
+not ok 1 TestTiti.test1_withFailure
+# example_with_luaunit.lua:109: expected: 2, actual: 1
+# stack traceback:
+# example_with_luaunit.lua:109: in function 'TestTiti.test1_withFailure'
+not ok 2 TestTiti.test2_withFailure
+# example_with_luaunit.lua:118: expected: "bof"
+# actual: "hop"
+# stack traceback:
+# example_with_luaunit.lua:118: in function 'TestTiti.test2_withFailure'
+ok 3 TestTiti.test3
+# Starting class: TestToto
+not ok 4 TestToto.test1_withFailure
+# example_with_luaunit.lua:21: expected: 2, actual: 1
+# stack traceback:
+# example_with_luaunit.lua:21: in function 'TestToto.test1_withFailure'
+not ok 5 TestToto.test2_withFailure
+# example_with_luaunit.lua:30: expected: "bof"
+# actual: "hop"
+# stack traceback:
+# example_with_luaunit.lua:30: in function 'TestToto.test2_withFailure'
+ok 6 TestToto.test3
+not ok 7 TestToto.test4
+# example_with_luaunit.lua:43: Received the not expected value: 1
+# stack traceback:
+# example_with_luaunit.lua:43: in function 'TestToto.test4'
+not ok 8 TestToto.test5
+# example_with_luaunit.lua:49: expected: false or nil, actual: 1
+# stack traceback:
+# example_with_luaunit.lua:49: in function 'TestToto.test5'
+not ok 9 TestToto.test6
+# example_with_luaunit.lua:57: expected: false, actual: nil
+# stack traceback:
+# example_with_luaunit.lua:57: in function 'TestToto.test6'
+not ok 10 TestToto.test7
+# example_with_luaunit.lua:63: expected: {1, 2, three=3}
+# actual: {1, 2}
+# stack traceback:
+# example_with_luaunit.lua:63: in function 'TestToto.test7'
+not ok 11 TestToto.test8a
+# example_with_luaunit.lua:81: Bouhouhoum error!
+# stack traceback:
+# example_with_luaunit.lua:81: in function 'funcWithError'
+# example_with_luaunit.lua:68: in function 'TestToto.test8a'
+not ok 12 TestToto.test8b
+# example_with_luaunit.lua:81: Bouhouhoum error!
+# stack traceback:
+# example_with_luaunit.lua:81: in function 'funcWithError'
+# example_with_luaunit.lua:77: in function 'funcWithFuncWithError'
+# example_with_luaunit.lua:73: in function 'TestToto.test8b'
+ok 13 # SKIP Test is skipped because ...
+not ok 14 test1_withAssertionError
+# example_with_luaunit.lua:134: assertion failed!
+# stack traceback:
+# example_with_luaunit.lua:134: in function 'test1_withAssertionError'
+not ok 15 test2_withAssertionError
+# example_with_luaunit.lua:140: assertion failed!
+# stack traceback:
+# example_with_luaunit.lua:140: in function 'test2_withAssertionError'
+ok 16 test3
+# Ran 15 tests in 0.000 seconds, 3 successes, 8 failures, 4 errors, 1 skipped
diff --git a/Data/Libraries/luaunit/test/ref/exampleTextDefault.txt b/Data/Libraries/luaunit/test/ref/exampleTextDefault.txt
new file mode 100644
index 0000000..9af3673
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/exampleTextDefault.txt
@@ -0,0 +1,72 @@
+FF.FF.FFFFEESEE.
+Tests with errors:
+------------------
+1) TestToto.test8a
+example_with_luaunit.lua:81: Bouhouhoum error!
+stack traceback:
+ example_with_luaunit.lua:81: in function 'funcWithError'
+ example_with_luaunit.lua:68: in function 'TestToto.test8a'
+
+2) TestToto.test8b
+example_with_luaunit.lua:81: Bouhouhoum error!
+stack traceback:
+ example_with_luaunit.lua:81: in function 'funcWithError'
+ example_with_luaunit.lua:77: in function 'funcWithFuncWithError'
+ example_with_luaunit.lua:73: in function 'TestToto.test8b'
+
+3) test1_withAssertionError
+example_with_luaunit.lua:134: assertion failed!
+stack traceback:
+ example_with_luaunit.lua:134: in function 'test1_withAssertionError'
+
+4) test2_withAssertionError
+example_with_luaunit.lua:140: assertion failed!
+stack traceback:
+ example_with_luaunit.lua:140: in function 'test2_withAssertionError'
+
+Failed tests:
+-------------
+1) TestTiti.test1_withFailure
+example_with_luaunit.lua:109: expected: 2, actual: 1
+stack traceback:
+ example_with_luaunit.lua:109: in function 'TestTiti.test1_withFailure'
+
+2) TestTiti.test2_withFailure
+example_with_luaunit.lua:118: expected: "bof"
+actual: "hop"
+stack traceback:
+ example_with_luaunit.lua:118: in function 'TestTiti.test2_withFailure'
+
+3) TestToto.test1_withFailure
+example_with_luaunit.lua:21: expected: 2, actual: 1
+stack traceback:
+ example_with_luaunit.lua:21: in function 'TestToto.test1_withFailure'
+
+4) TestToto.test2_withFailure
+example_with_luaunit.lua:30: expected: "bof"
+actual: "hop"
+stack traceback:
+ example_with_luaunit.lua:30: in function 'TestToto.test2_withFailure'
+
+5) TestToto.test4
+example_with_luaunit.lua:43: Received the not expected value: 1
+stack traceback:
+ example_with_luaunit.lua:43: in function 'TestToto.test4'
+
+6) TestToto.test5
+example_with_luaunit.lua:49: expected: false or nil, actual: 1
+stack traceback:
+ example_with_luaunit.lua:49: in function 'TestToto.test5'
+
+7) TestToto.test6
+example_with_luaunit.lua:57: expected: false, actual: nil
+stack traceback:
+ example_with_luaunit.lua:57: in function 'TestToto.test6'
+
+8) TestToto.test7
+example_with_luaunit.lua:63: expected: {1, 2, three=3}
+actual: {1, 2}
+stack traceback:
+ example_with_luaunit.lua:63: in function 'TestToto.test7'
+
+Ran 15 tests in 0.009 seconds, 3 successes, 8 failures, 4 errors, 1 skipped
diff --git a/Data/Libraries/luaunit/test/ref/exampleTextQuiet.txt b/Data/Libraries/luaunit/test/ref/exampleTextQuiet.txt
new file mode 100644
index 0000000..38ba67d
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/exampleTextQuiet.txt
@@ -0,0 +1,72 @@
+FF.FF.FFFFEESEE.
+Tests with errors:
+------------------
+1) TestToto.test8a
+example_with_luaunit.lua:81: Bouhouhoum error!
+stack traceback:
+ example_with_luaunit.lua:81: in function 'funcWithError'
+ example_with_luaunit.lua:68: in function 'TestToto.test8a'
+
+2) TestToto.test8b
+example_with_luaunit.lua:81: Bouhouhoum error!
+stack traceback:
+ example_with_luaunit.lua:81: in function 'funcWithError'
+ example_with_luaunit.lua:77: in function 'funcWithFuncWithError'
+ example_with_luaunit.lua:73: in function 'TestToto.test8b'
+
+3) test1_withAssertionError
+example_with_luaunit.lua:134: assertion failed!
+stack traceback:
+ example_with_luaunit.lua:134: in function 'test1_withAssertionError'
+
+4) test2_withAssertionError
+example_with_luaunit.lua:140: assertion failed!
+stack traceback:
+ example_with_luaunit.lua:140: in function 'test2_withAssertionError'
+
+Failed tests:
+-------------
+1) TestTiti.test1_withFailure
+example_with_luaunit.lua:109: expected: 2, actual: 1
+stack traceback:
+ example_with_luaunit.lua:109: in function 'TestTiti.test1_withFailure'
+
+2) TestTiti.test2_withFailure
+example_with_luaunit.lua:118: expected: "bof"
+actual: "hop"
+stack traceback:
+ example_with_luaunit.lua:118: in function 'TestTiti.test2_withFailure'
+
+3) TestToto.test1_withFailure
+example_with_luaunit.lua:21: expected: 2, actual: 1
+stack traceback:
+ example_with_luaunit.lua:21: in function 'TestToto.test1_withFailure'
+
+4) TestToto.test2_withFailure
+example_with_luaunit.lua:30: expected: "bof"
+actual: "hop"
+stack traceback:
+ example_with_luaunit.lua:30: in function 'TestToto.test2_withFailure'
+
+5) TestToto.test4
+example_with_luaunit.lua:43: Received the not expected value: 1
+stack traceback:
+ example_with_luaunit.lua:43: in function 'TestToto.test4'
+
+6) TestToto.test5
+example_with_luaunit.lua:49: expected: false or nil, actual: 1
+stack traceback:
+ example_with_luaunit.lua:49: in function 'TestToto.test5'
+
+7) TestToto.test6
+example_with_luaunit.lua:57: expected: false, actual: nil
+stack traceback:
+ example_with_luaunit.lua:57: in function 'TestToto.test6'
+
+8) TestToto.test7
+example_with_luaunit.lua:63: expected: {1, 2, three=3}
+actual: {1, 2}
+stack traceback:
+ example_with_luaunit.lua:63: in function 'TestToto.test7'
+
+Ran 15 tests in 0.000 seconds, 3 successes, 8 failures, 4 errors, 1 skipped
diff --git a/Data/Libraries/luaunit/test/ref/exampleTextVerbose.txt b/Data/Libraries/luaunit/test/ref/exampleTextVerbose.txt
new file mode 100644
index 0000000..3d0c8ea
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/exampleTextVerbose.txt
@@ -0,0 +1,105 @@
+Started on 04/28/19 21:02:44
+ TestTiti.test1_withFailure ... FAIL
+example_with_luaunit.lua:109: expected: 2, actual: 1
+ TestTiti.test2_withFailure ... FAIL
+example_with_luaunit.lua:118: expected: "bof"
+actual: "hop"
+ TestTiti.test3 ... Ok
+ TestToto.test1_withFailure ... FAIL
+example_with_luaunit.lua:21: expected: 2, actual: 1
+ TestToto.test2_withFailure ... FAIL
+example_with_luaunit.lua:30: expected: "bof"
+actual: "hop"
+ TestToto.test3 ... Ok
+ TestToto.test4 ... FAIL
+example_with_luaunit.lua:43: Received the not expected value: 1
+ TestToto.test5 ... FAIL
+example_with_luaunit.lua:49: expected: false or nil, actual: 1
+ TestToto.test6 ... FAIL
+example_with_luaunit.lua:57: expected: false, actual: nil
+ TestToto.test7 ... FAIL
+example_with_luaunit.lua:63: expected: {1, 2, three=3}
+actual: {1, 2}
+ TestToto.test8a ... ERROR
+example_with_luaunit.lua:81: Bouhouhoum error!
+ TestToto.test8b ... ERROR
+example_with_luaunit.lua:81: Bouhouhoum error!
+ TestToto.test_skipped ... SKIP
+Test is skipped because ...
+ test1_withAssertionError ... ERROR
+example_with_luaunit.lua:134: assertion failed!
+ test2_withAssertionError ... ERROR
+example_with_luaunit.lua:140: assertion failed!
+ test3 ... Ok
+=========================================================
+Tests with errors:
+------------------
+1) TestToto.test8a
+example_with_luaunit.lua:81: Bouhouhoum error!
+stack traceback:
+ example_with_luaunit.lua:81: in function 'funcWithError'
+ example_with_luaunit.lua:68: in function 'TestToto.test8a'
+
+2) TestToto.test8b
+example_with_luaunit.lua:81: Bouhouhoum error!
+stack traceback:
+ example_with_luaunit.lua:81: in function 'funcWithError'
+ example_with_luaunit.lua:77: in function 'funcWithFuncWithError'
+ example_with_luaunit.lua:73: in function 'TestToto.test8b'
+
+3) test1_withAssertionError
+example_with_luaunit.lua:134: assertion failed!
+stack traceback:
+ example_with_luaunit.lua:134: in function 'test1_withAssertionError'
+
+4) test2_withAssertionError
+example_with_luaunit.lua:140: assertion failed!
+stack traceback:
+ example_with_luaunit.lua:140: in function 'test2_withAssertionError'
+
+Failed tests:
+-------------
+1) TestTiti.test1_withFailure
+example_with_luaunit.lua:109: expected: 2, actual: 1
+stack traceback:
+ example_with_luaunit.lua:109: in function 'TestTiti.test1_withFailure'
+
+2) TestTiti.test2_withFailure
+example_with_luaunit.lua:118: expected: "bof"
+actual: "hop"
+stack traceback:
+ example_with_luaunit.lua:118: in function 'TestTiti.test2_withFailure'
+
+3) TestToto.test1_withFailure
+example_with_luaunit.lua:21: expected: 2, actual: 1
+stack traceback:
+ example_with_luaunit.lua:21: in function 'TestToto.test1_withFailure'
+
+4) TestToto.test2_withFailure
+example_with_luaunit.lua:30: expected: "bof"
+actual: "hop"
+stack traceback:
+ example_with_luaunit.lua:30: in function 'TestToto.test2_withFailure'
+
+5) TestToto.test4
+example_with_luaunit.lua:43: Received the not expected value: 1
+stack traceback:
+ example_with_luaunit.lua:43: in function 'TestToto.test4'
+
+6) TestToto.test5
+example_with_luaunit.lua:49: expected: false or nil, actual: 1
+stack traceback:
+ example_with_luaunit.lua:49: in function 'TestToto.test5'
+
+7) TestToto.test6
+example_with_luaunit.lua:57: expected: false, actual: nil
+stack traceback:
+ example_with_luaunit.lua:57: in function 'TestToto.test6'
+
+8) TestToto.test7
+example_with_luaunit.lua:63: expected: {1, 2, three=3}
+actual: {1, 2}
+stack traceback:
+ example_with_luaunit.lua:63: in function 'TestToto.test7'
+
+Ran 15 tests in 0.000 seconds, 3 successes, 8 failures, 4 errors, 1 skipped
diff --git a/Data/Libraries/luaunit/test/ref/exampleXmlDefault.txt b/Data/Libraries/luaunit/test/ref/exampleXmlDefault.txt
new file mode 100644
index 0000000..db288f5
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/exampleXmlDefault.txt
@@ -0,0 +1,36 @@
+# XML output to test/ref/exampleXmlDefault.xml
+# Started on 04/28/19 21:02:44
+# Starting class: TestTiti
+# Starting test: TestTiti.test1_withFailure
+# Failure: example_with_luaunit.lua:109: expected: 2, actual: 1
+# Starting test: TestTiti.test2_withFailure
+# Failure: example_with_luaunit.lua:118: expected: "bof"
+# actual: "hop"
+# Starting test: TestTiti.test3
+# Starting class: TestToto
+# Starting test: TestToto.test1_withFailure
+# Failure: example_with_luaunit.lua:21: expected: 2, actual: 1
+# Starting test: TestToto.test2_withFailure
+# Failure: example_with_luaunit.lua:30: expected: "bof"
+# actual: "hop"
+# Starting test: TestToto.test3
+# Starting test: TestToto.test4
+# Failure: example_with_luaunit.lua:43: Received the not expected value: 1
+# Starting test: TestToto.test5
+# Failure: example_with_luaunit.lua:49: expected: false or nil, actual: 1
+# Starting test: TestToto.test6
+# Failure: example_with_luaunit.lua:57: expected: false, actual: nil
+# Starting test: TestToto.test7
+# Failure: example_with_luaunit.lua:63: expected: {1, 2, three=3}
+# actual: {1, 2}
+# Starting test: TestToto.test8a
+# Error: example_with_luaunit.lua:81: Bouhouhoum error!
+# Starting test: TestToto.test8b
+# Error: example_with_luaunit.lua:81: Bouhouhoum error!
+# Starting test: TestToto.test_skipped
+# Starting test: test1_withAssertionError
+# Error: example_with_luaunit.lua:134: assertion failed!
+# Starting test: test2_withAssertionError
+# Error: example_with_luaunit.lua:140: assertion failed!
+# Starting test: test3
+# Ran 15 tests in 0.009 seconds, 3 successes, 8 failures, 4 errors, 1 skipped
diff --git a/Data/Libraries/luaunit/test/ref/exampleXmlDefault.xml b/Data/Libraries/luaunit/test/ref/exampleXmlDefault.xml
new file mode 100644
index 0000000..c403c80
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/exampleXmlDefault.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="15" timestamp="2019-04-28T21:02:44" time="0.009" errors="4" failures="8" skipped="1">
+ <properties>
+ <property name="Lua Version" value="Lua 5.4"/>
+ <property name="LuaUnit Version" value="3.4"/>
+ </properties>
+ <testcase classname="TestTiti" name="TestTiti.test1_withFailure" time="0.000">
+ <failure type="example_with_luaunit.lua:109: expected: 2, actual: 1">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:109: in function 'TestTiti.test1_withFailure']]></failure>
+ </testcase>
+ <testcase classname="TestTiti" name="TestTiti.test2_withFailure" time="0.000">
+ <failure type="example_with_luaunit.lua:118: expected: &quot;bof&quot;
+actual: &quot;hop&quot;">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:118: in function 'TestTiti.test2_withFailure']]></failure>
+ </testcase>
+ <testcase classname="TestTiti" name="TestTiti.test3" time="0.000">
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test1_withFailure" time="0.000">
+ <failure type="example_with_luaunit.lua:21: expected: 2, actual: 1">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:21: in function 'TestToto.test1_withFailure']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test2_withFailure" time="0.000">
+ <failure type="example_with_luaunit.lua:30: expected: &quot;bof&quot;
+actual: &quot;hop&quot;">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:30: in function 'TestToto.test2_withFailure']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test3" time="0.000">
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test4" time="0.000">
+ <failure type="example_with_luaunit.lua:43: Received the not expected value: 1">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:43: in function 'TestToto.test4']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test5" time="0.000">
+ <failure type="example_with_luaunit.lua:49: expected: false or nil, actual: 1">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:49: in function 'TestToto.test5']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test6" time="0.000">
+ <failure type="example_with_luaunit.lua:57: expected: false, actual: nil">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:57: in function 'TestToto.test6']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test7" time="0.000">
+ <failure type="example_with_luaunit.lua:63: expected: {1, 2, three=3}
+actual: {1, 2}">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:63: in function 'TestToto.test7']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test8a" time="0.000">
+ <error type="example_with_luaunit.lua:81: Bouhouhoum error!">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:81: in function 'funcWithError'
+ example_with_luaunit.lua:68: in function 'TestToto.test8a']]></error>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test8b" time="0.000">
+ <error type="example_with_luaunit.lua:81: Bouhouhoum error!">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:81: in function 'funcWithError'
+ example_with_luaunit.lua:77: in function 'funcWithFuncWithError'
+ example_with_luaunit.lua:73: in function 'TestToto.test8b']]></error>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test_skipped" time="0.000">
+ <skipped>Test is skipped because ...</skipped>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="test1_withAssertionError" time="0.000">
+ <error type="example_with_luaunit.lua:134: assertion failed!">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:134: in function 'test1_withAssertionError']]></error>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="test2_withAssertionError" time="0.000">
+ <error type="example_with_luaunit.lua:140: assertion failed!">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:140: in function 'test2_withAssertionError']]></error>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="test3" time="0.000">
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
diff --git a/Data/Libraries/luaunit/test/ref/exampleXmlQuiet.txt b/Data/Libraries/luaunit/test/ref/exampleXmlQuiet.txt
new file mode 100644
index 0000000..171688a
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/exampleXmlQuiet.txt
@@ -0,0 +1,36 @@
+# XML output to test/ref/exampleXmlQuiet.xml
+# Started on 04/28/19 21:02:44
+# Starting class: TestTiti
+# Starting test: TestTiti.test1_withFailure
+# Failure: example_with_luaunit.lua:109: expected: 2, actual: 1
+# Starting test: TestTiti.test2_withFailure
+# Failure: example_with_luaunit.lua:118: expected: "bof"
+# actual: "hop"
+# Starting test: TestTiti.test3
+# Starting class: TestToto
+# Starting test: TestToto.test1_withFailure
+# Failure: example_with_luaunit.lua:21: expected: 2, actual: 1
+# Starting test: TestToto.test2_withFailure
+# Failure: example_with_luaunit.lua:30: expected: "bof"
+# actual: "hop"
+# Starting test: TestToto.test3
+# Starting test: TestToto.test4
+# Failure: example_with_luaunit.lua:43: Received the not expected value: 1
+# Starting test: TestToto.test5
+# Failure: example_with_luaunit.lua:49: expected: false or nil, actual: 1
+# Starting test: TestToto.test6
+# Failure: example_with_luaunit.lua:57: expected: false, actual: nil
+# Starting test: TestToto.test7
+# Failure: example_with_luaunit.lua:63: expected: {1, 2, three=3}
+# actual: {1, 2}
+# Starting test: TestToto.test8a
+# Error: example_with_luaunit.lua:81: Bouhouhoum error!
+# Starting test: TestToto.test8b
+# Error: example_with_luaunit.lua:81: Bouhouhoum error!
+# Starting test: TestToto.test_skipped
+# Starting test: test1_withAssertionError
+# Error: example_with_luaunit.lua:134: assertion failed!
+# Starting test: test2_withAssertionError
+# Error: example_with_luaunit.lua:140: assertion failed!
+# Starting test: test3
+# Ran 15 tests in 0.000 seconds, 3 successes, 8 failures, 4 errors, 1 skipped
diff --git a/Data/Libraries/luaunit/test/ref/exampleXmlQuiet.xml b/Data/Libraries/luaunit/test/ref/exampleXmlQuiet.xml
new file mode 100644
index 0000000..9f8fbcf
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/exampleXmlQuiet.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="15" timestamp="2019-04-28T21:02:44" time="0.000" errors="4" failures="8" skipped="1">
+ <properties>
+ <property name="Lua Version" value="Lua 5.4"/>
+ <property name="LuaUnit Version" value="3.4"/>
+ </properties>
+ <testcase classname="TestTiti" name="TestTiti.test1_withFailure" time="0.000">
+ <failure type="example_with_luaunit.lua:109: expected: 2, actual: 1">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:109: in function 'TestTiti.test1_withFailure']]></failure>
+ </testcase>
+ <testcase classname="TestTiti" name="TestTiti.test2_withFailure" time="0.000">
+ <failure type="example_with_luaunit.lua:118: expected: &quot;bof&quot;
+actual: &quot;hop&quot;">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:118: in function 'TestTiti.test2_withFailure']]></failure>
+ </testcase>
+ <testcase classname="TestTiti" name="TestTiti.test3" time="0.000">
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test1_withFailure" time="0.000">
+ <failure type="example_with_luaunit.lua:21: expected: 2, actual: 1">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:21: in function 'TestToto.test1_withFailure']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test2_withFailure" time="0.000">
+ <failure type="example_with_luaunit.lua:30: expected: &quot;bof&quot;
+actual: &quot;hop&quot;">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:30: in function 'TestToto.test2_withFailure']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test3" time="0.000">
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test4" time="0.000">
+ <failure type="example_with_luaunit.lua:43: Received the not expected value: 1">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:43: in function 'TestToto.test4']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test5" time="0.000">
+ <failure type="example_with_luaunit.lua:49: expected: false or nil, actual: 1">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:49: in function 'TestToto.test5']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test6" time="0.000">
+ <failure type="example_with_luaunit.lua:57: expected: false, actual: nil">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:57: in function 'TestToto.test6']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test7" time="0.000">
+ <failure type="example_with_luaunit.lua:63: expected: {1, 2, three=3}
+actual: {1, 2}">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:63: in function 'TestToto.test7']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test8a" time="0.000">
+ <error type="example_with_luaunit.lua:81: Bouhouhoum error!">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:81: in function 'funcWithError'
+ example_with_luaunit.lua:68: in function 'TestToto.test8a']]></error>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test8b" time="0.000">
+ <error type="example_with_luaunit.lua:81: Bouhouhoum error!">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:81: in function 'funcWithError'
+ example_with_luaunit.lua:77: in function 'funcWithFuncWithError'
+ example_with_luaunit.lua:73: in function 'TestToto.test8b']]></error>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test_skipped" time="0.000">
+ <skipped>Test is skipped because ...</skipped>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="test1_withAssertionError" time="0.000">
+ <error type="example_with_luaunit.lua:134: assertion failed!">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:134: in function 'test1_withAssertionError']]></error>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="test2_withAssertionError" time="0.000">
+ <error type="example_with_luaunit.lua:140: assertion failed!">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:140: in function 'test2_withAssertionError']]></error>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="test3" time="0.000">
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
diff --git a/Data/Libraries/luaunit/test/ref/exampleXmlVerbose.txt b/Data/Libraries/luaunit/test/ref/exampleXmlVerbose.txt
new file mode 100644
index 0000000..1b6410b
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/exampleXmlVerbose.txt
@@ -0,0 +1,36 @@
+# XML output to test/ref/exampleXmlVerbose.xml
+# Started on 04/28/19 21:02:44
+# Starting class: TestTiti
+# Starting test: TestTiti.test1_withFailure
+# Failure: example_with_luaunit.lua:109: expected: 2, actual: 1
+# Starting test: TestTiti.test2_withFailure
+# Failure: example_with_luaunit.lua:118: expected: "bof"
+# actual: "hop"
+# Starting test: TestTiti.test3
+# Starting class: TestToto
+# Starting test: TestToto.test1_withFailure
+# Failure: example_with_luaunit.lua:21: expected: 2, actual: 1
+# Starting test: TestToto.test2_withFailure
+# Failure: example_with_luaunit.lua:30: expected: "bof"
+# actual: "hop"
+# Starting test: TestToto.test3
+# Starting test: TestToto.test4
+# Failure: example_with_luaunit.lua:43: Received the not expected value: 1
+# Starting test: TestToto.test5
+# Failure: example_with_luaunit.lua:49: expected: false or nil, actual: 1
+# Starting test: TestToto.test6
+# Failure: example_with_luaunit.lua:57: expected: false, actual: nil
+# Starting test: TestToto.test7
+# Failure: example_with_luaunit.lua:63: expected: {1, 2, three=3}
+# actual: {1, 2}
+# Starting test: TestToto.test8a
+# Error: example_with_luaunit.lua:81: Bouhouhoum error!
+# Starting test: TestToto.test8b
+# Error: example_with_luaunit.lua:81: Bouhouhoum error!
+# Starting test: TestToto.test_skipped
+# Starting test: test1_withAssertionError
+# Error: example_with_luaunit.lua:134: assertion failed!
+# Starting test: test2_withAssertionError
+# Error: example_with_luaunit.lua:140: assertion failed!
+# Starting test: test3
+# Ran 15 tests in 0.010 seconds, 3 successes, 8 failures, 4 errors, 1 skipped
diff --git a/Data/Libraries/luaunit/test/ref/exampleXmlVerbose.xml b/Data/Libraries/luaunit/test/ref/exampleXmlVerbose.xml
new file mode 100644
index 0000000..7687c45
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/exampleXmlVerbose.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="15" timestamp="2019-04-28T21:02:44" time="0.010" errors="4" failures="8" skipped="1">
+ <properties>
+ <property name="Lua Version" value="Lua 5.4"/>
+ <property name="LuaUnit Version" value="3.4"/>
+ </properties>
+ <testcase classname="TestTiti" name="TestTiti.test1_withFailure" time="0.000">
+ <failure type="example_with_luaunit.lua:109: expected: 2, actual: 1">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:109: in function 'TestTiti.test1_withFailure']]></failure>
+ </testcase>
+ <testcase classname="TestTiti" name="TestTiti.test2_withFailure" time="0.000">
+ <failure type="example_with_luaunit.lua:118: expected: &quot;bof&quot;
+actual: &quot;hop&quot;">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:118: in function 'TestTiti.test2_withFailure']]></failure>
+ </testcase>
+ <testcase classname="TestTiti" name="TestTiti.test3" time="0.000">
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test1_withFailure" time="0.000">
+ <failure type="example_with_luaunit.lua:21: expected: 2, actual: 1">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:21: in function 'TestToto.test1_withFailure']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test2_withFailure" time="0.000">
+ <failure type="example_with_luaunit.lua:30: expected: &quot;bof&quot;
+actual: &quot;hop&quot;">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:30: in function 'TestToto.test2_withFailure']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test3" time="0.000">
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test4" time="0.000">
+ <failure type="example_with_luaunit.lua:43: Received the not expected value: 1">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:43: in function 'TestToto.test4']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test5" time="0.000">
+ <failure type="example_with_luaunit.lua:49: expected: false or nil, actual: 1">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:49: in function 'TestToto.test5']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test6" time="0.000">
+ <failure type="example_with_luaunit.lua:57: expected: false, actual: nil">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:57: in function 'TestToto.test6']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test7" time="0.000">
+ <failure type="example_with_luaunit.lua:63: expected: {1, 2, three=3}
+actual: {1, 2}">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:63: in function 'TestToto.test7']]></failure>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test8a" time="0.000">
+ <error type="example_with_luaunit.lua:81: Bouhouhoum error!">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:81: in function 'funcWithError'
+ example_with_luaunit.lua:68: in function 'TestToto.test8a']]></error>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test8b" time="0.000">
+ <error type="example_with_luaunit.lua:81: Bouhouhoum error!">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:81: in function 'funcWithError'
+ example_with_luaunit.lua:77: in function 'funcWithFuncWithError'
+ example_with_luaunit.lua:73: in function 'TestToto.test8b']]></error>
+ </testcase>
+ <testcase classname="TestToto" name="TestToto.test_skipped" time="0.000">
+ <skipped>Test is skipped because ...</skipped>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="test1_withAssertionError" time="0.000">
+ <error type="example_with_luaunit.lua:134: assertion failed!">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:134: in function 'test1_withAssertionError']]></error>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="test2_withAssertionError" time="0.000">
+ <error type="example_with_luaunit.lua:140: assertion failed!">
+ <![CDATA[stack traceback:
+ example_with_luaunit.lua:140: in function 'test2_withAssertionError']]></error>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="test3" time="0.000">
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
diff --git a/Data/Libraries/luaunit/test/ref/some_lists_comparisons.txt b/Data/Libraries/luaunit/test/ref/some_lists_comparisons.txt
new file mode 100644
index 0000000..414c5a7
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/some_lists_comparisons.txt
@@ -0,0 +1,844 @@
+Started on 11/08/16 21:28:53
+ TestListCompare.test1 ... FAIL
+test/some_lists_comparisons.lua:22: expected:
+{
+ 121221,
+ 122211,
+ 121221,
+ 122211,
+ 121221,
+ 122212,
+ 121212,
+ 122112,
+ 121221,
+ 121212,
+ 122121
+}
+actual:
+{
+ 121221,
+ 122211,
+ 121221,
+ 122211,
+ 121221,
+ 122212,
+ 121212,
+ 122112,
+ 122121,
+ 121212,
+ 122121
+}
+List difference analysis:
+* lists A (actual) and B (expected) have the same size
+* lists A and B start differing at index 9
+* lists A and B are equal again from index 10
+* Common parts:
+ = A[1], B[1]: 121221
+ = A[2], B[2]: 122211
+ = A[3], B[3]: 121221
+ = A[4], B[4]: 122211
+ = A[5], B[5]: 121221
+ = A[6], B[6]: 122212
+ = A[7], B[7]: 121212
+ = A[8], B[8]: 122112
+* Differing parts:
+ - A[9]: 122121
+ + B[9]: 121221
+* Common parts at the end of the lists
+ = A[10], B[10]: 121212
+ = A[11], B[11]: 122121
+ TestListCompare.test1b ... FAIL
+test/some_lists_comparisons.lua:28: expected:
+{
+ 121221,
+ 122211,
+ 121221,
+ 122112,
+ 121212,
+ 121122,
+ 121212,
+ 122122,
+ 121212,
+ 122112,
+ 121212
+}
+actual:
+{
+ 121221,
+ 122211,
+ 121221,
+ 122112,
+ 121212,
+ 121122,
+ 121212,
+ 122122,
+ 121212,
+ 122112,
+ 122112
+}
+List difference analysis:
+* lists A (actual) and B (expected) have the same size
+* lists A and B start differing at index 11
+* Common parts:
+ = A[1], B[1]: 121221
+ = A[2], B[2]: 122211
+ = A[3], B[3]: 121221
+ = A[4], B[4]: 122112
+ = A[5], B[5]: 121212
+ = A[6], B[6]: 121122
+ = A[7], B[7]: 121212
+ = A[8], B[8]: 122122
+ = A[9], B[9]: 121212
+ = A[10], B[10]: 122112
+* Differing parts:
+ - A[11]: 122112
+ + B[11]: 121212
+ TestListCompare.test1c ... FAIL
+test/some_lists_comparisons.lua:34: expected:
+{
+ 121212,
+ 122121,
+ 111212,
+ 122121,
+ 122121,
+ 121212,
+ 121121,
+ 121212,
+ 121221,
+ 122212,
+ 112121
+}
+actual:
+{
+ 122112,
+ 122121,
+ 111212,
+ 122121,
+ 122121,
+ 121212,
+ 121121,
+ 121212,
+ 121221,
+ 122212,
+ 112121
+}
+List difference analysis:
+* lists A (actual) and B (expected) have the same size
+* lists A and B start differing at index 1
+* lists A and B are equal again from index 2
+* Differing parts:
+ - A[1]: 122112
+ + B[1]: 121212
+* Common parts at the end of the lists
+ = A[2], B[2]: 122121
+ = A[3], B[3]: 111212
+ = A[4], B[4]: 122121
+ = A[5], B[5]: 122121
+ = A[6], B[6]: 121212
+ = A[7], B[7]: 121121
+ = A[8], B[8]: 121212
+ = A[9], B[9]: 121221
+ = A[10], B[10]: 122212
+ = A[11], B[11]: 112121
+ TestListCompare.test2 ... FAIL
+test/some_lists_comparisons.lua:43: expected: {1, 2, 3, 4, 5, 6, 8, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+actual: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+List difference analysis:
+* lists A (actual) and B (expected) have the same size
+* lists A and B start differing at index 7
+* lists A and B are equal again from index 9
+* Common parts:
+ = A[1], B[1]: 1
+ = A[2], B[2]: 2
+ = A[3], B[3]: 3
+ = A[4], B[4]: 4
+ = A[5], B[5]: 5
+ = A[6], B[6]: 6
+* Differing parts:
+ - A[7]: 7
+ + B[7]: 8
+ - A[8]: 8
+ + B[8]: 7
+* Common parts at the end of the lists
+ = A[9], B[9]: 9
+ = A[10], B[10]: 10
+ = A[11], B[11]: 11
+ = A[12], B[12]: 12
+ = A[13], B[13]: 13
+ = A[14], B[14]: 14
+ = A[15], B[15]: 15
+ = A[16], B[16]: 16
+ = A[17], B[17]: 17
+ = A[18], B[18]: 18
+ = A[19], B[19]: 19
+ = A[20], B[20]: 20
+ TestListCompare.test3 ... FAIL
+test/some_lists_comparisons.lua:57: expected: {1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+actual: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+List difference analysis:
+* list sizes differ: list A (actual) has 20 items, list B (expected) has 19 items
+* lists A and B start differing at index 7
+* lists A and B are equal again from index 8 for A, 7 for B
+* Common parts:
+ = A[1], B[1]: 1
+ = A[2], B[2]: 2
+ = A[3], B[3]: 3
+ = A[4], B[4]: 4
+ = A[5], B[5]: 5
+ = A[6], B[6]: 6
+* Present only in one list:
+ - A[7]: 7
+* Common parts at the end of the lists
+ = A[8], B[7]: 8
+ = A[9], B[8]: 9
+ = A[10], B[9]: 10
+ = A[11], B[10]: 11
+ = A[12], B[11]: 12
+ = A[13], B[12]: 13
+ = A[14], B[13]: 14
+ = A[15], B[14]: 15
+ = A[16], B[15]: 16
+ = A[17], B[16]: 17
+ = A[18], B[17]: 18
+ = A[19], B[18]: 19
+ = A[20], B[19]: 20
+ TestListCompare.test4 ... FAIL
+test/some_lists_comparisons.lua:74: expected: {1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+actual: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+List difference analysis:
+* list sizes differ: list A (actual) has 20 items, list B (expected) has 17 items
+* lists A and B start differing at index 7
+* lists A and B are equal again from index 10 for A, 7 for B
+* Common parts:
+ = A[1], B[1]: 1
+ = A[2], B[2]: 2
+ = A[3], B[3]: 3
+ = A[4], B[4]: 4
+ = A[5], B[5]: 5
+ = A[6], B[6]: 6
+* Present only in one list:
+ - A[7]: 7
+ - A[8]: 8
+ - A[9]: 9
+* Common parts at the end of the lists
+ = A[10], B[7]: 10
+ = A[11], B[8]: 11
+ = A[12], B[9]: 12
+ = A[13], B[10]: 13
+ = A[14], B[11]: 14
+ = A[15], B[12]: 15
+ = A[16], B[13]: 16
+ = A[17], B[14]: 17
+ = A[18], B[15]: 18
+ = A[19], B[16]: 19
+ = A[20], B[17]: 20
+ TestListCompare.test5a ... FAIL
+test/some_lists_comparisons.lua:98: expected: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+actual: {1, 2, 3, 4, 6, 5, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+List difference analysis:
+* list sizes differ: list A (expected) has 17 items, list B (actual) has 20 items
+* lists A and B start differing at index 5
+* lists A and B are equal again from index 7 for A, 10 for B
+* Common parts:
+ = A[1], B[1]: 1
+ = A[2], B[2]: 2
+ = A[3], B[3]: 3
+ = A[4], B[4]: 4
+* Differing parts:
+ - A[5]: 6
+ + B[5]: 5
+ - A[6]: 5
+ + B[6]: 6
+* Present only in one list:
+ + B[7]: 7
+ + B[8]: 8
+ + B[9]: 9
+* Common parts at the end of the lists
+ = A[7], B[10]: 10
+ = A[8], B[11]: 11
+ = A[9], B[12]: 12
+ = A[10], B[13]: 13
+ = A[11], B[14]: 14
+ = A[12], B[15]: 15
+ = A[13], B[16]: 16
+ = A[14], B[17]: 17
+ = A[15], B[18]: 18
+ = A[16], B[19]: 19
+ = A[17], B[20]: 20
+ TestListCompare.test5b ... FAIL
+test/some_lists_comparisons.lua:103: expected: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+actual: {1, 2, 3, 4, 6, 5, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+List difference analysis:
+* list sizes differ: list A (actual) has 17 items, list B (expected) has 20 items
+* lists A and B start differing at index 5
+* lists A and B are equal again from index 7 for A, 10 for B
+* Common parts:
+ = A[1], B[1]: 1
+ = A[2], B[2]: 2
+ = A[3], B[3]: 3
+ = A[4], B[4]: 4
+* Differing parts:
+ - A[5]: 6
+ + B[5]: 5
+ - A[6]: 5
+ + B[6]: 6
+* Present only in one list:
+ + B[7]: 7
+ + B[8]: 8
+ + B[9]: 9
+* Common parts at the end of the lists
+ = A[7], B[10]: 10
+ = A[8], B[11]: 11
+ = A[9], B[12]: 12
+ = A[10], B[13]: 13
+ = A[11], B[14]: 14
+ = A[12], B[15]: 15
+ = A[13], B[16]: 16
+ = A[14], B[17]: 17
+ = A[15], B[18]: 18
+ = A[16], B[19]: 19
+ = A[17], B[20]: 20
+ TestListCompare.test5c ... FAIL
+test/some_lists_comparisons.lua:109: expected: <table 01-00CF52E8> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+actual: <table 02-00CF5158> {1, 2, 3, 4, 6, 5, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+List difference analysis:
+* list sizes differ: list <table 02-00CF5158> A (actual) has 17 items, list <table 01-00CF52E8> B (expected) has 20 items
+* lists A and B start differing at index 5
+* lists A and B are equal again from index 7 for A, 10 for B
+* Common parts:
+ = A[1], B[1]: 1
+ = A[2], B[2]: 2
+ = A[3], B[3]: 3
+ = A[4], B[4]: 4
+* Differing parts:
+ - A[5]: 6
+ + B[5]: 5
+ - A[6]: 5
+ + B[6]: 6
+* Present only in one list:
+ + B[7]: 7
+ + B[8]: 8
+ + B[9]: 9
+* Common parts at the end of the lists
+ = A[7], B[10]: 10
+ = A[8], B[11]: 11
+ = A[9], B[12]: 12
+ = A[10], B[13]: 13
+ = A[11], B[14]: 14
+ = A[12], B[15]: 15
+ = A[13], B[16]: 16
+ = A[14], B[17]: 17
+ = A[15], B[18]: 18
+ = A[16], B[19]: 19
+ = A[17], B[20]: 20
+ TestListCompare.test6 ... FAIL
+test/some_lists_comparisons.lua:117: expected:
+{
+ "aaa",
+ "bbb",
+ "ccc",
+ function: 00E70160,
+ 1.1,
+ 2.1,
+ 8=true,
+ 9=false,
+ 10=thread: 00E35480,
+ 11=thread: 00E35480,
+ 12=thread: 00E35480
+}
+actual:
+{
+ "aaa",
+ "bbb",
+ "ccc",
+ function: 00E70160,
+ 1.1,
+ 2.1,
+ 8=false,
+ 9=false,
+ 10=thread: 00E35480,
+ 11=thread: 00E35480,
+ 12=thread: 00E35480
+}
+List difference analysis:
+* lists A (actual) and B (expected) have the same size
+* lists A and B start differing at index 8
+* lists A and B are equal again from index 9
+* Common parts:
+ = A[1], B[1]: "aaa"
+ = A[2], B[2]: "bbb"
+ = A[3], B[3]: "ccc"
+ = A[4], B[4]: function: 00E70160
+ = A[5], B[5]: 1.1
+ = A[6], B[6]: 2.1
+ = A[7], B[7]: nil
+* Differing parts:
+ - A[8]: false
+ + B[8]: true
+* Common parts at the end of the lists
+ = A[9], B[9]: false
+ = A[10], B[10]: thread: 00E35480
+ = A[11], B[11]: thread: 00E35480
+ = A[12], B[12]: thread: 00E35480
+ TestListCompare.test7 ... FAIL
+test/some_lists_comparisons.lua:123: expected: {{1, 2, 3}, {1, 2}, {{1}, {2}}, {"aa", "cc"}, 1, 2, 1.33, #Inf, {a=1}, {}}
+actual: {{1, 2, 3}, {1, 2}, {{2}, {2}}, {"aa", "bb"}, 1, 2, 1.33, #Inf, {a=1}, {}}
+List difference analysis:
+* lists A (actual) and B (expected) have the same size
+* lists A and B start differing at index 3
+* lists A and B are equal again from index 5
+* Common parts:
+ = A[1], B[1]: {1, 2, 3}
+ = A[2], B[2]: {1, 2}
+* Differing parts:
+ - A[3]: {{2}, {2}}
+ + B[3]: {{1}, {2}}
+ - A[4]: {"aa", "bb"}
+ + B[4]: {"aa", "cc"}
+* Common parts at the end of the lists
+ = A[5], B[5]: 1
+ = A[6], B[6]: 2
+ = A[7], B[7]: 1.33
+ = A[8], B[8]: #Inf
+ = A[9], B[9]: {a=1}
+ = A[10], B[10]: {}
+=========================================================
+Failed tests:
+-------------
+1) TestListCompare.test1
+test/some_lists_comparisons.lua:22: expected:
+{
+ 121221,
+ 122211,
+ 121221,
+ 122211,
+ 121221,
+ 122212,
+ 121212,
+ 122112,
+ 121221,
+ 121212,
+ 122121
+}
+actual:
+{
+ 121221,
+ 122211,
+ 121221,
+ 122211,
+ 121221,
+ 122212,
+ 121212,
+ 122112,
+ 122121,
+ 121212,
+ 122121
+}
+List difference analysis:
+* lists A (actual) and B (expected) have the same size
+* lists A and B start differing at index 9
+* lists A and B are equal again from index 10
+* Common parts:
+ = A[1], B[1]: 121221
+ = A[2], B[2]: 122211
+ = A[3], B[3]: 121221
+ = A[4], B[4]: 122211
+ = A[5], B[5]: 121221
+ = A[6], B[6]: 122212
+ = A[7], B[7]: 121212
+ = A[8], B[8]: 122112
+* Differing parts:
+ - A[9]: 122121
+ + B[9]: 121221
+* Common parts at the end of the lists
+ = A[10], B[10]: 121212
+ = A[11], B[11]: 122121
+stack traceback:
+ test/some_lists_comparisons.lua:22: in function 'TestListCompare.test1'
+
+2) TestListCompare.test1b
+test/some_lists_comparisons.lua:28: expected:
+{
+ 121221,
+ 122211,
+ 121221,
+ 122112,
+ 121212,
+ 121122,
+ 121212,
+ 122122,
+ 121212,
+ 122112,
+ 121212
+}
+actual:
+{
+ 121221,
+ 122211,
+ 121221,
+ 122112,
+ 121212,
+ 121122,
+ 121212,
+ 122122,
+ 121212,
+ 122112,
+ 122112
+}
+List difference analysis:
+* lists A (actual) and B (expected) have the same size
+* lists A and B start differing at index 11
+* Common parts:
+ = A[1], B[1]: 121221
+ = A[2], B[2]: 122211
+ = A[3], B[3]: 121221
+ = A[4], B[4]: 122112
+ = A[5], B[5]: 121212
+ = A[6], B[6]: 121122
+ = A[7], B[7]: 121212
+ = A[8], B[8]: 122122
+ = A[9], B[9]: 121212
+ = A[10], B[10]: 122112
+* Differing parts:
+ - A[11]: 122112
+ + B[11]: 121212
+stack traceback:
+ test/some_lists_comparisons.lua:28: in function 'TestListCompare.test1b'
+
+3) TestListCompare.test1c
+test/some_lists_comparisons.lua:34: expected:
+{
+ 121212,
+ 122121,
+ 111212,
+ 122121,
+ 122121,
+ 121212,
+ 121121,
+ 121212,
+ 121221,
+ 122212,
+ 112121
+}
+actual:
+{
+ 122112,
+ 122121,
+ 111212,
+ 122121,
+ 122121,
+ 121212,
+ 121121,
+ 121212,
+ 121221,
+ 122212,
+ 112121
+}
+List difference analysis:
+* lists A (actual) and B (expected) have the same size
+* lists A and B start differing at index 1
+* lists A and B are equal again from index 2
+* Differing parts:
+ - A[1]: 122112
+ + B[1]: 121212
+* Common parts at the end of the lists
+ = A[2], B[2]: 122121
+ = A[3], B[3]: 111212
+ = A[4], B[4]: 122121
+ = A[5], B[5]: 122121
+ = A[6], B[6]: 121212
+ = A[7], B[7]: 121121
+ = A[8], B[8]: 121212
+ = A[9], B[9]: 121221
+ = A[10], B[10]: 122212
+ = A[11], B[11]: 112121
+stack traceback:
+ test/some_lists_comparisons.lua:34: in function 'TestListCompare.test1c'
+
+4) TestListCompare.test2
+test/some_lists_comparisons.lua:43: expected: {1, 2, 3, 4, 5, 6, 8, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+actual: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+List difference analysis:
+* lists A (actual) and B (expected) have the same size
+* lists A and B start differing at index 7
+* lists A and B are equal again from index 9
+* Common parts:
+ = A[1], B[1]: 1
+ = A[2], B[2]: 2
+ = A[3], B[3]: 3
+ = A[4], B[4]: 4
+ = A[5], B[5]: 5
+ = A[6], B[6]: 6
+* Differing parts:
+ - A[7]: 7
+ + B[7]: 8
+ - A[8]: 8
+ + B[8]: 7
+* Common parts at the end of the lists
+ = A[9], B[9]: 9
+ = A[10], B[10]: 10
+ = A[11], B[11]: 11
+ = A[12], B[12]: 12
+ = A[13], B[13]: 13
+ = A[14], B[14]: 14
+ = A[15], B[15]: 15
+ = A[16], B[16]: 16
+ = A[17], B[17]: 17
+ = A[18], B[18]: 18
+ = A[19], B[19]: 19
+ = A[20], B[20]: 20
+stack traceback:
+ test/some_lists_comparisons.lua:43: in function 'TestListCompare.test2'
+
+5) TestListCompare.test3
+test/some_lists_comparisons.lua:57: expected: {1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+actual: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+List difference analysis:
+* list sizes differ: list A (actual) has 20 items, list B (expected) has 19 items
+* lists A and B start differing at index 7
+* lists A and B are equal again from index 8 for A, 7 for B
+* Common parts:
+ = A[1], B[1]: 1
+ = A[2], B[2]: 2
+ = A[3], B[3]: 3
+ = A[4], B[4]: 4
+ = A[5], B[5]: 5
+ = A[6], B[6]: 6
+* Present only in one list:
+ - A[7]: 7
+* Common parts at the end of the lists
+ = A[8], B[7]: 8
+ = A[9], B[8]: 9
+ = A[10], B[9]: 10
+ = A[11], B[10]: 11
+ = A[12], B[11]: 12
+ = A[13], B[12]: 13
+ = A[14], B[13]: 14
+ = A[15], B[14]: 15
+ = A[16], B[15]: 16
+ = A[17], B[16]: 17
+ = A[18], B[17]: 18
+ = A[19], B[18]: 19
+ = A[20], B[19]: 20
+stack traceback:
+ test/some_lists_comparisons.lua:57: in function 'TestListCompare.test3'
+
+6) TestListCompare.test4
+test/some_lists_comparisons.lua:74: expected: {1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+actual: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+List difference analysis:
+* list sizes differ: list A (actual) has 20 items, list B (expected) has 17 items
+* lists A and B start differing at index 7
+* lists A and B are equal again from index 10 for A, 7 for B
+* Common parts:
+ = A[1], B[1]: 1
+ = A[2], B[2]: 2
+ = A[3], B[3]: 3
+ = A[4], B[4]: 4
+ = A[5], B[5]: 5
+ = A[6], B[6]: 6
+* Present only in one list:
+ - A[7]: 7
+ - A[8]: 8
+ - A[9]: 9
+* Common parts at the end of the lists
+ = A[10], B[7]: 10
+ = A[11], B[8]: 11
+ = A[12], B[9]: 12
+ = A[13], B[10]: 13
+ = A[14], B[11]: 14
+ = A[15], B[12]: 15
+ = A[16], B[13]: 16
+ = A[17], B[14]: 17
+ = A[18], B[15]: 18
+ = A[19], B[16]: 19
+ = A[20], B[17]: 20
+stack traceback:
+ test/some_lists_comparisons.lua:74: in function 'TestListCompare.test4'
+
+7) TestListCompare.test5a
+test/some_lists_comparisons.lua:98: expected: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+actual: {1, 2, 3, 4, 6, 5, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+List difference analysis:
+* list sizes differ: list A (expected) has 17 items, list B (actual) has 20 items
+* lists A and B start differing at index 5
+* lists A and B are equal again from index 7 for A, 10 for B
+* Common parts:
+ = A[1], B[1]: 1
+ = A[2], B[2]: 2
+ = A[3], B[3]: 3
+ = A[4], B[4]: 4
+* Differing parts:
+ - A[5]: 6
+ + B[5]: 5
+ - A[6]: 5
+ + B[6]: 6
+* Present only in one list:
+ + B[7]: 7
+ + B[8]: 8
+ + B[9]: 9
+* Common parts at the end of the lists
+ = A[7], B[10]: 10
+ = A[8], B[11]: 11
+ = A[9], B[12]: 12
+ = A[10], B[13]: 13
+ = A[11], B[14]: 14
+ = A[12], B[15]: 15
+ = A[13], B[16]: 16
+ = A[14], B[17]: 17
+ = A[15], B[18]: 18
+ = A[16], B[19]: 19
+ = A[17], B[20]: 20
+stack traceback:
+ test/some_lists_comparisons.lua:98: in function 'TestListCompare.test5a'
+
+8) TestListCompare.test5b
+test/some_lists_comparisons.lua:103: expected: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+actual: {1, 2, 3, 4, 6, 5, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+List difference analysis:
+* list sizes differ: list A (actual) has 17 items, list B (expected) has 20 items
+* lists A and B start differing at index 5
+* lists A and B are equal again from index 7 for A, 10 for B
+* Common parts:
+ = A[1], B[1]: 1
+ = A[2], B[2]: 2
+ = A[3], B[3]: 3
+ = A[4], B[4]: 4
+* Differing parts:
+ - A[5]: 6
+ + B[5]: 5
+ - A[6]: 5
+ + B[6]: 6
+* Present only in one list:
+ + B[7]: 7
+ + B[8]: 8
+ + B[9]: 9
+* Common parts at the end of the lists
+ = A[7], B[10]: 10
+ = A[8], B[11]: 11
+ = A[9], B[12]: 12
+ = A[10], B[13]: 13
+ = A[11], B[14]: 14
+ = A[12], B[15]: 15
+ = A[13], B[16]: 16
+ = A[14], B[17]: 17
+ = A[15], B[18]: 18
+ = A[16], B[19]: 19
+ = A[17], B[20]: 20
+stack traceback:
+ test/some_lists_comparisons.lua:103: in function 'TestListCompare.test5b'
+
+9) TestListCompare.test5c
+test/some_lists_comparisons.lua:109: expected: <table 01-00CF52E8> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+actual: <table 02-00CF5158> {1, 2, 3, 4, 6, 5, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+List difference analysis:
+* list sizes differ: list <table 02-00CF5158> A (actual) has 17 items, list <table 01-00CF52E8> B (expected) has 20 items
+* lists A and B start differing at index 5
+* lists A and B are equal again from index 7 for A, 10 for B
+* Common parts:
+ = A[1], B[1]: 1
+ = A[2], B[2]: 2
+ = A[3], B[3]: 3
+ = A[4], B[4]: 4
+* Differing parts:
+ - A[5]: 6
+ + B[5]: 5
+ - A[6]: 5
+ + B[6]: 6
+* Present only in one list:
+ + B[7]: 7
+ + B[8]: 8
+ + B[9]: 9
+* Common parts at the end of the lists
+ = A[7], B[10]: 10
+ = A[8], B[11]: 11
+ = A[9], B[12]: 12
+ = A[10], B[13]: 13
+ = A[11], B[14]: 14
+ = A[12], B[15]: 15
+ = A[13], B[16]: 16
+ = A[14], B[17]: 17
+ = A[15], B[18]: 18
+ = A[16], B[19]: 19
+ = A[17], B[20]: 20
+stack traceback:
+ test/some_lists_comparisons.lua:109: in function 'TestListCompare.test5c'
+
+10) TestListCompare.test6
+test/some_lists_comparisons.lua:117: expected:
+{
+ "aaa",
+ "bbb",
+ "ccc",
+ function: 00E70160,
+ 1.1,
+ 2.1,
+ 8=true,
+ 9=false,
+ 10=thread: 00E35480,
+ 11=thread: 00E35480,
+ 12=thread: 00E35480
+}
+actual:
+{
+ "aaa",
+ "bbb",
+ "ccc",
+ function: 00E70160,
+ 1.1,
+ 2.1,
+ 8=false,
+ 9=false,
+ 10=thread: 00E35480,
+ 11=thread: 00E35480,
+ 12=thread: 00E35480
+}
+List difference analysis:
+* lists A (actual) and B (expected) have the same size
+* lists A and B start differing at index 8
+* lists A and B are equal again from index 9
+* Common parts:
+ = A[1], B[1]: "aaa"
+ = A[2], B[2]: "bbb"
+ = A[3], B[3]: "ccc"
+ = A[4], B[4]: function: 00E70160
+ = A[5], B[5]: 1.1
+ = A[6], B[6]: 2.1
+ = A[7], B[7]: nil
+* Differing parts:
+ - A[8]: false
+ + B[8]: true
+* Common parts at the end of the lists
+ = A[9], B[9]: false
+ = A[10], B[10]: thread: 00E35480
+ = A[11], B[11]: thread: 00E35480
+ = A[12], B[12]: thread: 00E35480
+stack traceback:
+ test/some_lists_comparisons.lua:117: in function 'TestListCompare.test6'
+
+11) TestListCompare.test7
+test/some_lists_comparisons.lua:123: expected: {{1, 2, 3}, {1, 2}, {{1}, {2}}, {"aa", "cc"}, 1, 2, 1.33, #Inf, {a=1}, {}}
+actual: {{1, 2, 3}, {1, 2}, {{2}, {2}}, {"aa", "bb"}, 1, 2, 1.33, #Inf, {a=1}, {}}
+List difference analysis:
+* lists A (actual) and B (expected) have the same size
+* lists A and B start differing at index 3
+* lists A and B are equal again from index 5
+* Common parts:
+ = A[1], B[1]: {1, 2, 3}
+ = A[2], B[2]: {1, 2}
+* Differing parts:
+ - A[3]: {{2}, {2}}
+ + B[3]: {{1}, {2}}
+ - A[4]: {"aa", "bb"}
+ + B[4]: {"aa", "cc"}
+* Common parts at the end of the lists
+ = A[5], B[5]: 1
+ = A[6], B[6]: 2
+ = A[7], B[7]: 1.33
+ = A[8], B[8]: #Inf
+ = A[9], B[9]: {a=1}
+ = A[10], B[10]: {}
+stack traceback:
+ test/some_lists_comparisons.lua:123: in function 'TestListCompare.test7'
+
+Ran 11 tests in 0.005 seconds, 0 successes, 11 failures
diff --git a/Data/Libraries/luaunit/test/ref/testWithXmlDefault.txt b/Data/Libraries/luaunit/test/ref/testWithXmlDefault.txt
new file mode 100644
index 0000000..c60800f
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/testWithXmlDefault.txt
@@ -0,0 +1,11 @@
+# XML output to test/ref/testWithXmlDefault.xml
+# Started on 04/28/19 21:05:11
+# Starting class: TestFailuresWithXml
+# Starting test: TestFailuresWithXml.test_failure_with_cdata_xml
+# Failure: test/test_with_xml.lua:13: expected: "got it"
+# actual: "cdata does not like ]]>"
+# Starting test: TestFailuresWithXml.test_failure_with_simple_xml
+# Failure: test/test_with_xml.lua:9: expected: "got it"
+# actual: '<toto>ti"ti</toto>'
+# Starting test: TestThatLastsALongTime
+# Ran 3 tests in 1.101 seconds, 1 success, 2 failures
diff --git a/Data/Libraries/luaunit/test/ref/testWithXmlDefault.xml b/Data/Libraries/luaunit/test/ref/testWithXmlDefault.xml
new file mode 100644
index 0000000..0ce8362
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/testWithXmlDefault.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="3" timestamp="2019-04-28T21:05:11" time="1.101" errors="0" failures="2" skipped="0">
+ <properties>
+ <property name="Lua Version" value="Lua 5.4"/>
+ <property name="LuaUnit Version" value="3.4"/>
+ </properties>
+ <testcase classname="TestFailuresWithXml" name="TestFailuresWithXml.test_failure_with_cdata_xml" time="0.000">
+ <failure type="test/test_with_xml.lua:13: expected: &quot;got it&quot;
+actual: &quot;cdata does not like ]]&gt;&quot;">
+ <![CDATA[stack traceback:
+ test/test_with_xml.lua:13: in function 'TestFailuresWithXml.test_failure_with_cdata_xml']]></failure>
+ </testcase>
+ <testcase classname="TestFailuresWithXml" name="TestFailuresWithXml.test_failure_with_simple_xml" time="0.000">
+ <failure type="test/test_with_xml.lua:9: expected: &quot;got it&quot;
+actual: &apos;&lt;toto&gt;ti&quot;ti&lt;/toto&gt;&apos;">
+ <![CDATA[stack traceback:
+ test/test_with_xml.lua:9: in function 'TestFailuresWithXml.test_failure_with_simple_xml']]></failure>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="TestThatLastsALongTime" time="0.000">
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
diff --git a/Data/Libraries/luaunit/test/ref/testWithXmlQuiet.txt b/Data/Libraries/luaunit/test/ref/testWithXmlQuiet.txt
new file mode 100644
index 0000000..f3ef77b
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/testWithXmlQuiet.txt
@@ -0,0 +1,11 @@
+# XML output to test/ref/testWithXmlQuiet.xml
+# Started on 04/28/19 21:05:13
+# Starting class: TestFailuresWithXml
+# Starting test: TestFailuresWithXml.test_failure_with_cdata_xml
+# Failure: test/test_with_xml.lua:13: expected: "got it"
+# actual: "cdata does not like ]]>"
+# Starting test: TestFailuresWithXml.test_failure_with_simple_xml
+# Failure: test/test_with_xml.lua:9: expected: "got it"
+# actual: '<toto>ti"ti</toto>'
+# Starting test: TestThatLastsALongTime
+# Ran 3 tests in 1.105 seconds, 1 success, 2 failures
diff --git a/Data/Libraries/luaunit/test/ref/testWithXmlQuiet.xml b/Data/Libraries/luaunit/test/ref/testWithXmlQuiet.xml
new file mode 100644
index 0000000..0a89946
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/testWithXmlQuiet.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="3" timestamp="2019-04-28T21:05:13" time="1.105" errors="0" failures="2" skipped="0">
+ <properties>
+ <property name="Lua Version" value="Lua 5.4"/>
+ <property name="LuaUnit Version" value="3.4"/>
+ </properties>
+ <testcase classname="TestFailuresWithXml" name="TestFailuresWithXml.test_failure_with_cdata_xml" time="0.000">
+ <failure type="test/test_with_xml.lua:13: expected: &quot;got it&quot;
+actual: &quot;cdata does not like ]]&gt;&quot;">
+ <![CDATA[stack traceback:
+ test/test_with_xml.lua:13: in function 'TestFailuresWithXml.test_failure_with_cdata_xml']]></failure>
+ </testcase>
+ <testcase classname="TestFailuresWithXml" name="TestFailuresWithXml.test_failure_with_simple_xml" time="0.000">
+ <failure type="test/test_with_xml.lua:9: expected: &quot;got it&quot;
+actual: &apos;&lt;toto&gt;ti&quot;ti&lt;/toto&gt;&apos;">
+ <![CDATA[stack traceback:
+ test/test_with_xml.lua:9: in function 'TestFailuresWithXml.test_failure_with_simple_xml']]></failure>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="TestThatLastsALongTime" time="0.000">
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
diff --git a/Data/Libraries/luaunit/test/ref/testWithXmlVerbose.txt b/Data/Libraries/luaunit/test/ref/testWithXmlVerbose.txt
new file mode 100644
index 0000000..8c0a529
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/testWithXmlVerbose.txt
@@ -0,0 +1,11 @@
+# XML output to test/ref/testWithXmlVerbose.xml
+# Started on 04/28/19 21:05:12
+# Starting class: TestFailuresWithXml
+# Starting test: TestFailuresWithXml.test_failure_with_cdata_xml
+# Failure: test/test_with_xml.lua:13: expected: "got it"
+# actual: "cdata does not like ]]>"
+# Starting test: TestFailuresWithXml.test_failure_with_simple_xml
+# Failure: test/test_with_xml.lua:9: expected: "got it"
+# actual: '<toto>ti"ti</toto>'
+# Starting test: TestThatLastsALongTime
+# Ran 3 tests in 1.101 seconds, 1 success, 2 failures
diff --git a/Data/Libraries/luaunit/test/ref/testWithXmlVerbose.xml b/Data/Libraries/luaunit/test/ref/testWithXmlVerbose.xml
new file mode 100644
index 0000000..2ba7668
--- /dev/null
+++ b/Data/Libraries/luaunit/test/ref/testWithXmlVerbose.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuites>
+ <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="3" timestamp="2019-04-28T21:05:12" time="1.101" errors="0" failures="2" skipped="0">
+ <properties>
+ <property name="Lua Version" value="Lua 5.4"/>
+ <property name="LuaUnit Version" value="3.4"/>
+ </properties>
+ <testcase classname="TestFailuresWithXml" name="TestFailuresWithXml.test_failure_with_cdata_xml" time="0.000">
+ <failure type="test/test_with_xml.lua:13: expected: &quot;got it&quot;
+actual: &quot;cdata does not like ]]&gt;&quot;">
+ <![CDATA[stack traceback:
+ test/test_with_xml.lua:13: in function 'TestFailuresWithXml.test_failure_with_cdata_xml']]></failure>
+ </testcase>
+ <testcase classname="TestFailuresWithXml" name="TestFailuresWithXml.test_failure_with_simple_xml" time="0.000">
+ <failure type="test/test_with_xml.lua:9: expected: &quot;got it&quot;
+actual: &apos;&lt;toto&gt;ti&quot;ti&lt;/toto&gt;&apos;">
+ <![CDATA[stack traceback:
+ test/test_with_xml.lua:9: in function 'TestFailuresWithXml.test_failure_with_simple_xml']]></failure>
+ </testcase>
+ <testcase classname="[TestFunctions]" name="TestThatLastsALongTime" time="0.000">
+ </testcase>
+ <system-out/>
+ <system-err/>
+ </testsuite>
+</testsuites>
diff --git a/Data/Libraries/luaunit/test/some_lists_comparisons.lua b/Data/Libraries/luaunit/test/some_lists_comparisons.lua
new file mode 100644
index 0000000..329190a
--- /dev/null
+++ b/Data/Libraries/luaunit/test/some_lists_comparisons.lua
@@ -0,0 +1,147 @@
+
+local lu = require('luaunit')
+
+local function range(start, stop)
+ -- return list of { start ... stop }
+ local i
+ local ret = {}
+ i=start
+ while i <= stop do
+ table.insert(ret, i)
+ i = i + 1
+ end
+ return ret
+end
+
+
+TestListCompare = {}
+
+ function TestListCompare:test1()
+ local A = { 121221, 122211, 121221, 122211, 121221, 122212, 121212, 122112, 122121, 121212, 122121 }
+ local B = { 121221, 122211, 121221, 122211, 121221, 122212, 121212, 122112, 121221, 121212, 122121 }
+ lu.assertEquals( A, B )
+ end
+
+ function TestListCompare:test1b()
+ local A = { 121221, 122211, 121221, 122112, 121212, 121122, 121212, 122122, 121212, 122112, 122112 }
+ local B = { 121221, 122211, 121221, 122112, 121212, 121122, 121212, 122122, 121212, 122112, 121212 }
+ lu.assertEquals( A, B )
+ end
+
+ function TestListCompare:test1c()
+ local A = { 122112, 122121, 111212, 122121, 122121, 121212, 121121, 121212, 121221, 122212, 112121 }
+ local B = { 121212, 122121, 111212, 122121, 122121, 121212, 121121, 121212, 121221, 122212, 112121 }
+ lu.assertEquals( A, B )
+ end
+
+
+ -- long list of numbers, same size, swapped values
+ function TestListCompare:test2()
+ local x=7
+ local A, B = range(1,20), range(1,20)
+ B[x], B[x+1] = B[x+1], B[x]
+ lu.assertEquals( A, B )
+ end
+
+ -- long list of numbers, one hole
+ function TestListCompare:test3()
+ local x=7
+ local A, B = range(1,20), {}
+ local i=1
+ while i <= #A do
+ if i ~= x then
+ table.insert( B, A[i] )
+ end
+ i = i + 1
+ end
+ lu.assertEquals( A, B )
+ end
+
+
+ -- long list of numbers, one bigger hole
+ function TestListCompare:test4()
+ local x=7
+ local x2=8
+ local x3=9
+ local A, B = range(1,20), {}
+ local i=1
+ while i <= #A do
+ if i ~= x and i ~= x2 and i ~= x3 then
+ table.insert( B, A[i] )
+ end
+ i = i + 1
+ end
+ lu.assertEquals( A, B )
+ end
+
+ -- long list, difference + big hole
+ function TestListCompare:sub_test5()
+ local x=7
+ local x2=8
+ local x3=9
+ local A, B = range(1,20), {}
+ local i=1
+ while i <= #A do
+ if i ~= x and i ~= x2 and i ~= x3 then
+ table.insert( B, A[i] )
+ end
+ i = i + 1
+ end
+ x = 5
+ B[x], B[x+1] = B[x+1], B[x]
+ return A, B
+ end
+
+ function TestListCompare:test5a()
+ local A, B = self:sub_test5()
+ lu.ORDER_ACTUAL_EXPECTED = false
+ lu.assertEquals( A, B )
+ end
+
+ function TestListCompare:test5b()
+ local A, B = self:sub_test5()
+ lu.assertEquals( B, A )
+ end
+
+ function TestListCompare:test5c()
+ local A, B = self :sub_test5()
+ lu.PRINT_TABLE_REF_IN_ERROR_MSG = true
+ lu.assertEquals( B, A )
+ end
+
+ function TestListCompare:test6()
+ local f1 = function () return nil end
+ local t1 = coroutine.create( function(v) local y=v+1 end )
+ local A = { 'aaa', 'bbb', 'ccc', f1, 1.1, 2.1, nil, true, false, t1, t1, t1 }
+ local B = { 'aaa', 'bbb', 'ccc', f1, 1.1, 2.1, nil, false, false, t1, t1, t1 }
+ lu.assertEquals( B, A )
+ end
+
+ function TestListCompare:test7()
+ local A = { {1,2,3}, {1,2}, { {1}, {2} }, { 'aa', 'cc'}, 1, 2, 1.33, 1/0, { a=1 }, {} }
+ local B = { {1,2,3}, {1,2}, { {2}, {2} }, { 'aa', 'bb'}, 1, 2, 1.33, 1/0, { a=1 }, {} }
+ lu.assertEquals( B, A )
+ end
+
+ function TestListCompare:tearDown()
+ -- cancel effect of test5a
+ lu.ORDER_ACTUAL_EXPECTED = true
+ -- cancel effect of test5c
+ lu.PRINT_TABLE_REF_IN_ERROR_MSG = false
+ end
+-- end TestListCompare
+
+--[[
+TestDictCompare = {}
+ function XTestDictCompare:test1()
+ lu.assertEquals( {one=1,two=2, three=3}, {one=1,two=1, three=3} )
+ end
+
+ function XTestDictCompare:test2()
+ lu.assertEquals( {one=1,two=2, three=3, four=4, five=5}, {one=1,two=1, three=3, four=4, five=5} )
+ end
+-- end TestDictCompare
+]]
+
+
+os.exit( lu.run() ) \ No newline at end of file
diff --git a/Data/Libraries/luaunit/test/test_luaunit.lua b/Data/Libraries/luaunit/test/test_luaunit.lua
new file mode 100644
index 0000000..10fa019
--- /dev/null
+++ b/Data/Libraries/luaunit/test/test_luaunit.lua
@@ -0,0 +1,4413 @@
+--[[
+Author: Philippe Fremy <phil@freehackers.org>
+License: BSD License, see LICENSE.txt
+]]--
+
+local TABLE_REF_PAT='table: 0?x?[%x]+'
+local TABLE_IDX_PAT='table %d%d'
+local TABLE_IDX_REF_PAT='table %d%d%-0?x?[%x]+'
+
+-- Return a function that appends its arguments to the `callInfo` table
+local function callRecorder( callInfo )
+ return function( ... )
+ for _, v in pairs({...}) do
+ table.insert( callInfo, v )
+ end
+ end
+end
+
+-- This is a bit tricky since the test uses the features that it tests.
+
+local function range(start, stop)
+ -- return list of { start ... stop }
+ local i
+ local ret = {}
+ i=start
+ while i <= stop do
+ table.insert(ret, i)
+ i = i + 1
+ end
+ return ret
+end
+
+
+local lu = require('luaunit')
+
+local Mock = { __class__ = 'Mock' }
+
+function Mock.new(runner)
+ local t = lu.genericOutput.new(runner)
+ t.calls = {}
+ local t_MT = {
+ __index = function( tab, key )
+ local callInfo = { key }
+ table.insert( tab.calls, callInfo )
+ return callRecorder( callInfo )
+ end
+ }
+ return setmetatable( t, t_MT )
+end
+
+
+TestMock = {}
+ function TestMock:testMock()
+ local m = Mock.new()
+ m.titi( 42 )
+ m.toto( 33, "abc", { 21} )
+ lu.assertEquals( m.calls[1][1], 'titi' )
+ lu.assertEquals( m.calls[1][2], 42 )
+ lu.assertEquals( #m.calls[1], 2 )
+
+ lu.assertEquals( m.calls[2][1], 'toto' )
+ lu.assertEquals( m.calls[2][2], 33 )
+ lu.assertEquals( m.calls[2][3], 'abc' )
+ lu.assertEquals( m.calls[2][4][1], 21 )
+ lu.assertEquals( #m.calls[2], 4 )
+
+ lu.assertEquals( #m.calls, 2 )
+ end
+
+------------------------------------------------------------------
+--
+-- Utility Tests
+--
+------------------------------------------------------------------
+
+TestLuaUnitUtilities = { __class__ = 'TestLuaUnitUtilities' }
+
+ function TestLuaUnitUtilities:setUp()
+ self.old_PRINT_TABLE_REF_IN_ERROR_MSG = lu.PRINT_TABLE_REF_IN_ERROR_MSG
+ end
+
+ function TestLuaUnitUtilities:tearDown()
+ lu.PRINT_TABLE_REF_IN_ERROR_MSG = self.old_PRINT_TABLE_REF_IN_ERROR_MSG
+ end
+
+ function TestLuaUnitUtilities:test_genSortedIndex()
+ lu.assertEquals( lu.private.__genSortedIndex( { 2, 5, 7} ), {1,2,3} )
+ lu.assertEquals( lu.private.__genSortedIndex( { a='1', h='2', c='3' } ), {'a', 'c', 'h'} )
+ lu.assertEquals( lu.private.__genSortedIndex( { 1, 'z', a='1', h='2', c='3' } ), { 1, 2, 'a', 'c', 'h' } )
+ lu.assertEquals( lu.private.__genSortedIndex( { b=4, a=3, true, foo="bar", nil, bar=false, 42, c=5 } ),
+ { 1, 3, 'a', 'b', 'bar', 'c', 'foo' } )
+ end
+
+ function TestLuaUnitUtilities:test_sortedNextWorks()
+ local t1 = {}
+ local _
+ t1['aaa'] = 'abc'
+ t1['ccc'] = 'def'
+ t1['bbb'] = 'cba'
+
+ -- mimic semantics of "generic for" loop
+ local sortedNext, state = lu.private.sortedPairs(t1)
+
+ local k, v = sortedNext( state, nil )
+ lu.assertEquals( k, 'aaa' )
+ lu.assertEquals( v, 'abc' )
+ k, v = sortedNext( state, k )
+ lu.assertEquals( k, 'bbb' )
+ lu.assertEquals( v, 'cba' )
+ k, v = sortedNext( state, k )
+ lu.assertEquals( k, 'ccc' )
+ lu.assertEquals( v, 'def' )
+ k, v = sortedNext( state, k )
+ lu.assertEquals( k, nil )
+ lu.assertEquals( v, nil )
+
+ -- check if starting the iteration a second time works
+ k, v = sortedNext( state, nil )
+ lu.assertEquals( k, 'aaa' )
+ lu.assertEquals( v, 'abc' )
+
+ -- run a generic for loop (internally using a separate state)
+ local tested = {}
+ for _, v in lu.private.sortedPairs(t1) do table.insert(tested, v) end
+ lu.assertEquals( tested, {'abc', 'cba', 'def'} )
+
+ -- test bisection algorithm by searching for non-existing key values
+ k, v = sortedNext( state, '' ) -- '' would come before any of the keys
+ lu.assertNil( k )
+ lu.assertNil( v )
+ k, v = sortedNext( state, 'xyz' ) -- 'xyz' would be after any other key
+ lu.assertNil( k )
+ lu.assertNil( v )
+
+ -- finally let's see if we successfully find an "out of sequence" key
+ k, v = sortedNext( state, 'bbb' )
+ lu.assertEquals( k, 'ccc' )
+ lu.assertEquals( v, 'def' )
+ end
+
+ function TestLuaUnitUtilities:test_sortedNextWorksOnTwoTables()
+ local t1 = { aaa = 'abc', ccc = 'def' }
+ local t2 = { ['3'] = '33', ['1'] = '11' }
+
+ local sortedNext, state1, state2, _
+ _, state1 = lu.private.sortedPairs(t1)
+ sortedNext, state2 = lu.private.sortedPairs(t2)
+
+ local k, v = sortedNext( state1, nil )
+ lu.assertEquals( k, 'aaa' )
+ lu.assertEquals( v, 'abc' )
+
+ k, v = sortedNext( state2, nil )
+ lu.assertEquals( k, '1' )
+ lu.assertEquals( v, '11' )
+
+ k, v = sortedNext( state1, 'aaa' )
+ lu.assertEquals( k, 'ccc' )
+ lu.assertEquals( v, 'def' )
+
+ k, v = sortedNext( state2, '1' )
+ lu.assertEquals( k, '3' )
+ lu.assertEquals( v, '33' )
+ end
+
+ function TestLuaUnitUtilities:test_randomizeTable()
+ local t, tref, n = {}, {}, 20
+ for i = 1, n do
+ t[i], tref[i] = i, i
+ end
+ lu.assertEquals( #t, n )
+
+ lu.private.randomizeTable( t )
+ lu.assertEquals( #t, n )
+ lu.assertNotEquals( t, tref)
+ table.sort(t)
+ lu.assertEquals( t, tref )
+ end
+
+ function TestLuaUnitUtilities:test_strSplitOneCharDelim()
+ local t = lu.private.strsplit( '\n', '122333' )
+ lu.assertEquals( t[1], '122333')
+ lu.assertEquals( #t, 1 )
+
+ local t = lu.private.strsplit( '\n', '1\n22\n333\n' )
+ lu.assertEquals( t[1], '1')
+ lu.assertEquals( t[2], '22')
+ lu.assertEquals( t[3], '333')
+ lu.assertEquals( t[4], '')
+ lu.assertEquals( #t, 4 )
+ -- test invalid (empty) delimiter
+ lu.assertErrorMsgContains('delimiter is nil or empty string!',
+ lu.private.strsplit, '', '1\n22\n333\n')
+ lu.assertErrorMsgContains('delimiter is nil or empty string!',
+ lu.private.strsplit, nil, '1\n22\n333\n')
+ end
+
+ function TestLuaUnitUtilities:test_strSplit3CharDelim()
+ local t = lu.private.strsplit( '2\n3', '1\n22\n332\n3' )
+ lu.assertEquals( t[1], '1\n2')
+ lu.assertEquals( t[2], '3')
+ lu.assertEquals( t[3], '')
+ lu.assertEquals( #t, 3 )
+ end
+
+ function TestLuaUnitUtilities:test_strSplitWithNil()
+ lu.assertEquals( nil, lu.private.strsplit('-', nil) )
+ end
+
+ function TestLuaUnitUtilities:test_protectedCall()
+ local function boom() error("Something went wrong.") end
+ local err = lu.LuaUnit:protectedCall(nil, boom, "kaboom")
+
+ -- check that err received the expected fields
+ lu.assertEquals(err.status, "ERROR")
+ lu.assertStrContains(err.msg, "Something went wrong.")
+ lu.assertStrMatches(err.trace, "^stack traceback:.*in %a+ 'kaboom'.*")
+ end
+
+ function TestLuaUnitUtilities:test_prefixString()
+ lu.assertEquals( lu.private.prefixString( '12 ', 'ab\ncd\nde'), '12 ab\n12 cd\n12 de' )
+ end
+
+ function TestLuaUnitUtilities:test_is_table_equals()
+ -- Make sure that _is_table_equals() doesn't fall for these traps
+ -- (See https://github.com/bluebird75/luaunit/issues/48)
+ local A, B, C = {}, {}, {}
+
+ A.self = A
+ B.self = B
+ lu.assertEquals(A, B)
+
+ A, B = {}, {}
+ A.circular = C
+ B.circular = A
+ C.circular = B
+ lu.assertEquals(A, B)
+ lu.assertEquals(B, C)
+ lu.assertEquals(C, A)
+
+ A = {}
+ A[{}] = A
+ lu.assertEquals( A, A )
+
+ A = {}
+ A[A] = 1
+ lu.assertEquals( A, A )
+ end
+
+ function TestLuaUnitUtilities:test_suitableForMismatchFormatting()
+ lu.assertFalse( lu.private.tryMismatchFormatting( {1,2}, {2,1} ) )
+ lu.assertFalse( lu.private.tryMismatchFormatting( nil, { 1,2,3} ) )
+ lu.assertFalse( lu.private.tryMismatchFormatting( {1,2,3}, {} ) )
+ lu.assertFalse( lu.private.tryMismatchFormatting( "123", "123" ) )
+ lu.assertFalse( lu.private.tryMismatchFormatting( "123", "123" ) )
+ lu.assertFalse( lu.private.tryMismatchFormatting( {'a','b','c'}, {'c', 'b', 'a'} ))
+ lu.assertFalse( lu.private.tryMismatchFormatting( {1,2,3, toto='titi'}, {1,2,3, toto='tata', tutu="bloup" } ) )
+ lu.assertFalse( lu.private.tryMismatchFormatting( {1,2,3, [5]=1000}, {1,2,3} ) )
+
+ local i=0
+ local l1, l2={}, {}
+ while i <= lu.LIST_DIFF_ANALYSIS_THRESHOLD+1 do
+ i = i + 1
+ table.insert( l1, i )
+ table.insert( l2, i+1 )
+ end
+
+ lu.assertTrue( lu.private.tryMismatchFormatting( l1, l2 ) )
+ end
+
+
+ function TestLuaUnitUtilities:test_diffAnalysisThreshold()
+ local threshold = lu.LIST_DIFF_ANALYSIS_THRESHOLD
+ lu.assertFalse( lu.private.tryMismatchFormatting( range(1,threshold-1), range(1,threshold-2), lu.DEFAULT_DEEP_ANALYSIS ) )
+ lu.assertTrue( lu.private.tryMismatchFormatting( range(1,threshold), range(1,threshold), lu.DEFAULT_DEEP_ANALYSIS ) )
+
+ lu.assertFalse( lu.private.tryMismatchFormatting( range(1,threshold-1), range(1,threshold-2), lu.DISABLE_DEEP_ANALYSIS ) )
+ lu.assertFalse( lu.private.tryMismatchFormatting( range(1,threshold), range(1,threshold), lu.DISABLE_DEEP_ANALYSIS ) )
+
+ lu.assertTrue( lu.private.tryMismatchFormatting( range(1,threshold-1), range(1,threshold-2), lu.FORCE_DEEP_ANALYSIS ) )
+ lu.assertTrue( lu.private.tryMismatchFormatting( range(1,threshold), range(1,threshold), lu.FORCE_DEEP_ANALYSIS ) )
+ end
+
+ function TestLuaUnitUtilities:test_table_ref_default()
+ local unknown_table_idx = 'table 00%-unknown ref'
+
+ local ts = function(t) return t[1]..t[2] end
+ local t1 = {'1','2'}
+ lu.assertStrMatches( tostring(t1), TABLE_REF_PAT )
+ lu.assertStrMatches( lu.private.table_ref(t1), TABLE_IDX_PAT )
+
+ local mt = { __tostring = ts }
+ setmetatable( t1, mt )
+ lu.assertStrMatches( tostring(t1), '12' )
+ lu.assertStrMatches( lu.private.table_ref(t1), TABLE_IDX_PAT )
+
+ -- how does it deal with protected metatable ?
+ -- metatable, obviously protected
+ local t1 = setmetatable( { 1, 2 }, { __metatable="private" } )
+ lu.assertStrMatches( lu.private.table_ref(t1), TABLE_IDX_PAT )
+
+ -- metatable, protected but still returns a table so more difficult to catch
+ local t1 = setmetatable( { 1, 2 }, { __metatable={ "private" } } )
+ lu.assertStrMatches( lu.private.table_ref(t1), TABLE_IDX_PAT )
+
+ -- protected metatable + __tostring, no way to get references
+ local t1 = setmetatable( { 1, 2 }, { __metatable="private", __tostring=ts } )
+ lu.assertStrMatches( lu.private.table_ref(t1), unknown_table_idx )
+
+ local t1 = setmetatable( { 1, 2 }, { __metatable={ "private" }, __tostring=ts } )
+ lu.assertStrMatches( lu.private.table_ref(t1), unknown_table_idx )
+ end
+
+ function TestLuaUnitUtilities:test_table_ref_print_ref()
+ local unknown_table_ref = 'table 00%-unknown ref'
+
+ lu.PRINT_TABLE_REF_IN_ERROR_MSG = true
+ local ts = function(t) return t[1]..t[2] end
+ local t1 = {'1','2'}
+ lu.assertStrMatches( tostring(t1), TABLE_REF_PAT )
+ lu.assertStrMatches( lu.private.table_ref(t1), 'table %d%d%-0?x?[%x]+' )
+
+ local mt = { __tostring = ts }
+ setmetatable( t1, mt )
+ lu.assertStrMatches( tostring(t1), '12' )
+ lu.assertStrMatches( lu.private.table_ref(t1), 'table %d%d%-0?x?[%x]+' )
+
+ -- how does it deal with protected metatable ?
+ -- metatable, obviously protected
+ local t1 = setmetatable( { 1, 2 }, { __metatable="private" } )
+ lu.assertStrMatches( lu.private.table_ref(t1), 'table %d%d%-0?x?[%x]+' )
+
+ -- metatable, protected but still returns a table so more difficult to catch
+ local t1 = setmetatable( { 1, 2 }, { __metatable={ "private" } } )
+ lu.assertStrMatches( lu.private.table_ref(t1), 'table %d%d%-0?x?[%x]+' )
+
+ -- protected metatable + __tostring, no way to get references
+ local t1 = setmetatable( { 1, 2 }, { __metatable="private", __tostring=ts } )
+ lu.assertStrMatches( lu.private.table_ref(t1), unknown_table_ref )
+
+ local t1 = setmetatable( { 1, 2 }, { __metatable={ "private" }, __tostring=ts } )
+ lu.assertStrMatches( lu.private.table_ref(t1), unknown_table_ref )
+ end
+
+ function TestLuaUnitUtilities:test_prettystr_numbers()
+ lu.assertEquals( lu.prettystr( 1 ), "1" )
+ if lu._LUAVERSION < 'Lua 5.4' or lu._LUAVERSION:sub(1,6) == "LuaJIT" then
+ lu.assertEquals( lu.prettystr( 1 ), "1" )
+ lu.assertEquals( lu.prettystr( 1.0 ), "1" )
+ else
+ lu.assertEquals( lu.prettystr( 1 ), "1" )
+ lu.assertEquals( lu.prettystr( 1.0 ), "1.0" )
+ end
+ lu.assertEquals( lu.prettystr( 1.1 ), "1.1" )
+ lu.assertEquals( lu.prettystr( 1/0 ), "#Inf" )
+ lu.assertEquals( lu.prettystr( -1/0 ), "-#Inf" )
+ lu.assertEquals( lu.prettystr( 0/0 ), "#NaN" )
+ end
+
+ function TestLuaUnitUtilities:test_prettystr_strings()
+ lu.assertEquals( lu.prettystr( 'abc' ), '"abc"' )
+ lu.assertEquals( lu.prettystr( 'ab\ncd' ), '"ab\ncd"' )
+ lu.assertEquals( lu.prettystr( 'ab"cd' ), "'ab\"cd'" )
+ lu.assertEquals( lu.prettystr( "ab'cd" ), '"ab\'cd"' )
+ end
+
+ function TestLuaUnitUtilities:test_prettystr_tables1()
+ lu.assertEquals( lu.prettystr( {1,2,3} ), "{1, 2, 3}" )
+ lu.assertEquals( lu.prettystr( {a=1,bb=2,ab=3} ), '{a=1, ab=3, bb=2}' )
+ lu.assertEquals( lu.prettystr( { [{}] = 1 }), '{{}=1}' )
+ lu.assertEquals( lu.prettystr( { 1, [{}] = 1, 2 }), '{1, 2, {}=1}' )
+ lu.assertEquals( lu.prettystr( { 1, [{one=1}] = 1, 2, "test", false }), '{1, 2, "test", false, {one=1}=1}' )
+ end
+
+ function TestLuaUnitUtilities:test_prettystr_tables2()
+ -- test the (private) key string formatting within _table_tostring()
+ lu.assertEquals( lu.prettystr( {a = 1} ), '{a=1}' )
+ lu.assertEquals( lu.prettystr( {a0 = 2} ), '{a0=2}' )
+ lu.assertEquals( lu.prettystr( {['a0!'] = 3} ), '{"a0!"=3}' )
+ lu.assertEquals( lu.prettystr( {["foo\nbar"] = 1}), [[{"foo
+bar"=1}]] )
+ lu.assertEquals( lu.prettystr( {["foo'bar"] = 2}), [[{"foo'bar"=2}]] )
+ lu.assertEquals( lu.prettystr( {['foo"bar'] = 3}), [[{'foo"bar'=3}]] )
+ end
+
+ function TestLuaUnitUtilities:test_prettystr_tables3()
+ -- test with a table containing a metatable for __tostring
+ local t1 = {'1','2'}
+ lu.assertStrMatches( tostring(t1), 'table: 0?x?[%x]+' )
+ lu.assertEquals( lu.prettystr(t1), '{"1", "2"}' )
+
+ -- add metatable
+ local function ts(t) return string.format( 'Point<%s,%s>', t[1], t[2] ) end
+ setmetatable( t1, { __tostring = ts } )
+
+ lu.assertEquals( tostring(t1), 'Point<1,2>' )
+ lu.assertEquals( lu.prettystr(t1), 'Point<1,2>' )
+
+ local function ts2(t)
+ return string.format( 'Point:\n x=%s\n y=%s', t[1], t[2] )
+ end
+
+ local t2 = {'1','2'}
+ setmetatable( t2, { __tostring = ts2 } )
+
+ lu.assertEquals( tostring(t2), [[Point:
+ x=1
+ y=2]] )
+ lu.assertEquals( lu.prettystr(t2), [[Point:
+ x=1
+ y=2]] )
+
+ -- nested table
+ local t3 = {'3', t1}
+ lu.assertEquals( lu.prettystr(t3), [[{"3", Point<1,2>}]] )
+
+ local t4 = {'3', t2}
+ lu.assertEquals( lu.prettystr(t4), [[{"3", Point:
+ x=1
+ y=2}]] )
+
+ local t5 = {1,2,{3,4},string.rep('W', lu.LINE_LENGTH), t2, 33}
+ lu.assertEquals( lu.prettystr(t5), [[{
+ 1,
+ 2,
+ {3, 4},
+ "]]..string.rep('W', lu.LINE_LENGTH)..[[",
+ Point:
+ x=1
+ y=2,
+ 33
+}]] )
+ end
+
+ function TestLuaUnitUtilities:test_prettystr_adv_tables()
+ local t1 = {1,2,3,4,5,6}
+ lu.assertEquals(lu.prettystr(t1), "{1, 2, 3, 4, 5, 6}" )
+
+ local t2 = {'aaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbb', 'ccccccccccccccccc', 'ddddddddddddd', 'eeeeeeeeeeeeeeeeee', 'ffffffffffffffff', 'ggggggggggg', 'hhhhhhhhhhhhhh'}
+ lu.assertEquals(lu.prettystr(t2), table.concat( {
+ '{',
+ ' "aaaaaaaaaaaaaaaaa",',
+ ' "bbbbbbbbbbbbbbbbbbbb",',
+ ' "ccccccccccccccccc",',
+ ' "ddddddddddddd",',
+ ' "eeeeeeeeeeeeeeeeee",',
+ ' "ffffffffffffffff",',
+ ' "ggggggggggg",',
+ ' "hhhhhhhhhhhhhh"',
+ '}',
+ } , '\n' ) )
+
+ lu.assertTrue( lu.private.hasNewLine( lu.prettystr(t2)) )
+
+ local t2bis = { 1,2,3,'12345678901234567890123456789012345678901234567890123456789012345678901234567890', 4,5,6 }
+ lu.assertEquals(lu.prettystr(t2bis), [[{
+ 1,
+ 2,
+ 3,
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ 4,
+ 5,
+ 6
+}]] )
+
+ local t3 = { l1a = { l2a = { l3a='012345678901234567890123456789012345678901234567890123456789' },
+ l2b='bbb' }, l1b = 4}
+ lu.assertEquals(lu.prettystr(t3), [[{
+ l1a={
+ l2a={l3a="012345678901234567890123456789012345678901234567890123456789"},
+ l2b="bbb"
+ },
+ l1b=4
+}]] )
+
+ local t4 = { a=1, b=2, c=3 }
+ lu.assertEquals(lu.prettystr(t4), '{a=1, b=2, c=3}' )
+
+ local t5 = { t1, t2, t3 }
+ lu.assertEquals( lu.prettystr(t5), [[{
+ {1, 2, 3, 4, 5, 6},
+ {
+ "aaaaaaaaaaaaaaaaa",
+ "bbbbbbbbbbbbbbbbbbbb",
+ "ccccccccccccccccc",
+ "ddddddddddddd",
+ "eeeeeeeeeeeeeeeeee",
+ "ffffffffffffffff",
+ "ggggggggggg",
+ "hhhhhhhhhhhhhh"
+ },
+ {
+ l1a={
+ l2a={l3a="012345678901234567890123456789012345678901234567890123456789"},
+ l2b="bbb"
+ },
+ l1b=4
+ }
+}]] )
+
+ local t6 = { t1=t1, t2=t2, t3=t3, t4=t4 }
+ lu.assertEquals(lu.prettystr(t6),[[{
+ t1={1, 2, 3, 4, 5, 6},
+ t2={
+ "aaaaaaaaaaaaaaaaa",
+ "bbbbbbbbbbbbbbbbbbbb",
+ "ccccccccccccccccc",
+ "ddddddddddddd",
+ "eeeeeeeeeeeeeeeeee",
+ "ffffffffffffffff",
+ "ggggggggggg",
+ "hhhhhhhhhhhhhh"
+ },
+ t3={
+ l1a={
+ l2a={l3a="012345678901234567890123456789012345678901234567890123456789"},
+ l2b="bbb"
+ },
+ l1b=4
+ },
+ t4={a=1, b=2, c=3}
+}]])
+ end
+
+ function TestLuaUnitUtilities:test_prettystrTableCycles()
+ local t = {}
+ t.__index = t
+ lu.assertStrMatches(lu.prettystr(t), "(<"..TABLE_IDX_PAT..">) {__index=%1}")
+
+ local t1 = {}
+ local t2 = {}
+ t1.t2 = t2
+ t2.t1 = t1
+ local t3 = { t1 = t1, t2 = t2 }
+ lu.assertStrMatches(lu.prettystr(t1), "(<"..TABLE_IDX_PAT..">) {t2=(<"..TABLE_IDX_PAT..">) {t1=%1}}")
+ lu.assertStrMatches(lu.prettystr(t3), "(<"..TABLE_IDX_PAT..">) {t1=(<"..TABLE_IDX_PAT..">) {t2=(<"..TABLE_IDX_PAT..">) {t1=%2}}, t2=%3}")
+
+ local t4 = {1,2}
+ local t5 = {3,4,t4}
+ t4[3] = t5
+ lu.assertStrMatches(lu.prettystr(t5), "(<"..TABLE_IDX_PAT..">) {3, 4, (<"..TABLE_IDX_PAT..">) {1, 2, %1}}")
+
+ local t6 = {}
+ t6[t6] = 1
+ lu.assertStrMatches(lu.prettystr(t6), "(<"..TABLE_IDX_PAT..">) {%1=1}" )
+
+ local t7, t8 = {"t7"}, {"t8"}
+ t7[t8] = 1
+ t8[t7] = 2
+ lu.assertStrMatches(lu.prettystr(t7), '(<'..TABLE_IDX_PAT..'>) {"t7", (<'..TABLE_IDX_PAT..'>) {"t8", %1=2}=1}')
+
+ local t9 = {"t9", {}}
+ t9[{t9}] = 1
+
+ lu.assertStrMatches(lu.prettystr(t9, true), '(<'..TABLE_IDX_PAT..'>) {\n?%s*"t9",\n?%s*(<'..TABLE_IDX_PAT..'>) {},\n?%s*(<'..TABLE_IDX_PAT..'>) {%1}=1\n?}')
+ end
+
+ function TestLuaUnitUtilities:test_prettystrPairs()
+ local foo, bar, str1, str2 = nil, nil
+
+ -- test all combinations of: foo = nil, "foo", "fo\no" (embedded
+ -- newline); and bar = nil, "bar", "bar\n" (trailing newline)
+
+ str1, str2 = lu.private.prettystrPairs(foo, bar)
+ lu.assertEquals(str1, "nil")
+ lu.assertEquals(str2, "nil")
+ str1, str2 = lu.private.prettystrPairs(foo, bar, "_A", "_B")
+ lu.assertEquals(str1, "nil_B")
+ lu.assertEquals(str2, "nil")
+
+ bar = "bar"
+ str1, str2 = lu.private.prettystrPairs(foo, bar)
+ lu.assertEquals(str1, "nil")
+ lu.assertEquals(str2, '"bar"')
+ str1, str2 = lu.private.prettystrPairs(foo, bar, "_A", "_B")
+ lu.assertEquals(str1, "nil_B")
+ lu.assertEquals(str2, '"bar"')
+
+ bar = "bar\n"
+ str1, str2 = lu.private.prettystrPairs(foo, bar)
+ lu.assertEquals(str1, "\nnil")
+ lu.assertEquals(str2, '\n"bar\n"')
+ str1, str2 = lu.private.prettystrPairs(foo, bar, "_A", "_B")
+ lu.assertEquals(str1, "\nnil_A")
+ lu.assertEquals(str2, '\n"bar\n"')
+
+ foo = "foo"
+ bar = nil
+ str1, str2 = lu.private.prettystrPairs(foo, bar)
+ lu.assertEquals(str1, '"foo"')
+ lu.assertEquals(str2, "nil")
+ str1, str2 = lu.private.prettystrPairs(foo, bar, "_A", "_B")
+ lu.assertEquals(str1, '"foo"_B')
+ lu.assertEquals(str2, "nil")
+
+ bar = "bar"
+ str1, str2 = lu.private.prettystrPairs(foo, bar)
+ lu.assertEquals(str1, '"foo"')
+ lu.assertEquals(str2, '"bar"')
+ str1, str2 = lu.private.prettystrPairs(foo, bar, "_A", "_B")
+ lu.assertEquals(str1, '"foo"_B')
+ lu.assertEquals(str2, '"bar"')
+
+ bar = "bar\n"
+ str1, str2 = lu.private.prettystrPairs(foo, bar)
+ lu.assertEquals(str1, '\n"foo"')
+ lu.assertEquals(str2, '\n"bar\n"')
+ str1, str2 = lu.private.prettystrPairs(foo, bar, "_A", "_B")
+ lu.assertEquals(str1, '\n"foo"_A')
+ lu.assertEquals(str2, '\n"bar\n"')
+
+ foo = "fo\no"
+ bar = nil
+ str1, str2 = lu.private.prettystrPairs(foo, bar)
+ lu.assertEquals(str1, '\n"fo\no"')
+ lu.assertEquals(str2, "\nnil")
+ str1, str2 = lu.private.prettystrPairs(foo, bar, "_A", "_B")
+ lu.assertEquals(str1, '\n"fo\no"_A')
+ lu.assertEquals(str2, "\nnil")
+
+ bar = "bar"
+ str1, str2 = lu.private.prettystrPairs(foo, bar)
+ lu.assertEquals(str1, '\n"fo\no"')
+ lu.assertEquals(str2, '\n"bar"')
+ str1, str2 = lu.private.prettystrPairs(foo, bar, "_A", "_B")
+ lu.assertEquals(str1, '\n"fo\no"_A')
+ lu.assertEquals(str2, '\n"bar"')
+
+ bar = "bar\n"
+ str1, str2 = lu.private.prettystrPairs(foo, bar)
+ lu.assertEquals(str1, '\n"fo\no"')
+ lu.assertEquals(str2, '\n"bar\n"')
+ str1, str2 = lu.private.prettystrPairs(foo, bar, "_A", "_B")
+ lu.assertEquals(str1, '\n"fo\no"_A')
+ lu.assertEquals(str2, '\n"bar\n"')
+ end
+
+ function TestLuaUnitUtilities:test_FailFmt()
+ -- raise failure from within nested functions
+ local function babar(level)
+ lu.private.fail_fmt(level, 'toto', "hex=%X", 123)
+ end
+ local function bar(level)
+ lu.private.fail_fmt(level, nil, "hex=%X", 123)
+ end
+ local function foo(level)
+ bar(level)
+ end
+
+ local _, err = pcall(foo) -- default level 1 = error position in bar()
+ local line1, prefix = err:match("test[\\/]test_luaunit%.lua:(%d+): (.*)hex=7B$")
+ lu.assertEquals(prefix, lu.FAILURE_PREFIX)
+ lu.assertNotNil(line1)
+
+ _, err = pcall(foo, 2) -- level 2 = error position within foo()
+ local line2
+ line2 , prefix = err:match("test[\\/]test_luaunit%.lua:(%d+): (.*)hex=7B$")
+ lu.assertEquals(prefix, lu.FAILURE_PREFIX)
+ lu.assertNotNil(line2)
+ -- make sure that "line2" position is exactly 3 lines after "line1"
+ lu.assertEquals(tonumber(line2), tonumber(line1) + 3)
+
+ _, err = pcall(babar, 1)
+ local _, prefix = err:match("test[\\/]test_luaunit%.lua:(%d+): (.*)hex=7B$")
+ lu.assertEquals(prefix, lu.FAILURE_PREFIX .. 'toto\n')
+
+ end
+
+ function TestLuaUnitUtilities:test_IsFunction()
+ -- previous LuaUnit.isFunction was superseded by LuaUnit.asFunction
+ -- (which can also serve as a boolean expression)
+ lu.assertNotNil( lu.LuaUnit.asFunction( function (v,y) end ) )
+ lu.assertNil( lu.LuaUnit.asFunction( nil ) )
+ lu.assertNil( lu.LuaUnit.asFunction( "not a function" ) )
+ end
+
+ function TestLuaUnitUtilities:test_splitClassMethod()
+ lu.assertEquals( lu.LuaUnit.splitClassMethod( 'toto' ), nil )
+ lu.assertEquals( {lu.LuaUnit.splitClassMethod( 'toto.titi' )},
+ {'toto', 'titi'} )
+ end
+
+ function TestLuaUnitUtilities:test_isTestName()
+ lu.assertEquals( lu.LuaUnit.isTestName( 'testToto' ), true )
+ lu.assertEquals( lu.LuaUnit.isTestName( 'TestToto' ), true )
+ lu.assertEquals( lu.LuaUnit.isTestName( 'TESTToto' ), true )
+ lu.assertEquals( lu.LuaUnit.isTestName( 'xTESTToto' ), false )
+ lu.assertEquals( lu.LuaUnit.isTestName( '' ), false )
+ end
+
+ function TestLuaUnitUtilities:test_parseCmdLine()
+ --test names
+ lu.assertEquals( lu.LuaUnit.parseCmdLine(), {} )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { 'someTest' } ), { testNames={'someTest'} } )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { 'someTest', 'someOtherTest' } ), { testNames={'someTest', 'someOtherTest'} } )
+
+ -- verbosity
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '--verbose' } ), { verbosity=lu.VERBOSITY_VERBOSE } )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '-v' } ), { verbosity=lu.VERBOSITY_VERBOSE } )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '--quiet' } ), { verbosity=lu.VERBOSITY_QUIET } )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '-q' } ), { verbosity=lu.VERBOSITY_QUIET } )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '-v', '-q' } ), { verbosity=lu.VERBOSITY_QUIET } )
+
+ --output
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '--output', 'toto' } ), { output='toto'} )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '-o', 'toto' } ), { output='toto'} )
+ lu.assertErrorMsgContains( 'Missing argument after -o', lu.LuaUnit.parseCmdLine, { '-o', } )
+
+ --name
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '--name', 'toto' } ), { fname='toto'} )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '-n', 'toto' } ), { fname='toto'} )
+ lu.assertErrorMsgContains( 'Missing argument after -n', lu.LuaUnit.parseCmdLine, { '-n', } )
+
+ --patterns
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '--pattern', 'toto' } ), { pattern={'toto'} } )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '-p', 'toto' } ), { pattern={'toto'} } )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '-p', 'titi', '-p', 'toto' } ), { pattern={'titi', 'toto'} } )
+ lu.assertErrorMsgContains( 'Missing argument after -p', lu.LuaUnit.parseCmdLine, { '-p', } )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '--exclude', 'toto' } ), { pattern={'!toto'} } )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '-x', 'toto' } ), { pattern={'!toto'} } )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '-x', 'titi', '-x', 'toto' } ), { pattern={'!titi', '!toto'} } )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '-x', 'titi', '-p', 'foo', '-x', 'toto' } ), { pattern={'!titi', 'foo', '!toto'} } )
+ lu.assertErrorMsgContains( 'Missing argument after -x', lu.LuaUnit.parseCmdLine, { '-x', } )
+
+ -- repeat
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '--repeat', '123' } ), { exeRepeat=123 } )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '-r', '123' } ), { exeRepeat=123 } )
+ lu.assertErrorMsgContains( 'Malformed -r argument', lu.LuaUnit.parseCmdLine, { '-r', 'bad' } )
+ lu.assertErrorMsgContains( 'Missing argument after -r', lu.LuaUnit.parseCmdLine, { '-r', } )
+
+ -- shuffle
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '--shuffle' } ), { shuffle=true } )
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '-s' } ), { shuffle=true } )
+
+ --megamix
+ lu.assertEquals( lu.LuaUnit.parseCmdLine( { '-p', 'toto', 'titi', '-v', 'tata', '-o', 'tintin', '-p', 'tutu', 'prout', '-n', 'toto.xml' } ),
+ { pattern={'toto', 'tutu'}, verbosity=lu.VERBOSITY_VERBOSE, output='tintin', testNames={'titi', 'tata', 'prout'}, fname='toto.xml' } )
+
+ lu.assertErrorMsgContains( 'option: -$', lu.LuaUnit.parseCmdLine, { '-$', } )
+ end
+
+ function TestLuaUnitUtilities:test_patternFilter()
+ lu.assertEquals( lu.private.patternFilter( nil, 'toto'), true )
+ lu.assertEquals( lu.private.patternFilter( {}, 'toto'), true )
+
+ -- positive pattern
+ lu.assertEquals( lu.private.patternFilter( {'toto'}, 'toto'), true )
+ lu.assertEquals( lu.private.patternFilter( {'toto'}, 'yyytotoxxx'), true )
+ lu.assertEquals( lu.private.patternFilter( {'titi', 'toto'}, 'yyytotoxxx'), true )
+ lu.assertEquals( lu.private.patternFilter( {'titi', 'toto'}, 'tutu'), false )
+ lu.assertEquals( lu.private.patternFilter( {'titi', 'to..'}, 'yyytoxxx'), true )
+
+ -- negative pattern
+ lu.assertEquals( lu.private.patternFilter( {'!toto'}, 'toto'), false )
+ lu.assertEquals( lu.private.patternFilter( {'!t.t.'}, 'titi'), false )
+ lu.assertEquals( lu.private.patternFilter( {'!toto'}, 'titi'), true )
+ lu.assertEquals( lu.private.patternFilter( {'!toto'}, 'yyytotoxxx'), false )
+ lu.assertEquals( lu.private.patternFilter( {'!titi', '!toto'}, 'yyytotoxxx'), false )
+ lu.assertEquals( lu.private.patternFilter( {'!titi', '!toto'}, 'tutu'), true )
+ lu.assertEquals( lu.private.patternFilter( {'!titi', '!to..'}, 'yyytoxxx'), false )
+
+ -- combine patterns
+ lu.assertEquals( lu.private.patternFilter( { 'foo' }, 'foo'), true )
+ lu.assertEquals( lu.private.patternFilter( { 'foo', '!foo' }, 'foo'), false )
+ lu.assertEquals( lu.private.patternFilter( { 'foo', '!foo', 'foo' }, 'foo'), true )
+ lu.assertEquals( lu.private.patternFilter( { 'foo', '!foo', 'foo', '!foo' }, 'foo'), false )
+
+ lu.assertEquals( lu.private.patternFilter( { '!foo' }, 'foo'), false )
+ lu.assertEquals( lu.private.patternFilter( { '!foo', 'foo' }, 'foo'), true )
+ lu.assertEquals( lu.private.patternFilter( { '!foo', 'foo', '!foo' }, 'foo'), false )
+ lu.assertEquals( lu.private.patternFilter( { '!foo', 'foo', '!foo', 'foo' }, 'foo'), true )
+
+ lu.assertEquals( lu.private.patternFilter( { 'f..', '!foo', '__foo__' }, 'toto'), false )
+ lu.assertEquals( lu.private.patternFilter( { 'f..', '!foo', '__foo__' }, 'fii'), true )
+ lu.assertEquals( lu.private.patternFilter( { 'f..', '!foo', '__foo__' }, 'foo'), false )
+ lu.assertEquals( lu.private.patternFilter( { 'f..', '!foo', '__foo__' }, '__foo__'), true )
+
+ lu.assertEquals( lu.private.patternFilter( { '!f..', 'foo', '!__foo__' }, 'toto'), false )
+ lu.assertEquals( lu.private.patternFilter( { '!f..', 'foo', '!__foo__' }, 'fii'), false )
+ lu.assertEquals( lu.private.patternFilter( { '!f..', 'foo', '!__foo__' }, 'foo'), true )
+ lu.assertEquals( lu.private.patternFilter( { '!f..', 'foo', '!__foo__' }, '__foo__'), false )
+ end
+
+ function TestLuaUnitUtilities:test_applyPatternFilter()
+ local dummy = function() end
+ local testset = {
+ { 'toto.foo', dummy}, { 'toto.bar', dummy},
+ { 'titi.foo', dummy}, { 'titi.bar', dummy},
+ { 'tata.foo', dummy}, { 'tata.bar', dummy},
+ { 'foo.bar', dummy}, { 'foobar.test', dummy},
+ }
+
+ -- default action: include everything
+ local included, excluded = lu.LuaUnit.applyPatternFilter( nil, testset )
+ lu.assertEquals( #included, 8 )
+ lu.assertEquals( excluded, {} )
+
+ -- single exclude pattern (= select anything not matching "bar")
+ included, excluded = lu.LuaUnit.applyPatternFilter( {'!bar'}, testset )
+ lu.assertEquals( included, {testset[1], testset[3], testset[5]} )
+ lu.assertEquals( #excluded, 5 )
+
+ -- single include pattern
+ included, excluded = lu.LuaUnit.applyPatternFilter( {'t.t.'}, testset )
+ lu.assertEquals( #included, 6 )
+ lu.assertEquals( excluded, {testset[7], testset[8]} )
+
+ -- single include and exclude patterns
+ included, excluded = lu.LuaUnit.applyPatternFilter( {'foo', '!test'}, testset )
+ lu.assertEquals( included, {testset[1], testset[3], testset[5], testset[7]} )
+ lu.assertEquals( #excluded, 4 )
+
+ -- multiple (specific) includes
+ included, excluded = lu.LuaUnit.applyPatternFilter( {'toto', 'titi'}, testset )
+ lu.assertEquals( included, {testset[1], testset[2], testset[3], testset[4]} )
+ lu.assertEquals( #excluded, 4 )
+
+ -- multiple excludes
+ included, excluded = lu.LuaUnit.applyPatternFilter( {'!tata', '!%.bar'}, testset )
+ lu.assertEquals( included, {testset[1], testset[3], testset[8]} )
+ lu.assertEquals( #excluded, 5 )
+
+ -- combined test
+ included, excluded = lu.LuaUnit.applyPatternFilter( {'t[oai]', 'bar$', 'test', '!%.b', '!titi'}, testset )
+ lu.assertEquals( included, {testset[1], testset[5], testset[8]} )
+ lu.assertEquals( #excluded, 5 )
+
+ --[[ Combining positive and negative filters ]]--
+ included, excluded = lu.LuaUnit.applyPatternFilter( {'foo', 'bar', '!t.t.', '%.bar'}, testset )
+ lu.assertEquals( included, {testset[2], testset[4], testset[6], testset[7], testset[8]} )
+ lu.assertEquals( #excluded, 3 )
+ end
+
+ function TestLuaUnitUtilities:test_strMatch()
+ lu.assertEquals( lu.private.strMatch('toto', 't.t.'), true )
+ lu.assertEquals( lu.private.strMatch('toto', 't.t.', 1, 4), true )
+ lu.assertEquals( lu.private.strMatch('toto', 't.t.', 2, 5), false )
+ lu.assertEquals( lu.private.strMatch('toto', '.t.t.'), false )
+ lu.assertEquals( lu.private.strMatch('ototo', 't.t.'), false )
+ lu.assertEquals( lu.private.strMatch('totot', 't.t.'), false )
+ lu.assertEquals( lu.private.strMatch('ototot', 't.t.'), false )
+ lu.assertEquals( lu.private.strMatch('ototot', 't.t.',2,3), false )
+ lu.assertEquals( lu.private.strMatch('ototot', 't.t.',2,5), true )
+ lu.assertEquals( lu.private.strMatch('ototot', 't.t.',2,6), false )
+ end
+
+ function TestLuaUnitUtilities:test_expandOneClass()
+ local result = {}
+ lu.LuaUnit.expandOneClass( result, 'titi', {} )
+ lu.assertEquals( result, {} )
+
+ result = {}
+ lu.LuaUnit.expandOneClass( result, 'MyTestToto1', MyTestToto1 )
+ lu.assertEquals( result, {
+ {'MyTestToto1.test1', MyTestToto1 },
+ {'MyTestToto1.test2', MyTestToto1 },
+ {'MyTestToto1.test3', MyTestToto1 },
+ {'MyTestToto1.testa', MyTestToto1 },
+ {'MyTestToto1.testb', MyTestToto1 },
+ } )
+ end
+
+ function TestLuaUnitUtilities:test_expandClasses()
+ local result
+ result = lu.LuaUnit.expandClasses( {} )
+ lu.assertEquals( result, {} )
+
+ result = lu.LuaUnit.expandClasses( { { 'MyTestFunction', MyTestFunction } } )
+ lu.assertEquals( result, { { 'MyTestFunction', MyTestFunction } } )
+
+ result = lu.LuaUnit.expandClasses( { { 'MyTestToto1.test1', MyTestToto1 } } )
+ lu.assertEquals( result, { { 'MyTestToto1.test1', MyTestToto1 } } )
+
+ result = lu.LuaUnit.expandClasses( { { 'MyTestToto1', MyTestToto1 } } )
+ lu.assertEquals( result, {
+ {'MyTestToto1.test1', MyTestToto1 },
+ {'MyTestToto1.test2', MyTestToto1 },
+ {'MyTestToto1.test3', MyTestToto1 },
+ {'MyTestToto1.testa', MyTestToto1 },
+ {'MyTestToto1.testb', MyTestToto1 },
+ } )
+ end
+
+ function TestLuaUnitUtilities:test_xmlEscape()
+ lu.assertEquals( lu.private.xmlEscape( 'abc' ), 'abc' )
+ lu.assertEquals( lu.private.xmlEscape( 'a"bc' ), 'a&quot;bc' )
+ lu.assertEquals( lu.private.xmlEscape( "a'bc" ), 'a&apos;bc' )
+ lu.assertEquals( lu.private.xmlEscape( "a<b&c>" ), 'a&lt;b&amp;c&gt;' )
+ end
+
+ function TestLuaUnitUtilities:test_xmlCDataEscape()
+ lu.assertEquals( lu.private.xmlCDataEscape( 'abc' ), 'abc' )
+ lu.assertEquals( lu.private.xmlCDataEscape( 'a"bc' ), 'a"bc' )
+ lu.assertEquals( lu.private.xmlCDataEscape( "a'bc" ), "a'bc" )
+ lu.assertEquals( lu.private.xmlCDataEscape( "a<b&c>" ), 'a<b&c>' )
+ lu.assertEquals( lu.private.xmlCDataEscape( "a<b]]>--" ), 'a<b]]&gt;--' )
+ end
+
+ function TestLuaUnitUtilities:test_hasNewline()
+ lu.assertEquals( lu.private.hasNewLine(''), false )
+ lu.assertEquals( lu.private.hasNewLine('abc'), false )
+ lu.assertEquals( lu.private.hasNewLine('ab\nc'), true )
+ end
+
+ function TestLuaUnitUtilities:test_stripStackTrace2()
+ local errMsg1 = "example_with_luaunit.lua:130: in function 'test2_withFailure'"
+ local realStackTrace1=[[stack traceback:
+ example_with_luaunit.lua:130: in function 'test2_withFailure'
+ ./luaunit.lua:1449: in function <./luaunit.lua:1449>
+ [C]: in function 'xpcall'
+ ./luaunit.lua:1449: in function 'protectedCall'
+ ./luaunit.lua:1508: in function 'execOneFunction'
+ ./luaunit.lua:1596: in function 'internalRunSuiteByInstances'
+ ./luaunit.lua:1660: in function 'internalRunSuiteByNames'
+ ./luaunit.lua:1736: in function 'runSuite'
+ example_with_luaunit.lua:140: in main chunk
+ [C]: in ?]]
+
+ local errMsg2 = 'example_with_luaunit.lua:58: expected 2, got 3'
+ local realStackTrace2=[[stack traceback:
+ example_with_luaunit.lua:58: in function 'TestToto.test7'
+ ./luaunit.lua:1517: in function <./luaunit.lua:1517>
+ [C]: in function 'xpcall'
+ ./luaunit.lua:1517: in function 'protectedCall'
+ ./luaunit.lua:1578: in function 'execOneFunction'
+ ./luaunit.lua:1677: in function 'internalRunSuiteByInstances'
+ ./luaunit.lua:1730: in function 'internalRunSuiteByNames'
+ ./luaunit.lua:1806: in function 'runSuite'
+ example_with_luaunit.lua:140: in main chunk
+ [C]: in ?]]
+
+ local errMsg3 = './test\\test_luaunit.lua:3013: expected: 2, actual: 1'
+ local realStackTrace3 = [[stack traceback:
+ ./luaunit.lua:1331: in function 'failure'
+ ./luaunit.lua:1436: in function 'assertEquals'
+ ./test\test_luaunit.lua:3013: in function 'methodInstance'
+ ./luaunit.lua:3023: in function <./luaunit.lua:3023>
+ [C]: in function 'xpcall'
+ ./luaunit.lua:3023: in function 'protectedCall'
+ ./luaunit.lua:3104: in function 'execOneFunction'
+ ./luaunit.lua:3213: in function 'internalRunSuiteByInstances'
+ ./luaunit.lua:3277: in function 'internalRunSuiteByNames'
+ ...
+ ./luaunit.lua:3023: in function <./luaunit.lua:3023>
+ [C]: in function 'xpcall'
+ ./luaunit.lua:3023: in function 'protectedCall'
+ ./luaunit.lua:3104: in function 'execOneFunction'
+ ./luaunit.lua:3213: in function 'internalRunSuiteByInstances'
+ ./luaunit.lua:3277: in function 'internalRunSuiteByNames'
+ ./luaunit.lua:3327: in function <./luaunit.lua:3293>
+ (tail call): ?
+ run_unit_tests.lua:22: in main chunk
+ [C]: ?
+ ]]
+
+ local errMsg4_1 = 'reduce_reporting.lua:7: expected: 2, actual: 1'
+ local errMsg4_2 = 'reduce_reporting.lua:12: expected: 2, actual: 1'
+ local errMsg4_3 = 'reduce_reporting.lua:20: expected: 2, actual: 1'
+ local realStackTrace4 = [[stack traceback:
+ ./luaunit.lua:1199: in function 'failure'
+ ./luaunit.lua:1304: in function 'assertEquals'
+ reduce_reporting.lua:7: in function 'my_assertEquals'
+ reduce_reporting.lua:12: in function 'my_sub_test_under_exec'
+ reduce_reporting.lua:20: in function 'my_test_under_exec'
+ ./luaunit.lua:2891: in function <./luaunit.lua:2891>
+ [C]: in function 'xpcall'
+ ./luaunit.lua:2891: in function 'protectedCall'
+ ./luaunit.lua:2972: in function 'execOneFunction'
+ ./luaunit.lua:3081: in function 'internalRunSuiteByInstances'
+ ./luaunit.lua:3145: in function 'internalRunSuiteByNames'
+ ./luaunit.lua:3195: in function 'runSuite'
+ reduce_reporting.lua:18: in main chunk
+ [C]: in ?
+ ]]
+
+ local strippedStackTrace
+ local expectedStackTrace
+
+ strippedStackTrace=lu.private.stripLuaunitTrace2( realStackTrace1, errMsg1 )
+ expectedStackTrace=[[stack traceback:
+ example_with_luaunit.lua:130: in function 'test2_withFailure']]
+ lu.assertEquals( strippedStackTrace, expectedStackTrace )
+
+ strippedStackTrace=lu.private.stripLuaunitTrace2( realStackTrace2, errMsg2 )
+ expectedStackTrace=[[stack traceback:
+ example_with_luaunit.lua:58: in function 'TestToto.test7']]
+ lu.assertEquals( strippedStackTrace, expectedStackTrace )
+
+ strippedStackTrace=lu.private.stripLuaunitTrace2( realStackTrace3, errMsg3 )
+ expectedStackTrace=[[stack traceback:
+ ./test\test_luaunit.lua:3013: in function 'methodInstance']]
+ lu.assertEquals( strippedStackTrace, expectedStackTrace )
+
+ strippedStackTrace=lu.private.stripLuaunitTrace2( realStackTrace4, errMsg4_1 )
+ expectedStackTrace=[[stack traceback:
+ reduce_reporting.lua:7: in function 'my_assertEquals'
+ reduce_reporting.lua:12: in function 'my_sub_test_under_exec'
+ reduce_reporting.lua:20: in function 'my_test_under_exec']]
+ lu.assertEquals( strippedStackTrace, expectedStackTrace )
+
+ strippedStackTrace=lu.private.stripLuaunitTrace2( realStackTrace4, errMsg4_2 )
+ expectedStackTrace=[[stack traceback:
+ reduce_reporting.lua:12: in function 'my_sub_test_under_exec'
+ reduce_reporting.lua:20: in function 'my_test_under_exec']]
+ lu.assertEquals( strippedStackTrace, expectedStackTrace )
+
+ strippedStackTrace=lu.private.stripLuaunitTrace2( realStackTrace4, errMsg4_3 )
+ expectedStackTrace=[[stack traceback:
+ reduce_reporting.lua:20: in function 'my_test_under_exec']]
+ lu.assertEquals( strippedStackTrace, expectedStackTrace )
+
+
+ end
+
+ function TestLuaUnitUtilities:test_lstrip()
+ lu.assertEquals(lu.private.lstrip("toto"), "toto")
+ lu.assertEquals(lu.private.lstrip("toto "), "toto ")
+ lu.assertEquals(lu.private.lstrip(" toto "), "toto ")
+ lu.assertEquals(lu.private.lstrip("\t\ttoto "), "toto ")
+ lu.assertEquals(lu.private.lstrip("\t \ttoto "), "toto ")
+ lu.assertEquals(lu.private.lstrip("\t \ttoto \n titi"), "toto \n titi")
+ lu.assertEquals(lu.private.lstrip(""), "")
+ end
+
+ function TestLuaUnitUtilities:test_extractFileLineNbInfo()
+ local s
+ s = "luaunit2/example_with_luaunit.lua:124: in function 'test1_withFailure'"
+ lu.assertEquals(lu.private.extractFileLineInfo(s), "luaunit2/example_with_luaunit.lua:124")
+
+ s = " ./test\\test_luaunit.lua:2996: expected: 2, actual: 1"
+ lu.assertEquals(lu.private.extractFileLineInfo(s), "./test\\test_luaunit.lua:2996" )
+ end
+
+ function TestLuaUnitUtilities:test_eps_value()
+ -- calculate epsilon
+ local local_eps = 1.0
+ while (1.0 + 0.5 * local_eps) ~= 1.0 do
+ local_eps = 0.5 * local_eps
+ end
+ -- print( local_eps, lu.EPS)
+ lu.assertEquals( local_eps, lu.EPS )
+ end
+
+
+------------------------------------------------------------------
+--
+-- Outputter Tests
+--
+------------------------------------------------------------------
+
+TestLuaUnitOutputters = { __class__ = 'TestOutputters' }
+
+ -- JUnitOutput:startSuite() can raise errors on its own, cover those
+ function TestLuaUnitOutputters:testJUnitOutputErrors()
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType('junit')
+ local outputter = runner.outputType.new(runner)
+
+ -- missing file name
+ lu.assertErrorMsgContains('With Junit, an output filename must be supplied',
+ outputter.startSuite, outputter)
+
+ -- test adding .xml extension, catch output error
+ outputter.fname = '/tmp/nonexistent.dir/foobar'
+ lu.assertErrorMsgContains('Could not open file for writing: /tmp/nonexistent.dir/foobar.xml',
+ outputter.startSuite, outputter)
+ end
+
+------------------------------------------------------------------
+--
+-- Assertion Tests
+--
+------------------------------------------------------------------
+
+local function assertFailure( ... )
+ -- ensure that execution generates a failure type error
+ lu.assertErrorMsgMatches(lu.FAILURE_PREFIX .. ".*", ...)
+end
+
+local function assertBadFindArgTable( ... )
+ lu.assertErrorMsgMatches( ".* bad argument .* to 'find' %(string expected, got table%)", ...)
+end
+local function assertBadFindArgNil( ... )
+ lu.assertErrorMsgMatches( ".* bad argument .* to 'find' %(string expected, got nil%)", ...)
+end
+local function assertBadIndexNumber( ... )
+ lu.assertErrorMsgMatches( ".* attempt to index .*a number value.*", ... )
+end
+local function assertBadIndexNil( ... )
+ lu.assertErrorMsgMatches( ".* attempt to index .*a nil value.*", ... )
+end
+local function assertBadMethodNil( ... )
+ lu.assertErrorMsgMatches( ".* attempt to call .*a nil value.*", ... )
+end
+
+
+TestLuaUnitAssertions = { __class__ = 'TestLuaUnitAssertions' }
+
+ function TestLuaUnitAssertions:test_assertEquals()
+ local f = function() return true end
+ local g = function() return true end
+
+ lu.assertEquals( 1, 1 )
+ lu.assertEquals( "abc", "abc" )
+ lu.assertEquals( nil, nil )
+ lu.assertEquals( true, true )
+ lu.assertEquals( f, f)
+ lu.assertEquals( {1,2,3}, {1,2,3})
+ lu.assertEquals( {one=1,two=2,three=3}, {one=1,two=2,three=3})
+ lu.assertEquals( {one=1,two=2,three=3}, {two=2,three=3,one=1})
+ lu.assertEquals( {one=1,two={1,2},three=3}, {two={1,2},three=3,one=1})
+ lu.assertEquals( {one=1,two={1,{2,nil}},three=3}, {two={1,{2,nil}},three=3,one=1})
+ lu.assertEquals( {nil}, {nil} )
+
+ assertFailure( lu.assertEquals, 1, 2)
+ assertFailure( lu.assertEquals, 1, "abc" )
+ assertFailure( lu.assertEquals, 0, nil )
+ assertFailure( lu.assertEquals, false, nil )
+ assertFailure( lu.assertEquals, true, 1 )
+ assertFailure( lu.assertEquals, f, 1 )
+ assertFailure( lu.assertEquals, f, g )
+ assertFailure( lu.assertEquals, {1,2,3}, {2,1,3} )
+ assertFailure( lu.assertEquals, {1,2,3}, nil )
+ assertFailure( lu.assertEquals, {1,2,3}, 1 )
+ assertFailure( lu.assertEquals, {1,2,3}, true )
+ assertFailure( lu.assertEquals, {1,2,3}, {one=1,two=2,three=3} )
+ assertFailure( lu.assertEquals, {1,2,3}, {one=1,two=2,three=3,four=4} )
+ assertFailure( lu.assertEquals, {one=1,two=2,three=3}, {2,1,3} )
+ assertFailure( lu.assertEquals, {one=1,two=2,three=3}, nil )
+ assertFailure( lu.assertEquals, {one=1,two=2,three=3}, 1 )
+ assertFailure( lu.assertEquals, {one=1,two=2,three=3}, true )
+ assertFailure( lu.assertEquals, {one=1,two=2,three=3}, {1,2,3} )
+ assertFailure( lu.assertEquals, {one=1,two={1,2},three=3}, {two={2,1},three=3,one=1})
+
+ -- check assertions for which # operator returns two different length depending
+ -- on how the table is built, eventhough the final table is the same
+ local t1 = {1, nil, 3} -- length is 3
+ local t2 = {1, [3]=3} -- length is 1
+ lu.assertEquals( t1, t2 )
+ end
+
+ function TestLuaUnitAssertions:test_assertEqualsTableWithCycles()
+
+ -- Table with same cyclic structrure should compare equal
+ local t1, t2 = {1}, {1}
+ t1.self = t1
+ t2.self = t2
+ lu.assertEquals( t1, t2 )
+
+ -- add one differing element
+ t1[2] = 2
+ t2[2] = 3
+ lu.assertNotEquals( t1, t2 )
+
+ -- cross cycle
+ local t3, t4 = {}, {}
+ t3.other = t4
+ t4.other = t3
+ lu.assertEquals( t3, t4 )
+
+ -- 3 level cycle
+ local t5a, t6a, t7a = {}, {}, {}
+ t6a.t5 = t5a
+ t7a.t6 = t6a
+ t5a.t7 = t7a
+
+ local t5b, t6b, t7b = {}, {}, {}
+ t6b.t5 = t5b
+ t7b.t6 = t6b
+ t5b.t7 = t7b
+
+ lu.assertEquals( t5a, t5b )
+ lu.assertEquals( t6a, t6b )
+ lu.assertEquals( t7a, t7b )
+ lu.assertNotEquals( t5a, t6a )
+
+ -- 3 level cycles vs 2 level cycles
+ local t8a, t9a, t10a = {}, {}, {}
+ t8a.other = t9a
+ t9a.other = t10a
+ t10a.other = t8a
+
+ local t8b, t9b = {}, {}
+ t8b.other = t9b
+ t9b.other = t8b
+ -- print( 't8a='..lu.prettystr(t8a))
+ -- print( 't8b='..lu.prettystr(t8b))
+ lu.assertNotEquals( t8a, t8b )
+
+ local t11, t12 = {}, {}
+ t11.cycle = t8a
+ t12.cycle = t8b
+ lu.assertNotEquals( t11, t12 )
+
+ -- issue #116
+ local a={}
+ local b={}
+ a.x = b; b.x = a
+ local a1={}
+ local b1={}
+ a1.x = b1; b1.x = a1
+ lu.assertEquals(a, a1)
+ end
+
+ function TestLuaUnitAssertions:test_assertEqualsTableAsKeys()
+ assertFailure( lu.assertEquals, {[{}] = 1}, { [{}] = 1})
+ assertFailure( lu.assertEquals, {[{one=1, two=2}] = 1}, { [{two=2, one=1}] = 1})
+ assertFailure( lu.assertEquals, {[{1}]=2, [{1}]=3}, {[{1}]=3, [{1}]=2} )
+ assertFailure( lu.assertEquals, {[{1}]=2, [{1}]=3}, {[{1}]=2, [{1}]=3} )
+
+ assertFailure( lu.assertEquals, {[{}] = 1}, {[{}] = 2})
+ assertFailure( lu.assertEquals, {[{}] = 1}, {[{one=1}] = 2})
+ assertFailure( lu.assertEquals, {[{}] = 1}, {[{}] = 1, 2})
+ assertFailure( lu.assertEquals, {[{}] = 1}, {[{}] = 1, [{}] = 1})
+ assertFailure( lu.assertEquals, {[{"one"}]=1}, {[{"one", 1}]=2} )
+ assertFailure( lu.assertEquals, {[{"one"}]=1,[{"one"}]=1}, {[{"one"}]=1} )
+ end
+
+ function TestLuaUnitAssertions:test_assertAlmostEquals()
+ lu.assertAlmostEquals( 1, 1, 0.1 )
+ lu.assertAlmostEquals( 1, 1 ) -- default margin (= M.EPS)
+ lu.assertAlmostEquals( 1, 1, 0 ) -- zero margin
+ assertFailure( lu.assertAlmostEquals, 0, lu.EPS, 0 ) -- zero margin
+
+ lu.assertAlmostEquals( 1, 1.1, 0.2 )
+ lu.assertAlmostEquals( -1, -1.1, 0.2 )
+ lu.assertAlmostEquals( 0.1, -0.1, 0.3 )
+ lu.assertAlmostEquals( 0.1, -0.1, 0.2 )
+
+ -- Due to rounding errors, these user-supplied margins are too small.
+ -- The tests should respect them, and so are required to fail.
+ assertFailure( lu.assertAlmostEquals, 1, 1.1, 0.1 )
+ assertFailure( lu.assertAlmostEquals, -1, -1.1, 0.1 )
+ -- Check that an explicit zero margin gets respected too
+ assertFailure( lu.assertAlmostEquals, 1.1 - 1, 0.1, 0 )
+ assertFailure( lu.assertAlmostEquals, -1 - (-1.1), 0.1, 0 )
+ -- Tests pass when adding M.EPS, either explicitly or implicitly
+ lu.assertAlmostEquals( 1, 1.1, 0.1 + lu.EPS)
+ lu.assertAlmostEquals( 1.1 - 1, 0.1 )
+ lu.assertAlmostEquals( -1, -1.1, 0.1 + lu.EPS )
+ lu.assertAlmostEquals( -1 - (-1.1), 0.1 )
+
+ assertFailure( lu.assertAlmostEquals, 1, 1.11, 0.1 )
+ assertFailure( lu.assertAlmostEquals, -1, -1.11, 0.1 )
+ end
+
+ function TestLuaUnitAssertions:test_assertAlmostEqualsTables()
+ lu.assertAlmostEquals( {1}, {1}, 0.1 )
+ lu.assertAlmostEquals( {1}, {1} ) -- default margin (= M.EPS)
+ lu.assertAlmostEquals( {1}, {1}, 0 ) -- zero margin
+ assertFailure( lu.assertAlmostEquals, {0}, {lu.EPS}, 0 ) -- zero margin
+
+ lu.assertAlmostEquals( {1}, {1.1}, 0.2 )
+ lu.assertAlmostEquals( {-1}, {-1.1}, 0.2 )
+ lu.assertAlmostEquals( {0.1}, {-0.1}, 0.3 )
+ lu.assertAlmostEquals( {0.1}, {-0.1}, 0.2 )
+ lu.assertAlmostEquals( {1, -1, 0.1, 0.1},
+ {1.1, -1.1, 0.1, -0.1}, 0.3 )
+
+ lu.assertAlmostEquals( {a=1, b=-1, c=0.1, d=0.1},
+ {a=1.1, b=-1.1, c=0.1, d=-0.1}, 0.3 )
+
+ lu.assertAlmostEquals( {0, {a=1, b=-1, c=0.1, d=0.1}},
+ {0, {a=1.1, b=-1.1, c=0.1, d=-0.1}}, 0.3 )
+
+ -- Due to rounding errors, these user-supplied margins are too small.
+ -- The tests should respect them, and so are required to fail.
+ assertFailure( lu.assertAlmostEquals, {1}, {1.1}, 0.1 )
+ assertFailure( lu.assertAlmostEquals, {-1}, {-1.1}, 0.1 )
+ -- Check that an explicit zero margin gets respected too
+ assertFailure( lu.assertAlmostEquals, {1.1 - 1}, {0.1}, 0 )
+ assertFailure( lu.assertAlmostEquals, {-1 - (-1.1)}, {0.1}, 0 )
+ -- Tests pass when adding M.EPS, either explicitly or implicitly
+ lu.assertAlmostEquals( 1, 1.1, 0.1 + lu.EPS)
+ lu.assertAlmostEquals( 1.1 - 1, 0.1 )
+ lu.assertAlmostEquals( -1, -1.1, 0.1 + lu.EPS )
+ lu.assertAlmostEquals( -1 - (-1.1), 0.1 )
+ lu.assertAlmostEquals( { 1, 1.1-1, -1},
+ {1.1, 0.1, -1.1},
+ 0.1 + lu.EPS )
+
+ -- tables with more diversity
+ lu.assertAlmostEquals( {1 , 'abc', nil, false, true, {1,2} },
+ {1.1, 'abc', nil, false, true, {1,2} },
+ 0.3)
+
+ lu.assertAlmostEquals( {1 , 'abc', { 2, 3}, false, true, {1,2} },
+ {1.1, 'abc', {2.1, 3.2}, false, true, {1,2} },
+ 0.3)
+
+
+ -- difference on something else than numeric comparison
+ assertFailure( lu.assertAlmostEquals, {1, 'abc'}, {1, 'def'}, 0.1 )
+ assertFailure( lu.assertAlmostEquals, {1, false}, {1, true}, 0.1 )
+ assertFailure( lu.assertAlmostEquals, {1, 'abc'}, {1, nil}, 0.1 )
+ end
+
+ function TestLuaUnitAssertions:test_assertAlmostEqualsErrors()
+ lu.assertErrorMsgContains( "margin must be a number", lu.assertAlmostEquals, -1, 1, "foobar" )
+ lu.assertErrorMsgContains( "must supply only number or table arguments", lu.assertAlmostEquals, -1, nil, 0 )
+ lu.assertErrorMsgContains( "must supply only number or table arguments", lu.assertAlmostEquals, nil, nil, 0 )
+ lu.assertErrorMsgContains( "must supply only number or table arguments", lu.assertAlmostEquals, '123', '345', 0 )
+ lu.assertErrorMsgContains( "margin must not be negative", lu.assertAlmostEquals, 1, 1.1, -0.1 )
+ end
+
+ function TestLuaUnitAssertions:test_assertNotEquals()
+ local f = function() return true end
+ local g = function() return true end
+
+ lu.assertNotEquals( 1, 2 )
+ lu.assertNotEquals( "abc", 2 )
+ lu.assertNotEquals( "abc", "def" )
+ lu.assertNotEquals( 1, 2)
+ lu.assertNotEquals( 1, "abc" )
+ lu.assertNotEquals( 0, nil )
+ lu.assertNotEquals( false, nil )
+ lu.assertNotEquals( true, 1 )
+ lu.assertNotEquals( f, 1 )
+ lu.assertNotEquals( f, g )
+ lu.assertNotEquals( {one=1,two=2,three=3}, true )
+ lu.assertNotEquals( {one=1,two={1,2},three=3}, {two={2,1},three=3,one=1} )
+
+ assertFailure( lu.assertNotEquals, 1, 1)
+ assertFailure( lu.assertNotEquals, "abc", "abc" )
+ assertFailure( lu.assertNotEquals, nil, nil )
+ assertFailure( lu.assertNotEquals, true, true )
+ assertFailure( lu.assertNotEquals, f, f)
+ assertFailure( lu.assertNotEquals, {one=1,two={1,{2,nil}},three=3}, {two={1,{2,nil}},three=3,one=1})
+ end
+
+ function TestLuaUnitAssertions:test_assertNotAlmostEquals()
+ lu.assertNotAlmostEquals( 1, 1.2, 0.1 )
+ lu.assertNotAlmostEquals( 1, 1.01 ) -- default margin (= M.EPS)
+ lu.assertNotAlmostEquals( 1, 1.01, 0 ) -- zero margin
+ lu.assertNotAlmostEquals( 0, lu.EPS, 0 ) -- zero margin
+
+ lu.assertNotAlmostEquals( 1, 1.3, 0.2 )
+ lu.assertNotAlmostEquals( -1, -1.3, 0.2 )
+ lu.assertNotAlmostEquals( 0.1, -0.1, 0.1 )
+
+ lu.assertNotAlmostEquals( 1, 1.1, 0.09 )
+ lu.assertNotAlmostEquals( -1, -1.1, 0.09 )
+ lu.assertNotAlmostEquals( 0.1, -0.1, 0.11 )
+
+ -- Due to rounding errors, these user-supplied margins are too small.
+ -- The tests should respect them, and so are expected to pass.
+ lu.assertNotAlmostEquals( 1, 1.1, 0.1 )
+ lu.assertNotAlmostEquals( -1, -1.1, 0.1 )
+ -- Check that an explicit zero margin gets respected too
+ lu.assertNotAlmostEquals( 1.1 - 1, 0.1, 0 )
+ lu.assertNotAlmostEquals( -1 - (-1.1), 0.1, 0 )
+ -- Tests fail when adding M.EPS, either explicitly or implicitly
+ assertFailure( lu.assertNotAlmostEquals, 1, 1.1, 0.1 + lu.EPS)
+ assertFailure( lu.assertNotAlmostEquals, 1.1 - 1, 0.1 )
+ assertFailure( lu.assertNotAlmostEquals, -1, -1.1, 0.1 + lu.EPS )
+ assertFailure( lu.assertNotAlmostEquals, -1 - (-1.1), 0.1 )
+
+ assertFailure( lu.assertNotAlmostEquals, 1, 1.11, 0.2 )
+ assertFailure( lu.assertNotAlmostEquals, -1, -1.11, 0.2 )
+ lu.assertErrorMsgContains( "must supply only number arguments", lu.assertNotAlmostEquals, -1, 1, "foobar" )
+ lu.assertErrorMsgContains( "must supply only number arguments", lu.assertNotAlmostEquals, -1, nil, 0 )
+ lu.assertErrorMsgContains( "must supply only number arguments", lu.assertNotAlmostEquals, nil, 1, 0 )
+ lu.assertErrorMsgContains( "margin must not be negative", lu.assertNotAlmostEquals, 1, 1.1, -0.1 )
+ end
+
+ function TestLuaUnitAssertions:test_assertNotEqualsDifferentTypes2()
+ lu.assertNotEquals( 2, "abc" )
+ end
+
+ function TestLuaUnitAssertions:test_assertIsTrue()
+ lu.assertIsTrue(true)
+ -- assertIsTrue is strict
+ assertFailure( lu.assertIsTrue, false)
+ assertFailure( lu.assertIsTrue, nil )
+ assertFailure( lu.assertIsTrue, 0)
+ assertFailure( lu.assertIsTrue, 1)
+ assertFailure( lu.assertIsTrue, "")
+ assertFailure( lu.assertIsTrue, "abc")
+ assertFailure( lu.assertIsTrue, function() return true end )
+ assertFailure( lu.assertIsTrue, {} )
+ assertFailure( lu.assertIsTrue, { 1 } )
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsTrue()
+ assertFailure( lu.assertNotIsTrue, true)
+ lu.assertNotIsTrue( false)
+ lu.assertNotIsTrue( nil )
+ lu.assertNotIsTrue( 0)
+ lu.assertNotIsTrue( 1)
+ lu.assertNotIsTrue( "")
+ lu.assertNotIsTrue( "abc")
+ lu.assertNotIsTrue( function() return true end )
+ lu.assertNotIsTrue( {} )
+ lu.assertNotIsTrue( { 1 } )
+ end
+
+ function TestLuaUnitAssertions:test_assertIsFalse()
+ lu.assertIsFalse(false)
+ assertFailure( lu.assertIsFalse, nil) -- assertIsFalse is strict !
+ assertFailure( lu.assertIsFalse, true)
+ assertFailure( lu.assertIsFalse, 0 )
+ assertFailure( lu.assertIsFalse, 1 )
+ assertFailure( lu.assertIsFalse, "" )
+ assertFailure( lu.assertIsFalse, "abc" )
+ assertFailure( lu.assertIsFalse, function() return true end )
+ assertFailure( lu.assertIsFalse, {} )
+ assertFailure( lu.assertIsFalse, { 1 } )
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsFalse()
+ assertFailure(lu.assertNotIsFalse, false)
+ lu.assertNotIsFalse( true)
+ lu.assertNotIsFalse( 0 )
+ lu.assertNotIsFalse( 1 )
+ lu.assertNotIsFalse( "" )
+ lu.assertNotIsFalse( "abc" )
+ lu.assertNotIsFalse( function() return true end )
+ lu.assertNotIsFalse( {} )
+ lu.assertNotIsFalse( { 1 } )
+ end
+
+ function TestLuaUnitAssertions:test_assertEvalToTrue()
+ lu.assertEvalToTrue(true)
+ assertFailure( lu.assertEvalToTrue, false)
+ assertFailure( lu.assertEvalToTrue, nil )
+ lu.assertEvalToTrue(0)
+ lu.assertEvalToTrue(1)
+ lu.assertEvalToTrue("")
+ lu.assertEvalToTrue("abc")
+ lu.assertEvalToTrue( function() return true end )
+ lu.assertEvalToTrue( {} )
+ lu.assertEvalToTrue( { 1 } )
+ end
+
+ function TestLuaUnitAssertions:test_assertEvalToFalse()
+ lu.assertEvalToFalse(false)
+ lu.assertEvalToFalse(nil)
+ assertFailure( lu.assertEvalToFalse, true)
+ assertFailure( lu.assertEvalToFalse, 0 )
+ assertFailure( lu.assertEvalToFalse, 1 )
+ assertFailure( lu.assertEvalToFalse, "" )
+ assertFailure( lu.assertEvalToFalse, "abc" )
+ assertFailure( lu.assertEvalToFalse, function() return true end )
+ assertFailure( lu.assertEvalToFalse, {} )
+ assertFailure( lu.assertEvalToFalse, { 1 } )
+ end
+
+ function TestLuaUnitAssertions:test_assertNil()
+ lu.assertNil(nil)
+ assertFailure( lu.assertTrue, false)
+ assertFailure( lu.assertNil, 0)
+ assertFailure( lu.assertNil, "")
+ assertFailure( lu.assertNil, "abc")
+ assertFailure( lu.assertNil, function() return true end )
+ assertFailure( lu.assertNil, {} )
+ assertFailure( lu.assertNil, { 1 } )
+ end
+
+ function TestLuaUnitAssertions:test_assertNotNil()
+ assertFailure( lu.assertNotNil, nil)
+ lu.assertNotNil( false )
+ lu.assertNotNil( 0 )
+ lu.assertNotNil( "" )
+ lu.assertNotNil( "abc" )
+ lu.assertNotNil( function() return true end )
+ lu.assertNotNil( {} )
+ lu.assertNotNil( { 1 } )
+ end
+
+ function TestLuaUnitAssertions:test_assertStrContains()
+ lu.assertStrContains( 'abcdef', 'abc' )
+ lu.assertStrContains( 'abcdef', 'bcd' )
+ lu.assertStrContains( 'abcdef', 'abcdef' )
+ lu.assertStrContains( 'abc0', 0 )
+ assertFailure( lu.assertStrContains, 'ABCDEF', 'abc' )
+ assertFailure( lu.assertStrContains, '', 'abc' )
+ lu.assertStrContains( 'abcdef', '' )
+ assertFailure( lu.assertStrContains, 'abcdef', 'abcx' )
+ assertFailure( lu.assertStrContains, 'abcdef', 'abcdefg' )
+ assertFailure( lu.assertStrContains, 'abcdef', 0 )
+ assertBadFindArgTable( lu.assertStrContains, 'abcdef', {} )
+ assertBadFindArgNil( lu.assertStrContains, 'abcdef', nil )
+
+ lu.assertStrContains( 'abcdef', 'abc', false )
+ lu.assertStrContains( 'abcdef', 'abc', true )
+ lu.assertStrContains( 'abcdef', 'a.c', true )
+
+ assertFailure( lu.assertStrContains, 'abcdef', '.abc', true )
+ end
+
+ function TestLuaUnitAssertions:test_assertStrIContains()
+ lu.assertStrIContains( 'ABcdEF', 'aBc' )
+ lu.assertStrIContains( 'abCDef', 'bcd' )
+ lu.assertStrIContains( 'abcdef', 'abcDef' )
+ assertFailure( lu.assertStrIContains, '', 'aBc' )
+ lu.assertStrIContains( 'abcDef', '' )
+ assertFailure( lu.assertStrIContains, 'abcdef', 'abcx' )
+ assertFailure( lu.assertStrIContains, 'abcdef', 'abcdefg' )
+ end
+
+ function TestLuaUnitAssertions:test_assertNotStrContains()
+ assertFailure( lu.assertNotStrContains, 'abcdef', 'abc' )
+ assertFailure( lu.assertNotStrContains, 'abcdef', 'bcd' )
+ assertFailure( lu.assertNotStrContains, 'abcdef', 'abcdef' )
+ lu.assertNotStrContains( '', 'abc' )
+ assertFailure( lu.assertNotStrContains, 'abcdef', '' )
+ assertFailure( lu.assertNotStrContains, 'abc0', 0 )
+ lu.assertNotStrContains( 'abcdef', 'abcx' )
+ lu.assertNotStrContains( 'abcdef', 'abcdefg' )
+ assertBadFindArgTable( lu.assertNotStrContains, 'abcdef', {} )
+ assertBadFindArgNil( lu.assertNotStrContains, 'abcdef', nil )
+
+ assertFailure( lu.assertNotStrContains, 'abcdef', 'abc', false )
+ assertFailure( lu.assertNotStrContains, 'abcdef', 'a.c', true )
+ lu.assertNotStrContains( 'abcdef', 'a.cx', true )
+ end
+
+ function TestLuaUnitAssertions:test_assertNotStrIContains()
+ assertFailure( lu.assertNotStrIContains, 'aBcdef', 'abc' )
+ assertFailure( lu.assertNotStrIContains, 'abcdef', 'aBc' )
+ assertFailure( lu.assertNotStrIContains, 'abcdef', 'bcd' )
+ assertFailure( lu.assertNotStrIContains, 'abcdef', 'abcdef' )
+ lu.assertNotStrIContains( '', 'abc' )
+ assertFailure( lu.assertNotStrIContains, 'abcdef', '' )
+ assertBadIndexNumber( lu.assertNotStrIContains, 'abc0', 0 )
+ lu.assertNotStrIContains( 'abcdef', 'abcx' )
+ lu.assertNotStrIContains( 'abcdef', 'abcdefg' )
+ assertBadMethodNil( lu.assertNotStrIContains, 'abcdef', {} )
+ assertBadIndexNil( lu.assertNotStrIContains, 'abcdef', nil )
+ end
+
+ function TestLuaUnitAssertions:test_assertStrMatches()
+ lu.assertStrMatches( 'abcdef', 'abcdef' )
+ lu.assertStrMatches( 'abcdef', '..cde.' )
+ assertFailure( lu.assertStrMatches, 'abcdef', '..def')
+ assertFailure( lu.assertStrMatches, 'abCDEf', '..cde.')
+ lu.assertStrMatches( 'abcdef', 'bcdef', 2 )
+ lu.assertStrMatches( 'abcdef', 'bcde', 2, 5 )
+ lu.assertStrMatches( 'abcdef', 'b..e', 2, 5 )
+ lu.assertStrMatches( 'abcdef', 'ab..e', nil, 5 )
+ assertFailure( lu.assertStrMatches, 'abcdef', '' )
+ assertFailure( lu.assertStrMatches, '', 'abcdef' )
+
+ assertFailure( lu.assertStrMatches, 'abcdef', 0 )
+ assertBadFindArgTable( lu.assertStrMatches, 'abcdef', {} )
+ assertBadFindArgNil( lu.assertStrMatches, 'abcdef', nil )
+ end
+
+ function TestLuaUnitAssertions:test_assertItemsEquals()
+ lu.assertItemsEquals(nil, nil)
+ lu.assertItemsEquals({},{})
+ lu.assertItemsEquals({1,2,3}, {3,1,2})
+ lu.assertItemsEquals({nil},{nil})
+ lu.assertItemsEquals({one=1,two=2,three=3}, {two=2,one=1,three=3})
+ lu.assertItemsEquals({one=1,two=2,three=3}, {a=1,b=2,c=3})
+ lu.assertItemsEquals({1,2,three=3}, {3,1,two=2})
+
+ assertFailure(lu.assertItemsEquals, {1}, {})
+ assertFailure(lu.assertItemsEquals, nil, {1,2,3})
+ assertFailure(lu.assertItemsEquals, {1,2,3}, nil)
+ assertFailure(lu.assertItemsEquals, {1,2,3,4}, {3,1,2})
+ assertFailure(lu.assertItemsEquals, {1,2,3}, {3,1,2,4})
+ assertFailure(lu.assertItemsEquals, {one=1,two=2,three=3,four=4}, {a=1,b=2,c=3})
+ assertFailure(lu.assertItemsEquals, {one=1,two=2,three=3}, {a=1,b=2,c=3,d=4})
+ assertFailure(lu.assertItemsEquals, {1,2,three=3}, {3,4,a=1,b=2})
+ assertFailure(lu.assertItemsEquals, {1,2,three=3,four=4}, {3,a=1,b=2})
+
+ lu.assertItemsEquals({one=1,two={1,2},three=3}, {one={1,2},two=1,three=3})
+ lu.assertItemsEquals({one=1,
+ two={1,{3,2,one=1}},
+ three=3},
+ {two={1,{3,2,one=1}},
+ one=1,
+ three=3})
+ -- itemsEquals is not recursive:
+ assertFailure( lu.assertItemsEquals,{1,{2,1},3}, {3,1,{1,2}})
+ assertFailure( lu.assertItemsEquals,{one=1,two={1,2},three=3}, {one={2,1},two=1,three=3})
+ assertFailure( lu.assertItemsEquals,{one=1,two={1,{3,2,one=1}},three=3}, {two={{3,one=1,2},1},one=1,three=3})
+ assertFailure( lu.assertItemsEquals,{one=1,two={1,{3,2,one=1}},three=3}, {two={{3,2,one=1},1},one=1,three=3})
+
+ assertFailure(lu.assertItemsEquals, {one=1,two=2,three=3}, {two=2,one=1,three=2})
+ assertFailure(lu.assertItemsEquals, {one=1,two=2,three=3}, {two=2,one=1,four=4})
+ assertFailure(lu.assertItemsEquals, {one=1,two=2,three=3}, {two=2,one=1,'three'})
+ assertFailure(lu.assertItemsEquals, {one=1,two=2,three=3}, {two=2,one=1,nil})
+ assertFailure(lu.assertItemsEquals, {one=1,two=2,three=3}, {two=2,one=1})
+ end
+
+ function TestLuaUnitAssertions:test_assertTableContains()
+ local t = {3, 'some value', 1, 2}
+
+ assertFailure(lu.assertTableContains, t, 0)
+ lu.assertTableContains(t, 1)
+ lu.assertTableContains(t, 2)
+ lu.assertTableContains(t, 3)
+ assertFailure(lu.assertTableContains, t, 4)
+ lu.assertTableContains(t, 'some value')
+ assertFailure(lu.assertTableContains, t, 'other value')
+
+ t = {red = 'cherry', yellow = 'lemon', blue = 'grape'}
+
+ lu.assertTableContains(t, 'lemon')
+ lu.assertTableContains(t, 'grape')
+ lu.assertTableContains(t, 'cherry')
+ assertFailure(lu.assertTableContains, t, 'kiwi')
+
+ t = {a={1,2,3}, b={4,5,6} }
+ lu.assertTableContains(t, {1,2,3} )
+ lu.assertTableContains(t, {4,5,6} )
+ assertFailure(lu.assertTableContains, t, {3,2,1} )
+
+
+ end
+
+ function TestLuaUnitAssertions:test_assertNotTableContains()
+ local t = {3, 'some value', 1, 2}
+
+ lu.assertNotTableContains(t, 0)
+ assertFailure(lu.assertNotTableContains, t, 1)
+ assertFailure(lu.assertNotTableContains, t, 2)
+ assertFailure(lu.assertNotTableContains, t, 3)
+ lu.assertNotTableContains(t, 4)
+ assertFailure(lu.assertNotTableContains, t, 'some value')
+ lu.assertNotTableContains(t, 'other value')
+
+ t = {red = 'cherry', yellow = 'lemon', blue = 'grape'}
+
+ assertFailure(lu.assertNotTableContains, t, 'lemon')
+ assertFailure(lu.assertNotTableContains, t, 'grape')
+ assertFailure(lu.assertNotTableContains, t, 'cherry')
+ lu.assertNotTableContains(t, 'kiwi')
+ end
+
+ function TestLuaUnitAssertions:test_assertIsNumber()
+ lu.assertIsNumber(1)
+ lu.assertIsNumber(1.4)
+ assertFailure(lu.assertIsNumber, "hi there!")
+ assertFailure(lu.assertIsNumber, nil)
+ assertFailure(lu.assertIsNumber, {})
+ assertFailure(lu.assertIsNumber, {1,2,3})
+ assertFailure(lu.assertIsNumber, {1})
+ assertFailure(lu.assertIsNumber, coroutine.create( function(v) local y=v+1 end ) )
+ assertFailure(lu.assertIsNumber, true)
+ end
+
+ function TestLuaUnitAssertions:test_assertIsNaN()
+ assertFailure(lu.assertIsNaN, "hi there!")
+ assertFailure(lu.assertIsNaN, nil)
+ assertFailure(lu.assertIsNaN, {})
+ assertFailure(lu.assertIsNaN, {1,2,3})
+ assertFailure(lu.assertIsNaN, {1})
+ assertFailure(lu.assertIsNaN, coroutine.create( function(v) local y=v+1 end ) )
+ lu.assertIsNaN(0 / 0)
+ lu.assertIsNaN(-0 / 0)
+ lu.assertIsNaN(0 / -0)
+ lu.assertIsNaN(-0 / -0)
+ local inf = math.huge
+ lu.assertIsNaN(inf / inf)
+ lu.assertIsNaN(-inf / inf)
+ lu.assertIsNaN(inf / -inf)
+ lu.assertIsNaN(-inf / -inf)
+ lu.assertIsNaN(inf - inf)
+ lu.assertIsNaN((-inf) + inf)
+ lu.assertIsNaN(inf + (-inf))
+ lu.assertIsNaN((-inf) - (-inf))
+ lu.assertIsNaN(0 * inf)
+ lu.assertIsNaN(-0 * inf)
+ lu.assertIsNaN(0 * -inf)
+ lu.assertIsNaN(-0 * -inf)
+ lu.assertIsNaN(math.sqrt(-1))
+ if lu._LUAVERSION == "Lua 5.1" or lu._LUAVERSION == "Lua 5.2" then
+ -- Lua 5.3 will complain/error "bad argument #2 to 'fmod' (zero)"
+ lu.assertIsNaN(math.fmod(1, 0))
+ lu.assertIsNaN(math.fmod(1, -0))
+ end
+ lu.assertIsNaN(math.fmod(inf, 1))
+ lu.assertIsNaN(math.fmod(-inf, 1))
+ assertFailure(lu.assertIsNaN, 0 / 1) -- 0.0
+ assertFailure(lu.assertIsNaN, 1 / 0) -- inf
+ assertFailure(lu.assertIsNaN, -1 / 0)-- -inf
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsNaN()
+ -- not NaN
+ lu.assertNotIsNaN( "hi there!")
+ lu.assertNotIsNaN( nil)
+ lu.assertNotIsNaN( {})
+ lu.assertNotIsNaN( {1,2,3})
+ lu.assertNotIsNaN( {1})
+ lu.assertNotIsNaN( coroutine.create( function(v) local y=v+1 end ) )
+
+ -- is NaN
+ lu.assertFailure( lu.assertNotIsNaN, 0 / 0)
+ lu.assertFailure( lu.assertNotIsNaN, -0 / 0)
+ lu.assertFailure( lu.assertNotIsNaN, 0 / -0)
+ lu.assertFailure( lu.assertNotIsNaN, -0 / -0)
+ local inf = math.huge
+ lu.assertFailure( lu.assertNotIsNaN, inf / inf)
+ lu.assertFailure( lu.assertNotIsNaN, -inf / inf)
+ lu.assertFailure( lu.assertNotIsNaN, inf / -inf)
+ lu.assertFailure( lu.assertNotIsNaN, -inf / -inf)
+ lu.assertFailure( lu.assertNotIsNaN, inf - inf)
+ lu.assertFailure( lu.assertNotIsNaN, (-inf) + inf)
+ lu.assertFailure( lu.assertNotIsNaN, inf + (-inf))
+ lu.assertFailure( lu.assertNotIsNaN, (-inf) - (-inf))
+ lu.assertFailure( lu.assertNotIsNaN, 0 * inf)
+ lu.assertFailure( lu.assertNotIsNaN, -0 * inf)
+ lu.assertFailure( lu.assertNotIsNaN, 0 * -inf)
+ lu.assertFailure( lu.assertNotIsNaN, -0 * -inf)
+ lu.assertFailure( lu.assertNotIsNaN, math.sqrt(-1))
+ if lu._LUAVERSION == "Lua 5.1" or lu._LUAVERSION == "Lua 5.2" then
+ -- Lua 5.3 will complain/error "bad argument #2 to 'fmod' (zero)"
+ lu.assertFailure( lu.assertNotIsNaN, math.fmod(1, 0))
+ lu.assertFailure( lu.assertNotIsNaN, math.fmod(1, -0))
+ end
+ lu.assertFailure( lu.assertNotIsNaN, math.fmod(inf, 1))
+ lu.assertFailure( lu.assertNotIsNaN, math.fmod(-inf, 1))
+
+ -- not NaN
+ assertFailure(lu.assertNotIsNaN, 0 / 1) -- 0.0
+ assertFailure(lu.assertNotIsNaN, 1 / 0) -- inf
+ assertFailure(lu.assertNotIdNaN, -1 / 0) -- -inf
+ end
+
+ function TestLuaUnitAssertions:test_assertIsInf()
+ assertFailure(lu.assertIsInf, "hi there!")
+ assertFailure(lu.assertIsInf, nil)
+ assertFailure(lu.assertIsInf, {})
+ assertFailure(lu.assertIsInf, {1,2,3})
+ assertFailure(lu.assertIsInf, {1})
+ assertFailure(lu.assertIsInf, coroutine.create( function(v) local y=v+1 end ) )
+
+ assertFailure(lu.assertIsInf, 0 )
+ assertFailure(lu.assertIsInf, 1 )
+ assertFailure(lu.assertIsInf, 0 / 0) -- NaN
+ assertFailure(lu.assertIsInf, -0 / 0) -- NaN
+ assertFailure(lu.assertIsInf, 0 / 1) -- 0.0
+
+ lu.assertIsInf(1 / 0) -- inf
+ lu.assertIsInf(math.log(0)) -- -inf
+ lu.assertIsInf(math.huge) -- inf
+ lu.assertIsInf(-math.huge) -- -inf
+ end
+
+ function TestLuaUnitAssertions:test_assertIsPlusInf()
+ assertFailure(lu.assertIsPlusInf, "hi there!")
+ assertFailure(lu.assertIsPlusInf, nil)
+ assertFailure(lu.assertIsPlusInf, {})
+ assertFailure(lu.assertIsPlusInf, {1,2,3})
+ assertFailure(lu.assertIsPlusInf, {1})
+ assertFailure(lu.assertIsPlusInf, coroutine.create( function(v) local y=v+1 end ) )
+
+ assertFailure(lu.assertIsPlusInf, 0 )
+ assertFailure(lu.assertIsPlusInf, 1 )
+ assertFailure(lu.assertIsPlusInf, 0 / 0) -- NaN
+ assertFailure(lu.assertIsPlusInf, -0 / 0) -- NaN
+ assertFailure(lu.assertIsPlusInf, 0 / 1) -- 0.0
+ assertFailure(lu.assertIsPlusInf, math.log(0)) -- -inf
+ assertFailure(lu.assertIsPlusInf, -math.huge) -- -inf
+
+ lu.assertIsPlusInf(1 / 0) -- inf
+ lu.assertIsPlusInf(math.huge) -- inf
+
+ -- behavior with -0 is lua version dependant:
+ -- lua51, lua53: -0 does NOT represent the value minus zero BUT plus zero
+ -- lua52, luajit: -0 represents the value minus zero
+ -- this is verified with the value 1/-0
+ -- lua 5.1, 5.3: 1/-0 = inf
+ -- lua 5.2, luajit: 1/-0 = -inf
+ if lu._LUAVERSION ~= "Lua 5.2" and lu._LUAVERSION:sub(1,6) ~= "LuaJIT" then
+ lu.assertIsPlusInf( 1/-0 )
+ else
+ assertFailure( lu.assertIsPlusInf, 1/-0 )
+ end
+ end
+
+
+ function TestLuaUnitAssertions:test_assertIsMinusInf()
+ assertFailure(lu.assertIsMinusInf, "hi there!")
+ assertFailure(lu.assertIsMinusInf, nil)
+ assertFailure(lu.assertIsMinusInf, {})
+ assertFailure(lu.assertIsMinusInf, {1,2,3})
+ assertFailure(lu.assertIsMinusInf, {1})
+ assertFailure(lu.assertIsMinusInf, coroutine.create( function(v) local y=v+1 end ) )
+
+ assertFailure(lu.assertIsMinusInf, 0 )
+ assertFailure(lu.assertIsMinusInf, 1 )
+ assertFailure(lu.assertIsMinusInf, 0 / 0) -- NaN
+ assertFailure(lu.assertIsMinusInf, -0 / 0) -- NaN
+ assertFailure(lu.assertIsMinusInf, 0 / 1) -- 0.0
+ assertFailure(lu.assertIsMinusInf, -math.log(0)) -- inf
+ assertFailure(lu.assertIsMinusInf, math.huge) -- inf
+
+ lu.assertIsMinusInf( math.log(0)) -- -inf
+ lu.assertIsMinusInf(-1 / 0) -- -inf
+ lu.assertIsMinusInf(-math.huge) -- -inf
+
+ -- behavior with -0 is lua version dependant:
+ -- lua51, lua53: -0 does NOT represent the value minus zero BUT plus zero
+ -- lua52, luajit: -0 represents the value minus zero
+ -- this is verified with the value 1/-0
+ -- lua 5.1, 5.3: 1/-0 = inf
+ -- lua 5.2, luajit: 1/-0 = -inf
+ if lu._LUAVERSION ~= "Lua 5.2" and lu._LUAVERSION:sub(1,6) ~= "LuaJIT" then
+ assertFailure( lu.assertIsMinusInf, 1/-0 )
+ else
+ lu.assertIsMinusInf( 1/-0 )
+ end
+
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsInf()
+ -- not inf
+ lu.assertNotIsInf( "hi there!")
+ lu.assertNotIsInf( nil)
+ lu.assertNotIsInf( {})
+ lu.assertNotIsInf( {1,2,3})
+ lu.assertNotIsInf( {1})
+ lu.assertNotIsInf( coroutine.create( function(v) local y=v+1 end ) )
+
+ -- not inf
+ lu.assertNotIsInf( 0 )
+ lu.assertNotIsInf( 1 )
+ lu.assertNotIsInf( 0 / 0) -- NaN
+ lu.assertNotIsInf( -0 / 0) -- NaN
+ lu.assertNotIsInf( 0 / 1) -- 0.0
+
+ -- inf
+ assertFailure( lu.assertNotIsInf, 1 / 0) -- inf
+ assertFailure( lu.assertNotIsInf, math.log(0)) -- -inf
+ assertFailure( lu.assertNotIsInf, math.huge) -- inf
+ assertFailure( lu.assertNotIsInf, math.huge) -- -inf
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsPlusInf()
+ -- not inf
+ lu.assertNotIsPlusInf( "hi there!")
+ lu.assertNotIsPlusInf( nil)
+ lu.assertNotIsPlusInf( {})
+ lu.assertNotIsPlusInf( {1,2,3})
+ lu.assertNotIsPlusInf( {1})
+ lu.assertNotIsPlusInf( coroutine.create( function(v) local y=v+1 end ) )
+
+ lu.assertNotIsPlusInf( 0 )
+ lu.assertNotIsPlusInf( 1 )
+ lu.assertNotIsPlusInf( 0 / 0) -- NaN
+ lu.assertNotIsPlusInf( -0 / 0) -- NaN
+ lu.assertNotIsPlusInf( 0 / 1) -- 0.0
+ lu.assertNotIsPlusInf( math.log(0)) -- -inf
+ lu.assertNotIsPlusInf( -math.huge) -- -inf
+
+ -- inf
+ assertFailure( lu.assertNotIsPlusInf, 1 / 0) -- inf
+ assertFailure( lu.assertNotIsPlusInf, math.huge) -- inf
+ end
+
+
+ function TestLuaUnitAssertions:test_assertNotIsMinusInf()
+ -- not inf
+ lu.assertNotIsMinusInf( "hi there!")
+ lu.assertNotIsMinusInf( nil)
+ lu.assertNotIsMinusInf( {})
+ lu.assertNotIsMinusInf( {1,2,3})
+ lu.assertNotIsMinusInf( {1})
+ lu.assertNotIsMinusInf( coroutine.create( function(v) local y=v+1 end ) )
+
+ lu.assertNotIsMinusInf( 0 )
+ lu.assertNotIsMinusInf( 1 )
+ lu.assertNotIsMinusInf( 0 / 0) -- NaN
+ lu.assertNotIsMinusInf( -0 / 0) -- NaN
+ lu.assertNotIsMinusInf( 0 / 1) -- 0.0
+ lu.assertNotIsMinusInf( -math.log(0)) -- inf
+ lu.assertNotIsMinusInf( math.huge) -- inf
+
+ -- inf
+ assertFailure( lu.assertNotIsMinusInf, math.log(0)) -- -inf
+ assertFailure( lu.assertNotIsMinusInf, -1 / 0) -- -inf
+ assertFailure( lu.assertNotIsMinusInf, -math.huge) -- -inf
+ end
+
+ -- enable it only for debugging
+ --[[
+ function Xtest_printHandlingOfZeroAndInf()
+ local inf = 1/0
+ print( ' inf = ' .. inf )
+ print( '-inf = ' .. -inf )
+ print( ' 1/inf = ' .. 1/inf )
+ print( '-1/inf = ' .. -1/inf )
+ print( ' 1/-inf = ' .. 1/-inf )
+ print( '-1/-inf = ' .. -1/-inf )
+ print()
+ print( ' 1/-0 = ' .. 1/-0 )
+ print()
+ print( ' -0 = ' .. -0 )
+ print( ' 0/-1 = ' .. 0/-1 )
+ print( ' 0*-1 = ' .. 0*-1 )
+ print( '-0/-1 = ' .. -0/-1 )
+ print( '-0*-1 = ' .. -0*-1 )
+ print( '(-0)/-1 = ' .. (-0)/-1 )
+ print( ' 1/(0/-1) = ' .. 1/(0/-1) )
+ print( ' 1/(-0/-1) = ' .. 1/(-0/-1) )
+ print( '-1/(0/-1) = ' .. -1/(0/-1) )
+ print( '-1/(-0/-1) = ' .. -1/(-0/-1) )
+
+ print()
+ local minusZero = -1 / (1/0)
+ print( 'minusZero = -1 / (1/0)' )
+ print( 'minusZero = '..minusZero)
+ print( ' 1/minusZero = ' .. 1/minusZero )
+ print()
+ print( 'minusZero/-1 = ' .. minusZero/-1 )
+ print( 'minusZero*-1 = ' .. minusZero*-1 )
+ print( ' 1/(minusZero/-1) = ' .. 1/(minusZero/-1) )
+ print( '-1/(minusZero/-1) = ' .. -1/(minusZero/-1) )
+
+ end
+ ]]
+
+ --[[ #### Important note when dealing with -0 and infinity ####
+
+ 1. Dealing with infinity is consistent, the only difference is whether the resulting 0 is integer or float
+
+ Lua 5.3: dividing by infinity yields float 0
+ With inf = 1/0:
+ -inf = -inf
+ 1/inf = 0.0
+ -1/inf = -0.0
+ 1/-inf = -0.0
+ -1/-inf = 0.0
+
+ Lua 5.2 and 5.1 and luajit: dividing by infinity yields integer 0
+ -inf =-1.#INF
+ 1/inf = 0
+ -1/inf = -0
+ 1/-inf = -0
+ -1/-inf = 0
+
+ 2. Dealing with minus 0 is totally inconsistent mathematically and accross lua versions if you use the syntax -0.
+ It works correctly if you create the value by minusZero = -1 / (1/0)
+
+ Enable the function above to see the extent of the damage of -0 :
+
+ Lua 5.1:
+ * -0 is consistently considered as 0
+ * 0 multipllied or diveded by -1 is still 0
+ * -0 multipllied or diveded by -1 is still 0
+
+ Lua 5.2 and LuaJIT:
+ * -0 is consistently -0
+ * 0 multipllied or diveded by -1 is correctly -0
+ * -0 multipllied or diveded by -1 is correctly 0
+
+ Lua 5.3:
+ * -0 is consistently considered as 0
+ * 0 multipllied by -1 is correctly -0 but divided by -1 yields 0
+ * -0 multipllied by -1 is 0 but diveded by -1 is -0
+ ]]
+
+ function TestLuaUnitAssertions:test_assertIsPlusZero()
+ assertFailure(lu.assertIsPlusZero, "hi there!")
+ assertFailure(lu.assertIsPlusZero, nil)
+ assertFailure(lu.assertIsPlusZero, {})
+ assertFailure(lu.assertIsPlusZero, {1,2,3})
+ assertFailure(lu.assertIsPlusZero, {1})
+ assertFailure(lu.assertIsPlusZero, coroutine.create( function(v) local y=v+1 end ) )
+
+ local inf = 1/0
+ assertFailure(lu.assertIsPlusZero, 1 )
+ assertFailure(lu.assertIsPlusZero, 0 / 0) -- NaN
+ assertFailure(lu.assertIsPlusZero, -0 / 0) -- NaN
+ assertFailure(lu.assertIsPlusZero, math.log(0)) -- inf
+ assertFailure(lu.assertIsPlusZero, math.huge) -- inf
+ assertFailure(lu.assertIsPlusZero, -math.huge) -- -inf
+ assertFailure(lu.assertIsPlusZero, -1/inf) -- -0.0
+
+ lu.assertIsPlusZero( 0 / 1)
+ lu.assertIsPlusZero( 0 )
+ lu.assertIsPlusZero( 1/inf )
+
+ -- behavior with -0 is lua version dependant, see note above
+ if lu._LUAVERSION ~= "Lua 5.2" and lu._LUAVERSION:sub(1,6) ~= "LuaJIT" then
+ lu.assertIsPlusZero( -0 )
+ else
+ assertFailure( lu.assertIsPlusZero, -0 )
+ end
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsPlusZero()
+ -- not plus zero
+ lu.assertNotIsPlusZero( "hi there!")
+ lu.assertNotIsPlusZero( nil)
+ lu.assertNotIsPlusZero( {})
+ lu.assertNotIsPlusZero( {1,2,3})
+ lu.assertNotIsPlusZero( {1})
+ lu.assertNotIsPlusZero( coroutine.create( function(v) local y=v+1 end ) )
+
+ local inf = 1/0
+ lu.assertNotIsPlusZero( 1 )
+ lu.assertNotIsPlusZero( 0 / 0) -- NaN
+ lu.assertNotIsPlusZero( -0 / 0) -- NaN
+ lu.assertNotIsPlusZero( math.log(0)) -- inf
+ lu.assertNotIsPlusZero( math.huge) -- inf
+ lu.assertNotIsPlusZero( -math.huge) -- -inf
+ lu.assertNotIsPlusZero( -1/inf ) -- -0.0
+
+ -- plus zero
+ assertFailure( lu.assertNotIsPlusZero, 0 / 1)
+ assertFailure( lu.assertNotIsPlusZero, 0 )
+ assertFailure( lu.assertNotIsPlusZero, 1/inf )
+
+ -- behavior with -0 is lua version dependant, see note above
+ if lu._LUAVERSION ~= "Lua 5.2" and lu._LUAVERSION:sub(1,6) ~= "LuaJIT" then
+ assertFailure( lu.assertNotIsPlusZero, -0 )
+ else
+ lu.assertNotIsPlusZero( -0 )
+ end
+ end
+
+
+ function TestLuaUnitAssertions:test_assertIsMinusZero()
+ assertFailure(lu.assertIsMinusZero, "hi there!")
+ assertFailure(lu.assertIsMinusZero, nil)
+ assertFailure(lu.assertIsMinusZero, {})
+ assertFailure(lu.assertIsMinusZero, {1,2,3})
+ assertFailure(lu.assertIsMinusZero, {1})
+ assertFailure(lu.assertIsMinusZero, coroutine.create( function(v) local y=v+1 end ) )
+
+ local inf = 1/0
+ assertFailure(lu.assertIsMinusZero, 1 )
+ assertFailure(lu.assertIsMinusZero, 0 / 0) -- NaN
+ assertFailure(lu.assertIsMinusZero, -0 / 0) -- NaN
+ assertFailure(lu.assertIsMinusZero, math.log(0)) -- inf
+ assertFailure(lu.assertIsMinusZero, math.huge) -- inf
+ assertFailure(lu.assertIsMinusZero, -math.huge) -- -inf
+ assertFailure(lu.assertIsMinusZero, 1/inf) -- -0.0
+ assertFailure(lu.assertIsMinusZero, 0 )
+
+
+ lu.assertIsMinusZero( -1/inf )
+ lu.assertIsMinusZero( 1/-inf )
+
+ -- behavior with -0 is lua version dependant, see note above
+ if lu._LUAVERSION ~= "Lua 5.2" and lu._LUAVERSION:sub(1,6) ~= "LuaJIT" then
+ assertFailure( lu.assertIsMinusZero, -0 )
+ else
+ lu.assertIsMinusZero( -0 )
+ end
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsMinusZero()
+ lu.assertNotIsMinusZero( "hi there!")
+ lu.assertNotIsMinusZero( nil)
+ lu.assertNotIsMinusZero( {})
+ lu.assertNotIsMinusZero( {1,2,3})
+ lu.assertNotIsMinusZero( {1})
+ lu.assertNotIsMinusZero( coroutine.create( function(v) local y=v+1 end ) )
+
+ local inf = 1/0
+ lu.assertNotIsMinusZero( 1 )
+ lu.assertNotIsMinusZero( 0 / 0) -- NaN
+ lu.assertNotIsMinusZero( -0 / 0) -- NaN
+ lu.assertNotIsMinusZero( math.log(0)) -- inf
+ lu.assertNotIsMinusZero( math.huge) -- inf
+ lu.assertNotIsMinusZero( -math.huge) -- -inf
+ lu.assertNotIsMinusZero( 0 )
+ lu.assertNotIsMinusZero( 1/inf) -- -0.0
+
+ assertFailure( lu.assertNotIsMinusZero, -1/inf )
+ assertFailure( lu.assertNotIsMinusZero, 1/-inf )
+
+ -- behavior with -0 is lua version dependant, see note above
+ if lu._LUAVERSION ~= "Lua 5.2" and lu._LUAVERSION:sub(1,6) ~= "LuaJIT" then
+ lu.assertNotIsMinusZero( -0 )
+ else
+ assertFailure( lu.assertNotIsMinusZero, -0 )
+ end
+ end
+
+ function TestLuaUnitAssertions:test_assertIsString()
+ assertFailure(lu.assertIsString, 1)
+ assertFailure(lu.assertIsString, 1.4)
+ lu.assertIsString("hi there!")
+ assertFailure(lu.assertIsString, nil)
+ assertFailure(lu.assertIsString, {})
+ assertFailure(lu.assertIsString, {1,2,3})
+ assertFailure(lu.assertIsString, {1})
+ assertFailure(lu.assertIsString, coroutine.create( function(v) local y=v+1 end ) )
+ assertFailure(lu.assertIsString, true)
+ end
+
+ function TestLuaUnitAssertions:test_assertIsTable()
+ assertFailure(lu.assertIsTable, 1)
+ assertFailure(lu.assertIsTable, 1.4)
+ assertFailure(lu.assertIsTable, "hi there!")
+ assertFailure(lu.assertIsTable, nil)
+ lu.assertIsTable({})
+ lu.assertIsTable({1,2,3})
+ lu.assertIsTable({1})
+ assertFailure(lu.assertIsTable, true)
+ assertFailure(lu.assertIsTable, coroutine.create( function(v) local y=v+1 end ) )
+ end
+
+ function TestLuaUnitAssertions:test_assertIsBoolean()
+ assertFailure(lu.assertIsBoolean, 1)
+ assertFailure(lu.assertIsBoolean, 1.4)
+ assertFailure(lu.assertIsBoolean, "hi there!")
+ assertFailure(lu.assertIsBoolean, nil)
+ assertFailure(lu.assertIsBoolean, {})
+ assertFailure(lu.assertIsBoolean, {1,2,3})
+ assertFailure(lu.assertIsBoolean, {1})
+ assertFailure(lu.assertIsBoolean, coroutine.create( function(v) local y=v+1 end ) )
+ lu.assertIsBoolean(true)
+ lu.assertIsBoolean(false)
+ end
+
+ function TestLuaUnitAssertions:test_assertIsNil()
+ assertFailure(lu.assertIsNil, 1)
+ assertFailure(lu.assertIsNil, 1.4)
+ assertFailure(lu.assertIsNil, "hi there!")
+ lu.assertIsNil(nil)
+ assertFailure(lu.assertIsNil, {})
+ assertFailure(lu.assertIsNil, {1,2,3})
+ assertFailure(lu.assertIsNil, {1})
+ assertFailure(lu.assertIsNil, false)
+ assertFailure(lu.assertIsNil, coroutine.create( function(v) local y=v+1 end ) )
+ end
+
+ function TestLuaUnitAssertions:test_assertIsFunction()
+ local f = function() return true end
+
+ assertFailure(lu.assertIsFunction, 1)
+ assertFailure(lu.assertIsFunction, 1.4)
+ assertFailure(lu.assertIsFunction, "hi there!")
+ assertFailure(lu.assertIsFunction, nil)
+ assertFailure(lu.assertIsFunction, {})
+ assertFailure(lu.assertIsFunction, {1,2,3})
+ assertFailure(lu.assertIsFunction, {1})
+ assertFailure(lu.assertIsFunction, false)
+ assertFailure(lu.assertIsFunction, coroutine.create( function(v) local y=v+1 end ) )
+ lu.assertIsFunction(f)
+ end
+
+ function TestLuaUnitAssertions:test_assertIsThread()
+ assertFailure(lu.assertIsThread, 1)
+ assertFailure(lu.assertIsThread, 1.4)
+ assertFailure(lu.assertIsThread, "hi there!")
+ assertFailure(lu.assertIsThread, nil)
+ assertFailure(lu.assertIsThread, {})
+ assertFailure(lu.assertIsThread, {1,2,3})
+ assertFailure(lu.assertIsThread, {1})
+ assertFailure(lu.assertIsThread, false)
+ assertFailure(lu.assertIsThread, function(v) local y=v+1 end )
+ lu.assertIsThread(coroutine.create( function(v) local y=v+1 end ) )
+ end
+
+ function TestLuaUnitAssertions:test_assertIsUserdata()
+ assertFailure(lu.assertIsUserdata, 1)
+ assertFailure(lu.assertIsUserdata, 1.4)
+ assertFailure(lu.assertIsUserdata, "hi there!")
+ assertFailure(lu.assertIsUserdata, nil)
+ assertFailure(lu.assertIsUserdata, {})
+ assertFailure(lu.assertIsUserdata, {1,2,3})
+ assertFailure(lu.assertIsUserdata, {1})
+ assertFailure(lu.assertIsUserdata, false)
+ assertFailure(lu.assertIsUserdata, function(v) local y=v+1 end )
+ assertFailure(lu.assertIsUserdata, coroutine.create( function(v) local y=v+1 end ) )
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsNumber()
+ assertFailure(lu.assertNotIsNumber, 1 )
+ assertFailure(lu.assertNotIsNumber, 1.4 )
+ lu.assertNotIsNumber( "hi there!")
+ lu.assertNotIsNumber( nil)
+ lu.assertNotIsNumber( {})
+ lu.assertNotIsNumber( {1,2,3})
+ lu.assertNotIsNumber( {1})
+ lu.assertNotIsNumber( coroutine.create( function(v) local y=v+1 end ) )
+ lu.assertNotIsNumber( true)
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsNaN()
+ lu.assertNotIsNaN( "hi there!" )
+ lu.assertNotIsNaN( nil )
+ lu.assertNotIsNaN( {} )
+ lu.assertNotIsNaN( {1,2,3} )
+ lu.assertNotIsNaN( {1} )
+ lu.assertNotIsNaN( coroutine.create( function(v) local y=v+1 end ) )
+ assertFailure(lu.assertNotIsNaN, 0 / 0)
+ assertFailure(lu.assertNotIsNaN, -0 / 0)
+ assertFailure(lu.assertNotIsNaN, 0 / -0)
+ assertFailure(lu.assertNotIsNaN, -0 / -0)
+ local inf = math.huge
+ assertFailure(lu.assertNotIsNaN, inf / inf)
+ assertFailure(lu.assertNotIsNaN, -inf / inf)
+ assertFailure(lu.assertNotIsNaN, inf / -inf)
+ assertFailure(lu.assertNotIsNaN, -inf / -inf)
+ assertFailure(lu.assertNotIsNaN, inf - inf)
+ assertFailure(lu.assertNotIsNaN, (-inf) + inf)
+ assertFailure(lu.assertNotIsNaN, inf + (-inf))
+ assertFailure(lu.assertNotIsNaN, (-inf) - (-inf))
+ assertFailure(lu.assertNotIsNaN, 0 * inf)
+ assertFailure(lu.assertNotIsNaN, -0 * inf)
+ assertFailure(lu.assertNotIsNaN, 0 * -inf)
+ assertFailure(lu.assertNotIsNaN, -0 * -inf)
+ assertFailure(lu.assertNotIsNaN, math.sqrt(-1))
+ if lu._LUAVERSION == "Lua 5.1" or lu._LUAVERSION == "Lua 5.2" then
+ -- Lua 5.3 will complain/error "bad argument #2 to 'fmod' (zero)"
+ assertFailure(lu.assertNotIsNaN, math.fmod(1, 0))
+ assertFailure(lu.assertNotIsNaN, math.fmod(1, -0))
+ end
+ assertFailure(lu.assertNotIsNaN, math.fmod(inf, 1))
+ assertFailure(lu.assertNotIsNaN, math.fmod(-inf, 1))
+ lu.assertNotIsNaN( 0 / 1 ) -- 0.0
+ lu.assertNotIsNaN( 1 / 0 ) -- inf
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsInf()
+ lu.assertNotIsInf( "hi there!" )
+ lu.assertNotIsInf( nil)
+ lu.assertNotIsInf( {})
+ lu.assertNotIsInf( {1,2,3})
+ lu.assertNotIsInf( {1})
+ lu.assertNotIsInf( coroutine.create( function(v) local y=v+1 end ) )
+ lu.assertNotIsInf( 0 / 0 ) -- NaN
+ lu.assertNotIsInf( 0 / 1 ) -- 0.0
+ assertFailure(lu.assertNotIsInf, 1 / 0 )
+ assertFailure(lu.assertNotIsInf, math.log(0) )
+ assertFailure(lu.assertNotIsInf, math.huge )
+ assertFailure(lu.assertNotIsInf, -math.huge )
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsString()
+ lu.assertNotIsString( 1)
+ lu.assertNotIsString( 1.4)
+ assertFailure( lu.assertNotIsString, "hi there!")
+ lu.assertNotIsString( nil)
+ lu.assertNotIsString( {})
+ lu.assertNotIsString( {1,2,3})
+ lu.assertNotIsString( {1})
+ lu.assertNotIsString( coroutine.create( function(v) local y=v+1 end ) )
+ lu.assertNotIsString( true)
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsTable()
+ lu.assertNotIsTable( 1)
+ lu.assertNotIsTable( 1.4)
+ lu.assertNotIsTable( "hi there!")
+ lu.assertNotIsTable( nil)
+ assertFailure( lu.assertNotIsTable, {})
+ assertFailure( lu.assertNotIsTable, {1,2,3})
+ assertFailure( lu.assertNotIsTable, {1})
+ lu.assertNotIsTable( true)
+ lu.assertNotIsTable( coroutine.create( function(v) local y=v+1 end ) )
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsBoolean()
+ lu.assertNotIsBoolean( 1)
+ lu.assertNotIsBoolean( 1.4)
+ lu.assertNotIsBoolean( "hi there!")
+ lu.assertNotIsBoolean( nil)
+ lu.assertNotIsBoolean( {})
+ lu.assertNotIsBoolean( {1,2,3})
+ lu.assertNotIsBoolean( {1})
+ lu.assertNotIsBoolean( coroutine.create( function(v) local y=v+1 end ) )
+ assertFailure( lu.assertNotIsBoolean, true)
+ assertFailure( lu.assertNotIsBoolean, false)
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsNil()
+ lu.assertNotIsNil( 1)
+ lu.assertNotIsNil( 1.4)
+ lu.assertNotIsNil( "hi there!")
+ assertFailure( lu.assertNotIsNil, nil)
+ lu.assertNotIsNil( {})
+ lu.assertNotIsNil( {1,2,3})
+ lu.assertNotIsNil( {1})
+ lu.assertNotIsNil( false)
+ lu.assertNotIsNil( coroutine.create( function(v) local y=v+1 end ) )
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsFunction()
+ local f = function() return true end
+
+ lu.assertNotIsFunction( 1)
+ lu.assertNotIsFunction( 1.4)
+ lu.assertNotIsFunction( "hi there!")
+ lu.assertNotIsFunction( nil)
+ lu.assertNotIsFunction( {})
+ lu.assertNotIsFunction( {1,2,3})
+ lu.assertNotIsFunction( {1})
+ lu.assertNotIsFunction( false)
+ lu.assertNotIsFunction( coroutine.create( function(v) local y=v+1 end ) )
+ assertFailure( lu.assertNotIsFunction, f)
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsThread()
+ lu.assertNotIsThread( 1)
+ lu.assertNotIsThread( 1.4)
+ lu.assertNotIsThread( "hi there!")
+ lu.assertNotIsThread( nil)
+ lu.assertNotIsThread( {})
+ lu.assertNotIsThread( {1,2,3})
+ lu.assertNotIsThread( {1})
+ lu.assertNotIsThread( false)
+ lu.assertNotIsThread( function(v) local y=v+1 end )
+ assertFailure( lu.assertNotIsThread, coroutine.create( function(v) local y=v+1 end ) )
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIsUserdata()
+ lu.assertNotIsUserdata( 1)
+ lu.assertNotIsUserdata( 1.4)
+ lu.assertNotIsUserdata( "hi there!")
+ lu.assertNotIsUserdata( nil)
+ lu.assertNotIsUserdata( {})
+ lu.assertNotIsUserdata( {1,2,3})
+ lu.assertNotIsUserdata( {1})
+ lu.assertNotIsUserdata( false)
+ lu.assertNotIsUserdata( function(v) local y=v+1 end )
+ lu.assertNotIsUserdata( coroutine.create( function(v) local y=v+1 end ) )
+ end
+
+ function TestLuaUnitAssertions:test_assertIs()
+ local f = function() return true end
+ local g = function() return true end
+ local t1= {}
+ local t2={1,2}
+ local t3={1,2}
+ local t4= {a=1,{1,2},day="today"}
+ local s1='toto'
+ local s2='toto'
+ local s3='to'..'to'
+ local b1=true
+ local b2=false
+
+ lu.assertIs(1,1)
+ lu.assertIs(f,f)
+ lu.assertIs('toto', 'toto')
+ lu.assertIs(s1, s2)
+ lu.assertIs(s1, s3)
+ lu.assertIs(t1,t1)
+ lu.assertIs(t4,t4)
+ lu.assertIs(b1, true)
+ lu.assertIs(b2, false)
+
+ assertFailure(lu.assertIs, 1, 2)
+ assertFailure(lu.assertIs, 1.4, 1)
+ assertFailure(lu.assertIs, "hi there!", "hola")
+ assertFailure(lu.assertIs, nil, 1)
+ assertFailure(lu.assertIs, {}, {})
+ assertFailure(lu.assertIs, {1,2,3}, f)
+ assertFailure(lu.assertIs, f, g)
+ assertFailure(lu.assertIs, t2,t3 )
+ assertFailure(lu.assertIs, b2, nil)
+
+ -- tricky, table with protected metatable
+ local t5 = setmetatable( {1,2}, {__metatable='private'})
+ local t6 = {1,2}
+ lu.assertIs(t5, t5)
+ assertFailure( lu.assertIs, t5, t6)
+ end
+
+ function TestLuaUnitAssertions:test_assertNotIs()
+ local f = function() return true end
+ local g = function() return true end
+ local t1= {}
+ local t2={1,2}
+ local t3={1,2}
+ local t4= {a=1,{1,2},day="today"}
+ local s1='toto'
+ local s2='toto'
+ local b1=true
+ local b2=false
+
+ assertFailure( lu.assertNotIs, 1,1 )
+ assertFailure( lu.assertNotIs, f,f )
+ assertFailure( lu.assertNotIs, t1,t1 )
+ assertFailure( lu.assertNotIs, t4,t4)
+ assertFailure( lu.assertNotIs, s1,s2 )
+ assertFailure( lu.assertNotIs, 'toto', 'toto' )
+ assertFailure( lu.assertNotIs, b1, true )
+ assertFailure( lu.assertNotIs, b2, false )
+
+ lu.assertNotIs(1, 2)
+ lu.assertNotIs(1.4, 1)
+ lu.assertNotIs("hi there!", "hola")
+ lu.assertNotIs(nil, 1)
+ lu.assertNotIs({}, {})
+ lu.assertNotIs({1,2,3}, f)
+ lu.assertNotIs(f, g)
+ lu.assertNotIs(t2,t3)
+ lu.assertNotIs(b1, false)
+ lu.assertNotIs(b2, true)
+ lu.assertNotIs(b2, nil)
+ end
+
+ function TestLuaUnitAssertions:test_assertTableNum()
+ lu.assertEquals( 3, 3 )
+ lu.assertNotEquals( 3, 4 )
+ lu.assertEquals( {3}, {3} )
+ lu.assertNotEquals( {3}, 3 )
+ lu.assertNotEquals( {3}, {4} )
+ lu.assertEquals( {x=1}, {x=1} )
+ lu.assertNotEquals( {x=1}, {x=2} )
+ lu.assertNotEquals( {x=1}, {y=1} )
+ end
+ function TestLuaUnitAssertions:test_assertTableStr()
+ lu.assertEquals( '3', '3' )
+ lu.assertNotEquals( '3', '4' )
+ lu.assertEquals( {'3'}, {'3'} )
+ lu.assertNotEquals( {'3'}, '3' )
+ lu.assertNotEquals( {'3'}, {'4'} )
+ lu.assertEquals( {x='1'}, {x='1'} )
+ lu.assertNotEquals( {x='1'}, {x='2'} )
+ lu.assertNotEquals( {x='1'}, {y='1'} )
+ end
+ function TestLuaUnitAssertions:test_assertTableLev2()
+ lu.assertEquals( {x={'a'}}, {x={'a'}} )
+ lu.assertNotEquals( {x={'a'}}, {x={'b'}} )
+ lu.assertNotEquals( {x={'a'}}, {z={'a'}} )
+ lu.assertEquals( {{x=1}}, {{x=1}} )
+ lu.assertNotEquals( {{x=1}}, {{y=1}} )
+ lu.assertEquals( {{x='a'}}, {{x='a'}} )
+ lu.assertNotEquals( {{x='a'}}, {{x='b'}} )
+ end
+ function TestLuaUnitAssertions:test_assertTableList()
+ lu.assertEquals( {3,4,5}, {3,4,5} )
+ lu.assertNotEquals( {3,4,5}, {3,4,6} )
+ lu.assertNotEquals( {3,4,5}, {3,5,4} )
+ lu.assertEquals( {3,4,x=5}, {3,4,x=5} )
+ lu.assertNotEquals( {3,4,x=5}, {3,4,x=6} )
+ lu.assertNotEquals( {3,4,x=5}, {3,x=4,5} )
+ lu.assertNotEquals( {3,4,5}, {2,3,4,5} )
+ lu.assertNotEquals( {3,4,5}, {3,2,4,5} )
+ lu.assertNotEquals( {3,4,5}, {3,4,5,6} )
+ end
+
+ function TestLuaUnitAssertions:test_assertTableNil()
+ lu.assertEquals( {3,4,5}, {3,4,5} )
+ lu.assertNotEquals( {3,4,5}, {nil,3,4,5} )
+ lu.assertNotEquals( {3,4,5}, {nil,4,5} )
+ lu.assertEquals( {3,4,5}, {3,4,5,nil} ) -- lua quirk
+ lu.assertNotEquals( {3,4,5}, {3,4,nil} )
+ lu.assertNotEquals( {3,4,5}, {3,nil,5} )
+ lu.assertNotEquals( {3,4,5}, {3,4,nil,5} )
+ end
+
+ function TestLuaUnitAssertions:test_assertTableNilFront()
+ lu.assertEquals( {nil,4,5}, {nil,4,5} )
+ lu.assertNotEquals( {nil,4,5}, {nil,44,55} )
+ lu.assertEquals( {nil,'4','5'}, {nil,'4','5'} )
+ lu.assertNotEquals( {nil,'4','5'}, {nil,'44','55'} )
+ lu.assertEquals( {nil,{4,5}}, {nil,{4,5}} )
+ lu.assertNotEquals( {nil,{4,5}}, {nil,{44,55}} )
+ lu.assertNotEquals( {nil,{4}}, {nil,{44}} )
+ lu.assertEquals( {nil,{x=4,5}}, {nil,{x=4,5}} )
+ lu.assertEquals( {nil,{x=4,5}}, {nil,{5,x=4}} ) -- lua quirk
+ lu.assertEquals( {nil,{x=4,y=5}}, {nil,{y=5,x=4}} ) -- lua quirk
+ lu.assertNotEquals( {nil,{x=4,5}}, {nil,{y=4,5}} )
+ end
+
+ function TestLuaUnitAssertions:test_assertTableAdditions()
+ lu.assertEquals( {1,2,3}, {1,2,3} )
+ lu.assertNotEquals( {1,2,3}, {1,2,3,4} )
+ lu.assertNotEquals( {1,2,3,4}, {1,2,3} )
+ lu.assertEquals( {1,x=2,3}, {1,x=2,3} )
+ lu.assertNotEquals( {1,x=2,3}, {1,x=2,3,y=4} )
+ lu.assertNotEquals( {1,x=2,3,y=4}, {1,x=2,3} )
+ end
+
+ function TestLuaUnitAssertions:test_assertTableProtectedMt()
+ -- tricky, table with protected metatable
+ local t1 = setmetatable( {1,2}, {__metatable='private'})
+ local t2 = {1,2}
+ local t3 = setmetatable( {1,2}, {__metatable='private'})
+
+ lu.assertEquals(t1, t2)
+ lu.assertEquals(t2, t3)
+ end
+
+local function assertFailureEquals(msg, ...)
+ lu.assertErrorMsgEquals(lu.FAILURE_PREFIX .. msg, ...)
+end
+
+local function assertFailureMatches(msg, ...)
+ lu.assertErrorMsgMatches(lu.FAILURE_PREFIX .. msg, ...)
+end
+
+local function assertFailureContains(msg, ...)
+ lu.assertErrorMsgContains(lu.FAILURE_PREFIX .. msg, ...)
+end
+
+TestLuaUnitAssertionsError = {}
+
+ function TestLuaUnitAssertionsError:setUp()
+ self.f = function ( v )
+ local y = v + 1
+ end
+ self.f_with_error = function (v)
+ local y = v + 2
+ error('This is an error', 2)
+ end
+
+ self.f_with_table_error = function (v)
+ local y = v + 2
+ local ts = { __tostring = function() return 'This table has error!' end }
+ -- the error message is a table which converts to string
+ error( setmetatable( { this_table="has error" }, ts ) )
+ end
+
+
+ end
+
+ function TestLuaUnitAssertionsError:test_assertError()
+ local x = 1
+
+ -- f_with_error generates an error
+ local has_error = not pcall( self.f_with_error, x )
+ lu.assertEquals( has_error, true )
+
+ -- f does not generate an error
+ has_error = not pcall( self.f, x )
+ lu.assertEquals( has_error, false )
+
+ -- lu.assertError is happy with f_with_error
+ lu.assertError( self.f_with_error, x )
+
+ -- lu.assertError is unhappy with f
+ assertFailureEquals( "Expected an error when calling function but no error generated",
+ lu.assertError, self.f, x )
+
+ -- multiple arguments
+ local function f_with_multi_arguments(a,b,c)
+ if a == b and b == c then return end
+ error("three arguments not equal")
+ end
+
+ lu.assertError( f_with_multi_arguments, 1, 1, 3 )
+ lu.assertError( f_with_multi_arguments, 1, 3, 1 )
+ lu.assertError( f_with_multi_arguments, 3, 1, 1 )
+
+ assertFailureEquals( "Expected an error when calling function but no error generated",
+ lu.assertError, f_with_multi_arguments, 1, 1, 1 )
+
+ -- error generated as table
+ lu.assertError( self.f_with_table_error, 1 )
+
+ end
+
+ function TestLuaUnitAssertionsError:test_assertErrorMsgContains()
+ local x = 1
+ assertFailure( lu.assertErrorMsgContains, 'toto', self.f, x )
+ lu.assertErrorMsgContains( 'is an err', self.f_with_error, x )
+ lu.assertErrorMsgContains( 'This is an error', self.f_with_error, x )
+ assertFailure( lu.assertErrorMsgContains, ' This is an error', self.f_with_error, x )
+ assertFailure( lu.assertErrorMsgContains, 'This .. an error', self.f_with_error, x )
+ lu.assertErrorMsgContains("50", function() error(500) end)
+
+ -- error message is a table which converts to a string
+ lu.assertErrorMsgContains( 'This table has error', self.f_with_table_error, 1 )
+ end
+
+ function TestLuaUnitAssertionsError:test_assertErrorMsgEquals()
+ local x = 1
+ assertFailure( lu.assertErrorMsgEquals, 'toto', self.f, x )
+ assertFailure( lu.assertErrorMsgEquals, 'is an err', self.f_with_error, x )
+
+ -- expected string, receive string
+ lu.assertErrorMsgEquals( 'This is an error', self.f_with_error, x )
+
+ -- expected table, receive table
+ lu.assertErrorMsgEquals({1,2,3,4}, function() error({1,2,3,4}) end)
+
+ -- expected complex table, receive complex table
+ lu.assertErrorMsgEquals({
+ details = {1,2,3,4},
+ id = 10,
+ }, function() error({
+ details = {1,2,3,4},
+ id = 10,
+ }) end)
+
+ -- expected string, receive number converted to string
+ lu.assertErrorMsgEquals("500", function() error(500, 2) end)
+
+ -- one space added at the beginning
+ assertFailure( lu.assertErrorMsgEquals, ' This is an error', self.f_with_error, x )
+
+ -- pattern does not work
+ assertFailure( lu.assertErrorMsgEquals, 'This .. an error', self.f_with_error, x )
+
+ -- expected string, receive table which converts to string
+ lu.assertErrorMsgEquals( "This table has error!", self.f_with_table_error, x)
+
+ -- expected table, no error generated
+ assertFailure( lu.assertErrorMsgEquals, { 1 }, function( v ) return "{ 1 }" end, 33 )
+
+ -- expected table, error generated as string, no match
+ assertFailure( lu.assertErrorMsgEquals, { 1 }, function( v ) error( "{ 1 }" ) end, 33 )
+ end
+
+ function TestLuaUnitAssertionsError:test_assertErrorMsgMatches()
+ local x = 1
+ assertFailure( lu.assertErrorMsgMatches, 'toto', self.f, x )
+ assertFailure( lu.assertErrorMsgMatches, 'is an err', self.f_with_error, x )
+ lu.assertErrorMsgMatches( 'This is an error', self.f_with_error, x )
+ lu.assertErrorMsgMatches( 'This is .. error', self.f_with_error, x )
+ lu.assertErrorMsgMatches(".*500$", function() error(500, 2) end)
+ lu.assertErrorMsgMatches("This .* has error!", self.f_with_table_error, 33 )
+
+ -- one space added to cause failure
+ assertFailure( lu.assertErrorMsgMatches, ' This is an error', self.f_with_error, x )
+ assertFailure( lu.assertErrorMsgMatches, "This", self.f_with_table_error, 33 )
+
+
+
+ end
+
+------------------------------------------------------------------
+--
+-- Failure message tests
+--
+------------------------------------------------------------------
+
+TestLuaUnitErrorMsg = { __class__ = 'TestLuaUnitErrorMsg' }
+
+ function TestLuaUnitErrorMsg:setUp()
+ self.old_ORDER_ACTUAL_EXPECTED = lu.ORDER_ACTUAL_EXPECTED
+ self.old_PRINT_TABLE_REF_IN_ERROR_MSG = lu.PRINT_TABLE_REF_IN_ERROR_MSG
+ end
+
+ function TestLuaUnitErrorMsg:tearDown()
+ lu.ORDER_ACTUAL_EXPECTED = self.old_ORDER_ACTUAL_EXPECTED
+ lu.PRINT_TABLE_REF_IN_ERROR_MSG = self.old_PRINT_TABLE_REF_IN_ERROR_MSG
+ end
+
+ function TestLuaUnitErrorMsg:test_adjust_err_msg_with_iter()
+ local err_msg, status
+
+ --------------- FAIL ---------------------
+ -- file-line info, strip failure prefix, no iteration info
+ err_msg, status = lu.adjust_err_msg_with_iter(
+ '.\\test\\test_luaunit.lua:2247: LuaUnit test FAILURE: Expected an error when calling function but no error generated',
+ nil )
+ lu.assertEquals( { err_msg, status },
+ { '.\\test\\test_luaunit.lua:2247: Expected an error when calling function but no error generated',
+ lu.NodeStatus.FAIL } )
+
+ -- file-line info, strip failure prefix, with iteration info
+ err_msg, status = lu.adjust_err_msg_with_iter(
+ '.\\test\\test_luaunit.lua:2247: LuaUnit test FAILURE: Expected an error when calling function but no error generated',
+ 'iteration 33' )
+ lu.assertEquals( { err_msg, status },
+ { '.\\test\\test_luaunit.lua:2247: iteration 33, Expected an error when calling function but no error generated',
+ lu.NodeStatus.FAIL } )
+
+ -- no file-line info, strip failure prefix, no iteration info
+ err_msg, status = lu.adjust_err_msg_with_iter(
+ 'LuaUnit test FAILURE: Expected an error when calling function but no error generated',
+ nil )
+ lu.assertEquals( { err_msg, status },
+ { 'Expected an error when calling function but no error generated',
+ lu.NodeStatus.FAIL } )
+
+ -- no file-line info, strip failure prefix, with iteration info
+ err_msg, status = lu.adjust_err_msg_with_iter(
+ 'LuaUnit test FAILURE: Expected an error when calling function but no error generated',
+ 'iteration 33' )
+ lu.assertEquals( { err_msg, status },
+ { 'iteration 33, Expected an error when calling function but no error generated',
+ lu.NodeStatus.FAIL } )
+
+ --------------- ERROR ---------------------
+ -- file-line info, pure error, no iteration info, do nothing
+ err_msg, status = lu.adjust_err_msg_with_iter(
+ '.\\test\\test_luaunit.lua:2723: teardown error',
+ nil )
+ lu.assertEquals( { err_msg, status },
+ { '.\\test\\test_luaunit.lua:2723: teardown error',
+ lu.NodeStatus.ERROR } )
+
+ -- file-line info, pure error, add iteration info
+ err_msg, status = lu.adjust_err_msg_with_iter(
+ '.\\test\\test_luaunit.lua:2723: teardown error',
+ 'iteration 33' )
+ lu.assertEquals( { err_msg, status },
+ { '.\\test\\test_luaunit.lua:2723: iteration 33, teardown error',
+ lu.NodeStatus.ERROR } )
+
+ -- no file-line info, pure error, no iteration info, do nothing
+ err_msg, status = lu.adjust_err_msg_with_iter(
+ 'teardown error',
+ nil )
+ lu.assertEquals( { err_msg, status },
+ { 'teardown error',
+ lu.NodeStatus.ERROR } )
+
+ -- no file-line info, pure error, add iteration info
+ err_msg, status = lu.adjust_err_msg_with_iter(
+ 'teardown error',
+ 'iteration 33' )
+ lu.assertEquals( { err_msg, status },
+ { 'iteration 33, teardown error',
+ lu.NodeStatus.ERROR } )
+
+ --------------- PASS ---------------------
+ -- file-line info, success, return empty error message
+ err_msg, status = lu.adjust_err_msg_with_iter(
+ '.\\test\\test_luaunit.lua:2247: LuaUnit test SUCCESS: the test did actually work !',
+ nil )
+ lu.assertEquals( { err_msg, status },
+ { nil, lu.NodeStatus.SUCCESS } )
+
+ -- file-line info, success, return empty error message, even with iteration
+ err_msg, status = lu.adjust_err_msg_with_iter(
+ '.\\test\\test_luaunit.lua:2247: LuaUnit test SUCCESS: the test did actually work !',
+ 'iteration 33' )
+ lu.assertEquals( { err_msg, status },
+ { nil, lu.NodeStatus.SUCCESS } )
+
+ -- no file-line info, success, return empty error message
+ err_msg, status = lu.adjust_err_msg_with_iter(
+ 'LuaUnit test SUCCESS: the test did actually work !',
+ nil )
+ lu.assertEquals( { err_msg, status },
+ { nil, lu.NodeStatus.SUCCESS } )
+
+ -- no file-line info, success, return empty error message, even with iteration
+ err_msg, status = lu.adjust_err_msg_with_iter(
+ 'LuaUnit test SUCCESS: the test did actually work !',
+ 'iteration 33' )
+ lu.assertEquals( { err_msg, status },
+ { nil, lu.NodeStatus.SUCCESS } )
+
+ end
+
+
+ function TestLuaUnitErrorMsg:test_assertEqualsMsg()
+ assertFailureEquals( 'expected: 2, actual: 1', lu.assertEquals, 1, 2 )
+ assertFailureEquals( 'expected: "exp"\nactual: "act"', lu.assertEquals, 'act', 'exp' )
+ assertFailureEquals( 'expected: \n"exp\npxe"\nactual: \n"act\ntca"', lu.assertEquals, 'act\ntca', 'exp\npxe' )
+ assertFailureEquals( 'expected: true, actual: false', lu.assertEquals, false, true )
+ assertFailureEquals( 'expected: 1.2, actual: 1', lu.assertEquals, 1, 1.2)
+ assertFailureMatches( 'expected: {1, 2}\nactual: {2, 1}', lu.assertEquals, {2,1}, {1,2} )
+ assertFailureMatches( 'expected: {one=1, two=2}\nactual: {3, 2, 1}', lu.assertEquals, {3,2,1}, {one=1,two=2} )
+ assertFailureEquals( 'expected: 2, actual: nil', lu.assertEquals, nil, 2 )
+ assertFailureEquals( 'toto\nexpected: 2, actual: nil', lu.assertEquals, nil, 2, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertEqualsOrderReversedMsg()
+ lu.ORDER_ACTUAL_EXPECTED = false
+ assertFailureEquals( 'expected: 1, actual: 2', lu.assertEquals, 1, 2 )
+ assertFailureEquals( 'expected: "act"\nactual: "exp"', lu.assertEquals, 'act', 'exp' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertAlmostEqualsMsg()
+ assertFailureEquals('Values are not almost equal\nActual: 2, expected: 1, delta 1 above margin of 0.1', lu.assertAlmostEquals, 2, 1, 0.1 )
+ assertFailureEquals('toto\nValues are not almost equal\nActual: 2, expected: 1, delta 1 above margin of 0.1', lu.assertAlmostEquals, 2, 1, 0.1, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertAlmostEqualsOrderReversedMsg()
+ lu.ORDER_ACTUAL_EXPECTED = false
+ assertFailureEquals('Values are not almost equal\nActual: 1, expected: 2, delta 1 above margin of 0.1', lu.assertAlmostEquals, 2, 1, 0.1 )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotAlmostEqualsMsg()
+ -- single precision math Lua won't output an "exact" delta (0.1) here, so we do a partial match
+ assertFailureContains('Values are almost equal\nActual: 1.1, expected: 1, delta 0.1 below margin of 0.2', lu.assertNotAlmostEquals, 1.1, 1, 0.2 )
+ assertFailureContains('toto\nValues are almost equal\nActual: 1.1, expected: 1, delta 0.1 below margin of 0.2', lu.assertNotAlmostEquals, 1.1, 1, 0.2, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotAlmostEqualsOrderReversedMsg()
+ -- single precision math Lua won't output an "exact" delta (0.1) here, so we do a partial match
+ lu.ORDER_ACTUAL_EXPECTED = false
+ assertFailureContains('Values are almost equal\nActual: 1, expected: 1.1, delta 0.1 below margin of 0.2', lu.assertNotAlmostEquals, 1.1, 1, 0.2 )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotEqualsMsg()
+ assertFailureEquals( 'Received the not expected value: 1', lu.assertNotEquals, 1, 1 )
+ assertFailureMatches( 'Received the not expected value: {1, 2}', lu.assertNotEquals, {1,2}, {1,2} )
+ assertFailureEquals( 'Received the not expected value: nil', lu.assertNotEquals, nil, nil )
+ assertFailureEquals( 'toto\nReceived the not expected value: 1', lu.assertNotEquals, 1, 1, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotEqualsOrderReversedMsg()
+ lu.ORDER_ACTUAL_EXPECTED = false
+ assertFailureEquals( 'Received the not expected value: 1', lu.assertNotEquals, 1, 1 )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertTrueFalse()
+ assertFailureEquals( 'expected: true, actual: false', lu.assertTrue, false )
+ assertFailureEquals( 'expected: true, actual: nil', lu.assertTrue, nil )
+ assertFailureEquals( 'expected: false, actual: true', lu.assertFalse, true )
+ assertFailureEquals( 'expected: false, actual: nil', lu.assertFalse, nil )
+ assertFailureEquals( 'expected: false, actual: 0', lu.assertFalse, 0)
+ assertFailureMatches( 'expected: false, actual: {}', lu.assertFalse, {})
+ assertFailureEquals( 'expected: false, actual: "abc"', lu.assertFalse, 'abc')
+ assertFailureContains( 'expected: false, actual: function', lu.assertFalse, function () end )
+
+ assertFailureEquals( 'toto\nexpected: true, actual: false', lu.assertTrue, false, 'toto' )
+ assertFailureEquals( 'toto\nexpected: false, actual: 0', lu.assertFalse, 0, 'toto')
+ end
+
+ function TestLuaUnitErrorMsg:test_assertEvalToTrueFalse()
+ assertFailureEquals( 'expected: a value evaluating to true, actual: false', lu.assertEvalToTrue, false )
+ assertFailureEquals( 'expected: a value evaluating to true, actual: nil', lu.assertEvalToTrue, nil )
+ assertFailureEquals( 'expected: false or nil, actual: true', lu.assertEvalToFalse, true )
+ assertFailureEquals( 'expected: false or nil, actual: 0', lu.assertEvalToFalse, 0)
+ assertFailureMatches( 'expected: false or nil, actual: {}', lu.assertEvalToFalse, {})
+ assertFailureEquals( 'expected: false or nil, actual: "abc"', lu.assertEvalToFalse, 'abc')
+ assertFailureContains( 'expected: false or nil, actual: function', lu.assertEvalToFalse, function () end )
+ assertFailureEquals( 'toto\nexpected: a value evaluating to true, actual: false', lu.assertEvalToTrue, false, 'toto' )
+ assertFailureEquals( 'toto\nexpected: false or nil, actual: 0', lu.assertEvalToFalse, 0, 'toto')
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNil()
+ assertFailureEquals( 'expected: nil, actual: false', lu.assertNil, false )
+ assertFailureEquals( 'toto\nexpected: nil, actual: false', lu.assertNil, false, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotNil()
+ assertFailureEquals( 'expected: not nil, actual: nil', lu.assertNotNil, nil )
+ assertFailureEquals( 'toto\nexpected: not nil, actual: nil', lu.assertNotNil, nil, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertStrContains()
+ assertFailureEquals( 'Could not find substring "xxx" in string "abcdef"', lu.assertStrContains, 'abcdef', 'xxx' )
+ assertFailureEquals( 'Could not find substring "aBc" in string "abcdef"', lu.assertStrContains, 'abcdef', 'aBc' )
+ assertFailureEquals( 'Could not find substring "xxx" in string ""', lu.assertStrContains, '', 'xxx' )
+
+ assertFailureEquals( 'Could not find substring "xxx" in string "abcdef"', lu.assertStrContains, 'abcdef', 'xxx', false )
+ assertFailureEquals( 'Could not find substring "aBc" in string "abcdef"', lu.assertStrContains, 'abcdef', 'aBc', false )
+ assertFailureEquals( 'Could not find substring "xxx" in string ""', lu.assertStrContains, '', 'xxx', false )
+
+ assertFailureEquals( 'Could not find pattern "xxx" in string "abcdef"', lu.assertStrContains, 'abcdef', 'xxx', true )
+ assertFailureEquals( 'Could not find pattern "aBc" in string "abcdef"', lu.assertStrContains, 'abcdef', 'aBc', true )
+ assertFailureEquals( 'Could not find pattern "xxx" in string ""', lu.assertStrContains, '', 'xxx', true )
+
+ assertFailureEquals( 'toto\nCould not find pattern "xxx" in string ""', lu.assertStrContains, '', 'xxx', true, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertStrIContains()
+ assertFailureEquals( 'Could not find (case insensitively) substring "xxx" in string "abcdef"', lu.assertStrIContains, 'abcdef', 'xxx' )
+ assertFailureEquals( 'Could not find (case insensitively) substring "xxx" in string ""', lu.assertStrIContains, '', 'xxx' )
+
+ assertFailureEquals( 'toto\nCould not find (case insensitively) substring "xxx" in string "abcdef"', lu.assertStrIContains, 'abcdef', 'xxx', 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotStrContains()
+ assertFailureEquals( 'Found the not expected substring "abc" in string "abcdef"', lu.assertNotStrContains, 'abcdef', 'abc' )
+ assertFailureEquals( 'Found the not expected substring "abc" in string "abcdef"', lu.assertNotStrContains, 'abcdef', 'abc', false )
+ assertFailureEquals( 'Found the not expected pattern "..." in string "abcdef"', lu.assertNotStrContains, 'abcdef', '...', true)
+
+ assertFailureEquals( 'toto\nFound the not expected substring "abc" in string "abcdef"', lu.assertNotStrContains, 'abcdef', 'abc', false, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotStrIContains()
+ assertFailureEquals( 'Found (case insensitively) the not expected substring "aBc" in string "abcdef"', lu.assertNotStrIContains, 'abcdef', 'aBc' )
+ assertFailureEquals( 'Found (case insensitively) the not expected substring "abc" in string "abcdef"', lu.assertNotStrIContains, 'abcdef', 'abc' )
+ assertFailureEquals( 'toto\nFound (case insensitively) the not expected substring "abc" in string "abcdef"', lu.assertNotStrIContains, 'abcdef', 'abc', 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertStrMatches()
+ assertFailureEquals('Could not match pattern "xxx" with string "abcdef"', lu.assertStrMatches, 'abcdef', 'xxx' )
+ assertFailureEquals('toto\nCould not match pattern "xxx" with string "abcdef"', lu.assertStrMatches, 'abcdef', 'xxx', nil, nil, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertIsNumber()
+ assertFailureEquals( 'expected: a number value, actual: type string, value "abc"', lu.assertIsNumber, 'abc' )
+ assertFailureEquals( 'expected: a number value, actual: nil', lu.assertIsNumber, nil )
+ assertFailureEquals( 'toto\nexpected: a number value, actual: type string, value "abc"', lu.assertIsNumber, 'abc', 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertIsString()
+ assertFailureEquals( 'expected: a string value, actual: type number, value 1.2', lu.assertIsString, 1.2 )
+ assertFailureEquals( 'expected: a string value, actual: nil', lu.assertIsString, nil )
+ assertFailureEquals( 'toto\nexpected: a string value, actual: nil', lu.assertIsString, nil, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertIsTable()
+ assertFailureEquals( 'expected: a table value, actual: type number, value 1.2', lu.assertIsTable, 1.2 )
+ assertFailureEquals( 'expected: a table value, actual: nil', lu.assertIsTable, nil )
+ assertFailureEquals( 'toto\nexpected: a table value, actual: nil', lu.assertIsTable, nil, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertIsBoolean()
+ assertFailureEquals( 'expected: a boolean value, actual: type number, value 1.2', lu.assertIsBoolean, 1.2 )
+ assertFailureEquals( 'expected: a boolean value, actual: nil', lu.assertIsBoolean, nil )
+ assertFailureEquals( 'toto\nexpected: a boolean value, actual: nil', lu.assertIsBoolean, nil, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertIsFunction()
+ assertFailureEquals( 'expected: a function value, actual: type number, value 1.2', lu.assertIsFunction, 1.2 )
+ assertFailureEquals( 'expected: a function value, actual: nil', lu.assertIsFunction, nil )
+ assertFailureEquals( 'toto\nexpected: a function value, actual: nil', lu.assertIsFunction, nil, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertIsThread()
+ assertFailureEquals( 'expected: a thread value, actual: type number, value 1.2', lu.assertIsThread, 1.2 )
+ assertFailureEquals( 'expected: a thread value, actual: nil', lu.assertIsThread, nil )
+ assertFailureEquals( 'toto\nexpected: a thread value, actual: nil', lu.assertIsThread, nil, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertIsUserdata()
+ assertFailureEquals( 'expected: a userdata value, actual: type number, value 1.2', lu.assertIsUserdata, 1.2 )
+ assertFailureEquals( 'expected: a userdata value, actual: nil', lu.assertIsUserdata, nil )
+ assertFailureEquals( 'toto\nexpected: a userdata value, actual: nil', lu.assertIsUserdata, nil, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertIsNan()
+ assertFailureEquals( 'expected: NaN, actual: 33', lu.assertIsNaN, 33 )
+ assertFailureEquals( 'toto\nexpected: NaN, actual: 33', lu.assertIsNaN, 33, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotIsNan()
+ assertFailureEquals( 'expected: not NaN, actual: NaN', lu.assertNotIsNaN, 0 / 0 )
+ assertFailureEquals( 'toto\nexpected: not NaN, actual: NaN', lu.assertNotIsNaN, 0 / 0, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertIsInf()
+ assertFailureEquals( 'expected: #Inf, actual: 33', lu.assertIsInf, 33 )
+ assertFailureEquals( 'toto\nexpected: #Inf, actual: 33', lu.assertIsInf, 33, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertIsPlusInf()
+ assertFailureEquals( 'expected: #Inf, actual: 33', lu.assertIsPlusInf, 33 )
+ assertFailureEquals( 'toto\nexpected: #Inf, actual: 33', lu.assertIsPlusInf, 33, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertIsMinusInf()
+ assertFailureEquals( 'expected: -#Inf, actual: 33', lu.assertIsMinusInf, 33 )
+ assertFailureEquals( 'toto\nexpected: -#Inf, actual: 33', lu.assertIsMinusInf, 33, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotIsInf()
+ assertFailureEquals( 'expected: not infinity, actual: #Inf', lu.assertNotIsInf, 1 / 0 )
+ assertFailureEquals( 'toto\nexpected: not infinity, actual: -#Inf', lu.assertNotIsInf, -1 / 0, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotIsPlusInf()
+ assertFailureEquals( 'expected: not #Inf, actual: #Inf', lu.assertNotIsPlusInf, 1 / 0 )
+ assertFailureEquals( 'toto\nexpected: not #Inf, actual: #Inf', lu.assertNotIsPlusInf, 1 / 0, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotIsMinusInf()
+ assertFailureEquals( 'expected: not -#Inf, actual: -#Inf', lu.assertNotIsMinusInf, -1 / 0 )
+ assertFailureEquals( 'toto\nexpected: not -#Inf, actual: -#Inf', lu.assertNotIsMinusInf, -1 / 0, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertIsPlusZero()
+ assertFailureEquals( 'expected: +0.0, actual: 33', lu.assertIsPlusZero, 33 )
+ assertFailureEquals( 'toto\nexpected: +0.0, actual: 33', lu.assertIsPlusZero, 33, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertIsMinusZero()
+ assertFailureEquals( 'expected: -0.0, actual: 33', lu.assertIsMinusZero, 33 )
+ assertFailureEquals( 'toto\nexpected: -0.0, actual: 33', lu.assertIsMinusZero, 33, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotIsPlusZero()
+ assertFailureEquals( 'expected: not +0.0, actual: +0.0', lu.assertNotIsPlusZero, 0 )
+ assertFailureEquals( 'toto\nexpected: not +0.0, actual: +0.0', lu.assertNotIsPlusZero, 0, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotIsMinusZero()
+ local minusZero = -1 / (1/0)
+ assertFailureEquals( 'expected: not -0.0, actual: -0.0', lu.assertNotIsMinusZero, minusZero )
+ assertFailureEquals( 'toto\nexpected: not -0.0, actual: -0.0', lu.assertNotIsMinusZero, minusZero, 'toto' )
+ end
+
+
+ function TestLuaUnitErrorMsg:test_assertNotIsTrue()
+ assertFailureEquals('expected: not true, actual: true', lu.assertNotIsTrue, true )
+ assertFailureEquals('toto\nexpected: not true, actual: true', lu.assertNotIsTrue, true, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotIsFalse()
+ assertFailureEquals('expected: not false, actual: false', lu.assertNotIsFalse, false )
+ assertFailureEquals('toto\nexpected: not false, actual: false', lu.assertNotIsFalse, false, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotIsNil()
+ assertFailureEquals(
+ 'expected: not nil, actual: nil',
+ lu.assertNotIsNil, nil )
+ assertFailureEquals(
+ 'toto\nexpected: not nil, actual: nil',
+ lu.assertNotIsNil, nil, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotIsNumber()
+ assertFailureEquals( 'expected: not a number type, actual: value 123', lu.assertNotIsNumber, 123 )
+ assertFailureEquals( 'toto\nexpected: not a number type, actual: value 123', lu.assertNotIsNumber, 123, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotIsString()
+ assertFailureEquals( 'expected: not a string type, actual: value "abc"', lu.assertNotIsString, "abc" )
+ assertFailureEquals( 'toto\nexpected: not a string type, actual: value "abc"', lu.assertNotIsString, "abc", 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotIsTable()
+ assertFailureEquals( 'expected: not a table type, actual: value {1, 2, 3}', lu.assertNotIsTable, {1,2,3} )
+ assertFailureEquals( 'toto\nexpected: not a table type, actual: value {1, 2, 3}', lu.assertNotIsTable, {1,2,3}, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotIsBoolean()
+ assertFailureEquals( 'expected: not a boolean type, actual: value false', lu.assertNotIsBoolean, false )
+ assertFailureEquals( 'toto\nexpected: not a boolean type, actual: value false', lu.assertNotIsBoolean, false, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotIsFunction()
+ assertFailureContains( 'expected: not a function type, actual: value function:', lu.assertNotIsFunction, function() return true end )
+ assertFailureContains( 'toto\nexpected: not a function type, actual: value function:', lu.assertNotIsFunction, function() return true end, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotIsThread()
+ assertFailureContains( 'expected: not a thread type, actual: value thread:', lu.assertNotIsThread, coroutine.create( function(v) local y=v+1 end ) )
+ assertFailureContains( 'toto\nexpected: not a thread type, actual: value thread:', lu.assertNotIsThread, coroutine.create( function(v) local y=v+1 end ), 'toto' )
+ end
+
+ --[[ How do you create UserData ?
+ function TestLuaUnitErrorMsg:test_assertIsNotUserdata()
+ assertFailureEquals( 'Not expected: a userdata type, actual: value XXX ???', lu.assertIsNotUserdata, XXX ??? )
+ end
+ ]]
+
+ function TestLuaUnitErrorMsg:test_assertIs()
+ assertFailureEquals( 'expected and actual object should not be different\nExpected: 1\nReceived: 2', lu.assertIs, 2, 1 )
+ assertFailureMatches( 'expected and actual object should not be different\n'..
+ 'Expected: <'..TABLE_IDX_REF_PAT..'> {1, 2, 3, 4, 5, 6, 7, 8}\n'..
+ 'Received: <'..TABLE_IDX_REF_PAT..'> {1, 2, 3, 4, 5, 6, 7, 8}',
+ lu.assertIs, {1,2,3,4,5,6,7,8}, {1,2,3,4,5,6,7,8} )
+ lu.ORDER_ACTUAL_EXPECTED = false
+ assertFailureEquals( 'expected and actual object should not be different\nExpected: 2\nReceived: 1', lu.assertIs, 2, 1 )
+ assertFailureEquals( 'toto\nexpected and actual object should not be different\nExpected: 2\nReceived: 1', lu.assertIs, 2, 1, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertNotIs()
+ local v = {1,2}
+ assertFailureMatches( 'expected and actual object should be different: <'..TABLE_IDX_REF_PAT..'> {1, 2}', lu.assertNotIs, v, v )
+ lu.ORDER_ACTUAL_EXPECTED = false -- order shouldn't matter here, but let's cover it
+ assertFailureMatches( 'expected and actual object should be different: <'..TABLE_IDX_REF_PAT..'> {1, 2}', lu.assertNotIs, v, v )
+ assertFailureMatches( 'toto\nexpected and actual object should be different: <'..TABLE_IDX_REF_PAT..'> {1, 2}', lu.assertNotIs, v, v, 'toto' )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertItemsEquals()
+ assertFailureMatches('Content of the tables are not identical:\nExpected: {one=2, two=3}\nActual: {1, 2}' , lu.assertItemsEquals, {1,2}, {one=2, two=3} )
+ assertFailureContains('Content of the tables are not identical' , lu.assertItemsEquals, {}, {1} ) -- actual table empty, = doesn't contain expected value
+ assertFailureContains('Content of the tables are not identical' , lu.assertItemsEquals, nil, 'foobar' ) -- type mismatch
+ assertFailureContains('Content of the tables are not identical' , lu.assertItemsEquals, 'foo', 'bar' ) -- value mismatch
+ assertFailureContains('toto\nContent of the tables are not identical' , lu.assertItemsEquals, 'foo', 'bar', 'toto' ) -- value mismatch
+ end
+
+ function TestLuaUnitErrorMsg:test_assertError()
+ assertFailureEquals('Expected an error when calling function but no error generated' , lu.assertError, function( v ) local y = v+1 end, 3 )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertErrorMsgEquals()
+ assertFailureEquals('No error generated when calling function but expected error: "bla bla bla"' ,
+ lu.assertErrorMsgEquals, 'bla bla bla', function( v ) local y = v+1 end, 3 )
+ assertFailureEquals('Error message expected: "bla bla bla"\n' ..
+ 'Error message received: "toto xxx"\n' ,
+ lu.assertErrorMsgEquals, 'bla bla bla', function( v ) error('toto xxx',2) end, 3 )
+ assertFailureEquals('Error message expected: {1, 2, 3, 4}\nError message received: {1, 2, 3}\n' ,
+ lu.assertErrorMsgEquals, {1,2,3,4}, function( v ) error(v) end, {1,2,3})
+ assertFailureEquals('Error message expected: {details="bla bla bla"}\nError message received: {details="ble ble ble"}\n' ,
+ lu.assertErrorMsgEquals, {details="bla bla bla"}, function( v ) error(v) end, {details="ble ble ble"})
+ end
+
+ function TestLuaUnitErrorMsg:test_assertErrorMsgContains()
+ assertFailureEquals('No error generated when calling function but expected error containing: "bla bla bla"' ,
+ lu.assertErrorMsgContains, 'bla bla bla', function( v ) local y = v+1 end, 3 )
+ assertFailureEquals('Error message does not contain: "bla bla bla"\nError message received: "toto xxx"\n' ,
+ lu.assertErrorMsgContains, 'bla bla bla', function( v ) error('toto xxx',2) end, 3 )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertErrorMsgMatches()
+ assertFailureEquals('No error generated when calling function but expected error matching: "bla bla bla"' ,
+ lu.assertErrorMsgMatches, 'bla bla bla', function( v ) local y = v+1 end, 3 )
+
+ assertFailureEquals('Error message does not match pattern: "bla bla bla"\n' ..
+ 'Error message received: "toto xxx"\n' ,
+ lu.assertErrorMsgMatches, 'bla bla bla', function( v ) error('toto xxx',2) end, 3 )
+ end
+
+ function TestLuaUnitErrorMsg:test_assertErrorMsgContentEquals()
+ local f = function() error("This is error message") end
+ lu.assertErrorMsgContentEquals("This is error message", f)
+ local f1 = function(v1, v2) error("This is error message") end
+ lu.assertErrorMsgContentEquals("This is error message", f, 1, 2)
+ end
+
+ function TestLuaUnitErrorMsg:test_printTableWithRef()
+ lu.PRINT_TABLE_REF_IN_ERROR_MSG = true
+ assertFailureMatches( 'Received the not expected value: <'..TABLE_IDX_REF_PAT..'> {1, 2}', lu.assertNotEquals, {1,2}, {1,2} )
+ -- trigger multiline prettystr
+ assertFailureMatches( 'Received the not expected value: <'..TABLE_IDX_REF_PAT..'> {1, 2, 3, 4}', lu.assertNotEquals, {1,2,3,4}, {1,2,3,4} )
+ assertFailureMatches( 'expected: false, actual: <'..TABLE_IDX_REF_PAT..'> {}', lu.assertFalse, {})
+ local v = {1,2}
+ assertFailureMatches( 'expected and actual object should be different: <'..TABLE_IDX_REF_PAT..'> {1, 2}', lu.assertNotIs, v, v )
+ assertFailureMatches('Content of the tables are not identical:\nExpected: <'..TABLE_IDX_REF_PAT..'> {one=2, two=3}\nActual: <'..TABLE_IDX_REF_PAT..'> {1, 2}' , lu.assertItemsEquals, {1,2}, {one=2, two=3} )
+ assertFailureMatches( 'expected: <'..TABLE_IDX_REF_PAT..'> {1, 2}\nactual: <'..TABLE_IDX_REF_PAT..'> {2, 1}', lu.assertEquals, {2,1}, {1,2} )
+ -- trigger multiline prettystr
+ assertFailureMatches( 'expected: <'..TABLE_IDX_REF_PAT..'> {one=1, two=2}\nactual: <'..TABLE_IDX_REF_PAT..'> {3, 2, 1}', lu.assertEquals, {3,2,1}, {one=1,two=2} )
+ -- trigger mismatch formatting
+ lu.assertErrorMsgContains( [[lists <table ]] , lu.assertEquals, {3,2,1,4,1,1,1,1,1,1,1}, {1,2,3,4,1,1,1,1,1,1,1} )
+ lu.assertErrorMsgContains( [[and <table ]] , lu.assertEquals, {3,2,1,4,1,1,1,1,1,1,1}, {1,2,3,4,1,1,1,1,1,1,1} )
+
+ end
+
+------------------------------------------------------------------
+--
+-- Execution Tests
+--
+------------------------------------------------------------------
+
+local executedTests
+
+MyTestToto1 = {} --class
+ function MyTestToto1:test1() table.insert( executedTests, "MyTestToto1:test1" ) end
+ function MyTestToto1:testb() table.insert( executedTests, "MyTestToto1:testb" ) end
+ function MyTestToto1:test3() table.insert( executedTests, "MyTestToto1:test3" ) end
+ function MyTestToto1:testa() table.insert( executedTests, "MyTestToto1:testa" ) end
+ function MyTestToto1:test2() table.insert( executedTests, "MyTestToto1:test2" ) end
+
+MyTestToto2 = {} --class
+ function MyTestToto2:test1() table.insert( executedTests, "MyTestToto2:test1" ) end
+
+MyTestWithErrorsAndFailures = {} --class
+ function MyTestWithErrorsAndFailures:testWithFailure1() lu.assertEquals(1, 2) end
+ function MyTestWithErrorsAndFailures:testWithFailure2() lu.assertError( function() end ) end
+ function MyTestWithErrorsAndFailures:testWithError1() error('some error') end
+ function MyTestWithErrorsAndFailures:testOk() end
+
+MyTestOk = {} --class
+ function MyTestOk:testOk1() end
+ function MyTestOk:testOk2() end
+
+function MyTestFunction()
+ table.insert( executedTests, "MyTestFunction" )
+end
+
+TestLuaUnitExecution = { __class__ = 'TestLuaUnitExecution' }
+
+ function TestLuaUnitExecution:tearDown()
+ executedTests = {}
+ lu.LuaUnit.isTestName = lu.LuaUnit.isTestNameOld
+ end
+
+ function TestLuaUnitExecution:setUp()
+ executedTests = {}
+ lu.LuaUnit.isTestNameOld = lu.LuaUnit.isTestName
+ lu.LuaUnit.isTestName = function( s ) return (string.sub(s,1,6) == 'MyTest') end
+ end
+
+ function TestLuaUnitExecution:oneInstanceExists()
+ lu.assertEquals( #lu.LuaUnit.instances, 1 )
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuite( 'MyTestToto2', 'MyTestToto1', 'MyTestFunction' )
+
+ -- number of instances cleanup was done properly
+ lu.assertEquals( #lu.LuaUnit.instances, 1 )
+ end
+
+ function TestLuaUnitExecution:canNotExitDuringLuaUnitExecution()
+ lu.assertFailure(os.exit, 0)
+ end
+
+ function TestLuaUnitExecution:test_collectTests()
+ local allTests = lu.LuaUnit.collectTests()
+ lu.assertEquals( allTests, {"MyTestFunction", "MyTestOk", "MyTestToto1", "MyTestToto2","MyTestWithErrorsAndFailures"})
+ end
+
+ function TestLuaUnitExecution:test_MethodsAreExecutedInRightOrder()
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuite( 'MyTestToto1' )
+ lu.assertEquals( #executedTests, 5 )
+ lu.assertEquals( executedTests[1], "MyTestToto1:test1" )
+ lu.assertEquals( executedTests[2], "MyTestToto1:test2" )
+ lu.assertEquals( executedTests[3], "MyTestToto1:test3" )
+ lu.assertEquals( executedTests[4], "MyTestToto1:testa" )
+ lu.assertEquals( executedTests[5], "MyTestToto1:testb" )
+ end
+
+ function TestLuaUnitExecution:test_runSuite()
+ -- note: this also test that names are executed in explicit order
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuite( 'MyTestToto2', 'MyTestToto1', 'MyTestFunction' )
+ lu.assertEquals( #executedTests, 7 )
+ lu.assertEquals( executedTests[1], "MyTestToto2:test1" )
+ lu.assertEquals( executedTests[2], "MyTestToto1:test1" )
+ lu.assertEquals( executedTests[7], "MyTestFunction" )
+ end
+
+ function TestLuaUnitExecution:testRunSomeTestByGlobalInstance( )
+ lu.assertEquals( #executedTests, 0 )
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'Toto', MyTestToto1 } }, 'fake_run_unit_tests.lua' )
+ lu.assertEquals( #executedTests, 5 )
+
+ lu.assertEquals( #runner.result.allTests, 5 )
+ lu.assertEquals( runner.result.allTests[1].testName, "Toto.test1" )
+ lu.assertEquals( runner.result.allTests[5].testName, "Toto.testb" )
+ end
+
+ function TestLuaUnitExecution:testRunSomeTestByLocalInstance( )
+ local MyLocalTestToto1 = {} --class
+ function MyLocalTestToto1:test1() table.insert( executedTests, "MyLocalTestToto1:test1" ) end
+ local MyLocalTestToto2 = {} --class
+ function MyLocalTestToto2:test1() table.insert( executedTests, "MyLocalTestToto2:test1" ) end
+ function MyLocalTestToto2:test2() table.insert( executedTests, "MyLocalTestToto2:test2" ) end
+ local function MyLocalTestFunction() table.insert( executedTests, "MyLocalTestFunction" ) end
+
+ lu.assertEquals( #executedTests, 0 )
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( {
+ { 'MyLocalTestToto1', MyLocalTestToto1 },
+ { 'MyLocalTestToto2.test2', MyLocalTestToto2 },
+ { 'MyLocalTestFunction', MyLocalTestFunction },
+ }, 'fake_run_unit_tests.lua' )
+ lu.assertEquals( #executedTests, 3 )
+ lu.assertEquals( executedTests[1], 'MyLocalTestToto1:test1')
+ lu.assertEquals( executedTests[2], 'MyLocalTestToto2:test2')
+ lu.assertEquals( executedTests[3], 'MyLocalTestFunction')
+ end
+
+ function TestLuaUnitExecution:testRunReturnsNumberOfFailures()
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ local ret = runner:runSuite( 'MyTestWithErrorsAndFailures' )
+ lu.assertEquals(ret, 3)
+
+ ret = runner:runSuite( 'MyTestToto1' )
+ lu.assertEquals(ret, 0)
+ end
+
+ function TestLuaUnitExecution:testTestCountAndFailCount()
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuite( 'MyTestWithErrorsAndFailures' )
+ lu.assertEquals( runner.result.selectedCount, 4)
+ lu.assertEquals( runner.result.notSuccessCount, 3)
+ lu.assertEquals( runner.result.failureCount, 2)
+ lu.assertEquals( runner.result.errorCount, 1)
+
+ runner:runSuite( 'MyTestToto1' )
+ lu.assertEquals( runner.result.selectedCount, 5)
+ lu.assertEquals( runner.result.notSuccessCount, 0)
+ lu.assertEquals( runner.result.failureCount, 0)
+ lu.assertEquals( runner.result.errorCount, 0)
+ end
+
+ function TestLuaUnitExecution:testRunSetupAndTeardown()
+ local myExecutedTests = {}
+ local MyTestWithSetupTeardown = {}
+ function MyTestWithSetupTeardown:setUp() table.insert( myExecutedTests, '1setUp' ) end
+ function MyTestWithSetupTeardown:test1() table.insert( myExecutedTests, '1test1' ) end
+ function MyTestWithSetupTeardown:test2() table.insert( myExecutedTests, '1test2' ) end
+ function MyTestWithSetupTeardown:tearDown() table.insert( myExecutedTests, '1tearDown' ) end
+
+ local MyTestWithSetupTeardown2 = {}
+ function MyTestWithSetupTeardown2:setUp() table.insert( myExecutedTests, '2setUp' ) end
+ function MyTestWithSetupTeardown2:test1() table.insert( myExecutedTests, '2test1' ) end
+ function MyTestWithSetupTeardown2:tearDown() table.insert( myExecutedTests, '2tearDown' ) end
+
+ local MyTestWithSetupTeardown3 = {}
+ function MyTestWithSetupTeardown3:Setup() table.insert( myExecutedTests, '3Setup' ) end
+ function MyTestWithSetupTeardown3:test1() table.insert( myExecutedTests, '3test1' ) end
+ function MyTestWithSetupTeardown3:Teardown() table.insert( myExecutedTests, '3Teardown' ) end
+
+ local MyTestWithSetupTeardown4 = {}
+ function MyTestWithSetupTeardown4:setup() table.insert( myExecutedTests, '4setup' ) end
+ function MyTestWithSetupTeardown4:test1() table.insert( myExecutedTests, '4test1' ) end
+ function MyTestWithSetupTeardown4:teardown() table.insert( myExecutedTests, '4teardown' ) end
+
+ local MyTestWithSetupTeardown5 = {}
+ function MyTestWithSetupTeardown5:SetUp() table.insert( myExecutedTests, '5SetUp' ) end
+ function MyTestWithSetupTeardown5:test1() table.insert( myExecutedTests, '5test1' ) end
+ function MyTestWithSetupTeardown5:TearDown() table.insert( myExecutedTests, '5TearDown' ) end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'MyTestWithSetupTeardown.test1', MyTestWithSetupTeardown } } )
+ lu.assertEquals( runner.result.notSuccessCount, 0 )
+ lu.assertEquals( myExecutedTests[1], '1setUp' )
+ lu.assertEquals( myExecutedTests[2], '1test1')
+ lu.assertEquals( myExecutedTests[3], '1tearDown')
+ lu.assertEquals( #myExecutedTests, 3)
+
+ myExecutedTests = {}
+ runner:runSuiteByInstances( {
+ { 'MyTestWithSetupTeardown', MyTestWithSetupTeardown },
+ { 'MyTestWithSetupTeardown2', MyTestWithSetupTeardown2 },
+ { 'MyTestWithSetupTeardown3', MyTestWithSetupTeardown3 },
+ { 'MyTestWithSetupTeardown4', MyTestWithSetupTeardown4 },
+ { 'MyTestWithSetupTeardown5', MyTestWithSetupTeardown5 }
+ }, 'fake_run_unit_tests.lua' )
+ lu.assertEquals( runner.result.notSuccessCount, 0 )
+ lu.assertEquals( myExecutedTests[1], '1setUp' )
+ lu.assertEquals( myExecutedTests[2], '1test1')
+ lu.assertEquals( myExecutedTests[3], '1tearDown')
+ lu.assertEquals( myExecutedTests[4], '1setUp' )
+ lu.assertEquals( myExecutedTests[5], '1test2')
+ lu.assertEquals( myExecutedTests[6], '1tearDown')
+ lu.assertEquals( myExecutedTests[7], '2setUp' )
+ lu.assertEquals( myExecutedTests[8], '2test1')
+ lu.assertEquals( myExecutedTests[9], '2tearDown')
+ lu.assertEquals( myExecutedTests[10], '3Setup')
+ lu.assertEquals( myExecutedTests[11], '3test1')
+ lu.assertEquals( myExecutedTests[12], '3Teardown')
+ lu.assertEquals( myExecutedTests[13], '4setup')
+ lu.assertEquals( myExecutedTests[14], '4test1')
+ lu.assertEquals( myExecutedTests[15], '4teardown')
+ lu.assertEquals( myExecutedTests[16], '5SetUp')
+ lu.assertEquals( myExecutedTests[17], '5test1')
+ lu.assertEquals( myExecutedTests[18], '5TearDown')
+ lu.assertEquals( #myExecutedTests, 18)
+ end
+
+ function TestLuaUnitExecution:testWithSetupTeardownFailure1()
+ local myExecutedTests = {}
+
+ local MyTestWithSetupFailure = {}
+ function MyTestWithSetupFailure:setUp() table.insert( myExecutedTests, 'setUp' ) lu.assertEquals( 'b', 'c') end
+ function MyTestWithSetupFailure:test1() table.insert( myExecutedTests, 'test1' ) end
+ function MyTestWithSetupFailure:tearDown() table.insert( myExecutedTests, 'tearDown' ) end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'MyTestWithSetupFailure', MyTestWithSetupFailure } } )
+ lu.assertEquals( runner.result.notSuccessCount, 1 )
+ lu.assertEquals( runner.result.failureCount, 1 )
+ lu.assertEquals( runner.result.errorCount, 0 )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( myExecutedTests[1], 'setUp' )
+ lu.assertEquals( myExecutedTests[2], 'tearDown')
+ lu.assertEquals( #myExecutedTests, 2)
+ lu.assertEquals( runner.result.failedTests[1].status, lu.NodeStatus.FAIL )
+ end
+
+ function TestLuaUnitExecution:testWithSetupTeardownFailure2()
+ local myExecutedTests = {}
+
+ local MyTestWithSetupFailure = {}
+ function MyTestWithSetupFailure:setUp() table.insert( myExecutedTests, 'setUp' ) end
+ function MyTestWithSetupFailure:test1() table.insert( myExecutedTests, 'test1' ) end
+ function MyTestWithSetupFailure:tearDown() table.insert( myExecutedTests, 'tearDown' ) lu.assertEquals( 'b', 'c') end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'MyTestWithSetupFailure', MyTestWithSetupFailure } } )
+ lu.assertEquals( runner.result.notSuccessCount, 1 )
+ lu.assertEquals( runner.result.failureCount, 1 )
+ lu.assertEquals( runner.result.errorCount, 0 )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( myExecutedTests[1], 'setUp' )
+ lu.assertEquals( myExecutedTests[2], 'test1' )
+ lu.assertEquals( myExecutedTests[3], 'tearDown')
+ lu.assertEquals( #myExecutedTests, 3)
+ lu.assertEquals( runner.result.failedTests[1].status, lu.NodeStatus.FAIL )
+ end
+
+ function TestLuaUnitExecution:testWithSetupTeardownFailure3()
+ local myExecutedTests = {}
+
+ local MyTestWithSetupFailure = {}
+ function MyTestWithSetupFailure:setUp() table.insert( myExecutedTests, 'setUp' ) lu.assertEquals( 'b', 'c') end
+ function MyTestWithSetupFailure:test1() table.insert( myExecutedTests, 'test1' ) end
+ function MyTestWithSetupFailure:tearDown() table.insert( myExecutedTests, 'tearDown' ) lu.assertEquals( 'b', 'c') end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'MyTestWithSetupFailure', MyTestWithSetupFailure } } )
+ lu.assertEquals( runner.result.notSuccessCount, 1 )
+ -- Note: in the future, we may want to report two failures for this
+ lu.assertEquals( runner.result.failureCount, 1 )
+ lu.assertEquals( runner.result.errorCount, 0 )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( myExecutedTests[1], 'setUp' )
+ lu.assertEquals( myExecutedTests[2], 'tearDown')
+ lu.assertEquals( #myExecutedTests, 2)
+ lu.assertEquals( runner.result.failedTests[1].status, lu.NodeStatus.FAIL )
+ end
+
+ function TestLuaUnitExecution:testWithSetupTeardownFailure4()
+ local myExecutedTests = {}
+
+ local MyTestWithSetupFailure = {}
+ function MyTestWithSetupFailure:setUp() table.insert( myExecutedTests, 'setUp' ) lu.assertEquals( 'b', 'c') end
+ function MyTestWithSetupFailure:test1() table.insert( myExecutedTests, 'test1' ) lu.assertEquals( 'b', 'c') end
+ function MyTestWithSetupFailure:tearDown() table.insert( myExecutedTests, 'tearDown' ) lu.assertEquals( 'b', 'c') end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'MyTestWithSetupFailure', MyTestWithSetupFailure } } )
+ lu.assertEquals( runner.result.notSuccessCount, 1 )
+ -- Note: in the future, we may want to report two failures for this
+ lu.assertEquals( runner.result.failureCount, 1 )
+ lu.assertEquals( runner.result.errorCount, 0 )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( myExecutedTests[1], 'setUp' )
+ lu.assertEquals( myExecutedTests[2], 'tearDown')
+ lu.assertEquals( #myExecutedTests, 2)
+ lu.assertEquals( runner.result.failedTests[1].status, lu.NodeStatus.FAIL )
+ end
+
+ function TestLuaUnitExecution:testWithSetupTeardownFailure5()
+ local myExecutedTests = {}
+
+ local MyTestWithSetupFailure = {}
+ function MyTestWithSetupFailure:setUp() table.insert( myExecutedTests, 'setUp' ) end
+ function MyTestWithSetupFailure:test1() table.insert( myExecutedTests, 'test1' ) lu.assertEquals( 'b', 'c') end
+ function MyTestWithSetupFailure:tearDown() table.insert( myExecutedTests, 'tearDown' ) lu.assertEquals( 'b', 'c') end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'MyTestWithSetupFailure', MyTestWithSetupFailure } } )
+ lu.assertEquals( runner.result.notSuccessCount, 1 )
+ -- Note: in the future, we may want to report two failures for this
+ lu.assertEquals( runner.result.failureCount, 1 )
+ lu.assertEquals( runner.result.errorCount, 0 )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( myExecutedTests[1], 'setUp' )
+ lu.assertEquals( myExecutedTests[2], 'test1' )
+ lu.assertEquals( myExecutedTests[3], 'tearDown')
+ lu.assertEquals( #myExecutedTests, 3)
+ lu.assertEquals( runner.result.failedTests[1].status, lu.NodeStatus.FAIL )
+ end
+
+ function TestLuaUnitExecution:testWithSetupTeardownErrors1()
+ local myExecutedTests = {}
+
+ local MyTestWithSetupError = {}
+ function MyTestWithSetupError:setUp() table.insert( myExecutedTests, 'setUp' ) error('setup error') end
+ function MyTestWithSetupError:test1() table.insert( myExecutedTests, 'test1' ) end
+ function MyTestWithSetupError:tearDown() table.insert( myExecutedTests, 'tearDown' ) end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'MyTestWithSetupError', MyTestWithSetupError } } )
+ lu.assertEquals( runner.result.notSuccessCount, 1 )
+ lu.assertEquals( runner.result.failureCount, 0 )
+ lu.assertEquals( runner.result.errorCount, 1 )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( myExecutedTests[1], 'setUp' )
+ lu.assertEquals( myExecutedTests[2], 'tearDown')
+ lu.assertEquals( #myExecutedTests, 2)
+ lu.assertEquals( runner.result.errorTests[1].status, lu.NodeStatus.ERROR )
+ end
+
+ function TestLuaUnitExecution:testWithSetupTeardownErrors2()
+ local myExecutedTests = {}
+
+ local MyTestWithSetupError = {}
+ function MyTestWithSetupError:setUp() table.insert( myExecutedTests, 'setUp' ) end
+ function MyTestWithSetupError:test1() table.insert( myExecutedTests, 'test1' ) end
+ function MyTestWithSetupError:tearDown() table.insert( myExecutedTests, 'tearDown' ) error('teardown error') end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'MyTestWithSetupError', MyTestWithSetupError } } )
+ lu.assertEquals( runner.result.notSuccessCount, 1 )
+ lu.assertEquals( runner.result.failureCount, 0 )
+ lu.assertEquals( runner.result.errorCount, 1 )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( myExecutedTests[1], 'setUp' )
+ lu.assertEquals( myExecutedTests[2], 'test1' )
+ lu.assertEquals( myExecutedTests[3], 'tearDown')
+ lu.assertEquals( #myExecutedTests, 3)
+ lu.assertEquals( runner.result.errorTests[1].status, lu.NodeStatus.ERROR )
+ end
+
+ function TestLuaUnitExecution:testWithSetupTeardownErrors3()
+ local myExecutedTests = {}
+
+ local MyTestWithSetupError = {}
+ function MyTestWithSetupError:setUp() table.insert( myExecutedTests, 'setUp' ) error('setup error') end
+ function MyTestWithSetupError:test1() table.insert( myExecutedTests, 'test1' ) end
+ function MyTestWithSetupError:tearDown() table.insert( myExecutedTests, 'tearDown' ) error('teardown error') end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'MyTestWithSetupError', MyTestWithSetupError } } )
+ lu.assertEquals( runner.result.notSuccessCount, 1 )
+ -- Note: in the future, we may want to report two errors for this
+ lu.assertEquals( runner.result.failureCount, 0 )
+ lu.assertEquals( runner.result.errorCount, 1 )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( myExecutedTests[1], 'setUp' )
+ lu.assertEquals( myExecutedTests[2], 'tearDown')
+ lu.assertEquals( #myExecutedTests, 2)
+ lu.assertEquals( runner.result.errorTests[1].status, lu.NodeStatus.ERROR )
+ end
+
+ function TestLuaUnitExecution:testWithSetupTeardownErrors4()
+ local myExecutedTests = {}
+
+ local MyTestWithSetupError = {}
+ function MyTestWithSetupError:setUp() table.insert( myExecutedTests, 'setUp' ) error('setup error') end
+ function MyTestWithSetupError:test1() table.insert( myExecutedTests, 'test1' ) error('test error') end
+ function MyTestWithSetupError:tearDown() table.insert( myExecutedTests, 'tearDown' ) error('teardown error') end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'MyTestWithSetupError', MyTestWithSetupError } } )
+ lu.assertEquals( runner.result.notSuccessCount, 1 )
+ -- Note: in the future, we may want to report two errors for this
+ lu.assertEquals( runner.result.failureCount, 0 )
+ lu.assertEquals( runner.result.errorCount, 1 )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( myExecutedTests[1], 'setUp' )
+ lu.assertEquals( myExecutedTests[2], 'tearDown')
+ lu.assertEquals( #myExecutedTests, 2)
+ lu.assertEquals( runner.result.errorTests[1].status, lu.NodeStatus.ERROR )
+ end
+
+ function TestLuaUnitExecution:testWithSetupTeardownErrors5()
+ local myExecutedTests = {}
+
+ local MyTestWithSetupError = {}
+ function MyTestWithSetupError:setUp() table.insert( myExecutedTests, 'setUp' ) end
+ function MyTestWithSetupError:test1() table.insert( myExecutedTests, 'test1' ) error('test error') end
+ function MyTestWithSetupError:tearDown() table.insert( myExecutedTests, 'tearDown' ) error('teardown error') end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'MyTestWithSetupError', MyTestWithSetupError } } )
+ lu.assertEquals( runner.result.notSuccessCount, 1 )
+ -- Note: in the future, we may want to report two errors for this
+ lu.assertEquals( runner.result.failureCount, 0 )
+ lu.assertEquals( runner.result.errorCount, 1 )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( myExecutedTests[1], 'setUp' )
+ lu.assertEquals( myExecutedTests[2], 'test1' )
+ lu.assertEquals( myExecutedTests[3], 'tearDown')
+ lu.assertEquals( #myExecutedTests, 3)
+ lu.assertEquals( runner.result.errorTests[1].status, lu.NodeStatus.ERROR )
+ end
+
+ function TestLuaUnitExecution:testWithSetupTeardownErrorsAndFailures1()
+ local myExecutedTests = {}
+
+ local MyTestWithSetupError = {}
+ function MyTestWithSetupError:setUp() table.insert( myExecutedTests, 'setUp' ) lu.assertEquals( 'a', 'b') end
+ function MyTestWithSetupError:test1() table.insert( myExecutedTests, 'test1' ) end
+ function MyTestWithSetupError:tearDown() table.insert( myExecutedTests, 'tearDown' ) error('teardown error') end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'MyTestWithSetupError', MyTestWithSetupError } } )
+ lu.assertEquals( runner.result.notSuccessCount, 1 )
+ -- Note: in the future, we may want to report failure + error for this
+ lu.assertEquals( runner.result.failureCount, 1 )
+ lu.assertEquals( runner.result.errorCount, 0 )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( myExecutedTests[1], 'setUp' )
+ lu.assertEquals( myExecutedTests[2], 'tearDown')
+ lu.assertEquals( #myExecutedTests, 2)
+ -- The first error/failure set the whole test status
+ lu.assertEquals( runner.result.failedTests[1].status, lu.NodeStatus.FAIL )
+ end
+
+ function TestLuaUnitExecution:testWithSetupTeardownErrorsAndFailures2()
+ local myExecutedTests = {}
+
+ local MyTestWithSetupError = {}
+ function MyTestWithSetupError:setUp() table.insert( myExecutedTests, 'setUp' ) error('setup error') end
+ function MyTestWithSetupError:test1() table.insert( myExecutedTests, 'test1' ) end
+ function MyTestWithSetupError:tearDown() table.insert( myExecutedTests, 'tearDown' ) lu.assertEquals( 'a', 'b') end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'MyTestWithSetupError', MyTestWithSetupError } } )
+ lu.assertEquals( runner.result.notSuccessCount, 1 )
+ -- Note: in the future, we may want to report failure + error for this
+ lu.assertEquals( runner.result.failureCount, 0 )
+ lu.assertEquals( runner.result.errorCount, 1 )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( myExecutedTests[1], 'setUp' )
+ lu.assertEquals( myExecutedTests[2], 'tearDown')
+ lu.assertEquals( #myExecutedTests, 2)
+ -- The first error/failure set the whole test status
+ lu.assertEquals( runner.result.errorTests[1].status, lu.NodeStatus.ERROR )
+ end
+
+ function TestLuaUnitExecution:testWithSetupTeardownErrorsAndFailures3()
+ local myExecutedTests = {}
+
+ local MyTestWithSetupError = {}
+ function MyTestWithSetupError:setUp() table.insert( myExecutedTests, 'setUp' ) end
+ function MyTestWithSetupError:test1() table.insert( myExecutedTests, 'test1' ) error('test error') end
+ function MyTestWithSetupError:tearDown() table.insert( myExecutedTests, 'tearDown' ) lu.assertEquals( 'a', 'b') end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'MyTestWithSetupError', MyTestWithSetupError } } )
+ lu.assertEquals( runner.result.notSuccessCount, 1 )
+ -- Note: in the future, we may want to report failure + error for this
+ lu.assertEquals( runner.result.failureCount, 0 )
+ lu.assertEquals( runner.result.errorCount, 1 )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( myExecutedTests[1], 'setUp' )
+ lu.assertEquals( myExecutedTests[2], 'test1' )
+ lu.assertEquals( myExecutedTests[3], 'tearDown')
+ lu.assertEquals( #myExecutedTests, 3)
+ -- The first error/failure set the whole test status
+ lu.assertEquals( runner.result.errorTests[1].status, lu.NodeStatus.ERROR )
+ end
+
+ function TestLuaUnitExecution:testWithSetupTeardownErrorsAndFailures4()
+ local myExecutedTests = {}
+
+ local MyTestWithSetupError = {}
+ function MyTestWithSetupError:setUp() table.insert( myExecutedTests, 'setUp' ) end
+ function MyTestWithSetupError:test1() table.insert( myExecutedTests, 'test1' ) lu.assertEquals( 'a', 'b') end
+ function MyTestWithSetupError:tearDown() table.insert( myExecutedTests, 'tearDown' ) error('teardown error') end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'MyTestWithSetupError', MyTestWithSetupError } } )
+ lu.assertEquals( runner.result.notSuccessCount, 1 )
+ -- Note: in the future, we may want to report failure + error for this
+ lu.assertEquals( runner.result.failureCount, 1 )
+ lu.assertEquals( runner.result.errorCount, 0 )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( myExecutedTests[1], 'setUp' )
+ lu.assertEquals( myExecutedTests[2], 'test1' )
+ lu.assertEquals( myExecutedTests[3], 'tearDown')
+ lu.assertEquals( #myExecutedTests, 3)
+ -- The first error/failure set the whole test status
+ lu.assertEquals( runner.result.failedTests[1].status, lu.NodeStatus.FAIL )
+ end
+
+ function TestLuaUnitExecution:testWithSetupSuite_TeardownSuite()
+ local myExecutedTests = {}
+
+ local setupSuite = function() table.insert( myExecutedTests, 'setupSuite' ) end
+ local teardownSuite = function() table.insert( myExecutedTests, 'teardownSuite') end
+
+ local MyTestClassA = {
+ test1 = function() table.insert( myExecutedTests, 'Atest1' ) end
+ }
+
+ local MyTestClassB = {
+ test1 = function() table.insert( myExecutedTests, 'Btest1' ) end
+ }
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner.patternIncludeFilter = {"test"}
+
+
+ runner:internalRunSuiteByInstances( {
+ { 'setupSuite', setupSuite },
+ { 'teardownSuite', teardownSuite },
+ { 'MyTestClassA', MyTestClassA },
+ { 'MyTestClassB', MyTestClassB }
+ } )
+ lu.assertEquals( runner.result.notSuccessCount, 0 )
+ lu.assertEquals( myExecutedTests[1], 'setupSuite' )
+ lu.assertEquals( myExecutedTests[2], 'Atest1')
+ lu.assertEquals( myExecutedTests[3], 'Btest1')
+ lu.assertEquals( myExecutedTests[4], 'teardownSuite')
+ lu.assertEquals( #myExecutedTests, 4)
+ end
+
+ function TestLuaUnitExecution:testWithSetupClass_TeardownClass()
+ local myExecutedTests = {}
+
+ local MyTestClassA = {
+ setupClass = function() table.insert( myExecutedTests, 'AsetupClass' ) end,
+ teardownClass = function() table.insert( myExecutedTests, 'AteardownClass' ) end,
+ test1 = function() table.insert( myExecutedTests, 'Atest1' ) end,
+ test2 = function() table.insert( myExecutedTests, 'Atest2' ) end
+ }
+
+ local MyTestClassB = {
+ setupClass = function() table.insert( myExecutedTests, 'BsetupClass' ) end,
+ teardownClass = function() table.insert( myExecutedTests, 'BteardownClass' ) end,
+ test1 = function() table.insert( myExecutedTests, 'Btest1' ) end,
+ test2 = function() table.insert( myExecutedTests, 'Btest2' ) end
+ }
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner.patternIncludeFilter = {"test"}
+
+ runner:runSuiteByInstances( {
+ { 'MyTestClassA', MyTestClassA },
+ { 'MyTestClassB', MyTestClassB }
+ }, 'fake_run_unit_tests.lua' )
+ lu.assertEquals( runner.result.notSuccessCount, 0 )
+ lu.assertEquals( myExecutedTests[1], 'AsetupClass' )
+ lu.assertEquals( myExecutedTests[2], 'Atest1')
+ lu.assertEquals( myExecutedTests[3], 'Atest2')
+ lu.assertEquals( myExecutedTests[4], 'AteardownClass')
+
+ lu.assertEquals( myExecutedTests[5], 'BsetupClass' )
+ lu.assertEquals( myExecutedTests[6], 'Btest1')
+ lu.assertEquals( myExecutedTests[7], 'Btest2')
+ lu.assertEquals( myExecutedTests[8], 'BteardownClass')
+
+ lu.assertEquals( #myExecutedTests, 8)
+ end
+
+ function TestLuaUnitExecution:testWithSetupAndTeardownForSuiteAndClassAndTests()
+ local myExecutedTests = {}
+
+ local setupSuite = function() table.insert( myExecutedTests, 'setupSuite' ) end
+ local teardownSuite = function() table.insert( myExecutedTests, 'teardownSuite') end
+
+ local MyTestClassA = {
+ setupClass = function() table.insert( myExecutedTests, 'AsetupClass' ) end,
+ teardownClass = function() table.insert( myExecutedTests, 'AteardownClass' ) end,
+ test1 = function() table.insert( myExecutedTests, 'Atest1' ) end,
+ test2 = function() table.insert( myExecutedTests, 'Atest2' ) end
+ }
+
+ local MyTestClassB = {
+ test1 = function() table.insert( myExecutedTests, 'Btest1' ) end,
+ test2 = function() table.insert( myExecutedTests, 'Btest2' ) end,
+ setup = function() table.insert( myExecutedTests, 'Bsetup' ) end
+ }
+
+ local MyTestClassC = {
+ test1 = function() table.insert( myExecutedTests, 'Ctest1' ) end,
+ test2 = function() table.insert( myExecutedTests, 'Ctest2' ) end,
+ teardown = function() table.insert( myExecutedTests, 'Cteardown' ) end
+ }
+
+ local MyTestClassD = {
+ test1 = function() table.insert( myExecutedTests, 'Dtest1' ) end,
+ test2 = function() table.insert( myExecutedTests, 'Dtest2' ) end,
+ teardown = function() table.insert( myExecutedTests, 'Dteardown' ) end,
+ setup = function() table.insert( myExecutedTests, 'Dsetup' ) end,
+ setupClass = function() table.insert( myExecutedTests, 'DsetupClass' ) end,
+ teardownClass = function() table.insert( myExecutedTests, 'DteardownClass' ) end
+ }
+
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner.patternIncludeFilter = {"test"}
+
+ runner:internalRunSuiteByInstances( {
+ { 'MyTestClassA', MyTestClassA },
+ { 'MyTestClassB', MyTestClassB },
+ { 'MyTestClassC', MyTestClassC },
+ { 'MyTestClassD', MyTestClassD },
+ { 'setupSuite', setupSuite },
+ { 'teardownSuite', teardownSuite }
+ } )
+ lu.assertEquals( runner.result.notSuccessCount, 0 )
+ lu.assertEquals( myExecutedTests[1], 'setupSuite' )
+
+ lu.assertEquals( myExecutedTests[2], 'AsetupClass')
+ lu.assertEquals( myExecutedTests[3], 'Atest1')
+ lu.assertEquals( myExecutedTests[4], 'Atest2')
+ lu.assertEquals( myExecutedTests[5], 'AteardownClass')
+
+ lu.assertEquals( myExecutedTests[6], 'Bsetup')
+ lu.assertEquals( myExecutedTests[7], 'Btest1')
+ lu.assertEquals( myExecutedTests[8], 'Bsetup')
+ lu.assertEquals( myExecutedTests[9], 'Btest2')
+
+ lu.assertEquals( myExecutedTests[10], 'Ctest1')
+ lu.assertEquals( myExecutedTests[11], 'Cteardown')
+ lu.assertEquals( myExecutedTests[12], 'Ctest2')
+ lu.assertEquals( myExecutedTests[13], 'Cteardown')
+
+ lu.assertEquals( myExecutedTests[14], 'DsetupClass')
+ lu.assertEquals( myExecutedTests[15], 'Dsetup')
+ lu.assertEquals( myExecutedTests[16], 'Dtest1')
+ lu.assertEquals( myExecutedTests[17], 'Dteardown')
+ lu.assertEquals( myExecutedTests[18], 'Dsetup')
+ lu.assertEquals( myExecutedTests[19], 'Dtest2')
+ lu.assertEquals( myExecutedTests[20], 'Dteardown')
+ lu.assertEquals( myExecutedTests[21], 'DteardownClass')
+ lu.assertEquals( myExecutedTests[22], 'teardownSuite')
+
+
+ lu.assertEquals( #myExecutedTests, 22)
+ end
+
+ function TestLuaUnitExecution:test_failFromTest()
+
+ local function my_test_fails()
+ lu.assertEquals( 1, 1 )
+ lu.fail( 'Stop early.')
+ end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'my_test_fails', my_test_fails } } )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( runner.result.failureCount, 1 )
+ lu.assertEquals( runner.result.errorCount, 0 )
+ lu.assertStrContains( runner.result.failedTests[1].msg, 'Stop early.' )
+ end
+
+ function TestLuaUnitExecution:test_failIfFromTest()
+
+ local function my_test_fails()
+ lu.assertEquals( 1, 1 )
+ lu.failIf( false, 'NOOOOOOOOOO')
+ lu.failIf( nil, 'NOOOOOOOOOO')
+ lu.failIf( 1 == 1, 'YESSS')
+ end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'my_test_fails', my_test_fails } } )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( runner.result.errorCount, 0 )
+ lu.assertEquals( runner.result.failureCount, 1 )
+ lu.assertStrContains( runner.result.failedTests[1].msg, 'YESS' )
+ end
+
+ function TestLuaUnitExecution:test_callSuccessFromTest()
+
+ local function my_test_success()
+ lu.assertEquals( 1, 1 )
+ lu.success()
+ error('toto')
+ end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'my_test_success', my_test_success } } )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( runner.result.errorCount, 0 )
+ lu.assertEquals( runner.result.failureCount, 0 )
+ lu.assertEquals( runner.result.successCount, 1 )
+ end
+
+ function TestLuaUnitExecution:test_callSuccessIfFromTest()
+
+ local function my_test_fails()
+ lu.assertEquals( 1, 1 )
+ lu.successIf( false )
+ error('titi')
+ end
+
+ local function my_test_success()
+ lu.assertEquals( 1, 1 )
+ lu.successIf( true )
+ error('toto')
+ end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'my_test_fails', my_test_fails }, {'my_test_success', my_test_success} } )
+ lu.assertEquals( runner.result.selectedCount, 2 )
+ -- print( lu.prettystr( runner.result ) )
+ lu.assertEquals( runner.result.failureCount, 0 )
+ lu.assertEquals( runner.result.successCount, 1 )
+ lu.assertEquals( runner.result.errorCount, 1 )
+ lu.assertStrContains( runner.result.errorTests[1].msg, 'titi' )
+ end
+
+ function TestLuaUnitExecution:test_callSkipFromTest()
+
+ local function my_test_skip()
+ lu.skip('my_skip_msg_is_there')
+ error('skip does not work!')
+ end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'my_test_skip', my_test_skip } } )
+ lu.assertEquals( runner.result.selectedCount, 1 )
+ lu.assertEquals( runner.result.runCount, 0 )
+ lu.assertEquals( runner.result.failureCount, 0 )
+ lu.assertEquals( runner.result.errorCount, 0 )
+ lu.assertEquals( runner.result.successCount, 0 )
+ lu.assertEquals( runner.result.skippedCount, 1 )
+ lu.assertStrContains( runner.result.skippedTests[1].msg, 'my_skip_msg_is_there' )
+ end
+
+ function TestLuaUnitExecution:test_callSkipIfFromTest()
+
+ local function my_test_skip()
+ lu.skipIf( false, 'test is not skipped' )
+ error('titi')
+ end
+
+ local function my_test_no_skip()
+ lu.skipIf( true, 'test should be skipped' )
+ error('toto')
+ end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'my_test_skip', my_test_skip }, {'my_test_no_skip', my_test_no_skip} } )
+ lu.assertEquals( runner.result.selectedCount, 2 )
+ lu.assertEquals( runner.result.failureCount, 0 )
+ lu.assertEquals( runner.result.successCount, 0 )
+ lu.assertEquals( runner.result.errorCount, 1 )
+ lu.assertEquals( runner.result.skippedCount, 1 )
+ lu.assertEquals( runner.result.runCount, 1 )
+ lu.assertStrContains( runner.result.errorTests[1].msg, 'titi' )
+ lu.assertStrContains( runner.result.skippedTests[1].msg, 'test should be skipped' )
+ end
+
+
+ function TestLuaUnitExecution:test_callRunOnlyIfFromTest()
+
+ local function my_test_run_only_if()
+ lu.runOnlyIf( true, 'test is executed' )
+ error('titi')
+ end
+
+ local function my_test_not_run_only_if()
+ lu.runOnlyIf( false, 'test should be skipped' )
+ error('toto')
+ end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances( { { 'my_test_run_only_if', my_test_run_only_if }, {'my_test_not_run_only_if', my_test_not_run_only_if} } )
+ lu.assertEquals( runner.result.selectedCount, 2 )
+ lu.assertEquals( runner.result.failureCount, 0 )
+ lu.assertEquals( runner.result.successCount, 0 )
+ lu.assertEquals( runner.result.skippedCount, 1 )
+ lu.assertEquals( runner.result.errorCount, 1 )
+ lu.assertEquals( runner.result.runCount, 1 )
+ lu.assertStrContains( runner.result.errorTests[1].msg, 'titi' )
+ lu.assertStrContains( runner.result.skippedTests[1].msg, 'test should be skipped' )
+ end
+
+
+ function TestLuaUnitExecution:testWithRepeat()
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ local nbIter = 0
+
+ -- for runSuite() we need a function in the global scope
+ local function MyTestWithIteration()
+ nbIter = nbIter + 1
+ lu.assertTrue( nbIter <= 5 )
+ end
+
+ _G.MyTestWithIteration = MyTestWithIteration
+ nbIter = 0
+ runner:runSuite( '--repeat', '5',
+ 'MyTestWithIteration')
+ _G.MyTestWithIteration = nil -- clean up
+ lu.assertEquals( runner.result.successCount, 1 )
+ lu.assertEquals( runner.result.failureCount, 0 )
+ lu.assertEquals( runner.exeRepeat, 5 )
+ lu.assertEquals( runner.currentCount, 5 )
+ lu.assertEquals( nbIter, 5 )
+
+ _G.MyTestWithIteration = MyTestWithIteration
+ nbIter = 0
+ runner:runSuite( '--repeat', '10',
+ 'MyTestWithIteration')
+ _G.MyTestWithIteration = nil -- clean up
+ -- check if the current iteration got reflected in the failure message
+ lu.assertEquals( runner.result.successCount, 0 )
+ lu.assertEquals( runner.result.failureCount, 1 )
+ lu.assertEquals( runner.exeRepeat, 10 )
+ lu.assertEquals( runner.currentCount, 6 )
+ -- print( lu.prettystr( runner.result ) )
+ lu.assertStrContains(runner.result.failedTests[1].msg, "iteration 6")
+ lu.assertStrContains(runner.result.failedTests[1].msg, "expected: true, ")
+
+ local function MyTestWithIteration()
+ nbIter = nbIter + 1
+ if nbIter > 5 then
+ error( 'Exceeding 5')
+ end
+ end
+
+ _G.MyTestWithIteration = MyTestWithIteration
+ nbIter = 0
+ runner:runSuite( '--repeat', '10',
+ 'MyTestWithIteration')
+ _G.MyTestWithIteration = nil -- clean up
+ -- check if the current iteration got reflected in the failure message
+ lu.assertEquals( runner.result.successCount, 0 )
+ lu.assertEquals( runner.result.failureCount, 0 )
+ lu.assertEquals( runner.result.errorCount, 1 )
+ lu.assertEquals( runner.exeRepeat, 10 )
+ lu.assertEquals( runner.currentCount, 6 )
+ -- print( lu.prettystr( runner.result ) )
+ lu.assertStrContains(runner.result.errorTests[1].msg, "iteration 6")
+ lu.assertStrContains(runner.result.errorTests[1].msg, "Exceeding 5" )
+ end
+
+
+ function TestLuaUnitExecution:testOutputInterface()
+ local runner = lu.LuaUnit.new()
+ runner.outputType = Mock
+ runner:runSuite( 'MyTestWithErrorsAndFailures', 'MyTestOk' )
+ local m = runner.output
+
+ lu.assertEquals( m.calls[1][1], 'startSuite' )
+ lu.assertEquals(#m.calls[1], 2 )
+
+ lu.assertEquals( m.calls[2][1], 'startClass' )
+ lu.assertEquals( m.calls[2][3], 'MyTestWithErrorsAndFailures' )
+ lu.assertEquals(#m.calls[2], 3 )
+
+ lu.assertEquals( m.calls[3][1], 'startTest' )
+ lu.assertEquals( m.calls[3][3], 'MyTestWithErrorsAndFailures.testOk' )
+ lu.assertEquals(#m.calls[3], 3 )
+
+ lu.assertEquals( m.calls[4][1], 'endTest' )
+ lu.assertEquals(#m.calls[4], 3 )
+ lu.assertIsTable( m.calls[4][3] )
+ lu.assertEquals( m.calls[4][3].status, lu.NodeStatus.SUCCESS )
+
+ lu.assertEquals( m.calls[5][1], 'startTest' )
+ lu.assertEquals( m.calls[5][3], 'MyTestWithErrorsAndFailures.testWithError1' )
+ lu.assertEquals(#m.calls[5], 3 )
+
+ lu.assertEquals( m.calls[6][1], 'updateStatus' )
+ lu.assertEquals(#m.calls[6], 3 )
+
+ lu.assertEquals( m.calls[7][1], 'endTest' )
+ lu.assertEquals(#m.calls[7], 3 )
+ lu.assertIsTable( m.calls[7][3] )
+ lu.assertEquals( m.calls[7][3].status, lu.NodeStatus.ERROR )
+
+
+ lu.assertEquals( m.calls[8][1], 'startTest' )
+ lu.assertEquals( m.calls[8][3], 'MyTestWithErrorsAndFailures.testWithFailure1' )
+ lu.assertEquals(#m.calls[8], 3 )
+
+ lu.assertEquals( m.calls[9][1], 'updateStatus' )
+ lu.assertEquals(#m.calls[9], 3 )
+
+ lu.assertEquals( m.calls[10][1], 'endTest' )
+ lu.assertEquals(#m.calls[10], 3 )
+ lu.assertIsTable( m.calls[10][3] )
+ lu.assertEquals( m.calls[10][3].status, lu.NodeStatus.FAIL )
+
+ lu.assertEquals( m.calls[11][1], 'startTest' )
+ lu.assertEquals( m.calls[11][3], 'MyTestWithErrorsAndFailures.testWithFailure2' )
+ lu.assertEquals(#m.calls[11], 3 )
+
+ lu.assertEquals( m.calls[12][1], 'updateStatus' )
+ lu.assertEquals(#m.calls[12], 3 )
+
+ lu.assertEquals( m.calls[13][1], 'endTest' )
+ lu.assertEquals(#m.calls[13], 3 )
+ lu.assertIsTable(m.calls[13][3] )
+ lu.assertEquals( m.calls[13][3].status, lu.NodeStatus.FAIL )
+
+ lu.assertEquals( m.calls[14][1], 'endClass' )
+ lu.assertEquals(#m.calls[14], 2 )
+
+ lu.assertEquals( m.calls[15][1], 'startClass' )
+ lu.assertEquals( m.calls[15][3], 'MyTestOk' )
+ lu.assertEquals(#m.calls[15], 3 )
+
+ lu.assertEquals( m.calls[16][1], 'startTest' )
+ lu.assertEquals( m.calls[16][3], 'MyTestOk.testOk1' )
+ lu.assertEquals(#m.calls[16], 3 )
+
+ lu.assertEquals( m.calls[17][1], 'endTest' )
+ lu.assertEquals(#m.calls[17], 3 )
+ lu.assertIsTable( m.calls[17][3] )
+ lu.assertEquals( m.calls[17][3].status, lu.NodeStatus.SUCCESS )
+
+ lu.assertEquals( m.calls[18][1], 'startTest' )
+ lu.assertEquals( m.calls[18][3], 'MyTestOk.testOk2' )
+ lu.assertEquals(#m.calls[18], 3 )
+
+ lu.assertEquals( m.calls[19][1], 'endTest' )
+ lu.assertEquals(#m.calls[19], 3 )
+ lu.assertIsTable( m.calls[19][3] )
+ lu.assertEquals( m.calls[19][3].status, lu.NodeStatus.SUCCESS )
+
+ lu.assertEquals( m.calls[20][1], 'endClass' )
+ lu.assertEquals(#m.calls[20], 2 )
+
+ lu.assertEquals( m.calls[21][1], 'endSuite' )
+ lu.assertEquals(#m.calls[21], 2 )
+
+ lu.assertEquals( m.calls[22], nil )
+
+ end
+
+ function TestLuaUnitExecution:testInvocation()
+
+ lu.assertEquals( #lu.LuaUnit.instances, 1)
+ local runner = lu.LuaUnit.new()
+
+ -- this does not create a new registered instance
+ lu.assertEquals( #lu.LuaUnit.instances, 1)
+
+ -- test alternative "object" syntax for run(), passing self
+ runner:run('--output', 'nil', 'MyTestOk')
+
+ -- this does not create a new registered instance
+ lu.assertEquals( #lu.LuaUnit.instances, 1)
+
+ -- select class instance by name
+ runner.run('--output', 'nil', 'MyTestOk.testOk2')
+
+ -- this does not create a new registered instance
+ lu.assertEquals( #lu.LuaUnit.instances, 1)
+
+ -- check error handling
+ lu.assertErrorMsgContains('No such name in global space',
+ runner.runSuite, runner, 'foobar')
+ lu.assertEquals( #lu.LuaUnit.instances, 1)
+ lu.assertErrorMsgContains('Name must match a function or a table',
+ runner.runSuite, runner, '_VERSION')
+ lu.assertEquals( #lu.LuaUnit.instances, 1)
+ lu.assertErrorMsgContains('No such name in global space',
+ runner.runSuite, runner, 'foo.bar')
+ lu.assertEquals( #lu.LuaUnit.instances, 1)
+ lu.assertErrorMsgContains('must be a function, not',
+ runner.runSuite, runner, '_G._VERSION')
+ lu.assertEquals( #lu.LuaUnit.instances, 1)
+ lu.assertErrorMsgContains('Could not find method in class',
+ runner.runSuite, runner, 'MyTestOk.foobar')
+ lu.assertEquals( #lu.LuaUnit.instances, 1)
+ lu.assertErrorMsgContains('Instance must be a table or a function',
+ runner.expandClasses, {{'foobar', 'INVALID'}})
+ lu.assertEquals( #lu.LuaUnit.instances, 1)
+ lu.assertErrorMsgContains('Could not find method in class',
+ runner.expandClasses, {{'MyTestOk.foobar', {}}})
+ lu.assertEquals( #lu.LuaUnit.instances, 1)
+ end
+
+ function TestLuaUnitExecution:test_filterWithPattern()
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuite('-p', 'Function', '-p', 'Toto.' )
+ lu.assertEquals( executedTests[1], "MyTestFunction" )
+ lu.assertEquals( executedTests[2], "MyTestToto1:test1" )
+ lu.assertEquals( executedTests[3], "MyTestToto1:test2" )
+ lu.assertEquals( executedTests[4], "MyTestToto1:test3" )
+ lu.assertEquals( executedTests[5], "MyTestToto1:testa" )
+ lu.assertEquals( executedTests[6], "MyTestToto1:testb" )
+ lu.assertEquals( executedTests[7], "MyTestToto2:test1" )
+ lu.assertEquals( #executedTests, 7)
+
+ runner:runSuite('-p', 'Toto.', '-x', 'Toto2' )
+ lu.assertEquals( runner.result.selectedCount, 5) -- MyTestToto2 excluded
+ end
+
+ function TestLuaUnitExecution:test_endSuiteTwice()
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuite( 'MyTestWithErrorsAndFailures', 'MyTestOk' )
+ lu.assertErrorMsgContains('suite was already ended',
+ runner.endSuite, runner)
+ end
+
+ function TestLuaUnitExecution:test_withTableErrorInside(args)
+ local function my_test_with_table_error()
+ error {code = 123}
+ end
+
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuiteByInstances { { 'my_test_with_table_error', my_test_with_table_error } }
+ lu.assertStrContains(runner.result.allTests[1].msg, '{code=123}')
+ end
+
+
+
+------------------------------------------------------------------
+--
+-- Results Tests
+--
+------------------------------------------------------------------
+
+TestLuaUnitResults = { __class__ = 'TestLuaUnitResults' }
+
+ function TestLuaUnitResults:tearDown()
+ executedTests = {}
+ lu.LuaUnit.isTestName = lu.LuaUnit.isTestNameOld
+ end
+
+ function TestLuaUnitResults:setUp()
+ executedTests = {}
+ lu.LuaUnit.isTestNameOld = lu.LuaUnit.isTestName
+ lu.LuaUnit.isTestName = function( s ) return (string.sub(s,1,6) == 'MyTest') end
+ end
+
+ function TestLuaUnitResults:test_statusLine()
+ -- full success
+ local r = {runCount=5, duration=0.17, successCount=5, notSuccessCount=0, failureCount=0, errorCount=0, nonSelectedCount=0, skippedCount=0}
+ lu.assertEquals( lu.LuaUnit.statusLine(r), 'Ran 5 tests in 0.170 seconds, 5 successes, 0 failures')
+
+ -- 1 failure, nothing more displayed
+ r = {runCount=5, duration=0.17, successCount=4, notSuccessCount=1, failureCount=1, errorCount=0, nonSelectedCount=0, skippedCount=0}
+ lu.assertEquals( lu.LuaUnit.statusLine(r), 'Ran 5 tests in 0.170 seconds, 4 successes, 1 failure')
+
+ -- 1 error, no failure displayed
+ r = {runCount=5, duration=0.17, successCount=4, notSuccessCount=1, failureCount=0, errorCount=1, nonSelectedCount=0, skippedCount=0}
+ lu.assertEquals( lu.LuaUnit.statusLine(r), 'Ran 5 tests in 0.170 seconds, 4 successes, 1 error')
+
+ -- 1 error, 1 failure
+ r = {runCount=5, duration=0.17, successCount=3, notSuccessCount=2, failureCount=1, errorCount=1, nonSelectedCount=0, skippedCount=0}
+ lu.assertEquals( lu.LuaUnit.statusLine(r), 'Ran 5 tests in 0.170 seconds, 3 successes, 1 failure, 1 error')
+
+ -- 1 error, 1 failure, 1 non selected
+ r = {runCount=5, duration=0.17, successCount=3, notSuccessCount=2, failureCount=1, errorCount=1, nonSelectedCount=1, skippedCount=0}
+ lu.assertEquals( lu.LuaUnit.statusLine(r), 'Ran 5 tests in 0.170 seconds, 3 successes, 1 failure, 1 error, 1 non-selected')
+
+ -- full success, 1 non selected
+ r = {runCount=5, duration=0.17, successCount=5, notSuccessCount=0, failureCount=0, errorCount=0, nonSelectedCount=1, skippedCount=0}
+ lu.assertEquals( lu.LuaUnit.statusLine(r), 'Ran 5 tests in 0.170 seconds, 5 successes, 0 failures, 1 non-selected')
+
+ -- 1 error, 1 failure, 1 skipped
+ r = {runCount=5, duration=0.17, successCount=3, notSuccessCount=2, failureCount=1, errorCount=1, nonSelectedCount=0, skippedCount=1}
+ lu.assertEquals( lu.LuaUnit.statusLine(r), 'Ran 5 tests in 0.170 seconds, 3 successes, 1 failure, 1 error, 1 skipped')
+
+ -- full success, 1 skipped
+ r = {runCount=5, duration=0.17, successCount=5, notSuccessCount=0, failureCount=0, errorCount=0, nonSelectedCount=0, skippedCount=1}
+ lu.assertEquals( lu.LuaUnit.statusLine(r), 'Ran 5 tests in 0.170 seconds, 5 successes, 0 failures, 1 skipped')
+
+ -- full success, 1 skipped, 1 non-selected
+ r = {runCount=5, duration=0.17, successCount=5, notSuccessCount=0, failureCount=0, errorCount=0, nonSelectedCount=1, skippedCount=1}
+ lu.assertEquals( lu.LuaUnit.statusLine(r), 'Ran 5 tests in 0.170 seconds, 5 successes, 0 failures, 1 skipped, 1 non-selected')
+
+ end
+
+ function TestLuaUnitResults:test_nodeStatus()
+ local es = lu.NodeStatus.new()
+ lu.assertEquals( es.status, lu.NodeStatus.SUCCESS )
+ lu.assertTrue( es:isSuccess() )
+ lu.assertNil( es.msg )
+ lu.assertNil( es.stackTrace )
+ lu.assertStrContains( es:statusXML(), "<passed" )
+
+ es:fail( 'msgToto', 'stackTraceToto' )
+ lu.assertEquals( es.status, lu.NodeStatus.FAIL )
+ lu.assertTrue( es:isNotSuccess() )
+ lu.assertTrue( es:isFailure() )
+ lu.assertFalse( es:isError() )
+ lu.assertEquals( es.msg, 'msgToto' )
+ lu.assertEquals( es.stackTrace, 'stackTraceToto' )
+ lu.assertStrContains( es:statusXML(), "<failure" )
+
+ local es2 = lu.NodeStatus.new()
+ lu.assertEquals( es2.status, lu.NodeStatus.SUCCESS )
+ lu.assertNil( es2.msg )
+ lu.assertNil( es2.stackTrace )
+
+ es:error( 'msgToto2', 'stackTraceToto2' )
+ lu.assertEquals( es.status, lu.NodeStatus.ERROR )
+ lu.assertTrue( es:isNotSuccess() )
+ lu.assertFalse( es:isFailure() )
+ lu.assertTrue( es:isError() )
+ lu.assertEquals( es.msg, 'msgToto2' )
+ lu.assertEquals( es.stackTrace, 'stackTraceToto2' )
+ lu.assertStrContains( es:statusXML(), "<error" )
+
+ es:success()
+ lu.assertEquals( es.status, lu.NodeStatus.SUCCESS )
+ lu.assertTrue( es:isSuccess() )
+ lu.assertFalse( es:isNotSuccess() )
+ lu.assertFalse( es:isFailure() )
+ lu.assertFalse( es:isError() )
+ lu.assertNil( es.msg )
+ lu.assertNil( es.stackTrace )
+
+ end
+
+ function TestLuaUnitResults:test_runSuiteOk()
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuite( 'MyTestToto2', 'MyTestToto1', 'MyTestFunction' )
+ lu.assertEquals( #runner.result.allTests, 7 )
+ lu.assertEquals( #runner.result.failedTests, 0 )
+ lu.assertEquals( #runner.result.errorTests, 0 )
+
+ lu.assertEquals( runner.result.allTests[1].testName,"MyTestToto2.test1" )
+ lu.assertEquals( runner.result.allTests[1].number, 1 )
+ lu.assertEquals( runner.result.allTests[1].className, 'MyTestToto2' )
+ lu.assertEquals( runner.result.allTests[1].status, lu.NodeStatus.SUCCESS )
+
+ lu.assertEquals( runner.result.allTests[2].testName,"MyTestToto1.test1" )
+ lu.assertEquals( runner.result.allTests[2].number, 2 )
+ lu.assertEquals( runner.result.allTests[2].className, 'MyTestToto1' )
+ lu.assertEquals( runner.result.allTests[2].status, lu.NodeStatus.SUCCESS )
+
+ lu.assertEquals( runner.result.allTests[3].testName,"MyTestToto1.test2" )
+ lu.assertEquals( runner.result.allTests[3].number, 3 )
+ lu.assertEquals( runner.result.allTests[3].className, 'MyTestToto1' )
+ lu.assertEquals( runner.result.allTests[3].status, lu.NodeStatus.SUCCESS )
+
+ lu.assertEquals( runner.result.allTests[4].testName,"MyTestToto1.test3" )
+ lu.assertEquals( runner.result.allTests[4].number, 4 )
+ lu.assertEquals( runner.result.allTests[4].className, 'MyTestToto1' )
+ lu.assertEquals( runner.result.allTests[4].status, lu.NodeStatus.SUCCESS )
+
+ lu.assertEquals( runner.result.allTests[5].testName,"MyTestToto1.testa" )
+ lu.assertEquals( runner.result.allTests[5].number, 5 )
+ lu.assertEquals( runner.result.allTests[5].className, 'MyTestToto1' )
+ lu.assertEquals( runner.result.allTests[5].status, lu.NodeStatus.SUCCESS )
+
+ lu.assertEquals( runner.result.allTests[6].testName,"MyTestToto1.testb" )
+ lu.assertEquals( runner.result.allTests[6].number, 6 )
+ lu.assertEquals( runner.result.allTests[6].className, 'MyTestToto1' )
+ lu.assertEquals( runner.result.allTests[6].status, lu.NodeStatus.SUCCESS )
+
+ lu.assertEquals( runner.result.allTests[7].testName,"MyTestFunction" )
+ lu.assertEquals( runner.result.allTests[7].number, 7)
+ lu.assertEquals( runner.result.allTests[7].className, '[TestFunctions]' )
+ lu.assertEquals( runner.result.allTests[7].status, lu.NodeStatus.SUCCESS )
+
+ end
+
+ function TestLuaUnitResults:test_runSuiteWithFailures()
+ local runner = lu.LuaUnit.new()
+ runner:setOutputType( "NIL" )
+ runner:runSuite( 'MyTestWithErrorsAndFailures' )
+
+ lu.assertEquals( #runner.result.allTests, 4 )
+ lu.assertEquals( #runner.result.failedTests, 2 )
+ lu.assertEquals( #runner.result.errorTests, 1 )
+
+ lu.assertEquals( runner.result.allTests[1].number, 1 )
+ lu.assertEquals( runner.result.allTests[1].testName, "MyTestWithErrorsAndFailures.testOk" )
+ lu.assertEquals( runner.result.allTests[1].className, 'MyTestWithErrorsAndFailures' )
+ lu.assertEquals( runner.result.allTests[1].status, lu.NodeStatus.SUCCESS )
+ lu.assertIsNumber( runner.result.allTests[1].duration )
+ lu.assertIsNil( runner.result.allTests[1].msg )
+ lu.assertIsNil( runner.result.allTests[1].stackTrace )
+
+ lu.assertEquals( runner.result.allTests[2].testName, 'MyTestWithErrorsAndFailures.testWithError1' )
+ lu.assertEquals( runner.result.allTests[2].className, 'MyTestWithErrorsAndFailures' )
+ lu.assertEquals( runner.result.allTests[2].status, lu.NodeStatus.ERROR )
+ lu.assertIsString( runner.result.allTests[2].msg )
+ lu.assertIsString( runner.result.allTests[2].stackTrace )
+
+ lu.assertEquals( runner.result.allTests[3].testName, 'MyTestWithErrorsAndFailures.testWithFailure1' )
+ lu.assertEquals( runner.result.allTests[3].className, 'MyTestWithErrorsAndFailures' )
+ lu.assertEquals( runner.result.allTests[3].status, lu.NodeStatus.FAIL )
+ lu.assertIsString( runner.result.allTests[3].msg )
+ lu.assertIsString( runner.result.allTests[3].stackTrace )
+
+ lu.assertEquals( runner.result.allTests[4].testName, 'MyTestWithErrorsAndFailures.testWithFailure2' )
+ lu.assertEquals( runner.result.allTests[4].className, 'MyTestWithErrorsAndFailures' )
+ lu.assertEquals( runner.result.allTests[4].status, lu.NodeStatus.FAIL )
+ lu.assertIsString( runner.result.allTests[4].msg )
+ lu.assertIsString( runner.result.allTests[4].stackTrace )
+
+ lu.assertEquals( runner.result.errorTests[1].testName, 'MyTestWithErrorsAndFailures.testWithError1' )
+ lu.assertEquals( runner.result.errorTests[1].className, 'MyTestWithErrorsAndFailures' )
+ lu.assertEquals( runner.result.errorTests[1].status, lu.NodeStatus.ERROR )
+ lu.assertIsString( runner.result.errorTests[1].msg )
+ lu.assertIsString( runner.result.errorTests[1].stackTrace )
+
+ lu.assertEquals( runner.result.failedTests[1].testName, 'MyTestWithErrorsAndFailures.testWithFailure1' )
+ lu.assertEquals( runner.result.failedTests[1].className, 'MyTestWithErrorsAndFailures' )
+ lu.assertEquals( runner.result.failedTests[1].status, lu.NodeStatus.FAIL )
+ lu.assertIsString( runner.result.failedTests[1].msg )
+ lu.assertIsString( runner.result.failedTests[1].stackTrace )
+
+ lu.assertEquals( runner.result.failedTests[2].testName, 'MyTestWithErrorsAndFailures.testWithFailure2' )
+ lu.assertEquals( runner.result.failedTests[2].className, 'MyTestWithErrorsAndFailures' )
+ lu.assertEquals( runner.result.failedTests[2].status, lu.NodeStatus.FAIL )
+ lu.assertIsString( runner.result.failedTests[2].msg )
+ lu.assertIsString( runner.result.failedTests[2].stackTrace )
+
+ end
+
+ function TestLuaUnitResults:test_resultsWhileTestInProgress()
+ local MyMocker = { __class__ = "MyMocker" }
+ -- MyMocker is an outputter that creates a customized "Mock" instance
+ function MyMocker.new(runner)
+ local t = Mock.new(runner)
+ function t:startTest( _ )
+ local node = self.result.currentNode
+ if node.number == 1 then
+ lu.assertEquals( node.number, 1 )
+ lu.assertEquals( node.testName, 'MyTestWithErrorsAndFailures.testOk' )
+ lu.assertEquals( node.className, 'MyTestWithErrorsAndFailures' )
+ lu.assertEquals( node.status, lu.NodeStatus.SUCCESS )
+ elseif node.number == 2 then
+ lu.assertEquals( node.number, 2 )
+ lu.assertEquals( node.testName, 'MyTestWithErrorsAndFailures.testWithError1' )
+ lu.assertEquals( node.className, 'MyTestWithErrorsAndFailures' )
+ lu.assertEquals( node.status, lu.NodeStatus.SUCCESS )
+ end
+ end
+ function t:endTest( node )
+ lu.assertEquals( node, self.result.currentNode )
+ if node.number == 1 then
+ lu.assertEquals( node.status, lu.NodeStatus.SUCCESS )
+ elseif node.number == 2 then
+ lu.assertEquals( node.status, lu.NodeStatus.ERROR )
+ end
+ end
+ return t
+ end
+
+ local runner = lu.LuaUnit.new()
+ runner.outputType = MyMocker
+ runner:runSuite( 'MyTestWithErrorsAndFailures' )
+
+ local m = runner.output
+ lu.assertEquals( m.calls[1][1], 'startSuite' )
+ lu.assertEquals(#m.calls[1], 2 )
+ end
+
+
+-- To execute me , use: lua run_unit_tests.lua
diff --git a/Data/Libraries/luaunit/test/test_with_err_fail_pass.lua b/Data/Libraries/luaunit/test/test_with_err_fail_pass.lua
new file mode 100644
index 0000000..b137529
--- /dev/null
+++ b/Data/Libraries/luaunit/test/test_with_err_fail_pass.lua
@@ -0,0 +1,71 @@
+local lu = require('luaunit')
+
+--[[ Test used by functional tests ]]
+TestSomething = {} --class
+
+ function TestSomething:test1_Success1()
+ lu.assertEquals( 1+1, 2 )
+ end
+
+ function TestSomething:test1_Success2()
+ lu.assertEquals( 1+2, 3 )
+ end
+
+ function TestSomething:test2_Fail1()
+ lu.assertEquals( 1+1, 0 )
+ end
+
+ function TestSomething:test2_Fail2()
+ lu.assertEquals( 1+2, 0 )
+ end
+
+ function TestSomething:test3_Err1()
+ local v = 1 + { 1,2 }
+ end
+
+ function TestSomething:test3_Err2()
+ local v = 1 + { 1,2 }
+ end
+
+TestAnotherThing = {} --class
+
+ function TestAnotherThing:test1_Success1()
+ lu.assertEquals( 1+1, 2 )
+ end
+
+ function TestAnotherThing:test1_Success2()
+ lu.assertEquals( 1+2, 3 )
+ end
+
+ function TestAnotherThing:test2_Err1()
+ local v = 1 + { 1,2 }
+ end
+
+ function TestAnotherThing:test2_Err2()
+ local v = 1 + { 1,2 }
+ end
+
+ function TestAnotherThing:test3_Fail1()
+ lu.assertEquals( 1+1, 0 )
+ end
+
+ function TestAnotherThing:test3_Fail2()
+ lu.assertEquals( 1+2, 0 )
+ end
+
+
+function testFuncSuccess1()
+ lu.assertEquals( 1+1, 2 )
+end
+
+function testFuncFail1()
+ lu.assertEquals( 1+2, 0 )
+end
+
+function testFuncErr1()
+ local v = 1 + { 1,2 }
+end
+
+local runner = lu.LuaUnit.new()
+runner:setOutputType("text")
+os.exit( runner:runSuite() )
diff --git a/Data/Libraries/luaunit/test/test_with_xml.lua b/Data/Libraries/luaunit/test/test_with_xml.lua
new file mode 100644
index 0000000..365bc12
--- /dev/null
+++ b/Data/Libraries/luaunit/test/test_with_xml.lua
@@ -0,0 +1,23 @@
+
+local lu = require('luaunit')
+
+TestFailuresWithXml = {} --class
+
+ TestFailuresWithXml.__class__ = 'TestFailuresWithXml'
+
+ function TestFailuresWithXml:test_failure_with_simple_xml()
+ lu.assertEquals( '<toto>ti"ti</toto>', 'got it' )
+ end
+
+ function TestFailuresWithXml:test_failure_with_cdata_xml()
+ lu.assertEquals( 'cdata does not like ]]>', 'got it' )
+ end
+
+function TestThatLastsALongTime()
+ local start = os.clock()
+ while os.clock() - start < 1.1 do
+ end
+end
+
+lu.LuaUnit.verbosity = 2
+os.exit( lu.LuaUnit.run() )
diff --git a/Data/Resources/Icon/GameLab.ico b/Data/Resources/Icon/GameLab.ico
new file mode 100644
index 0000000..ae94a7d
--- /dev/null
+++ b/Data/Resources/Icon/GameLab.ico
Binary files differ
diff --git a/Data/Resources/Images/UI.csv b/Data/Resources/Images/UI.csv
new file mode 100644
index 0000000..e9c9eea
--- /dev/null
+++ b/Data/Resources/Images/UI.csv
@@ -0,0 +1,2 @@
+filePath type slice left right top bottom
+asdasd
diff --git a/Data/Resources/Images/UI.xlsx b/Data/Resources/Images/UI.xlsx
new file mode 100644
index 0000000..15e2235
--- /dev/null
+++ b/Data/Resources/Images/UI.xlsx
Binary files differ
diff --git a/Data/Resources/Shaders/UI.glsl b/Data/Resources/Shaders/UI.glsl
new file mode 100644
index 0000000..12a94db
--- /dev/null
+++ b/Data/Resources/Shaders/UI.glsl
@@ -0,0 +1,12 @@
+VERTEX_SHADER_BEGIN
+
+
+VERTEX_SHADER_END
+
+
+FRAGMENT_SHADER_BEGIN
+
+
+
+
+FRAGMENT_SHADER_END \ No newline at end of file
diff --git a/Data/Scripts/Editor/AssetBrowser.lua b/Data/Scripts/Editor/AssetBrowser.lua
new file mode 100644
index 0000000..e6e4a4a
--- /dev/null
+++ b/Data/Scripts/Editor/AssetBrowser.lua
@@ -0,0 +1,28 @@
+local Debug = GameLab.Debug
+local AssetBrowser = GameLab.Editor.GUI.EditorWindow.Extend("GameLab.Editor.AssetBrowser")
+local GL = GameLab.Engine.GL
+local Matrix44 = GameLab.Engine.Math.Matrix44
+local inspect = require("inspect")
+
+AssetBrowser.Ctor = function(self)
+ self.base.Ctor(self, "AssetBrowser")
+end
+
+AssetBrowser.OnGUI = function(self)
+ Debug.Log("AssetBrowser.OnGUI()")
+ GL.ClearColor({0,0,0,1})
+ GL.Clear(GL.EBufferType.ColorBuffer)
+ GL.Color({1,1,0,1})
+ GL.LoadPixelMatrix(-250, 250, -300, 300)
+ GL.Begin(GL.EPrimitiveType.Triangles)
+ GL.Vertex({0,0,-1})
+ GL.Vertex({0,300,-1})
+ GL.Vertex({250,0,-1})
+ GL.End()
+end
+
+AssetBrowser.OnFocus = function(self)
+
+end
+
+return AssetBrowser \ No newline at end of file
diff --git a/Data/Scripts/Editor/Properties.lua b/Data/Scripts/Editor/Properties.lua
new file mode 100644
index 0000000..864f17e
--- /dev/null
+++ b/Data/Scripts/Editor/Properties.lua
@@ -0,0 +1,4 @@
+-- 属性检查器properties
+
+
+
diff --git a/Data/Scripts/EditorApplication.lua b/Data/Scripts/EditorApplication.lua
new file mode 100644
index 0000000..d9f8b1f
--- /dev/null
+++ b/Data/Scripts/EditorApplication.lua
@@ -0,0 +1,71 @@
+local json = require "LiteJson.json"
+local inspect = require "inspect"
+local AssetBrowser = require "./Scripts/Editor/AssetBrowser"
+local EditorWindowManager = require "./Scripts/EditorGUI/EditorWindowManager"
+
+local Rendering = GameLab.Engine.Rendering
+local Debug = GameLab.Debug
+local GUI = GameLab.Editor.GUI
+local GL = GameLab.Engine.GL
+
+local app = GameLab.Editor.EditorApplication.New()
+
+if app == nil then
+ Debug.LogError("app is nil")
+end
+
+local mainWindow = GUI.ContainerWindow.New({400, 400, 800, 500}, GUI.EShowMode.MainWindow, {100, 100}, {700, 700})
+mainWindow:SetTitle("GameLab")
+mainWindow:SetIcon("./Data/Icon/GameLab.ico")
+
+app:SetMainWindow(mainWindow)
+
+local guiWindow = GUI.GUIWindow.New()
+guiWindow:SetContainerWindow(mainWindow)
+guiWindow:SetPosition({0,0, 500, 400})
+
+collectgarbage()
+
+Debug.Log(GameLab.Path.GetRootDirectory())
+
+Debug.Log(inspect{foo=1,2,3,4})
+
+local wnd = AssetBrowser.New()
+Debug.Log(inspect(mainWindow._type))
+guiWindow:SetInstance(wnd)
+
+local v = GameLab.Engine.Math.Vector4.New(1,2,3,4)
+Debug.Log(inspect(v))
+
+Debug.Log(EditorWindowManager.name)
+
+local c = Rendering.Color.New(1,1,1,1)
+Debug.Log(inspect(c))
+
+Debug.Log(inspect(GL.EBufferType))
+
+GL.ClearColor({1,1,1,1})
+GL.Clear(GL.EBufferType.ColorBuffer)
+
+local files = {
+ "README.txt",
+ "README.txt",
+ "README.txt",
+ "README.txt",
+ "README.txt",
+ "README.txt",
+ "README.txt",
+ "README.txt",
+ "README.txt",
+}
+
+GameLab.IO.ReadFilesAsync(files, function()
+ Debug.Log("finished")
+end)
+
+while true do
+
+ app:OnStep()
+ app:PullMessage()
+
+end \ No newline at end of file
diff --git a/Data/Scripts/EditorGUI/EditorImages.lua b/Data/Scripts/EditorGUI/EditorImages.lua
new file mode 100644
index 0000000..e98d064
--- /dev/null
+++ b/Data/Scripts/EditorGUI/EditorImages.lua
@@ -0,0 +1,2 @@
+-- 编辑器图片资源
+
diff --git a/Data/Scripts/EditorGUI/EditorWindowManager.lua b/Data/Scripts/EditorGUI/EditorWindowManager.lua
new file mode 100644
index 0000000..707038b
--- /dev/null
+++ b/Data/Scripts/EditorGUI/EditorWindowManager.lua
@@ -0,0 +1,5 @@
+local EditorWindowManager = {}
+
+EditorWindowManager.name = "asd"
+
+return EditorWindowManager \ No newline at end of file
diff --git a/Data/Scripts/Utils/Utils.lua b/Data/Scripts/Utils/Utils.lua
new file mode 100644
index 0000000..678217b
--- /dev/null
+++ b/Data/Scripts/Utils/Utils.lua
@@ -0,0 +1,4 @@
+local Utils = GameLab.Editor.Utils or {}
+GameLab.Editor.Utils = Utils
+
+
diff --git a/Data/boot.lua b/Data/boot.lua
new file mode 100644
index 0000000..6f49da7
--- /dev/null
+++ b/Data/boot.lua
@@ -0,0 +1,33 @@
+require("macro")
+
+-- 模块搜索目录
+local engineLuaLibs = "./DefaultContent/Libraries/?.lua" .. ";./DefaultContent/Libraries/?/init.lua" .. ";./DefaultContent/Libraries/?/?.lua" .. ";./DefaultContent/Libraries/?/?" ..
+ ";./DefaultContent/Plugins/?.lua" .. ";./DefaultContent/Plugins/?/init.lua" .. ";./DefaultContent/Plugins/?/?.lua" .. ";./DefaultContent/Plugins/?/?"
+local editorLuaLibs = "./Libraries/?.lua" .. ";./Libraries/?/init.lua" .. ";./Libraries/?/?.lua" .. ";./Libraries/?/?" ..
+ ";./Plugins/?.lua" .. ";./Plugins/?/init.lua" .. ";./Plugins/?/?.lua" .. ";./Plugins/?/?"
+local editorScripts = "./Scripts/?.lua"
+package.path=package.path .. ";" .. editorScripts .. ";" .. engineLuaLibs .. ";" .. editorLuaLibs
+
+local engineCLibs = "./DefaultContent/Libraries/?.dll" .. ";./DefaultContent/Plugins/?.dll"
+local editorCLibs = "./Libraries/?.dll" .. "./Plugins/?.dll"
+package.cpath=package.cpath .. ";" .. engineCLibs .. ";" .. editorCLibs
+
+-- debugging
+require("LuaPanda").start("127.0.0.1",8818)
+
+-- redirect
+if GAMELAB_DEBUG then
+ print = GameLab.Debug.Log
+end
+
+-- load gamelab modules
+require "GameLab"
+require "GameLab.Engine"
+require "GameLab.Engine.Math"
+require "GameLab.Engine.Rendering"
+require "GameLab.Engine.GL"
+require "GameLab.Editor"
+require "GameLab.Editor.GUI"
+
+-- launch editor
+dofile("./Scripts/EditorApplication.lua") \ No newline at end of file
diff --git a/Data/macro.lua b/Data/macro.lua
new file mode 100644
index 0000000..c8a4895
--- /dev/null
+++ b/Data/macro.lua
@@ -0,0 +1,3 @@
+-- "macros"
+GAMELAB_PROFILE = true
+GAMELAB_DEBUG = true
diff --git a/Data/readme.txt b/Data/readme.txt
new file mode 100644
index 0000000..f45359b
--- /dev/null
+++ b/Data/readme.txt
@@ -0,0 +1,7 @@
+编辑器资源
+* DefaultContent 运行时相关的脚本和资源
+* Icon 图标文件
+* Images 图片资源
+* Libraries 编辑器用到的模块
+* Scripts 编辑器脚本
+* Shaders 编辑器用到的着色器 \ No newline at end of file