From 3900ea22df757814f37d6a58adb6a8d8d1304be1 Mon Sep 17 00:00:00 2001 From: Nicolas Berthier Date: Fri, 15 Sep 2023 09:36:05 +0200 Subject: [PATCH] Import LSP tests --- .drom | 85 +-- .github/workflows/workflow.yml | 2 +- Makefile | 2 +- drom.toml | 8 + dune-project | 65 +++ opam/cobol_ast.opam | 2 + opam/cobol_common.opam | 2 + opam/cobol_config.opam | 2 + opam/cobol_data.opam | 3 + opam/cobol_indent.opam | 2 + opam/cobol_lsp.opam | 3 + opam/cobol_parser.opam | 2 + opam/cobol_preproc.opam | 2 + opam/cobol_typeck.opam | 2 + opam/ebcdic_lib.opam | 2 + opam/interop-js-stubs.opam | 2 + opam/node-js-stubs.opam | 2 + opam/polka-js-stubs.opam | 2 + opam/ppx_cobcflags.opam | 2 + opam/pretty.opam | 2 + opam/superbol-free.opam | 2 + opam/superbol-studio-oss.opam | 58 ++ opam/superbol-vscode-platform.opam | 2 + opam/superbol_free_lib.opam | 2 + opam/superbol_testutils.opam | 58 ++ opam/vscode-debugadapter.opam | 2 + opam/vscode-debugprotocol.opam | 2 + opam/vscode-js-stubs.opam | 2 + opam/vscode-json.opam | 2 + opam/vscode-languageclient-js-stubs.opam | 2 + opam/vscode-package-json.opam | 2 + src/lsp/cobol_data/dune | 2 +- src/lsp/cobol_data/package.toml | 1 + src/lsp/cobol_lsp/dune | 2 +- src/lsp/cobol_lsp/package.toml | 1 + src/testing/superbol_testutils/dune | 26 + src/testing/superbol_testutils/index.mld | 9 + src/testing/superbol_testutils/package.toml | 74 +++ src/testing/superbol_testutils/tempdir.ml | 38 ++ src/testing/superbol_testutils/version.mlt | 30 ++ test/lsp/dune | 10 + test/lsp/lsp_basics.ml | 34 ++ test/lsp/lsp_definition.ml | 340 ++++++++++++ test/lsp/lsp_formatting.ml | 570 ++++++++++++++++++++ test/lsp/lsp_hover.ml | 142 +++++ test/lsp/lsp_references.ml | 307 +++++++++++ test/lsp/lsp_testing.ml | 230 ++++++++ test/lsp/lsp_testing.mli | 41 ++ 48 files changed, 2151 insertions(+), 34 deletions(-) create mode 100644 opam/superbol-studio-oss.opam create mode 100644 opam/superbol_testutils.opam create mode 100644 src/testing/superbol_testutils/dune create mode 100644 src/testing/superbol_testutils/index.mld create mode 100644 src/testing/superbol_testutils/package.toml create mode 100644 src/testing/superbol_testutils/tempdir.ml create mode 100644 src/testing/superbol_testutils/version.mlt create mode 100644 test/lsp/dune create mode 100644 test/lsp/lsp_basics.ml create mode 100644 test/lsp/lsp_definition.ml create mode 100644 test/lsp/lsp_formatting.ml create mode 100644 test/lsp/lsp_hover.ml create mode 100644 test/lsp/lsp_references.ml create mode 100644 test/lsp/lsp_testing.ml create mode 100644 test/lsp/lsp_testing.mli diff --git a/.drom b/.drom index e39f36ef5..a14b2e48e 100644 --- a/.drom +++ b/.drom @@ -5,12 +5,12 @@ version:0.9.0 # hash of toml configuration files # used for generation of all files -48927d80102a3921577afcc15fb1d969:. +306a162bd34aef4c3753c84e38852da6:. # end context for . # begin context for .github/workflows/workflow.yml # file .github/workflows/workflow.yml -5e6a732ee2859a2a1051d6ff9ca00cf9:.github/workflows/workflow.yml +fc10b0887fb072e04e5bcbdd5a0c6668:.github/workflows/workflow.yml # end context for .github/workflows/workflow.yml # begin context for .gitignore @@ -30,7 +30,7 @@ d00f73c835ae4a1589d55ebda4ab381b:CHANGES.md # begin context for Makefile # file Makefile -65cc05cba8ef1ae01505eeee2168c932:Makefile +86f0208a874473207a92c1e552fa9cb5:Makefile # end context for Makefile # begin context for README.md @@ -80,67 +80,67 @@ c8281f46ba9a11d0b61bc8ef67eaa357:docs/style.css # begin context for dune-project # file dune-project -355eec9ea4e5f41b281eeb1ad9fdb005:dune-project +69659cb561ea7a5fbe7c54ac41297836:dune-project # end context for dune-project # begin context for opam/cobol_ast.opam # file opam/cobol_ast.opam -c4f04adcb1fdfeae6c4c116716a50f79:opam/cobol_ast.opam +ec5c2eceed94689d89cb57acb7ba70a9:opam/cobol_ast.opam # end context for opam/cobol_ast.opam # begin context for opam/cobol_common.opam # file opam/cobol_common.opam -f7be66b45891545323c32c334f4a9b34:opam/cobol_common.opam +7fdae3e0d7ba510cb09c43cbf86d482b:opam/cobol_common.opam # end context for opam/cobol_common.opam # begin context for opam/cobol_config.opam # file opam/cobol_config.opam -502615c63850d0561a1fdc12742abe28:opam/cobol_config.opam +1708e29f87b61476a786f030837cbcc5:opam/cobol_config.opam # end context for opam/cobol_config.opam # begin context for opam/cobol_data.opam # file opam/cobol_data.opam -a40db244980ce0f20ed6029d3613c69d:opam/cobol_data.opam +fea158982cf75a9547f3ef0d352851cb:opam/cobol_data.opam # end context for opam/cobol_data.opam # begin context for opam/cobol_indent.opam # file opam/cobol_indent.opam -9fba7024c8916051df7aa44e20fea1c1:opam/cobol_indent.opam +149fbfd39c68757f141ba98b614b9b5e:opam/cobol_indent.opam # end context for opam/cobol_indent.opam # begin context for opam/cobol_lsp.opam # file opam/cobol_lsp.opam -cc200b60ab1a488aa6e2277963597432:opam/cobol_lsp.opam +30120bee2b9a602fdecec129bf2cd782:opam/cobol_lsp.opam # end context for opam/cobol_lsp.opam # begin context for opam/cobol_parser.opam # file opam/cobol_parser.opam -6516dc8bcfb5af8b3cb7ee29e5a4649f:opam/cobol_parser.opam +e20b6d94b7638ca8bf1b1ed68291f39b:opam/cobol_parser.opam # end context for opam/cobol_parser.opam # begin context for opam/cobol_preproc.opam # file opam/cobol_preproc.opam -4b563136f022c0354e2dbfa0c56ce90a:opam/cobol_preproc.opam +e5f0e7bc592f5e31540cafe106fba453:opam/cobol_preproc.opam # end context for opam/cobol_preproc.opam # begin context for opam/cobol_typeck.opam # file opam/cobol_typeck.opam -cda6b61f14077793c7b1d901fe8956b9:opam/cobol_typeck.opam +b20e3376e11aab21f6a68cf7082b0593:opam/cobol_typeck.opam # end context for opam/cobol_typeck.opam # begin context for opam/ebcdic_lib.opam # file opam/ebcdic_lib.opam -dc1020a31ed90a83a337c95c27a94246:opam/ebcdic_lib.opam +57afdedc9df0af27a627b4d769f6f913:opam/ebcdic_lib.opam # end context for opam/ebcdic_lib.opam # begin context for opam/interop-js-stubs.opam # file opam/interop-js-stubs.opam -d76d644f5363b79c9befa582cdcaab09:opam/interop-js-stubs.opam +8e63107a8753774ac9da20a83d62102a:opam/interop-js-stubs.opam # end context for opam/interop-js-stubs.opam # begin context for opam/node-js-stubs.opam # file opam/node-js-stubs.opam -d1718b85ada6fb99b2dd82dae6b9534e:opam/node-js-stubs.opam +a75883b8f6964b189bd09fba55d02ba6:opam/node-js-stubs.opam # end context for opam/node-js-stubs.opam # begin context for opam/package-json.opam @@ -150,24 +150,29 @@ dcf0ebaa8b12787df9efcaa0ce8cbbe5:opam/package-json.opam # begin context for opam/polka-js-stubs.opam # file opam/polka-js-stubs.opam -ba0b2be6fba59f550f44c3a304c0f4cc:opam/polka-js-stubs.opam +2903b520d3f8efe71dea84ef5ce81b49:opam/polka-js-stubs.opam # end context for opam/polka-js-stubs.opam # begin context for opam/ppx_cobcflags.opam # file opam/ppx_cobcflags.opam -ba782c63d2f135a814fd05727ba4c8e7:opam/ppx_cobcflags.opam +01ebe086e2774dc55643ae9998f119dc:opam/ppx_cobcflags.opam # end context for opam/ppx_cobcflags.opam # begin context for opam/pretty.opam # file opam/pretty.opam -d73eea9a4c770fc30eff6a149520f8cf:opam/pretty.opam +ea407d3a5a5dcb71eba31fcc9615027b:opam/pretty.opam # end context for opam/pretty.opam # begin context for opam/superbol-free.opam # file opam/superbol-free.opam -6b0be7a6c240b89c59ac8dffd8e0947a:opam/superbol-free.opam +f5b27455d30e42f94791f0968addc0e5:opam/superbol-free.opam # end context for opam/superbol-free.opam +# begin context for opam/superbol-studio-oss.opam +# file opam/superbol-studio-oss.opam +73086859c292388b297ff23144822425:opam/superbol-studio-oss.opam +# end context for opam/superbol-studio-oss.opam + # begin context for opam/superbol-vscode-extension.opam # file opam/superbol-vscode-extension.opam 38d272283b51b83690fa806b0868b764:opam/superbol-vscode-extension.opam @@ -175,42 +180,47 @@ d73eea9a4c770fc30eff6a149520f8cf:opam/pretty.opam # begin context for opam/superbol-vscode-platform.opam # file opam/superbol-vscode-platform.opam -4a4d0c79bd785e5141207e4cf2fcc25c:opam/superbol-vscode-platform.opam +ca7992e93086d642b5f99bf45f8106d7:opam/superbol-vscode-platform.opam # end context for opam/superbol-vscode-platform.opam # begin context for opam/superbol_free_lib.opam # file opam/superbol_free_lib.opam -f61852a8af4b9b60a488a1f92e2ff7ec:opam/superbol_free_lib.opam +888a7dbb5c0bb96da593f0bc6b3c8717:opam/superbol_free_lib.opam # end context for opam/superbol_free_lib.opam +# begin context for opam/superbol_testutils.opam +# file opam/superbol_testutils.opam +d371610a1877addf208f1a71cb60872e:opam/superbol_testutils.opam +# end context for opam/superbol_testutils.opam + # begin context for opam/vscode-debugadapter.opam # file opam/vscode-debugadapter.opam -db3bed4b95b8d0e415ed80cab8a14600:opam/vscode-debugadapter.opam +25217490ea71687bd0c2667f7bf2ae23:opam/vscode-debugadapter.opam # end context for opam/vscode-debugadapter.opam # begin context for opam/vscode-debugprotocol.opam # file opam/vscode-debugprotocol.opam -33805f388804a5f500714d064065ff16:opam/vscode-debugprotocol.opam +9fff3d351291aed5f046b1fc6c914176:opam/vscode-debugprotocol.opam # end context for opam/vscode-debugprotocol.opam # begin context for opam/vscode-js-stubs.opam # file opam/vscode-js-stubs.opam -864671fd24729ac3a57950866dbf8c98:opam/vscode-js-stubs.opam +66c5073dea90f40cd6f609da93f770af:opam/vscode-js-stubs.opam # end context for opam/vscode-js-stubs.opam # begin context for opam/vscode-json.opam # file opam/vscode-json.opam -28321ac33387f4d6aecca7028cdeaa48:opam/vscode-json.opam +0756f72e5c71f1d987f7708f0fbc4e6c:opam/vscode-json.opam # end context for opam/vscode-json.opam # begin context for opam/vscode-languageclient-js-stubs.opam # file opam/vscode-languageclient-js-stubs.opam -a1c17810cd51e0bde571b7dd9f5ca577:opam/vscode-languageclient-js-stubs.opam +a6e3111bcd9763fba6e8255a6dc2ce2e:opam/vscode-languageclient-js-stubs.opam # end context for opam/vscode-languageclient-js-stubs.opam # begin context for opam/vscode-package-json.opam # file opam/vscode-package-json.opam -f30db7a6f59dea549001a9d434b93c48:opam/vscode-package-json.opam +5ff243a84c54077695ad5ab968c5e4c3:opam/vscode-package-json.opam # end context for opam/vscode-package-json.opam # begin context for scripts/after.sh @@ -295,7 +305,7 @@ f4bbb4a41a8b3b39f19a4fc62a5f4841:sphinx/license.rst # begin context for src/lsp/cobol_data/dune # file src/lsp/cobol_data/dune -81bbf8b89cb2c2065539f6c083343849:src/lsp/cobol_data/dune +7d01cb2c52deab141e4a1c0517a4bb3b:src/lsp/cobol_data/dune # end context for src/lsp/cobol_data/dune # begin context for src/lsp/cobol_data/version.mlt @@ -315,7 +325,7 @@ f4bbb4a41a8b3b39f19a4fc62a5f4841:sphinx/license.rst # begin context for src/lsp/cobol_lsp/dune # file src/lsp/cobol_lsp/dune -957f078deb602f8e0114c8abcc771abf:src/lsp/cobol_lsp/dune +f5b5ba58f2a9ef21787bfca4f4268580:src/lsp/cobol_lsp/dune # end context for src/lsp/cobol_lsp/dune # begin context for src/lsp/cobol_lsp/version.mlt @@ -403,6 +413,21 @@ b9a14c96cce8e365e1d7494d078d73fe:src/lsp/superbol-free/linking_flags.sh 940d29cde7f16cd0916ed1d5f9c41154:src/lsp/superbol_free_lib/version.mlt # end context for src/lsp/superbol_free_lib/version.mlt +# begin context for src/testing/superbol_testutils/dune +# file src/testing/superbol_testutils/dune +7750c38b7b159782010b6ff0beaacab2:src/testing/superbol_testutils/dune +# end context for src/testing/superbol_testutils/dune + +# begin context for src/testing/superbol_testutils/index.mld +# file src/testing/superbol_testutils/index.mld +9d7338b8da226419559c6db54ea6c9e4:src/testing/superbol_testutils/index.mld +# end context for src/testing/superbol_testutils/index.mld + +# begin context for src/testing/superbol_testutils/version.mlt +# file src/testing/superbol_testutils/version.mlt +940d29cde7f16cd0916ed1d5f9c41154:src/testing/superbol_testutils/version.mlt +# end context for src/testing/superbol_testutils/version.mlt + # begin context for src/vscode/interop-js-stubs/dune # file src/vscode/interop-js-stubs/dune 707a0383f1e544fb37662db29a4f14ad:src/vscode/interop-js-stubs/dune diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 9d2004b0f..28c63d2fb 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -61,7 +61,7 @@ jobs: - run: opam pin add . -y --no-action - - run: opam depext -y superbol-vscode-platform polka-js-stubs interop-js-stubs node-js-stubs vscode-js-stubs vscode-languageclient-js-stubs vscode-package-json vscode-json vscode-debugadapter vscode-debugprotocol superbol-free superbol_free_lib cobol_common cobol_parser ebcdic_lib cobol_lsp ppx_cobcflags pretty cobol_config cobol_ast cobol_indent cobol_preproc cobol_data cobol_typeck + - run: opam depext -y superbol-vscode-platform polka-js-stubs interop-js-stubs node-js-stubs vscode-js-stubs vscode-languageclient-js-stubs vscode-package-json vscode-json vscode-debugadapter vscode-debugprotocol superbol-free superbol_free_lib cobol_common cobol_parser ebcdic_lib cobol_lsp ppx_cobcflags pretty cobol_config cobol_ast cobol_indent cobol_preproc cobol_data cobol_typeck superbol_testutils # if: steps.cache-opam.outputs.cache-hit != 'true' - run: opam install -y opam/*.opam --deps-only --with-test diff --git a/Makefile b/Makefile index ac0d5a35a..9e7fa37c1 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ all: build build: ./scripts/before.sh build opam exec -- dune build @install - ./scripts/copy-bin.sh superbol-vscode-platform polka-js-stubs interop-js-stubs node-js-stubs vscode-js-stubs vscode-languageclient-js-stubs vscode-package-json vscode-json vscode-debugadapter vscode-debugprotocol superbol-free superbol_free_lib cobol_common cobol_parser ebcdic_lib cobol_lsp ppx_cobcflags pretty cobol_config cobol_ast cobol_indent cobol_preproc cobol_data cobol_typeck + ./scripts/copy-bin.sh superbol-vscode-platform polka-js-stubs interop-js-stubs node-js-stubs vscode-js-stubs vscode-languageclient-js-stubs vscode-package-json vscode-json vscode-debugadapter vscode-debugprotocol superbol-free superbol_free_lib cobol_common cobol_parser ebcdic_lib cobol_lsp ppx_cobcflags pretty cobol_config cobol_ast cobol_indent cobol_preproc cobol_data cobol_typeck superbol_testutils ./scripts/after.sh build build-deps: diff --git a/drom.toml b/drom.toml index 50a772ced..eaf32fed5 100644 --- a/drom.toml +++ b/drom.toml @@ -39,6 +39,10 @@ skip = ["@test", "@ocamlformat", "@ocp-indent", "README.md", "sphinx/about.rst", [dependencies] # project-wide tools dependencies (not for package-specific deps) +[tools] +menhir = "<20230608" +[tools.alcotest] +for-test = true [tools.ocamlformat] for-test = true [tools.odoc] @@ -192,3 +196,7 @@ dir = "src/lsp/cobol_data" [[package]] dir = "src/lsp/cobol_typeck" # edit 'src/lsp/cobol_lsp/package.toml' for package-specific options + +[[package]] +dir = "src/testing/superbol_testutils" +# edit 'src/testing/superbol_testutils/package.toml' for package-specific options diff --git a/dune-project b/dune-project index 85800061c..b91fe6e1d 100644 --- a/dune-project +++ b/dune-project @@ -29,6 +29,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -49,6 +51,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -65,6 +69,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -84,6 +90,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -103,6 +111,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -123,6 +133,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -140,6 +152,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -156,6 +170,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -177,6 +193,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -196,6 +214,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -210,6 +230,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -231,6 +253,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -246,6 +270,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -267,6 +293,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -280,6 +308,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -291,6 +321,7 @@ (ocaml (>= 4.14.0)) (toml (and (>= 7.1.0) (< 8.0.0))) (pretty (= version)) + (ppx_expect ( >= v0.16 )) (lsp (and ( >= 1.15 )( < 1.16 ))) (jsonrpc ( >= 1.15 )) (cobol_typeck (= version)) @@ -303,6 +334,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -317,6 +350,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -332,6 +367,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -349,6 +386,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -364,6 +403,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -380,6 +421,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -397,6 +440,8 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -409,10 +454,13 @@ (ppx_deriving ( >= 5.2.1 )) (cobol_parser (= version)) (cobol_ast (= version)) + (alcotest ( >= 1 )) ppx_inline_test ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) @@ -431,6 +479,23 @@ ppx_expect odoc ocamlformat + (menhir ( < 20230608 )) + alcotest + ) + ) + +(package + (name superbol_testutils) + (synopsis "The superbol-studio-oss project") + (description "This is the description\nof the superbol-studio-oss OCaml project\n") + (depends + (ocaml (>= 4.14.0)) + ppx_inline_test + ppx_expect + odoc + ocamlformat + (menhir ( < 20230608 )) + alcotest ) ) diff --git a/opam/cobol_ast.opam b/opam/cobol_ast.opam index 584eabfc2..5fd84994d 100644 --- a/opam/cobol_ast.opam +++ b/opam/cobol_ast.opam @@ -54,5 +54,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/cobol_common.opam b/opam/cobol_common.opam index 6d31a1968..99a3625b8 100644 --- a/opam/cobol_common.opam +++ b/opam/cobol_common.opam @@ -54,5 +54,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/cobol_config.opam b/opam/cobol_config.opam index c9f1eae1d..9686f3c87 100644 --- a/opam/cobol_config.opam +++ b/opam/cobol_config.opam @@ -56,5 +56,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/cobol_data.opam b/opam/cobol_data.opam index f5f403c1a..8881bf7a2 100644 --- a/opam/cobol_data.opam +++ b/opam/cobol_data.opam @@ -51,9 +51,12 @@ depends: [ "ppx_deriving" {>= "5.2.1"} "cobol_parser" {= version} "cobol_ast" {= version} + "alcotest" {>= "1" with-test} "ppx_inline_test" {with-test} "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/cobol_indent.opam b/opam/cobol_indent.opam index 5fac5f123..20561c4f6 100644 --- a/opam/cobol_indent.opam +++ b/opam/cobol_indent.opam @@ -55,5 +55,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/cobol_lsp.opam b/opam/cobol_lsp.opam index f0bf13697..a83cb12f2 100644 --- a/opam/cobol_lsp.opam +++ b/opam/cobol_lsp.opam @@ -50,6 +50,7 @@ depends: [ "dune" {>= "2.7.0"} "toml" {>= "7.1.0" & < "8.0.0"} "pretty" {= version} + "ppx_expect" {>= "v0.16" with-test} "lsp" {>= "1.15" & < "1.16"} "jsonrpc" {>= "1.15"} "cobol_typeck" {= version} @@ -62,5 +63,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/cobol_parser.opam b/opam/cobol_parser.opam index 881560154..00e05800a 100644 --- a/opam/cobol_parser.opam +++ b/opam/cobol_parser.opam @@ -60,5 +60,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/cobol_preproc.opam b/opam/cobol_preproc.opam index 5896e6de2..1e9734bd2 100644 --- a/opam/cobol_preproc.opam +++ b/opam/cobol_preproc.opam @@ -56,5 +56,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/cobol_typeck.opam b/opam/cobol_typeck.opam index e8a806264..a34cc44cf 100644 --- a/opam/cobol_typeck.opam +++ b/opam/cobol_typeck.opam @@ -57,5 +57,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/ebcdic_lib.opam b/opam/ebcdic_lib.opam index ba4e5b296..c449d4c56 100644 --- a/opam/ebcdic_lib.opam +++ b/opam/ebcdic_lib.opam @@ -52,5 +52,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/interop-js-stubs.opam b/opam/interop-js-stubs.opam index dd4a51ab1..9b9f968f3 100644 --- a/opam/interop-js-stubs.opam +++ b/opam/interop-js-stubs.opam @@ -55,5 +55,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/node-js-stubs.opam b/opam/node-js-stubs.opam index d20beb9ac..0dd9caea9 100644 --- a/opam/node-js-stubs.opam +++ b/opam/node-js-stubs.opam @@ -58,5 +58,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/polka-js-stubs.opam b/opam/polka-js-stubs.opam index 3473930e3..347bc7037 100644 --- a/opam/polka-js-stubs.opam +++ b/opam/polka-js-stubs.opam @@ -59,5 +59,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/ppx_cobcflags.opam b/opam/ppx_cobcflags.opam index e037a6b7c..938e45d67 100644 --- a/opam/ppx_cobcflags.opam +++ b/opam/ppx_cobcflags.opam @@ -53,5 +53,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/pretty.opam b/opam/pretty.opam index ff23cf131..955b1934d 100644 --- a/opam/pretty.opam +++ b/opam/pretty.opam @@ -54,5 +54,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/superbol-free.opam b/opam/superbol-free.opam index 50ea950a0..006da112e 100644 --- a/opam/superbol-free.opam +++ b/opam/superbol-free.opam @@ -53,5 +53,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/superbol-studio-oss.opam b/opam/superbol-studio-oss.opam new file mode 100644 index 000000000..6b45516b8 --- /dev/null +++ b/opam/superbol-studio-oss.opam @@ -0,0 +1,58 @@ +# This file was generated by `drom` from `drom.toml`. +# Do not modify, or add to the `skip` field of `drom.toml`. +opam-version: "2.0" +name: "superbol-studio-oss" +version: "0.1.0" +license: "MIT" +synopsis: "The superbol-studio-oss project" +description: """\ +This is the description +of the superbol-studio-oss OCaml project +""" +authors: [ + "Nicolas Berthier " + "David Declerck " + "Fabrice Le Fessant " + "Emilien Lemaire " +] +maintainer: [ + "Nicolas Berthier " + "David Declerck " + "Fabrice Le Fessant " + "Emilien Lemaire " +] +homepage: "https://ocamlpro.github.io/superbol-studio-oss" +doc: "https://ocamlpro.github.io/superbol-studio-oss/sphinx" +bug-reports: "https://github.com/ocamlpro/superbol-studio-oss/issues" +dev-repo: "git+https://github.com/ocamlpro/superbol-studio-oss.git" +tags: "org:ocamlpro" +build: [ + ["dune" "subst"] {dev} + ["sh" "-c" "./scripts/before.sh build '%{name}%'"] + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] + ["sh" "-c" "./scripts/after.sh build '%{name}%'"] +] +install: [ + ["sh" "-c" "./scripts/before.sh install '%{name}%'"] +] +depends: [ + "ocaml" {>= "4.14.0"} + "dune" {>= "2.7.0"} + "ppx_inline_test" {with-test} + "ppx_expect" {with-test} + "odoc" {with-doc} + "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} +] +# Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/superbol-vscode-platform.opam b/opam/superbol-vscode-platform.opam index 6404d1ddd..0861a108d 100644 --- a/opam/superbol-vscode-platform.opam +++ b/opam/superbol-vscode-platform.opam @@ -62,5 +62,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/superbol_free_lib.opam b/opam/superbol_free_lib.opam index d5f1655a5..ae7fa3a04 100644 --- a/opam/superbol_free_lib.opam +++ b/opam/superbol_free_lib.opam @@ -60,5 +60,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/superbol_testutils.opam b/opam/superbol_testutils.opam new file mode 100644 index 000000000..b488f5b71 --- /dev/null +++ b/opam/superbol_testutils.opam @@ -0,0 +1,58 @@ +# This file was generated by `drom` from `drom.toml`. +# Do not modify, or add to the `skip` field of `drom.toml`. +opam-version: "2.0" +name: "superbol_testutils" +version: "0.1.0" +license: "MIT" +synopsis: "The superbol-studio-oss project" +description: """\ +This is the description +of the superbol-studio-oss OCaml project +""" +authors: [ + "Nicolas Berthier " + "David Declerck " + "Fabrice Le Fessant " + "Emilien Lemaire " +] +maintainer: [ + "Nicolas Berthier " + "David Declerck " + "Fabrice Le Fessant " + "Emilien Lemaire " +] +homepage: "https://ocamlpro.github.io/superbol-vscode-platform" +doc: "https://ocamlpro.github.io/superbol-vscode-platform/sphinx" +bug-reports: "https://github.com/ocamlpro/superbol-vscode-platform/issues" +dev-repo: "git+https://github.com/ocamlpro/superbol-vscode-platform.git" +tags: "org:ocamlpro" +build: [ + ["dune" "subst"] {dev} + ["sh" "-c" "./scripts/before.sh build '%{name}%'"] + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] + ["sh" "-c" "./scripts/after.sh build '%{name}%'"] +] +install: [ + ["sh" "-c" "./scripts/before.sh install '%{name}%'"] +] +depends: [ + "ocaml" {>= "4.14.0"} + "dune" {>= "2.7.0"} + "ppx_inline_test" {with-test} + "ppx_expect" {with-test} + "odoc" {with-doc} + "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} +] +# Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/vscode-debugadapter.opam b/opam/vscode-debugadapter.opam index e24bb6eac..ef443c42a 100644 --- a/opam/vscode-debugadapter.opam +++ b/opam/vscode-debugadapter.opam @@ -60,5 +60,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/vscode-debugprotocol.opam b/opam/vscode-debugprotocol.opam index 18b8dc78f..7cf0d7d5d 100644 --- a/opam/vscode-debugprotocol.opam +++ b/opam/vscode-debugprotocol.opam @@ -58,5 +58,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/vscode-js-stubs.opam b/opam/vscode-js-stubs.opam index 31631083d..1c4990dda 100644 --- a/opam/vscode-js-stubs.opam +++ b/opam/vscode-js-stubs.opam @@ -58,5 +58,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/vscode-json.opam b/opam/vscode-json.opam index e6d597cc6..2a5753cb7 100644 --- a/opam/vscode-json.opam +++ b/opam/vscode-json.opam @@ -55,5 +55,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/vscode-languageclient-js-stubs.opam b/opam/vscode-languageclient-js-stubs.opam index 91611a989..5889facee 100644 --- a/opam/vscode-languageclient-js-stubs.opam +++ b/opam/vscode-languageclient-js-stubs.opam @@ -59,5 +59,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/opam/vscode-package-json.opam b/opam/vscode-package-json.opam index da05bcca0..280ecce46 100644 --- a/opam/vscode-package-json.opam +++ b/opam/vscode-package-json.opam @@ -56,5 +56,7 @@ depends: [ "ppx_expect" {with-test} "odoc" {with-doc} "ocamlformat" {with-test} + "menhir" {< "20230608"} + "alcotest" {with-test} ] # Content of `opam-trailer` field: \ No newline at end of file diff --git a/src/lsp/cobol_data/dune b/src/lsp/cobol_data/dune index b0e94ac17..a964e8783 100644 --- a/src/lsp/cobol_data/dune +++ b/src/lsp/cobol_data/dune @@ -5,7 +5,7 @@ (public_name cobol_data) (wrapped true) ; use field 'dune-libraries' to add libraries without opam deps - (libraries ppx_deriving cobol_parser cobol_ast ) + (libraries ppx_deriving cobol_parser cobol_ast alcotest ) ; use field 'dune-flags' to set this value (flags (:standard)) ; use field 'dune-stanzas' to add more stanzas here diff --git a/src/lsp/cobol_data/package.toml b/src/lsp/cobol_data/package.toml index 185b1e40c..bec6adf8c 100644 --- a/src/lsp/cobol_data/package.toml +++ b/src/lsp/cobol_data/package.toml @@ -56,6 +56,7 @@ skip = ["index.mld"] cobol_ast = "version" cobol_parser = "version" ppx_deriving = ">=5.2.1" +alcotest = { version = "1", for-test = true } # package tools dependencies [tools] diff --git a/src/lsp/cobol_lsp/dune b/src/lsp/cobol_lsp/dune index 97e0418cf..fb338ff7b 100644 --- a/src/lsp/cobol_lsp/dune +++ b/src/lsp/cobol_lsp/dune @@ -5,7 +5,7 @@ (public_name cobol_lsp) (wrapped true) ; use field 'dune-libraries' to add libraries without opam deps - (libraries toml pretty lsp jsonrpc cobol_typeck cobol_parser cobol_indent cobol_data cobol_config cobol_common ) + (libraries toml pretty ppx_expect lsp jsonrpc cobol_typeck cobol_parser cobol_indent cobol_data cobol_config cobol_common ) ; use field 'dune-flags' to set this value (flags (:standard)) ; use field 'dune-stanzas' to add more stanzas here diff --git a/src/lsp/cobol_lsp/package.toml b/src/lsp/cobol_lsp/package.toml index 621084821..383674bfc 100644 --- a/src/lsp/cobol_lsp/package.toml +++ b/src/lsp/cobol_lsp/package.toml @@ -63,6 +63,7 @@ jsonrpc = ">=1.15" lsp = ">=1.15 <1.16" pretty = "version" toml = "7.1.0" +ppx_expect = { version = ">=v0.16", for-test = true } # package tools dependencies [tools] diff --git a/src/testing/superbol_testutils/dune b/src/testing/superbol_testutils/dune new file mode 100644 index 000000000..e73ca30b9 --- /dev/null +++ b/src/testing/superbol_testutils/dune @@ -0,0 +1,26 @@ +; generated by drom from package skeleton 'library' + +(library + (name superbol_testutils) + (public_name superbol_testutils) + (wrapped true) + ; use field 'dune-libraries' to add libraries without opam deps + (libraries ) + ; use field 'dune-flags' to set this value + (flags (:standard)) + ; use field 'dune-stanzas' to add more stanzas here + + + ) + + +(rule + (targets version.ml) + (deps (:script version.mlt) package.toml) + (action (with-stdout-to %{targets} (run %{ocaml} unix.cma %{script})))) + +(documentation + (package superbol_testutils)) + +; use field 'dune-trailer' to add more stuff here + diff --git a/src/testing/superbol_testutils/index.mld b/src/testing/superbol_testutils/index.mld new file mode 100644 index 000000000..b190ad202 --- /dev/null +++ b/src/testing/superbol_testutils/index.mld @@ -0,0 +1,9 @@ +{1 Library superbol_testutils} + +This is the description +of the superbol-studio-oss OCaml project + + + +The entry point of this library is the module: {!Superbol_testutils}. + diff --git a/src/testing/superbol_testutils/package.toml b/src/testing/superbol_testutils/package.toml new file mode 100644 index 000000000..4feafaa6f --- /dev/null +++ b/src/testing/superbol_testutils/package.toml @@ -0,0 +1,74 @@ + +# name of package +name = "superbol_testutils" +skeleton = "library" + +# version if different from project version +# version = "0.1.0" + +# synopsis if different from project synopsis +# synopsis = ... + +# description if different from project description +# description = ... + +# kind is either "library", "program" or "virtual" +kind = "library" + +# authors if different from project authors +# authors = [ "Me " ] + +# name of a file to generate with the current version +gen-version = "version.ml" + +# supported file generators are "ocamllex", "ocamlyacc" and "menhir" +# default is [ "ocamllex", "ocamlyacc" ] +# generators = [ "ocamllex", "menhir" ] + +# menhir options for the package +#Example: +#version = "2.0" +#parser = { modules = ["parser"]; tokens = "Tokens" } +#tokens = { modules = ["tokens"]} +# menhir = ... + +# whether all modules should be packed/wrapped (default is true) +# pack-modules = false + +# whether the package can be silently skipped if missing deps (default is false) +# optional = true + +# module name used to pack modules (if pack-modules is true) +# pack = "Mylib" + +# preprocessing options +# preprocess = "per-module (((action (run ./toto.sh %{input-file})) mod))" +# preprocess = "pps ppx_deriving_encoding" + +# files to skip while updating at package level +# skip = [] + +# package library dependencies +# [dependencies] +# ez_file = ">=0.1 <1.3" +# base-unix = { libname = "unix", version = ">=base" } +[dependencies] +# ... + +# package tools dependencies +[tools] +# ... + +# package fields (depends on package skeleton) +#Examples: +# dune-stanzas = "(preprocess (pps ppx_deriving_encoding))" +# dune-libraries = "bigstring" +# dune-trailer = "(install (..))" +# opam-trailer = "pin-depends: [..]" +# no-opam-test = "yes" +# no-opam-doc = "yes" +# gen-opam = "some" | "all" +# dune-stanzas = "(flags (:standard (:include linking.sexp)))" +# static-clibs = "unix" +[fields] +# ... diff --git a/src/testing/superbol_testutils/tempdir.ml b/src/testing/superbol_testutils/tempdir.ml new file mode 100644 index 000000000..c22044a84 --- /dev/null +++ b/src/testing/superbol_testutils/tempdir.ml @@ -0,0 +1,38 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2021-2023 OCamlPro SAS *) +(* *) +(* All rights reserved. *) +(* This file is distributed under the terms of the *) +(* OCAMLPRO-NON-COMMERCIAL license. *) +(* *) +(**************************************************************************) + +(* https://discuss.ocaml.org/t/how-to-create-a-temporary-directory-in-ocaml/1815/4 *) +let rand_digits () = + Printf.sprintf "%06x" Random.State.(bits (make_self_init ()) land 0xFFFFFF) + +let mk_temp_dir ?(mode=0o700) ?dir pat = + let dir = match dir with + | Some d -> d + | None -> Filename.get_temp_dir_name () + in + let raise_err msg = raise (Sys_error msg) in + let rec loop count = + if count < 0 + then + raise_err "mk_temp_dir: too many failing attemps" + else + let dir = Printf.sprintf "%s/%s%s" dir pat (rand_digits ()) in + try (Unix.mkdir dir mode; dir) with + | Unix.Unix_error (Unix.EEXIST, _, _) -> loop (count - 1) + | Unix.Unix_error (Unix.EINTR, _, _) -> loop count + | Unix.Unix_error (e, _, _) -> + raise_err ("mk_temp_dir: " ^ (Unix.error_message e)) + in + loop 1000 + +let make_n_enter dirname_pattern = + let rundir = mk_temp_dir dirname_pattern in + Unix.chdir rundir; + rundir diff --git a/src/testing/superbol_testutils/version.mlt b/src/testing/superbol_testutils/version.mlt new file mode 100644 index 000000000..1bcf00592 --- /dev/null +++ b/src/testing/superbol_testutils/version.mlt @@ -0,0 +1,30 @@ +#!/usr/bin/env ocaml +;; +#load "unix.cma" + +let query cmd = + let chan = Unix.open_process_in cmd in + try + let out = input_line chan in + if Unix.close_process_in chan = Unix.WEXITED 0 then + Some out + else None + with End_of_file -> None + +let commit_hash = query "git show -s --pretty=format:%H" +let commit_date = query "git show -s --pretty=format:%ci" +let version = "0.1.0" + +let string_option = function + | None -> "None" + | Some s -> Printf.sprintf "Some %S" s + +let () = + Format.printf "@["; + Format.printf "let version = %S@," version; + Format.printf + "let commit_hash = %s@," (string_option commit_hash); + Format.printf + "let commit_date = %s@," (string_option commit_date); + Format.printf "@]@."; + () diff --git a/test/lsp/dune b/test/lsp/dune new file mode 100644 index 000000000..27fcddfaf --- /dev/null +++ b/test/lsp/dune @@ -0,0 +1,10 @@ +; if you modify this file, add 'test' to the 'skip' field in drom.toml + +(library + (name lsp_test_all) + (preprocess + (pps ppx_expect)) + (inline_tests + (modes best)) ; add js for testing with nodejs + (libraries cobol_lsp lsp superbol_free_lib superbol_testutils) + ) diff --git a/test/lsp/lsp_basics.ml b/test/lsp/lsp_basics.ml new file mode 100644 index 000000000..e59af1311 --- /dev/null +++ b/test/lsp/lsp_basics.ml @@ -0,0 +1,34 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2021-2023 OCamlPro SAS *) +(* *) +(* All rights reserved. *) +(* This file is distributed under the terms of the *) +(* OCAMLPRO-NON-COMMERCIAL license. *) +(* *) +(**************************************************************************) + +open Lsp_testing + +let%expect_test "add-empty-cobol-doc" = + let { projdir; end_with_postproc }, server = make_lsp_project () in + ignore @@ add_cobol_doc server ~projdir "prog.cob" ""; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} +|}];; + +let%expect_test "add-simple-cobol-doc" = + let { projdir; end_with_postproc }, server = make_lsp_project () in + ignore @@ add_cobol_doc server ~projdir "prog.cob" {cobol| + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + PROCEDURE DIVISION. + STOP RUN. + |cobol}; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} +|}];; diff --git a/test/lsp/lsp_definition.ml b/test/lsp/lsp_definition.ml new file mode 100644 index 000000000..8a7ea6623 --- /dev/null +++ b/test/lsp/lsp_definition.ml @@ -0,0 +1,340 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2021-2023 OCamlPro SAS *) +(* *) +(* All rights reserved. *) +(* This file is distributed under the terms of the *) +(* OCAMLPRO-NON-COMMERCIAL license. *) +(* *) +(**************************************************************************) + +open EzCompat (* StringMap *) +open Lsp.Types +open Lsp_testing + + +let print_definitions ~projdir server (doc, positions) : unit = + let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in + let location_as_srcloc = new srcloc_resuscitator_cache in + StringMap.iter begin fun position_name position -> + let params = DefinitionParams.create ~position ~textDocument:prog () in + Pretty.out "%s (line %d, character %d):@." + position_name position.line position.character; + match LSP.Request.lookup_definition server params with + | None | Some (`Location []) -> + Pretty.out "No definition found@." + | Some (`Location locs) -> + List.iter location_as_srcloc#print locs + (* Yojson.Safe.to_channel Stdlib.stdout @@ *) + (* Lsp.Client_request.yojson_of_result *) + (* (Lsp.Client_request.TextDocumentDefinition params) *) + (* (LSP.Request.lookup_definition server params); *) + end positions.pos_map +;; + + +let doc = + extract_position_markers {cobol| + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 DATA-_|1-data-name-in-def|_NAME PIC X. + PROCEDURE DIVISION. + DISPLAY _|2-data-name-in-display|_DATA-NAME + STOP RUN. + |cobol} +;; + +let%expect_test "simple-definition-requests" = + let { end_with_postproc; projdir }, server = make_lsp_project () in + print_definitions ~projdir server doc; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + 1-data-name-in-def (line 5, character 16): + __rootdir__/prog.cob:6.11-6.20: + 3 PROGRAM-ID. prog. + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 > 01 DATA-NAME PIC X. + ---- ^^^^^^^^^ + 7 PROCEDURE DIVISION. + 8 DISPLAY DATA-NAME + 2-data-name-in-display (line 7, character 18): + __rootdir__/prog.cob:6.11-6.20: + 3 PROGRAM-ID. prog. + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 > 01 DATA-NAME PIC X. + ---- ^^^^^^^^^ + 7 PROCEDURE DIVISION. + 8 DISPLAY DATA-NAME |}] + + +let doc = + extract_position_markers {cobol| + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + DATA DIVISION. + WORKING-STORAGE SECTION. + 0_|1-data-name-in-def|_1 DATA-_|2-data-name-in-def|_NAME P_|3-data-name-in-def|_IC X. + PROCEDURE DIVISION. + DISPLAY DATA-NAME + STOP RUN. + |cobol} +;; + +let%expect_test "simple-definition-requests-2" = + let { end_with_postproc; projdir }, server = make_lsp_project () in + print_definitions ~projdir server doc; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + 1-data-name-in-def (line 5, character 9): + __rootdir__/prog.cob:6.11-6.20: + 3 PROGRAM-ID. prog. + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 > 01 DATA-NAME PIC X. + ---- ^^^^^^^^^ + 7 PROCEDURE DIVISION. + 8 DISPLAY DATA-NAME + 2-data-name-in-def (line 5, character 16): + __rootdir__/prog.cob:6.11-6.20: + 3 PROGRAM-ID. prog. + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 > 01 DATA-NAME PIC X. + ---- ^^^^^^^^^ + 7 PROCEDURE DIVISION. + 8 DISPLAY DATA-NAME + 3-data-name-in-def (line 5, character 22): + __rootdir__/prog.cob:6.11-6.20: + 3 PROGRAM-ID. prog. + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 > 01 DATA-NAME PIC X. + ---- ^^^^^^^^^ + 7 PROCEDURE DIVISION. + 8 DISPLAY DATA-NAME |}] + + + +let doc = + extract_position_markers {cobol| + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 X. + 05 Y PIC 9. + PROCEDURE DIVISION. + DISPLAY _|1-data-name-in-display|_Y of _|2-data-name-in-display|_X. + STOP RUN. + |cobol} +;; + +let%expect_test "simple-definition-requests-2" = + let { end_with_postproc; projdir }, server = make_lsp_project () in + print_definitions ~projdir server doc; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + 1-data-name-in-display (line 8, character 20): + __rootdir__/prog.cob:7.15-7.16: + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 01 X. + 7 > 05 Y PIC 9. + ---- ^ + 8 PROCEDURE DIVISION. + 9 DISPLAY Y of X. + 2-data-name-in-display (line 8, character 25): + __rootdir__/prog.cob:6.11-6.12: + 3 PROGRAM-ID. prog. + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 > 01 X. + ---- ^ + 7 05 Y PIC 9. + 8 PROCEDURE DIVISION. |}] + + +let doc = + extract_position_markers {cobol| + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 X. + 05 Y PIC 9. + 66 Z RENAMES _|1-data-name-renamed|_Y. + PROCEDURE DIVISION. + DISPLAY _|2-data-name-in-display|_Z. + STOP RUN. + |cobol} +;; + +let%expect_test "definition-requests-renames" = + let { end_with_postproc; projdir }, server = make_lsp_project () in + print_definitions ~projdir server doc; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + 1-data-name-renamed (line 7, character 25): + __rootdir__/prog.cob:7.15-7.16: + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 01 X. + 7 > 05 Y PIC 9. + ---- ^ + 8 66 Z RENAMES Y. + 9 PROCEDURE DIVISION. + 2-data-name-in-display (line 9, character 20): + __rootdir__/prog.cob:8.15-8.16: + 5 WORKING-STORAGE SECTION. + 6 01 X. + 7 05 Y PIC 9. + 8 > 66 Z RENAMES Y. + ---- ^ + 9 PROCEDURE DIVISION. + 10 DISPLAY Z. |}] + + +let doc = + extract_position_markers {cobol| + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 Y PIC XXX. + 01 X. + 05 Y. + 10 Z PIC 999999. + 05 FILLER REDEFINES _|1-data-name-redefined|_Y. + 10 A PIC 9 OCCURS 6 TIMES. + 05 STH REDEFINES _|2-data-name-redefined|_Y. + 10 B PIC 99 OCCURS 3 TIMES. + 05 FILLER REDEFINES _|3-data-name-redefined|_Y. + 10 C PIC 999 OCCURS 2 TIMES. + PROCEDURE DIVISION. + DISPLAY _|4-data-name-in-display|_A. + |cobol} +;; + +let%expect_test "definition-requests-redefines" = + let { end_with_postproc; projdir }, server = make_lsp_project () in + print_definitions ~projdir server doc; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + 1-data-name-redefined (line 9, character 32): + __rootdir__/prog.cob:8.15-8.16: + 5 WORKING-STORAGE SECTION. + 6 01 Y PIC XXX. + 7 01 X. + 8 > 05 Y. + ---- ^ + 9 10 Z PIC 999999. + 10 05 FILLER REDEFINES Y. + 2-data-name-redefined (line 11, character 29): + __rootdir__/prog.cob:8.15-8.16: + 5 WORKING-STORAGE SECTION. + 6 01 Y PIC XXX. + 7 01 X. + 8 > 05 Y. + ---- ^ + 9 10 Z PIC 999999. + 10 05 FILLER REDEFINES Y. + 3-data-name-redefined (line 13, character 32): + __rootdir__/prog.cob:8.15-8.16: + 5 WORKING-STORAGE SECTION. + 6 01 Y PIC XXX. + 7 01 X. + 8 > 05 Y. + ---- ^ + 9 10 Z PIC 999999. + 10 05 FILLER REDEFINES Y. + 4-data-name-in-display (line 16, character 20): + __rootdir__/prog.cob:11.19-11.20: + 8 05 Y. + 9 10 Z PIC 999999. + 10 05 FILLER REDEFINES Y. + 11 > 10 A PIC 9 OCCURS 6 TIMES. + ---- ^ + 12 05 STH REDEFINES Y. + 13 10 B PIC 99 OCCURS 3 TIMES. |}] + + +let doc = + extract_position_markers {cobol| + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01. + 05 H1 PIC 999. + 05. + 10 _|1-data-name-in-def|_H PIC 999. + 05 H2 PIC 999. + 01 X. + 05 W PIC 999. + 05 FILLER. + 10 _|2-data-name-in-def|_Z PIC 999. + 01. + 05 _|3-data-name-in-def|_T PIC 999. + PROCEDURE DIVISION. + DISPLAY _|4-data-name-in-display|_Z OF X. + STOP RUN. + |cobol} +;; + +let%expect_test "definition-requests-filler" = + let { end_with_postproc; projdir }, server = make_lsp_project () in + print_definitions ~projdir server doc; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + 1-data-name-in-def (line 8, character 15): + __rootdir__/prog.cob:9.15-9.16: + 6 01. + 7 05 H1 PIC 999. + 8 05. + 9 > 10 H PIC 999. + ---- ^ + 10 05 H2 PIC 999. + 11 01 X. + 2-data-name-in-def (line 13, character 15): + __rootdir__/prog.cob:14.15-14.16: + 11 01 X. + 12 05 W PIC 999. + 13 05 FILLER. + 14 > 10 Z PIC 999. + ---- ^ + 15 01. + 16 05 T PIC 999. + 3-data-name-in-def (line 15, character 13): + __rootdir__/prog.cob:16.13-16.14: + 13 05 FILLER. + 14 10 Z PIC 999. + 15 01. + 16 > 05 T PIC 999. + ---- ^ + 17 PROCEDURE DIVISION. + 18 DISPLAY Z OF X. + 4-data-name-in-display (line 17, character 18): + __rootdir__/prog.cob:14.15-14.16: + 11 01 X. + 12 05 W PIC 999. + 13 05 FILLER. + 14 > 10 Z PIC 999. + ---- ^ + 15 01. + 16 05 T PIC 999. |}] diff --git a/test/lsp/lsp_formatting.ml b/test/lsp/lsp_formatting.ml new file mode 100644 index 000000000..e7d9f17fe --- /dev/null +++ b/test/lsp/lsp_formatting.ml @@ -0,0 +1,570 @@ +(******************************************************************************) +(* *) +(* Copyright (c) 2021-2023 OCamlPro SAS *) +(* *) +(* All rights reserved. *) +(* This file is distributed under the terms of the *) +(* OCAMLPRO-NON-COMMERCIAL license. *) +(* *) +(******************************************************************************) + +open Lsp.Types +open Lsp_testing + +let doc = {cobol| + PROGRAM-ID. HELLO. + PROCEDURE DIVISION. + para-1. + DISPLAY "HELLO" + STOP RUN. + |cobol};; + +let%expect_test "simple-formatting-request" = + let { projdir; end_with_postproc }, server = make_lsp_project () in + let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in + let params = + let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in + DocumentFormattingParams.create ~options ~textDocument:prog () + in + begin match LSP.Request.formatting server params with + | None -> Pretty.out "formatting error" + | Some l -> + List.iter (fun TextEdit.{newText;_} -> Pretty.out "%s" newText) l + end; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + >> Warning: Source format `auto` is not supported yet, using `fixed` + PROGRAM-ID. HELLO. + PROCEDURE DIVISION. + para-1. + DISPLAY "HELLO" + STOP RUN. |}] + + +let doc = {cobol| + para-1. + IF X>9 + THEN + IF X>6 + THEN + DISPLAY "2" + else + move 1 to x + else + move 1 to x. |cobol};; + +let%expect_test "formatting-request-nested-if" = + let { projdir; end_with_postproc }, server = make_lsp_project () in + let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in + let params = + let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in + DocumentFormattingParams.create ~options ~textDocument:prog () + in + begin match LSP.Request.formatting server params with + | None -> Pretty.out "formatting error" + | Some l -> + List.iter (fun TextEdit.{newText;_} -> Pretty.out "%s" newText) l + end; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Invalid syntax","range":{"end":{"character":14,"line":1},"start":{"character":8,"line":1}},"severity":1},{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + >> Warning: Source format `auto` is not supported yet, using `fixed` + para-1. + IF X>9 + THEN + IF X>6 + THEN + DISPLAY "2" + else + move 1 to x + else + move 1 to x. |}] + + +let doc = {cobol| + WORKING-STORAGE SECTION. + 01 x. + 05 y. + 10 z pic 999. + 05 h pic 99. + 66 z renames x. + 01 X1 + OCCURS 3 times + DEPENDING ON X2 + ASCENDING KEY is X3 + INDEXED BY X4 + value 999. |cobol};; + +let%expect_test "formatting-request-data" = + let { projdir; end_with_postproc }, server = make_lsp_project () in + let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in + let params = + let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in + DocumentFormattingParams.create ~options ~textDocument:prog () + in + begin match LSP.Request.formatting server params with + | None -> Pretty.out "formatting error" + | Some l -> + List.iter (fun TextEdit.{newText;_} -> Pretty.out "%s" newText) l + end; + end_with_postproc [%expect.output]; + [%expect{| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Invalid syntax","range":{"end":{"character":23,"line":1},"start":{"character":8,"line":1}},"severity":1},{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + >> Warning: Source format `auto` is not supported yet, using `fixed` + WORKING-STORAGE SECTION. + 01 x. + 05 y. + 10 z pic 999. + 05 h pic 99. + 66 z renames x. + 01 X1 + OCCURS 3 times + DEPENDING ON X2 + ASCENDING KEY is X3 + INDEXED BY X4 + value 999. |}] + + +let doc = {cobol| + IDENTIFICATION DIVISION. + PROGRAM-ID. X. + PROCEDURE DIVISION. + DISPLAY "I'm in X" + CALL "X1" + CALL "X2" + STOP RUN. + + IDENTIFICATION DIVISION. + PROGRAM-ID. X1. + PROCEDURE DIVISION. + DISPLAY "I'm in X1" + CALL "X11" + CALL "X12" + EXIT Program. + + IDENTIFICATION DIVISION. + PROGRAM-ID. X11. + PROCEDURE DIVISION. + DISPLAY "I'm in X11" + EXIT Program. + END PROGRAM X11. + + IDENTIFICATION DIVISION. + PROGRAM-ID. X12. + PROCEDURE DIVISION. + DISPLAY "I'm in X12" + EXIT Program. + END PROGRAM X12. + + END PROGRAM X1. + + IDENTIFICATION DIVISION. + PROGRAM-ID. X2. + PROCEDURE DIVISION. + DISPLAY "I'm in X2" + EXIT Program. + END PROGRAM X2. + + END PROGRAM X. + |cobol};; + +let%expect_test "formatting-request-nested-program" = + let { projdir; end_with_postproc }, server = make_lsp_project () in + let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in + let params = + let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in + DocumentFormattingParams.create ~options ~textDocument:prog () + in + begin match LSP.Request.formatting server params with + | None -> Pretty.out "formatting error" + | Some l -> + List.iter (fun TextEdit.{newText;_} -> Pretty.out "%s" newText) l + end; + end_with_postproc [%expect.output]; + [%expect{| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + >> Warning: Source format `auto` is not supported yet, using `fixed` + IDENTIFICATION DIVISION. + PROGRAM-ID. X. + PROCEDURE DIVISION. + DISPLAY "I'm in X" + CALL "X1" + CALL "X2" + STOP RUN. + IDENTIFICATION DIVISION. + PROGRAM-ID. X1. + PROCEDURE DIVISION. + DISPLAY "I'm in X1" + CALL "X11" + CALL "X12" + EXIT Program. + IDENTIFICATION DIVISION. + PROGRAM-ID. X11. + PROCEDURE DIVISION. + DISPLAY "I'm in X11" + EXIT Program. + END PROGRAM X11. + IDENTIFICATION DIVISION. + PROGRAM-ID. X12. + PROCEDURE DIVISION. + DISPLAY "I'm in X12" + EXIT Program. + END PROGRAM X12. + END PROGRAM X1. + IDENTIFICATION DIVISION. + PROGRAM-ID. X2. + PROCEDURE DIVISION. + DISPLAY "I'm in X2" + EXIT Program. + END PROGRAM X2. + END PROGRAM X. |}] + + +let doc = {cobol| + MOVE VAR-1 TO VAR-2 VAR-3 + VAR-4 + VAR-5. + |cobol};; + +let%expect_test "formatting-request-alignment-argument" = + let { projdir; end_with_postproc }, server = make_lsp_project () in + let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in + let params = + let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in + DocumentFormattingParams.create ~options ~textDocument:prog () + in + begin match LSP.Request.formatting server params with + | None -> Pretty.out "formatting error" + | Some l -> + List.iter (fun TextEdit.{newText;_} -> Pretty.out "%s" newText) l + end; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Invalid syntax","range":{"end":{"character":11,"line":1},"start":{"character":7,"line":1}},"severity":1},{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + >> Warning: Source format `auto` is not supported yet, using `fixed` + MOVE VAR-1 TO VAR-2 VAR-3 + VAR-4 + VAR-5. |}] + + +let doc = {cobol| + if x>1 + move 1 to x + else if x>2 + move 2 to x + else if x>3 + move 3 to x + else + move 4 to x. + |cobol};; + +let%expect_test "formatting-request-else-if" = + let { projdir; end_with_postproc }, server = make_lsp_project () in + let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in + let params = + let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in + DocumentFormattingParams.create ~options ~textDocument:prog () + in + begin match LSP.Request.formatting server params with + | None -> Pretty.out "formatting error" + | Some l -> + List.iter (fun TextEdit.{newText;_} -> Pretty.out "%s" newText) l + end; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Invalid syntax","range":{"end":{"character":10,"line":1},"start":{"character":8,"line":1}},"severity":1},{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + >> Warning: Source format `auto` is not supported yet, using `fixed` + if x>1 + move 1 to x + else if x>2 + move 2 to x + else if x>3 + move 3 to x + else + move 4 to x. |}] + + +let doc = {cobol| + IDENTIFICATION DIVISION. + PROGRAM-ID. MACESDS. + ENVIRONMENT DIVISION. + INPUT-OUTPUT SECTION. + FILE-CONTROL. + SELECT MACC ASSIGN TO RRDSFILE + ORGANIZATION RELATIVE + ACCESS MODE DYNAMIC + RELATIVE KEY RK + FILE STATUS FS. + DATA DIVISION. + FILE SECTION. + FD MACC. + 01 MREC. + 05 MNO PIC 9(5). + 05 MNAME PIC X(10). + WORKING-STORAGE SECTION. + 01 FS PIC X(2). + 01 A PIC 99 VALUE 00. + 01 B PIC 9(5) VALUE ZERO. + 01 IREC. + 05 INO PIC 9(5). + 05 INAME PIC X(10). + 01 RK PIC 9(02) VALUE 01. + PROCEDURE DIVISION. + 0001. + DISPLAY "ENTER 1.SEAR/2.WRITE/3.REWR/4.DEL/5.DELALL/6.DISP". + ACCEPT A. + IF A = 1 GO 1SEARCH + ELSE IF A = 2 GO 2WRITE + ELSE IF A = 3 GO 3REWRITE + ELSE IF A = 4 GO 4DELETE + ELSE IF A = 5 GO 5DELALL + ELSE IF A = 6 GO 6DISPLAY + ELSE DISPLAY "INVALID INPUT" + GO 0001. + STOP RUN. + 1SEARCH. + OPEN INPUT MACC. + ACCEPT B. + 0002. + READ MACC NEXT AT END DISPLAY B "NOT FOUND", GO 000X. + IF B = MNO DISPLAY "FOUND " MNO ":" , + DISPLAY " AT POS:" A " FOR NAME: " MNAME, + GO 000X. + ADD 1 TO A. + GO TO 0002. + 2WRITE. + OPEN I-O MACC. + IF FS = 00 PERFORM RKKEY UNTIL FS = 10 + ELSE OPEN OUTPUT MACC. + DISPLAY RK. + ACCEPT MNO. + ACCEPT MNAME. + WRITE MREC INVALID KEY DISPLAY "DUPLICATE KEY!". + GO 000X. + 3REWRITE. + OPEN I-O MACC. + ACCEPT RK. + ACCEPT MNO. + ACCEPT MNAME. + REWRITE MREC INVALID KEY DISPLAY "NOT FOUND". + GO 000X. + 4DELETE. + OPEN I-O MACC. + ACCEPT RK. + DELETE MACC INVALID KEY DISPLAY "NOT FOUND". + GO 000X. + 5DELALL. + OPEN I-O MACC. + MOVE 01 TO RK. + 0003. + DELETE MACC INVALID KEY GO 000X. + ADD 01 TO RK. + GO 0003. + 6DISPLAY. + OPEN INPUT MACC. + 0005. + READ MACC NEXT INTO IREC AT END GO 000X. + DISPLAY INO, " ", INAME. + GO 0005. + 000X. + CLOSE MACC. + DISPLAY "CONTINUE?1/0". + ACCEPT A. + IF A = 0 STOP RUN ELSE GO 0001. + RKKEY. + READ MACC NEXT. + ADD 1 TO RK. + |cobol};; + +let%expect_test "formatting-request-whole-program" = + let { projdir; end_with_postproc }, server = make_lsp_project () in + let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in + let params = + let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in + DocumentFormattingParams.create ~options ~textDocument:prog () + in + begin match LSP.Request.formatting server params with + | None -> Pretty.out "formatting error" + | Some l -> + List.iter (fun TextEdit.{newText;_} -> Pretty.out "%s" newText) l + end; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + src/lsp/cobol_ast/raw_misc_sections_visitor.ml:66: + (Cobol_ast__Raw_misc_sections_visitor.fold_select_clause): missing visitor + implementation + src/lsp/cobol_ast/raw_data_sections_visitor.ml:280: + (Cobol_ast__Raw_data_sections_visitor.fold_file_section): missing visitor + implementation + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + >> Warning: Source format `auto` is not supported yet, using `fixed` + IDENTIFICATION DIVISION. + PROGRAM-ID. MACESDS. + ENVIRONMENT DIVISION. + INPUT-OUTPUT SECTION. + FILE-CONTROL. + SELECT MACC ASSIGN TO RRDSFILE + ORGANIZATION RELATIVE + ACCESS MODE DYNAMIC + RELATIVE KEY RK + FILE STATUS FS. + DATA DIVISION. + FILE SECTION. + FD MACC. + 01 MREC. + 05 MNO PIC 9(5). + 05 MNAME PIC X(10). + WORKING-STORAGE SECTION. + 01 FS PIC X(2). + 01 A PIC 99 VALUE 00. + 01 B PIC 9(5) VALUE ZERO. + 01 IREC. + 05 INO PIC 9(5). + 05 INAME PIC X(10). + 01 RK PIC 9(02) VALUE 01. + PROCEDURE DIVISION. + 0001. + DISPLAY "ENTER 1.SEAR/2.WRITE/3.REWR/4.DEL/5.DELALL/6.DISP". + ACCEPT A. + IF A = 1 GO 1SEARCH + ELSE IF A = 2 GO 2WRITE + ELSE IF A = 3 GO 3REWRITE + ELSE IF A = 4 GO 4DELETE + ELSE IF A = 5 GO 5DELALL + ELSE IF A = 6 GO 6DISPLAY + ELSE DISPLAY "INVALID INPUT" + GO 0001. + STOP RUN. + 1SEARCH. + OPEN INPUT MACC. + ACCEPT B. + 0002. + READ MACC NEXT AT END DISPLAY B "NOT FOUND", GO 000X. + IF B = MNO DISPLAY "FOUND " MNO ":" , + DISPLAY " AT POS:" A " FOR NAME: " MNAME, + GO 000X. + ADD 1 TO A. + GO TO 0002. + 2WRITE. + OPEN I-O MACC. + IF FS = 00 PERFORM RKKEY UNTIL FS = 10 + ELSE OPEN OUTPUT MACC. + DISPLAY RK. + ACCEPT MNO. + ACCEPT MNAME. + WRITE MREC INVALID KEY DISPLAY "DUPLICATE KEY!". + GO 000X. + 3REWRITE. + OPEN I-O MACC. + ACCEPT RK. + ACCEPT MNO. + ACCEPT MNAME. + REWRITE MREC INVALID KEY DISPLAY "NOT FOUND". + GO 000X. + 4DELETE. + OPEN I-O MACC. + ACCEPT RK. + DELETE MACC INVALID KEY DISPLAY "NOT FOUND". + GO 000X. + 5DELALL. + OPEN I-O MACC. + MOVE 01 TO RK. + 0003. + DELETE MACC INVALID KEY GO 000X. + ADD 01 TO RK. + GO 0003. + 6DISPLAY. + OPEN INPUT MACC. + 0005. + READ MACC NEXT INTO IREC AT END GO 000X. + DISPLAY INO, " ", INAME. + GO 0005. + 000X. + CLOSE MACC. + DISPLAY "CONTINUE?1/0". + ACCEPT A. + IF A = 0 STOP RUN ELSE GO 0001. + RKKEY. + READ MACC NEXT. + ADD 1 TO RK. |}] + + + +let doc = {cobol| + CALL STH + NOT ON EXCEPTION + RAISE EXCEPTION exception-name-1 + EXCEPTION + DISPLAY "ERROR" + END-CALL. + |cobol};; + +let%expect_test "formatting-request-on-exception" = + let { projdir; end_with_postproc }, server = make_lsp_project () in + let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in + let params = + let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in + DocumentFormattingParams.create ~options ~textDocument:prog () + in + begin match LSP.Request.formatting server params with + | None -> Pretty.out "formatting error" + | Some l -> + List.iter (fun TextEdit.{newText;_} -> Pretty.out "%s" newText) l + end; + end_with_postproc [%expect.output]; + [%expect{| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Invalid syntax","range":{"end":{"character":11,"line":1},"start":{"character":7,"line":1}},"severity":1},{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + >> Warning: Source format `auto` is not supported yet, using `fixed` + CALL STH + NOT ON EXCEPTION + RAISE EXCEPTION exception-name-1 + EXCEPTION + DISPLAY "ERROR" + END-CALL. |}] + + +let doc = {cobol| + PROCEDURE DIVISION. + para-1. + PERFORM 3 TIMES + PERFORM PARA-2 + END-PERFORM + STOP RUN. + PARA-2. + DISPLAY "HELLO". + |cobol};; + +let%expect_test "formatting-request-perform" = + let { projdir; end_with_postproc }, server = make_lsp_project () in + let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in + let params = + let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in + DocumentFormattingParams.create ~options ~textDocument:prog () + in + begin match LSP.Request.formatting server params with + | None -> Pretty.out "formatting error" + | Some l -> + List.iter (fun TextEdit.{newText;_} -> Pretty.out "%s" newText) l + end; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Invalid syntax","range":{"end":{"character":16,"line":1},"start":{"character":7,"line":1}},"severity":1},{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + >> Warning: Source format `auto` is not supported yet, using `fixed` + PROCEDURE DIVISION. + para-1. + PERFORM 3 TIMES + PERFORM PARA-2 + END-PERFORM + STOP RUN. + PARA-2. + DISPLAY "HELLO". |}] diff --git a/test/lsp/lsp_hover.ml b/test/lsp/lsp_hover.ml new file mode 100644 index 000000000..2bbd96a2f --- /dev/null +++ b/test/lsp/lsp_hover.ml @@ -0,0 +1,142 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2021-2023 OCamlPro SAS *) +(* *) +(* All rights reserved. *) +(* This file is distributed under the terms of the *) +(* OCAMLPRO-NON-COMMERCIAL license. *) +(* *) +(**************************************************************************) + +open Lsp.Types +open Lsp_testing + +let print_hovered server ~projdir (prog, prog_positions) = + let server, prog = add_cobol_doc server ~projdir "prog.cob" prog in + let location_as_srcloc = new srcloc_resuscitator_cache in + let hover_position ?key position = + let params = HoverParams.create ~position ~textDocument:prog () in + Pretty.out "%a(line %d, character %d):@." + Fmt.(option ~none:nop @@ fmt "%s ") key + position.line position.character; + match LSP.Request.hover server params with + | None -> + Pretty.out "Hovering nothing worthy@." + | Some { contents = `List strings; range } -> + location_as_srcloc#print_optional_range_for ~uri:prog.uri range; + List.iter (fun MarkedString.{ value; _ } -> print_endline value) strings + | Some { contents = `MarkedString MarkedString.{ value; _ } | + `MarkupContent MarkupContent.{ value; _ }; range } -> + location_as_srcloc#print_optional_range_for ~uri:prog.uri range; + print_endline value + in + List.iter (fun pos -> hover_position pos) prog_positions.pos_anonymous; + StrMap.iter (fun key pos -> hover_position ~key pos) prog_positions.pos_map + +(* hover copy *) + +let lib = {cobol| + 01 FIELD PIC X. + |cobol};; + +let prog = + extract_position_markers {cobol| + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + DATA DIVISION. + WORKING-STORAGE SECTION. + _|_COP_|_Y "_|_li_|_b.cpy". + PROCEDURE DIVISION. + DISPLAY FI_|_ELD + STOP RUN. + |cobol};; + +let%expect_test "hover-copy" = + let { projdir; end_with_postproc }, server = make_lsp_project () in + let server, _ = add_cobol_doc server ~projdir "lib.cpy" lib in + print_hovered server ~projdir prog; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[],"uri":"file://__rootdir__/lib.cpy"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + (line 5, character 7): + __rootdir__/prog.cob:6.7-6.22: + 3 PROGRAM-ID. prog. + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 > COPY "lib.cpy". + ---- ^^^^^^^^^^^^^^^ + 7 PROCEDURE DIVISION. + 8 DISPLAY FIELD + ```cobol + 01 FIELD PIC X. + ``` + (line 5, character 10): + __rootdir__/prog.cob:6.7-6.22: + 3 PROGRAM-ID. prog. + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 > COPY "lib.cpy". + ---- ^^^^^^^^^^^^^^^ + 7 PROCEDURE DIVISION. + 8 DISPLAY FIELD + ```cobol + 01 FIELD PIC X. + ``` + (line 5, character 13): + __rootdir__/prog.cob:6.7-6.22: + 3 PROGRAM-ID. prog. + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 > COPY "lib.cpy". + ---- ^^^^^^^^^^^^^^^ + 7 PROCEDURE DIVISION. + 8 DISPLAY FIELD + ```cobol + 01 FIELD PIC X. + ``` + (line 5, character 15): + __rootdir__/prog.cob:6.7-6.22: + 3 PROGRAM-ID. prog. + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 > COPY "lib.cpy". + ---- ^^^^^^^^^^^^^^^ + 7 PROCEDURE DIVISION. + 8 DISPLAY FIELD + ```cobol + 01 FIELD PIC X. + ``` + (line 7, character 20): + Hovering nothing worthy |}];; + +(* Hover replaced *) + +let prog = + extract_position_markers {cobol| + REPLACE =="A"== BY =="B" "C"==. + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + PROCEDURE DIVISION. + DISPLAY "_|_A" + STOP RUN. + |cobol};; + +let%expect_test "hover-replaced" = + let { projdir; end_with_postproc }, server = make_lsp_project () in + print_hovered server ~projdir prog; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + (line 5, character 19): + __rootdir__/prog.cob:6.18-6.21: + 3 IDENTIFICATION DIVISION. + 4 PROGRAM-ID. prog. + 5 PROCEDURE DIVISION. + 6 > DISPLAY "A" + ---- ^^^ + 7 STOP RUN. + 8 + ``"B" "C"`` |}];; diff --git a/test/lsp/lsp_references.ml b/test/lsp/lsp_references.ml new file mode 100644 index 000000000..6108951a2 --- /dev/null +++ b/test/lsp/lsp_references.ml @@ -0,0 +1,307 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2021-2023 OCamlPro SAS *) +(* *) +(* All rights reserved. *) +(* This file is distributed under the terms of the *) +(* OCAMLPRO-NON-COMMERCIAL license. *) +(* *) +(**************************************************************************) +open EzCompat (* StringMap *) +open Lsp.Types +open Lsp_testing + + +let print_references ~projdir server (doc, positions) : unit = + let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in + let location_as_srcloc = new srcloc_resuscitator_cache in + Pretty.out "@."; + StringMap.iter begin fun position_name position -> + let params = + (*includeDeclaration*) + let context = ReferenceContext.create ~includeDeclaration:true in + ReferenceParams.create ~position ~textDocument:prog ~context () + in + Pretty.out "%s (line %d, character %d):@." + position_name position.line position.character; + match LSP.Request.lookup_references server params with + | None | Some [] -> + Pretty.out "No reference found@." + | Some locs -> + List.iter location_as_srcloc#print locs + end positions.pos_map +;; + +let doc = + extract_position_markers {cobol| + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 DATA-_|1-data-name-in-def|_NAME PI_|2-data-name-in-def|_C X. + PROCEDURE DIVISION. + DISPLAY _|3-data-name-in-display|_DATA-NAME + DISPLAY _|4-data-name-in-display|_X. + STOP RUN. + |cobol} +;; + + +let%expect_test "simple-references-requests" = + let { end_with_postproc; projdir }, server = make_lsp_project () in + print_references ~projdir server doc; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + src/lsp/cobol_ast/raw_data_sections_visitor.ml:231: + (Cobol_ast__Raw_data_sections_visitor.fold_data_clause): partial visitor + implementation + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + 1-data-name-in-def (line 5, character 16): + __rootdir__/prog.cob:6.11-6.20: + 3 PROGRAM-ID. prog. + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 > 01 DATA-NAME PIC X. + ---- ^^^^^^^^^ + 7 PROCEDURE DIVISION. + 8 DISPLAY DATA-NAME + __rootdir__/prog.cob:8.18-8.27: + 5 WORKING-STORAGE SECTION. + 6 01 DATA-NAME PIC X. + 7 PROCEDURE DIVISION. + 8 > DISPLAY DATA-NAME + ---- ^^^^^^^^^ + 9 DISPLAY X. + 10 STOP RUN. + 2-data-name-in-def (line 5, character 23): + __rootdir__/prog.cob:6.11-6.20: + 3 PROGRAM-ID. prog. + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 > 01 DATA-NAME PIC X. + ---- ^^^^^^^^^ + 7 PROCEDURE DIVISION. + 8 DISPLAY DATA-NAME + __rootdir__/prog.cob:8.18-8.27: + 5 WORKING-STORAGE SECTION. + 6 01 DATA-NAME PIC X. + 7 PROCEDURE DIVISION. + 8 > DISPLAY DATA-NAME + ---- ^^^^^^^^^ + 9 DISPLAY X. + 10 STOP RUN. + 3-data-name-in-display (line 7, character 18): + __rootdir__/prog.cob:6.11-6.20: + 3 PROGRAM-ID. prog. + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 > 01 DATA-NAME PIC X. + ---- ^^^^^^^^^ + 7 PROCEDURE DIVISION. + 8 DISPLAY DATA-NAME + __rootdir__/prog.cob:8.18-8.27: + 5 WORKING-STORAGE SECTION. + 6 01 DATA-NAME PIC X. + 7 PROCEDURE DIVISION. + 8 > DISPLAY DATA-NAME + ---- ^^^^^^^^^ + 9 DISPLAY X. + 10 STOP RUN. + 4-data-name-in-display (line 8, character 18): + No reference found |}] + + +let doc = + extract_position_markers {cobol| + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 X. + 05 Y PIC 9. + 66 Z RENAMES _|1-data-name-renamed|_Y. + PROCEDURE DIVISION. + DISPLAY _|2-data-name-in-display|_Z. + STOP RUN. + |cobol} +;; + +let%expect_test "references-requests-renames" = + let { end_with_postproc; projdir }, server = make_lsp_project () in + print_references ~projdir server doc; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + 1-data-name-renamed (line 7, character 25): + __rootdir__/prog.cob:7.15-7.16: + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 01 X. + 7 > 05 Y PIC 9. + ---- ^ + 8 66 Z RENAMES Y. + 9 PROCEDURE DIVISION. + __rootdir__/prog.cob:8.25-8.26: + 5 WORKING-STORAGE SECTION. + 6 01 X. + 7 05 Y PIC 9. + 8 > 66 Z RENAMES Y. + ---- ^ + 9 PROCEDURE DIVISION. + 10 DISPLAY Z. + 2-data-name-in-display (line 9, character 20): + __rootdir__/prog.cob:8.15-8.16: + 5 WORKING-STORAGE SECTION. + 6 01 X. + 7 05 Y PIC 9. + 8 > 66 Z RENAMES Y. + ---- ^ + 9 PROCEDURE DIVISION. + 10 DISPLAY Z. + __rootdir__/prog.cob:10.20-10.21: + 7 05 Y PIC 9. + 8 66 Z RENAMES Y. + 9 PROCEDURE DIVISION. + 10 > DISPLAY Z. + ---- ^ + 11 STOP RUN. + 12 |}] + + +let doc = + extract_position_markers {cobol| + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 X. + 05 Y. + 10 Z PIC 999999. + 05 FILLER REDEFINES Y. + 10 A PIC 9 OCCURS 6 TIMES. + 05 STH REDEFINES Y. + 10 B PIC 99 OCCURS 3 TIMES. + 05 FILLER REDEFINES Y. + 10 C PIC 999 OCCURS 2 TIMES. + PROCEDURE DIVISION. + DISPLAY _|1-data-name-in-display|_Y. + |cobol} +;; + +let%expect_test "references-requests-redefines" = + let { end_with_postproc; projdir }, server = make_lsp_project () in + print_references ~projdir server doc; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + 1-data-name-in-display (line 15, character 20): + __rootdir__/prog.cob:7.15-7.16: + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 01 X. + 7 > 05 Y. + ---- ^ + 8 10 Z PIC 999999. + 9 05 FILLER REDEFINES Y. + __rootdir__/prog.cob:9.32-9.33: + 6 01 X. + 7 05 Y. + 8 10 Z PIC 999999. + 9 > 05 FILLER REDEFINES Y. + ---- ^ + 10 10 A PIC 9 OCCURS 6 TIMES. + 11 05 STH REDEFINES Y. + __rootdir__/prog.cob:11.29-11.30: + 8 10 Z PIC 999999. + 9 05 FILLER REDEFINES Y. + 10 10 A PIC 9 OCCURS 6 TIMES. + 11 > 05 STH REDEFINES Y. + ---- ^ + 12 10 B PIC 99 OCCURS 3 TIMES. + 13 05 FILLER REDEFINES Y. + __rootdir__/prog.cob:13.32-13.33: + 10 10 A PIC 9 OCCURS 6 TIMES. + 11 05 STH REDEFINES Y. + 12 10 B PIC 99 OCCURS 3 TIMES. + 13 > 05 FILLER REDEFINES Y. + ---- ^ + 14 10 C PIC 999 OCCURS 2 TIMES. + 15 PROCEDURE DIVISION. + __rootdir__/prog.cob:16.20-16.21: + 13 05 FILLER REDEFINES Y. + 14 10 C PIC 999 OCCURS 2 TIMES. + 15 PROCEDURE DIVISION. + 16 > DISPLAY Y. + ---- ^ + 17 |}] + + +let doc = + extract_position_markers {cobol| + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 FILLER. + 05 X PIC 999. + 05 FILLER REDEFINES X. + 10 Z PIC 9 OCCURS 3 TIMES. + 66 Y RENAMES X. + PROCEDURE DIVISION. + DISPLAY _|1-data-name-in-display|_X . + MOVE 1 TO X. + STOP RUN. + |cobol} +;; + +let%expect_test "references-requests-filler" = + let { end_with_postproc; projdir }, server = make_lsp_project () in + print_references ~projdir server doc; + end_with_postproc [%expect.output]; + [%expect {| + {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + {"params":{"diagnostics":[{"message":"Source format `auto` is not supported yet, using `fixed`","range":{"end":{"character":0,"line":0},"start":{"character":0,"line":0}},"severity":2}],"uri":"file://__rootdir__/prog.cob"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} + 1-data-name-in-display (line 11, character 18): + __rootdir__/prog.cob:7.13-7.14: + 4 DATA DIVISION. + 5 WORKING-STORAGE SECTION. + 6 01 FILLER. + 7 > 05 X PIC 999. + ---- ^ + 8 05 FILLER REDEFINES X. + 9 10 Z PIC 9 OCCURS 3 TIMES. + __rootdir__/prog.cob:8.30-8.31: + 5 WORKING-STORAGE SECTION. + 6 01 FILLER. + 7 05 X PIC 999. + 8 > 05 FILLER REDEFINES X. + ---- ^ + 9 10 Z PIC 9 OCCURS 3 TIMES. + 10 66 Y RENAMES X. + __rootdir__/prog.cob:10.23-10.24: + 7 05 X PIC 999. + 8 05 FILLER REDEFINES X. + 9 10 Z PIC 9 OCCURS 3 TIMES. + 10 > 66 Y RENAMES X. + ---- ^ + 11 PROCEDURE DIVISION. + 12 DISPLAY X . + __rootdir__/prog.cob:12.18-12.19: + 9 10 Z PIC 9 OCCURS 3 TIMES. + 10 66 Y RENAMES X. + 11 PROCEDURE DIVISION. + 12 > DISPLAY X . + ---- ^ + 13 MOVE 1 TO X. + 14 STOP RUN. + __rootdir__/prog.cob:13.20-13.21: + 10 66 Y RENAMES X. + 11 PROCEDURE DIVISION. + 12 DISPLAY X . + 13 > MOVE 1 TO X. + ---- ^ + 14 STOP RUN. + 15 |}] diff --git a/test/lsp/lsp_testing.ml b/test/lsp/lsp_testing.ml new file mode 100644 index 000000000..7bd6ee593 --- /dev/null +++ b/test/lsp/lsp_testing.ml @@ -0,0 +1,230 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2021-2023 OCamlPro SAS *) +(* *) +(* All rights reserved. *) +(* This file is distributed under the terms of the *) +(* OCAMLPRO-NON-COMMERCIAL license. *) +(* *) +(**************************************************************************) + +(** This module gathers various utilities that can be used to test the LSP. *) + +(* Note that for now, only a single project directory may be used, and we may + need to clean it up after each test. *) + +open Cobol_common.Srcloc.TYPES + +open Lsp.Types +open Ez_file.V1 +open Ez_file.FileString.OP + +module StrMap = EzCompat.StringMap +module LSP = Cobol_lsp.INTERNAL + +(** {1 Server initialization} *) + +let layout = + LSP.Project.{ + project_config_filename = Superbol_free_lib.Command_lsp.project_config_filename; + } +and cache_config = + LSP.Project_cache.{ + cache_relative_filename = "lsp-cache"; + cache_verbose = false; + } + +let init_temp_project ?(toml = "") () = + let projdir = Superbol_testutils.Tempdir.make_n_enter "superbol-project" in + let toml_file = projdir // layout.project_config_filename in + EzFile.write_file toml_file toml; + projdir + +let make_server () = + LSP.Server.init ~config:{ project_layout = layout; cache_config } + +let add_cobol_doc server ?copybook ~projdir filename text = + let path = projdir // filename in + let uri = Lsp.Uri.of_path path in + EzFile.write_file path text; + let server = + LSP.Server.add ?copybook + DidOpenTextDocumentParams.{ + textDocument = TextDocumentItem.{ + languageId = "cobol"; version = 0; text; uri; + }; + } server + in + print_newline (); + server, TextDocumentIdentifier.create ~uri + +(* let projdir = init_temp_project () *) +(* let projdir_regexp = Str.(regexp @@ quote projdir) *) +(* let projdir_marker = "__rootdir__" *) + +(* let print_postproc jsonrpc = *) +(* EzString.split jsonrpc '\n' |> *) +(* List.filter_map begin function *) +(* | s when String.trim s = "" -> None (\* ignore json RPC header: *\) *) +(* | s when EzString.starts_with ~prefix:"Content-Length: " s -> None *) +(* | s -> Some (Str.global_replace projdir_regexp projdir_marker s) *) +(* end |> *) +(* String.concat "\n" |> *) +(* print_endline *) + +let projdir_marker = "__rootdir__" + +type test_project = + { + projdir: string; + end_with_postproc: string -> unit; + } + +let make_lsp_project ?toml () = + let projdir = init_temp_project ?toml () in + let projdir_regexp = Str.(regexp @@ quote projdir) in + let temp_dir_name = Filename.get_temp_dir_name () in + let end_with_postproc expected_output_string = + (* Remove temporary project directory *) + if EzString.starts_with ~prefix:temp_dir_name projdir + then EzFile.remove_dir ~all:true projdir + else Printf.eprintf "Leaving %s as is (does not look like a temporary \ + directory)" projdir; + (* Filter and print out results *) + EzString.split expected_output_string '\n' |> + List.filter_map begin function + | s when String.trim s = "" -> None (* ignore json RPC header: *) + | s when EzString.starts_with ~prefix:"Content-Length: " s -> None + | s -> Some (Str.global_replace projdir_regexp projdir_marker s) + end |> + String.concat "\n" |> + print_endline + in + (* Force project initialization (so we can flush before the next RPC) *) + ignore @@ LSP.Project.in_existing_dir projdir ~layout; + print_newline (); + { projdir; end_with_postproc }, make_server () + +(** {1 Cursor positions} *) + +(** Structure returned by {!extract_position_markers} below. *) +type positions = + { + pos_anonymous: Position.t list; + pos_map: Position.t StrMap.t; + } + +let position_marker = "_|_\\|_|[0-9a-zA-Z-+]+|_" +let position_or_newline_regexp = Str.(regexp @@ position_marker ^ "\\|\n") + +(** [extract_position_markers text] records and removes any cursor position + marker from [text], and returns the resulting text along with a set of + cursor positions. + + Anonymous markers are denoted {[_|_]}. They are listed in order of + appearance in [text] ([pos_anonymous]). + + Named markers are denoted {[_|some-name|_]}, where {[some-name]} may + comprise alphanumeric and [+] or [-] characters. They are recorded in + [pos_map]. *) +let extract_position_markers text = + let splits = Str.full_split position_or_newline_regexp text in + let acc, _, _, positions = + List.fold_left begin fun (acc, line, char, positions) -> function + | Str.Text t -> + t :: acc, line, char + String.length t, positions + | Str.Delim "\n" -> + "\n" :: acc, succ line, 0, positions + | Str.Delim "_|_" -> + acc, line, char, (line, char, None) :: positions + | Str.Delim d -> + let position_ident = Scanf.sscanf d "_|%s@|_" Fun.id in + acc, line, char, (line, char, Some position_ident) :: positions + end ([], 0, 0, []) splits + in + String.concat "" (List.rev acc), + List.fold_left begin fun acc (line, character, ident) -> + let pos = Lsp.Types.Position.create ~line ~character in + match ident with + | None -> { acc with pos_anonymous = pos :: acc.pos_anonymous } + | Some id -> { acc with pos_map = StrMap.add id pos acc.pos_map } + end { pos_anonymous = []; pos_map = StrMap.empty } positions + +(** {1 Helpers to reconstruct and print source locations} *) + +let srcloc_of_range ~uri : Range.t -> srcloc = + let pos_fname = Lsp.Uri.to_path uri in + let lines = EzFile.read_lines pos_fname in + let char_count = + Array.init (Array.length lines) (fun i -> String.length lines.(i)) in + ignore @@ Array.fold_left begin fun (idx, prev_count) line_length -> + char_count.(idx) <- line_length + prev_count + 1; (* + newline character *) + succ idx, char_count.(idx) + end (0, 0) char_count; + let lexpos_of_position Position.{ line; character } = + let pos_bol = if line = 0 then 0 else char_count.(line - 1) + and pos_lnum = line + 1 in + Lexing.{ pos_fname; pos_bol; pos_lnum; + pos_cnum = pos_bol + character } + in + fun Range.{ start; end_ } -> + let start_pos = lexpos_of_position start + and end_pos = lexpos_of_position end_ in + Cobol_common.Srcloc.raw (start_pos, end_pos) + +module UriCache = Ephemeron.K1.Make (Lsp.Uri) + +(* type srcloc_resuscitator = *) +(* { *) +(* srcloc_of_location: Location.t -> srcloc; *) +(* print_location: Location.t -> unit; *) +(* } *) + +(* let srcloc_resuscitator () = *) +(* let cache: (Range.t -> srcloc) UriCache.t = UriCache.create 1 in *) +(* let for_ ~uri = *) +(* try UriCache.find cache uri *) +(* with Not_found -> *) +(* let f = srcloc_of_range ~uri in *) +(* UriCache.replace cache uri f; *) +(* f *) +(* in *) +(* let srcloc_of_location Location.{ uri; range } = (for_ ~uri) range in *) +(* let print_location loc = *) +(* Pretty.out "%a@." Cobol_common.Srcloc.pp_srcloc (srcloc_of_location loc) *) +(* in *) +(* { *) +(* srcloc_of_location; *) +(* print_location; *) +(* } *) + +(** Helper class that encapsulates a cache so we do not always re-compute line + lengths and absolute character positions. (Looks much cleaner than the + equivalent code that is commented out above) *) +class srcloc_resuscitator_cache = object (self) + val cache: (Range.t -> srcloc) UriCache.t = + UriCache.create 1 + method private for_ ~uri = + try UriCache.find cache uri + with Not_found -> + let f = srcloc_of_range ~uri in + UriCache.replace cache uri f; + f + method of_ ~location:Location.{ uri; range } : srcloc = + (self#for_ ~uri) range + method print location = + Pretty.out "%a@." Cobol_common.Srcloc.pp_srcloc (self#of_ ~location) + method print_range_for ~uri range = + self#print (Location.create ~uri ~range) + method print_optional_range_for ~uri range = + Option.iter (self#print_range_for ~uri) range +end + +(* --- *) + +(* let%expect_test "initialize-server" = *) +(* ignore @@ LSP.Project.in_existing_dir projdir ~layout; *) +(* print_postproc [%expect.output]; *) +(* [%expect {| *) +(* {"params":{"diagnostics":[],"uri":"file://__rootdir__/superbol.toml"},"method":"textDocument/publishDiagnostics","jsonrpc":"2.0"} *) +(* |}];; *) diff --git a/test/lsp/lsp_testing.mli b/test/lsp/lsp_testing.mli new file mode 100644 index 000000000..e4a9d064d --- /dev/null +++ b/test/lsp/lsp_testing.mli @@ -0,0 +1,41 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2021-2023 OCamlPro SAS *) +(* *) +(* All rights reserved. *) +(* This file is distributed under the terms of the *) +(* OCAMLPRO-NON-COMMERCIAL license. *) +(* *) +(**************************************************************************) + +module StrMap = EzCompat.StringMap +module LSP = Cobol_lsp.INTERNAL + +type test_project = + { + projdir: string; + end_with_postproc: string -> unit; + } + +val make_lsp_project + : ?toml:string + -> unit + -> test_project * LSP.Types.registry +val add_cobol_doc + : LSP.Types.registry -> ?copybook:bool -> projdir:string -> string -> string + -> LSP.Types.registry * Lsp.Types.TextDocumentIdentifier.t + +type positions = + { + pos_anonymous: Lsp.Types.Position.t list; + pos_map: Lsp.Types.Position.t EzCompat.StringMap.t; + } + +val extract_position_markers: string -> string * positions + +class srcloc_resuscitator_cache: object + method of_: location:Lsp.Types.Location.t -> Cobol_common.Srcloc.srcloc + method print: Lsp.Types.Location.t -> unit + method print_range_for: uri:Lsp.Uri.t -> Lsp.Types.Range.t -> unit + method print_optional_range_for: uri:Lsp.Uri.t -> Lsp.Types.Range.t option -> unit +end