diff --git a/lua/kcl_lib-0.12.3-1.rockspec b/lua/kcl_lib-0.12.3-1.rockspec index 1f08a068..3bf032da 100644 --- a/lua/kcl_lib-0.12.3-1.rockspec +++ b/lua/kcl_lib-0.12.3-1.rockspec @@ -24,6 +24,7 @@ dependencies = { } test_dependencies = { "busted >= 2.2", + "penlight >= 1.15", } test = { type = "busted", diff --git a/lua/kcl_lib/raw_api.lua b/lua/kcl_lib/raw_api.lua index 1703958e..0fe73bf3 100644 --- a/lua/kcl_lib/raw_api.lua +++ b/lua/kcl_lib/raw_api.lua @@ -44,10 +44,79 @@ local function add_method(name, arg_name, return_name) end end +RawAPI.ping = add_method("KclService.Ping", "PingArgs", "PingResult") + +RawAPI.get_version = + add_method("KclService.GetVersion", "GetVersionArgs", "GetVersionResult") + +RawAPI.parse_program = add_method( + "KclService.ParseProgram", + "ParseProgramArgs", + "ParseProgramResult" +) + +RawAPI.parse_file = + add_method("KclService.ParseFile", "ParseFileArgs", "ParseFileResult") + +RawAPI.load_package = + add_method("KclService.LoadPackage", "LoadPackageArgs", "LoadPackageResult") + +RawAPI.list_options = + add_method("KclService.ListOptions", "ParseProgramArgs", "ListOptionsResult") + +RawAPI.list_variables = add_method( + "KclService.ListVariables", + "ListVariablesArgs", + "ListVariablesResult" +) + RawAPI.exec_program = add_method("KclService.ExecProgram", "ExecProgramArgs", "ExecProgramResult") +RawAPI.format_code = + add_method("KclService.FormatCode", "FormatCodeArgs", "FormatCodeResult") + RawAPI.format_path = add_method("KclService.FormatPath", "FormatPathArgs", "FormatPathResult") +RawAPI.lint_path = + add_method("KclService.LintPath", "LintPathArgs", "LintPathResult") + +RawAPI.override_file = add_method( + "KclService.OverrideFile", + "OverrideFileArgs", + "OverrideFileResult" +) + +RawAPI.get_schema_type_mapping = add_method( + "KclService.GetSchemaTypeMapping", + "GetSchemaTypeMappingArgs", + "GetSchemaTypeMappingResult" +) + +RawAPI.validate_code = add_method( + "KclService.ValidateCode", + "ValidateCodeArgs", + "ValidateCodeResult" +) + +RawAPI.load_settings_files = add_method( + "KclService.LoadSettingsFiles", + "LoadSettingsFilesArgs", + "LoadSettingsFilesResult" +) + +RawAPI.rename = add_method("KclService.Rename", "RenameArgs", "RenameResult") + +RawAPI.rename_code = + add_method("KclService.RenameCode", "RenameCodeArgs", "RenameCodeResult") + +RawAPI.test = add_method("KclService.Test", "TestArgs", "TestResult") + +RawAPI.update_dependencies = add_method( + "KclService.UpdateDependencies", + "UpdateDependenciesArgs", + "UpdateDependenciesResult" +) + return RawAPI:new() diff --git a/lua/spec/kcl_lib_raw_api_spec.lua b/lua/spec/kcl_lib_raw_api_spec.lua index 31f73315..a702c394 100644 --- a/lua/spec/kcl_lib_raw_api_spec.lua +++ b/lua/spec/kcl_lib_raw_api_spec.lua @@ -1,6 +1,9 @@ local io = require("io") local os = require("os") +local json = require("dkjson") +local pl_path = require("pl.path") + local api = require("kcl_lib.raw_api") describe("kcl_lib.raw_api", function() @@ -57,4 +60,200 @@ app: AppConfig { assert(os.remove(unformated_file)) end) end) + + describe("ping", function() + it("can call the native function", function() + local args = { value = "test" } + local result = assert(api:ping(args)) + assert.are.equal("test", result.value) + end) + end) + + describe("get_version", function() + it("can call the native function", function() + local args = {} + local result = assert(api:get_version(args)) + assert.is.match("%d+%.%d+%.%d+", result.version) + end) + end) + + describe("parse_program", function() + it("can call the native function", function() + local args = { paths = { "./spec/test_data/schema.k" } } + local result = assert(api:parse_program(args)) + assert(json.decode(result.ast_json)) + end) + end) + + describe("parse_file", function() + it("can call the native function", function() + local args = { path = "./spec/test_data/schema.k" } + local result = assert(api:parse_file(args)) + assert(json.decode(result.ast_json)) + end) + end) + + describe("load_package", function() + it("can call the native function", function() + local args = { + parse_args = { paths = { "./spec/test_data/schema.k" } }, + resolve_ast = true, + } + local result = assert(api:load_package(args)) + assert(json.decode(result.program)) + end) + end) + + describe("list_options", function() + it("can call the native function", function() + local args = { paths = { "./spec/test_data/options.k" } } + local result = assert(api:list_options(args)) + assert.are.equal(3, #result.options) + end) + end) + + describe("list_variables", function() + it("can call the native function", function() + local args = { files = { "./spec/test_data/schema.k" } } + local result = assert(api:list_variables(args)) + assert.are.equal("AppConfig", result.variables.app.variables[1].type_name) + end) + end) + + describe("format_code", function() + it("can call the native function", function() + local args = { source = "a = 1" } + local result = assert(api:format_code(args)) + assert.are.equal("a = 1\n", result.formatted) + end) + end) + + describe("lint_path", function() + it("can call the native function", function() + local args = { paths = { "./spec/test_data/lint_err.k" } } + local result = assert(api:lint_path(args)) + assert.are.equal("Module 'math' imported but unused", result.results[1]) + end) + end) + + describe("override_file", function() + it("can call the native function", function() + local filename = os.tmpname() + assert( + os.execute("cp ./spec/test_data/schema.k " .. filename), + "failed to copy schema.k to temporary file" + ) + local args = { file = filename, specs = { "a=1" } } + local result = assert(api:override_file(args)) + assert.is.truthy(result.result) + local file = assert( + io.open(filename, "r"), + "failed to open temporary file for reading" + ) + local data = file:read("*a") + file:close() + local expected_content = [[schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +a = 1 +]] + assert.are.equal(expected_content, data) + assert(os.remove(filename)) + end) + end) + + describe("get_schema_type_mapping", function() + it("can call the native function", function() + local args = + { exec_args = { k_filename_list = { "./spec/test_data/schema.k" } } } + local result = assert(api:get_schema_type_mapping(args)) + assert.are.equal( + "int", + result.schema_type_mapping["app"].properties.replicas.type + ) + end) + end) + + describe("validate_code", function() + it("can call the native function", function() + local args = { + code = "schema Person:\n name: str", + data = '{"name": "Alice"}', + format = "json", + } + local result = assert(api:validate_code(args)) + assert.are.equal(true, result.success) + end) + end) + + describe("load_settings_files", function() + it("can call the native function", function() + local args = + { work_dir = ".", files = { "./spec/test_data/kcl-settings.yaml" } } + local result = assert(api:load_settings_files(args)) + assert.are.equal("key", result.kcl_options[1].key) + end) + end) + + describe("rename", function() + it("can call the native function", function() + local filename = os.tmpname() + assert( + os.execute("cp ./spec/test_data/options.k " .. filename), + "failed to copy options.k to temporary file" + ) + local args = { + package_root = pl_path.dirname(filename), + symbol_path = "a", + file_paths = { filename }, + new_name = "z", + } + local result = assert(api:rename(args)) + assert.are.equal(1, #result.changed_files) + local file = assert( + io.open(filename, "r"), + "failed to open temporary file for reading" + ) + local data = file:read("*a") + file:close() + local expected_content = [[z = option("key1") +b = option("key2", required=True) +c = { + metadata.key = option("metadata-key") +}]] + assert.are.equal(expected_content, data) + assert(os.remove(filename)) + end) + end) + + describe("rename_code", function() + it("can call the native function", function() + local args = { + package_root = "/tmp", + symbol_path = "a", + source_codes = { ["/tmp/rename.k"] = "a = 1" }, + new_name = "z", + } + local result = assert(api:rename_code(args)) + assert.are.equal("z = 1", result.changed_codes["/tmp/rename.k"]) + end) + end) + + describe("test", function() + it("can call the native function", function() + local args = { pkg_list = { "./spec/test_data/test/..." } } + local result = assert(api:test(args)) + assert.are.equal(3, #result.info) + end) + end) + + describe("update_dependencies", function() + it("can call the native function", function() + local args = { manifest_path = "./spec/test_data/module" } + assert(api:update_dependencies(args)) + end) + end) end) diff --git a/lua/spec/test_data/kcl-settings.yaml b/lua/spec/test_data/kcl-settings.yaml new file mode 100644 index 00000000..7b7300d7 --- /dev/null +++ b/lua/spec/test_data/kcl-settings.yaml @@ -0,0 +1,5 @@ +kcl_cli_configs: + strict_range_check: true +kcl_options: + - key: key + value: value diff --git a/lua/spec/test_data/lint_err.k b/lua/spec/test_data/lint_err.k new file mode 100644 index 00000000..f5338c56 --- /dev/null +++ b/lua/spec/test_data/lint_err.k @@ -0,0 +1,8 @@ +import math + +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} diff --git a/lua/spec/test_data/module/kcl.mod b/lua/spec/test_data/module/kcl.mod new file mode 100644 index 00000000..3b9d5880 --- /dev/null +++ b/lua/spec/test_data/module/kcl.mod @@ -0,0 +1,8 @@ +[package] +name = "mod_update" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } +flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } diff --git a/lua/spec/test_data/module/main.k b/lua/spec/test_data/module/main.k new file mode 100644 index 00000000..b371e741 --- /dev/null +++ b/lua/spec/test_data/module/main.k @@ -0,0 +1,4 @@ +import helloworld +import flask + +a = helloworld.The_first_kcl_program diff --git a/lua/spec/test_data/options.k b/lua/spec/test_data/options.k new file mode 100644 index 00000000..1f6edf46 --- /dev/null +++ b/lua/spec/test_data/options.k @@ -0,0 +1,5 @@ +a = option("key1") +b = option("key2", required=True) +c = { + metadata.key = option("metadata-key") +} diff --git a/lua/spec/test_data/test/hello.k b/lua/spec/test_data/test/hello.k new file mode 100644 index 00000000..cd87f446 --- /dev/null +++ b/lua/spec/test_data/test/hello.k @@ -0,0 +1,11 @@ +schema Person: + name: str = "kcl" + age: int = 1 + + check: + 0 <= age <= 120, "age must be in [0, 120]" + +hello = Person { + name = "hello kcl" + age = 102 +} diff --git a/lua/spec/test_data/test/hello_test.k b/lua/spec/test_data/test/hello_test.k new file mode 100644 index 00000000..730dbc7a --- /dev/null +++ b/lua/spec/test_data/test/hello_test.k @@ -0,0 +1,13 @@ +test_person = lambda { + a = Person{} + assert a.name == 'kcl' +} +test_person_age = lambda { + a = Person{} + assert a.age == 1 +} +test_person_ok = lambda { + a = Person{} + assert a.name == "kcl" + assert a.age == 1 +}