Compare commits
8 commits
master
...
clojure-te
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae81b509db | ||
|
|
a671ed4e38 | ||
|
|
23aa68346c | ||
|
|
77fc49d1fd | ||
|
|
9667dbf47b | ||
|
|
d9c9b00c90 | ||
|
|
107fc028f2 | ||
|
|
ddc69f6613 |
51 changed files with 1594 additions and 2313 deletions
|
|
@ -5,7 +5,7 @@
|
|||
[clojure.string :as str]
|
||||
[flatland.ordered.map :refer [ordered-map]]))
|
||||
|
||||
(def graalvm-version "24")
|
||||
(def graalvm-version "23")
|
||||
|
||||
(defn run
|
||||
([cmd-name cmd]
|
||||
|
|
@ -101,6 +101,7 @@
|
|||
"export BABASHKA_FEATURE_JDBC=true
|
||||
export BABASHKA_FEATURE_POSTGRESQL=true
|
||||
script/test\nscript/run_lib_tests")
|
||||
(run "Run as lein command" ".circleci/script/lein")
|
||||
(run
|
||||
"Create uberjar"
|
||||
"mkdir -p /tmp/release
|
||||
|
|
@ -179,13 +180,10 @@ java -jar \"$jar\" --config .build/bb.edn --deps-root . release-artifact \"$refl
|
|||
(run "Build binary" (if (= "aarch64" arch)
|
||||
"script/uberjar\nscript/compile -H:PageSize=64K # --pgo=default.iprof"
|
||||
"script/uberjar\nscript/compile # --pgo=default.iprof") "30m")
|
||||
(run "Run tests" "script/test\nscript/run_lib_tests")
|
||||
(run "Release" ".circleci/script/release")
|
||||
{:persist_to_workspace {:root "/tmp"
|
||||
:paths ["release"]}}
|
||||
(run "Run tests" "script/test\nscript/run_lib_tests")
|
||||
(run "Release + publish"
|
||||
(str/join "\n" ["export BABASHKA_RELEASE=true"
|
||||
".circleci/script/release"]))
|
||||
{:save_cache
|
||||
{:paths ["~/.m2" "~/graalvm"]
|
||||
:key cache-key}}
|
||||
|
|
|
|||
|
|
@ -29,9 +29,7 @@ tar zcvf "$archive" bb # bbk
|
|||
|
||||
cd -
|
||||
|
||||
if [ "$BABASHKA_RELEASE" = "true" ]; then
|
||||
./bb --config .build/bb.edn --deps-root . release-artifact "/tmp/release/$archive"
|
||||
fi
|
||||
./bb --config .build/bb.edn --deps-root . release-artifact "/tmp/release/$archive"
|
||||
|
||||
## cleanup
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ task:
|
|||
skip: "changesIncludeOnly('logo/*', '**.md')"
|
||||
env:
|
||||
LEIN_ROOT: "true"
|
||||
GRAALVM_VERSION: "24"
|
||||
GRAALVM_VERSION: "23"
|
||||
GRAALVM_HOME: ${HOME}/graalvm-${GRAALVM_VERSION}/Contents/Home
|
||||
BABASHKA_PLATFORM: macos # used in release script
|
||||
BABASHKA_ARCH: aarch64
|
||||
|
|
|
|||
99
.github/workflows/build-windows.yml
vendored
99
.github/workflows/build-windows.yml
vendored
|
|
@ -1,99 +0,0 @@
|
|||
name: build
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- "logo/**"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- "logo/**"
|
||||
|
||||
# TODO: Add deploy if needed
|
||||
jobs:
|
||||
native:
|
||||
if: "!contains(github.event.head_commit.message, 'skip ci')"
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-2022
|
||||
name: windows
|
||||
static: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
LEIN_ROOT: "true"
|
||||
GRAALVM_VERSION: "24"
|
||||
BABASHKA_PLATFORM: ${{ matrix.name }} # used in release script
|
||||
BABASHKA_TEST_ENV: native
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BABASHKA_SHA: ${{ github.sha }}
|
||||
steps:
|
||||
- name: Git checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
submodules: 'true'
|
||||
|
||||
- name: Cache deps
|
||||
uses: actions/cache@v4
|
||||
id: cache-deps
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('project.clj') }}
|
||||
restore-keys: ${{ runner.os }}-maven-
|
||||
|
||||
- name: Setup GraalVM
|
||||
if: "matrix.static == false"
|
||||
uses: graalvm/setup-graalvm@v1.3.3
|
||||
with:
|
||||
java-version: '24'
|
||||
distribution: 'graalvm'
|
||||
components: 'native-image'
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install clojure tools
|
||||
uses: DeLaGuardo/setup-clojure@13.2
|
||||
with:
|
||||
cli: latest
|
||||
# lein: latest -- skipped because this uses some PS bullshit
|
||||
|
||||
- name: Babashka version
|
||||
id: babashka-version
|
||||
shell: bash
|
||||
run: |
|
||||
BABASHKA_VERSION=$(cat resources/BABASHKA_VERSION)
|
||||
echo "##[set-output name=version;]${BABASHKA_VERSION}"
|
||||
|
||||
- name: Build
|
||||
shell: cmd
|
||||
run: |
|
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein.bat', 'lein.bat')"
|
||||
call lein self-install
|
||||
|
||||
set GRAALVM_HOME=%JAVA_HOME%
|
||||
call script/uberjar.bat
|
||||
|
||||
call script/compile.bat
|
||||
|
||||
echo Creating zip archive
|
||||
|
||||
set zip=babashka-%BABASHKA_VERSION%-windows-amd64.zip
|
||||
|
||||
jar -cMf %zip% bb.exe
|
||||
|
||||
bb --config .build/bb.edn --deps-root . release-artifact %zip%
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: bb.exe
|
||||
name: babashka-${{ steps.babashka-version.outputs.version }}-${{ matrix.name }}-amd64
|
||||
|
||||
- name: Test binary and libs
|
||||
shell: cmd
|
||||
run: |
|
||||
set BABASHKA_CLASSPATH=
|
||||
set BABASHKA_TEST_ENV=native
|
||||
call script/test.bat :windows
|
||||
call script/run_lib_tests.bat
|
||||
31
.github/workflows/build.yml
vendored
31
.github/workflows/build.yml
vendored
|
|
@ -33,7 +33,7 @@ jobs:
|
|||
submodules: 'true'
|
||||
|
||||
- name: Cache deps
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v2
|
||||
id: cache-deps
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
|
|
@ -60,6 +60,9 @@ jobs:
|
|||
script/test
|
||||
script/run_lib_tests
|
||||
|
||||
- name: Run as lein command
|
||||
run: echo '{:a 1}' | lein bb '(:a *in*)'
|
||||
|
||||
- name: Build uberjar
|
||||
run: |
|
||||
mkdir -p /tmp/release
|
||||
|
|
@ -88,7 +91,7 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: macos-13
|
||||
- os: macos-12
|
||||
name: macos
|
||||
static: false
|
||||
#- os: ubuntu-latest
|
||||
|
|
@ -100,7 +103,7 @@ jobs:
|
|||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
LEIN_ROOT: "true"
|
||||
GRAALVM_VERSION: "24"
|
||||
GRAALVM_VERSION: "23"
|
||||
BABASHKA_PLATFORM: ${{ matrix.name }} # used in release script
|
||||
BABASHKA_TEST_ENV: native
|
||||
BABASHKA_XMX: "-J-Xmx6500m"
|
||||
|
|
@ -114,7 +117,7 @@ jobs:
|
|||
submodules: 'true'
|
||||
|
||||
- name: Cache deps
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v2
|
||||
id: cache-deps
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
|
|
@ -125,7 +128,7 @@ jobs:
|
|||
if: "matrix.static == false"
|
||||
uses: graalvm/setup-graalvm@v1
|
||||
with:
|
||||
java-version: '24'
|
||||
java-version: '23'
|
||||
distribution: 'graalvm'
|
||||
components: 'native-image'
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
@ -134,7 +137,7 @@ jobs:
|
|||
if: "matrix.static == true"
|
||||
uses: graalvm/setup-graalvm@v1
|
||||
with:
|
||||
version: '24'
|
||||
version: '23'
|
||||
distribution: 'graalvm'
|
||||
components: 'native-image'
|
||||
native-image-musl: true
|
||||
|
|
@ -172,6 +175,14 @@ jobs:
|
|||
BABASHKA_MUSL: "true"
|
||||
run: script/compile
|
||||
|
||||
- name: Test binary and libs
|
||||
run: |
|
||||
script/test
|
||||
script/run_lib_tests
|
||||
|
||||
- name: Release
|
||||
run: .circleci/script/release
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
|
@ -185,14 +196,6 @@ jobs:
|
|||
path: bb
|
||||
name: babashka-${{ steps.babashka-version.outputs.version }}-${{ matrix.name }}-static-amd64
|
||||
|
||||
- name: Test binary and libs
|
||||
run: |
|
||||
script/test
|
||||
script/run_lib_tests
|
||||
|
||||
- name: Release
|
||||
run: .circleci/script/release
|
||||
|
||||
docker:
|
||||
if: ${{ false }} # Disabled
|
||||
# if: "!contains(github.event.head_commit.message, 'skip ci') && github.event_name == 'push' && github.ref == 'refs/heads/master'"
|
||||
|
|
|
|||
84
CHANGELOG.md
84
CHANGELOG.md
|
|
@ -9,89 +9,9 @@ A preview of the next release can be installed from
|
|||
|
||||
## Unreleased
|
||||
|
||||
- [#1818](https://github.com/babashka/babashka/issues/1818): wrong argument order in `clojure.java.io/resource` implementation
|
||||
- Add `java.text.BreakIterator`
|
||||
- Bump `fs` to `0.5.25`
|
||||
- Bump `jsoup` to `1.20.1`
|
||||
- Bump `edamame` to `1.4.30`
|
||||
- [#1815](https://github.com/babashka/babashka/issues/1815): Make install-script wget-compatible ([@eval](https://github.com/eval))
|
||||
|
||||
|
||||
## 1.12.200 (2025-04-26)
|
||||
|
||||
- Improve Java reflection based on provided type hints (read blog post [here](https://blog.michielborkent.nl/babashka-java-reflection-type-hints.html))
|
||||
- Add compatibility with the [fusebox](https://github.com/potetm/fusebox) library
|
||||
- Fix virtual `ThreadBuilder` interop
|
||||
- Add `java.util.concurrent.ThreadLocalRandom`
|
||||
- Add `java.util.concurrent.locks.ReentrantLock`
|
||||
- Add classes:
|
||||
- `java.time.chrono.ChronoLocalDate`
|
||||
- `java.time.temporal.TemporalUnit`
|
||||
- `java.time.chrono.ChronoLocalDateTime`
|
||||
- `java.time.chrono.ChronoZonedDateTime`
|
||||
- `java.time.chrono.Chronology`
|
||||
|
||||
## 1.12.199 (2025-04-18)
|
||||
|
||||
- [#1806](https://github.com/babashka/babashka/issues/1806): Add `cheshire.factory` namespace ([@lread](https://github.com/lread))
|
||||
|
||||
## 1.12.198 (2025-04-17)
|
||||
|
||||
- Bump GraalVM to `24`
|
||||
- Bump SCI to `0.9.45`
|
||||
- Bump edamame to `1.4.28`
|
||||
- [#1801](https://github.com/babashka/babashka/issues/1801): Add `java.util.regex.PatternSyntaxException`
|
||||
- Bump core.async to `1.8.735`
|
||||
- Bump cheshire to `6.0.0`
|
||||
- Bump babashka.cli to `0.8.65`
|
||||
|
||||
## 1.12.197 (2025-02-28)
|
||||
|
||||
- [#1785](https://github.com/babashka/babashka/issues/1785): Allow subclasses of `Throwable` to have instance methods invoked ([@bobisageek](https://github.com/bobisageek))
|
||||
- [#1791](https://github.com/babashka/babashka/issues/1791): interop problem on Jsoup form element
|
||||
- [#1793](https://github.com/babashka/babashka/issues/1793): Bump `rewrite-clj` to `1.1.49` (fixes parsing of `foo//` among other things)
|
||||
- Bump `deps.clj`
|
||||
- Bump `fs`
|
||||
|
||||
## 1.12.196 (2024-12-24)
|
||||
|
||||
- [#1771](https://github.com/babashka/babashka/issues/1771): `*e*` in REPL should contain exception thrown by user, not a wrapped one
|
||||
- [#1777](https://github.com/babashka/babashka/issues/1777) Add `java.nio.file.attribute.UserDefinedFileAttributeView`
|
||||
- [#1776](https://github.com/babashka/babashka/issues/1776) `Add java.nio.file.attribute.PosixFileAttributes`
|
||||
- [#1761](https://github.com/babashka/babashka/issues/1761) Support calling `clojure.lang.RT/iter`
|
||||
- [#1760](https://github.com/babashka/babashka/issues/1760) For compatibility with [Fireworks v0.10.3](https://github.com/paintparty/fireworks), added the following to `:instance-checks` entry in `babashka.impl.classes/classes`([@paintparty](https://github.com/paintparty))
|
||||
- `clojure.lang.PersistentArrayMap$TransientArrayMap`
|
||||
- `clojure.lang.PersistentHashMap$TransientHashMap`
|
||||
- `clojure.lang.PersistentVector$TransientVector`
|
||||
- `java.lang.NoSuchFieldException`
|
||||
- `java.util.AbstractMap`
|
||||
- `java.util.AbstractSet`
|
||||
- `java.util.AbstractList`
|
||||
- [#1760](https://github.com/babashka/babashka/issues/1760) For compatibility with [Fireworks v0.10.3](https://github.com/paintparty/fireworks), added `volatile?` entry to `babashka.impl.clojure.core/core-extras`([@paintparty](https://github.com/paintparty))
|
||||
- Bump `babashka.cli` to `0.8.61`
|
||||
- Bump `clj-yaml` to `1.0.29`
|
||||
- [#1768](https://github.com/babashka/babashka/issues/1768): Add `taoensso.timbre` `color-str` function
|
||||
- Add classes:
|
||||
- `javax.crypto.KeyAgreement`
|
||||
- `java.security.KeyPairGenerator`
|
||||
- `java.security.KeyPair`
|
||||
- `java.security.spec.ECGenParameterSpec`
|
||||
- `java.security.spec.PKCS8EncodedKeySpec`
|
||||
- `java.security.spec.X509EncodedKeySpec`
|
||||
- `java.security.Signature`
|
||||
- Add `java.util.concurrent.CompletionStage`
|
||||
- Bump `core.async` to `1.7.701`
|
||||
- Bump `org.babashka/cli` to `0.8.162`
|
||||
|
||||
## 1.12.195 (2024-11-12)
|
||||
|
||||
- Include [jsoup](https://jsoup.org/) for HTML parsing. This makes bb compatible with the [hickory](https://github.com/clj-commons/hickory) library (and possibly other libraries?).
|
||||
- [#1752](https://github.com/babashka/babashka/issues/1752): include `java.lang.SecurityException` for `java.net.http.HttpClient` support ([@grzm](https://github.com/grzm))
|
||||
- [#1752](https://github.com/babashka/babashka/issues/1752): include `java.lang.SecurityException` for `java.net.http.HttpClient` support
|
||||
- [#1748](https://github.com/babashka/babashka/issues/1748): add `clojure.core/ensure`
|
||||
- Upgrade `taoensso/timbre`to `v6.6.0`
|
||||
- Upgrade `babashka.http-client` to `v0.4.22`
|
||||
- Add `:git/sha` from build to `bb describe` output ([@lispyclouds](https://github.com/lispyclouds))
|
||||
- Fix NPE with determining if executing from self-contained executable
|
||||
- Upgrade to `taoensso/timbre` `v6.6.0`
|
||||
|
||||
## 1.12.194 (2024-10-12)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ RUN apt update
|
|||
RUN apt install --no-install-recommends -yy build-essential zlib1g-dev
|
||||
WORKDIR "/opt"
|
||||
|
||||
ENV GRAALVM_VERSION="24"
|
||||
ENV GRAALVM_VERSION="23"
|
||||
ARG TARGETARCH
|
||||
# Do not set those directly, use TARGETARCH instead
|
||||
ENV BABASHKA_ARCH=
|
||||
|
|
|
|||
61
README.md
61
README.md
|
|
@ -4,7 +4,7 @@
|
|||
[](https://app.slack.com/client/T03RZGPFR/CLX41ASCS)
|
||||
[](https://opencollective.com/babashka) [](https://clojars.org/babashka/babashka)
|
||||
[](https://twitter.com/search?q=%23babashka&src=typed_query&f=live)
|
||||
[](https://book.babashka.org) [](https://gurubase.io/g/babashka)
|
||||
[](https://book.babashka.org)
|
||||
|
||||
<blockquote class="twitter-tweet" data-lang="en">
|
||||
<p lang="en" dir="ltr">Life's too short to remember how to write Bash code. I feel liberated.</p>
|
||||
|
|
@ -232,8 +232,6 @@ Install via the installer script for linux and macOS:
|
|||
|
||||
``` shell
|
||||
$ curl -sLO https://raw.githubusercontent.com/babashka/babashka/master/install
|
||||
# or
|
||||
$ wget -qO install https://raw.githubusercontent.com/babashka/babashka/master/install
|
||||
$ chmod +x install
|
||||
$ ./install
|
||||
```
|
||||
|
|
@ -305,16 +303,63 @@ Go [here](https://book.babashka.org/#built-in-namespaces) to see the full list o
|
|||
A list of projects (scripts, libraries, pods and tools) known to work with babashka.
|
||||
|
||||
## Badges
|
||||
<!-- note to editor: it seems a blank line must appear before code blocks within <details> -->
|
||||
|
||||
[](https://babashka.org)
|
||||
|
||||
The babashka compatible badge indicates that a [library can be used as babashka dependency](doc/projects.md).
|
||||
|
||||
[](https://book.babashka.org#badges)
|
||||
The babashka compatible badge indicates that a library can be used as babashka dependency.
|
||||
If this is the case for your library, we encourage you to proudly display this badge.
|
||||
|
||||
[](https://book.babashka.org#badges)
|
||||
The babashka built-in badge means that a library has been built directly into babashka and requires no extra dependencies to use it.
|
||||
<details><summary>Markdown</summary>
|
||||
|
||||
```markdown
|
||||
[](https://babashka.org)
|
||||
```
|
||||
</details>
|
||||
|
||||
<details><summary>AsciiDoc</summary>
|
||||
|
||||
```asciidoc
|
||||
https://babashka.org[image:https://raw.githubusercontent.com/babashka/babashka/master/logo/badge.svg[bb compatible]]
|
||||
```
|
||||
</details>
|
||||
|
||||
<details><summary>HTML</summary>
|
||||
|
||||
```html
|
||||
<a href="https://babashka.org" rel="nofollow"><img src="https://github.com/babashka/babashka/raw/master/logo/badge.svg" alt="bb compatible" style="max-width: 100%;"></a>
|
||||
```
|
||||
</details>
|
||||
<br/>
|
||||
|
||||
[](https://babashka.org)
|
||||
|
||||
The babashka built-in badge means that a [library has been built directly into babashka](https://book.babashka.org/#built-in-namespaces) and requires no extra dependencies to use it.
|
||||
|
||||
If this rare honor belongs to your library, you should display this badge.
|
||||
|
||||
See [the babashka book for details](https://book.babashka.org#badges).
|
||||
<details><summary>Markdown</summary>
|
||||
|
||||
```markdown
|
||||
[](https://babashka.org)
|
||||
```
|
||||
</details>
|
||||
|
||||
<details><summary>AsciiDoc</summary>
|
||||
|
||||
```asciidoc
|
||||
https://babashka.org[image:https://raw.githubusercontent.com/babashka/babashka/master/logo/built-in-badge.svg[bb built-in]]
|
||||
```
|
||||
</details>
|
||||
|
||||
<details><summary>HTML</summary>
|
||||
|
||||
```html
|
||||
<a href="https://babashka.org" rel="nofollow"><img src="https://github.com/babashka/babashka/raw/master/logo/built-in-badge.svg" alt="bb built-in" style="max-width: 100%;"></a>
|
||||
```
|
||||
</details>
|
||||
</br>
|
||||
|
||||
## Swag
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ image: Visual Studio 2022
|
|||
clone_folder: C:\projects\babashka
|
||||
|
||||
environment:
|
||||
GRAALVM_HOME: C:\projects\babashka\graalvm\graalvm-jdk-24+36.1
|
||||
JAVA_HOME: C:\projects\babashka\graalvm\graalvm-jdk-24+36.1
|
||||
GRAALVM_HOME: C:\projects\babashka\graalvm\graalvm-jdk-23+37.1
|
||||
JAVA_HOME: C:\projects\babashka\graalvm\graalvm-jdk-23+37.1
|
||||
BABASHKA_XMX: "-J-Xmx5g"
|
||||
|
||||
skip_commits:
|
||||
|
|
@ -44,7 +44,7 @@ clone_script:
|
|||
build_script:
|
||||
# TODO: Extract the zip by removing the top level folder to remove the hardcoded path for GRAALVM_HOME
|
||||
- cmd: >-
|
||||
powershell -Command "if (Test-Path('graalvm')) { return } else { (New-Object Net.WebClient).DownloadFile('https://download.oracle.com/graalvm/24/archive/graalvm-jdk-24_windows-x64_bin.zip', 'graalvm.zip') }"
|
||||
powershell -Command "if (Test-Path('graalvm')) { return } else { (New-Object Net.WebClient).DownloadFile('https://download.oracle.com/graalvm/23/archive/graalvm-jdk-23_windows-x64_bin.zip', 'graalvm.zip') }"
|
||||
|
||||
powershell -Command "if (Test-Path('graalvm')) { return } else { Expand-Archive graalvm.zip graalvm }"
|
||||
|
||||
|
|
|
|||
2
deps.clj
2
deps.clj
|
|
@ -1 +1 @@
|
|||
Subproject commit 976cf7b0e54901ada3f7e83f12a4c0aed039adc9
|
||||
Subproject commit 4fd62578e215b7341dd6c818259e47c461949573
|
||||
24
deps.edn
24
deps.edn
|
|
@ -25,12 +25,13 @@
|
|||
babashka/babashka.curl {:local/root "babashka.curl"}
|
||||
babashka/fs {:local/root "fs"}
|
||||
babashka/babashka.core {:local/root "babashka.core"}
|
||||
org.clojure/core.async {:mvn/version "1.8.741"},
|
||||
borkdude/graal.locking {:mvn/version "0.0.2"},
|
||||
org.clojure/core.async {:mvn/version "1.6.673"},
|
||||
org.clojure/tools.cli {:mvn/version "1.0.214"},
|
||||
org.clojure/data.csv {:mvn/version "1.0.0"},
|
||||
cheshire/cheshire {:mvn/version "6.0.0"}
|
||||
cheshire/cheshire {:mvn/version "5.13.0"}
|
||||
org.clojure/data.xml {:mvn/version "0.2.0-alpha8"}
|
||||
clj-commons/clj-yaml {:mvn/version "1.0.29"}
|
||||
clj-commons/clj-yaml {:mvn/version "1.0.28"}
|
||||
com.cognitect/transit-clj {:mvn/version "1.0.333"}
|
||||
org.clojure/test.check {:mvn/version "1.1.1"}
|
||||
nrepl/bencode {:mvn/version "1.2.0"}
|
||||
|
|
@ -42,17 +43,16 @@
|
|||
babashka/clojure-lanterna {:mvn/version "0.9.8-SNAPSHOT"}
|
||||
org.clojure/core.match {:mvn/version "1.0.0"}
|
||||
hiccup/hiccup {:mvn/version "2.0.0-RC1"}
|
||||
rewrite-clj/rewrite-clj {:mvn/version "1.1.49"}
|
||||
rewrite-clj/rewrite-clj {:mvn/version "1.1.48"}
|
||||
selmer/selmer {:mvn/version "1.12.59"}
|
||||
com.taoensso/timbre {:mvn/version "6.6.0"}
|
||||
org.clojure/tools.logging {:mvn/version "1.1.0"}
|
||||
org.clojure/data.priority-map {:mvn/version "1.1.0"}
|
||||
insn/insn {:mvn/version "0.5.2"}
|
||||
org.clojure/core.rrb-vector {:mvn/version "0.1.2"}
|
||||
org.babashka/cli {:mvn/version "0.8.65"}
|
||||
org.babashka/http-client {:mvn/version "0.4.22"}
|
||||
org.flatland/ordered {:mvn/version "1.15.12"}
|
||||
org.jsoup/jsoup {:mvn/version "1.20.1"}}
|
||||
org.babashka/cli {:mvn/version "0.8.59"}
|
||||
org.babashka/http-client {:mvn/version "0.4.21"}
|
||||
org.flatland/ordered {:mvn/version "1.15.12"}}
|
||||
:aliases {:babashka/dev
|
||||
{:main-opts ["-m" "babashka.main"]}
|
||||
:profile
|
||||
|
|
@ -172,13 +172,7 @@
|
|||
:git/sha "550dbc150a79c6ecc148d8a7e260e10bc36321c6"
|
||||
:deps/manifest :deps}
|
||||
prismatic/plumbing {:git/url "https://github.com/plumatic/plumbing",
|
||||
:git/sha "424bc704f2db422de34269c139a5494314b3a43b"}
|
||||
org.clj-commons/hickory {:git/url "https://github.com/clj-commons/hickory"
|
||||
:git/sha "9385b6708ef35f161732d8464b3a3aa57dd79f30"}
|
||||
com.potetm/fusebox {:git/url "https://github.com/potetm/fusebox"
|
||||
:git/sha "ac6d6a0a69510b009b3c1bb2247cd110fd9f7246"}
|
||||
net.sekao/odoyle-rules {:git/url "https://github.com/oakes/odoyle-rules"
|
||||
:git/sha "0b1d825ec45a998c4d3481dfb292e08ce6a47f0b"}}
|
||||
:git/sha "424bc704f2db422de34269c139a5494314b3a43b"}}
|
||||
:classpath-overrides {org.clojure/clojure nil
|
||||
org.clojure/spec.alpha nil}}
|
||||
:clj-nvd
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
## Prerequisites
|
||||
|
||||
- Install [lein](https://leiningen.org/) for producing uberjars
|
||||
- Download [GraalVM](https://www.graalvm.org/downloads/). Currently we use *Oracle GraalVM 24*.
|
||||
- Download [GraalVM](https://www.graalvm.org/downloads/). Currently we use *Oracle GraalVM 23*.
|
||||
- For Windows, installing Visual Studio 2019 with the "Desktop development
|
||||
with C++" workload is recommended.
|
||||
- Set `$GRAALVM_HOME` to the GraalVM distribution directory. On macOS this can look like:
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ reasons:
|
|||
|
||||
## Requirements
|
||||
|
||||
You need [lein](https://leiningen.org/) for running JVM tests and/or producing uberjars. For building binaries you need GraalVM. Currently we use Oracle GraalVM 24.
|
||||
You need [lein](https://leiningen.org/) for running JVM tests and/or producing uberjars. For building binaries you need GraalVM. Currently we use Oracle GraalVM 23.
|
||||
|
||||
## Clone repository
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ borkdude/missing.test.assertions,https://github.com/borkdude/missing.test.assert
|
|||
borkdude/rewrite-edn,https://github.com/borkdude/rewrite-edn
|
||||
camel-snake-kebab/camel-snake-kebab,https://github.com/clj-commons/camel-snake-kebab
|
||||
cc.qbits/auspex,https://github.com/mpenet/auspex
|
||||
cheshire/cheshire,https://github.com/dakrone/cheshire
|
||||
circleci/bond,https://github.com/circleci/bond
|
||||
cli-matic/cli-matic,https://github.com/l3nz/cli-matic.git
|
||||
clj-commons/clj-yaml,https://github.com/clj-commons/clj-yaml
|
||||
|
|
|
|||
|
|
|
@ -143,8 +143,7 @@
|
|||
'info 'infof 'warn 'warnf
|
||||
'error 'errorf
|
||||
'-log! 'with-level
|
||||
'spit-appender '-spy 'spy
|
||||
'color-str])
|
||||
'spit-appender '-spy 'spy])
|
||||
'log! (sci/copy-var log! tns)
|
||||
'*config* config
|
||||
'swap-config! (sci/copy-var swap-config! tns)
|
||||
|
|
|
|||
2
fs
2
fs
|
|
@ -1 +1 @@
|
|||
Subproject commit fdd5780bc4df4931332b56082c6c3a5c3c85066d
|
||||
Subproject commit 99d6a3b2f55b851a6949ed6eee31412b299dcf01
|
||||
36
install
36
install
|
|
@ -29,32 +29,6 @@ print_help() {
|
|||
exit 1
|
||||
}
|
||||
|
||||
has() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
fetch() {
|
||||
local url=$1
|
||||
local outfile=${2:-}
|
||||
|
||||
if has wget; then
|
||||
if [[ -n $outfile ]]; then
|
||||
wget -qO "$outfile" "$url"
|
||||
else
|
||||
wget -qO - "$url"
|
||||
fi
|
||||
elif has curl; then
|
||||
if [[ -n $outfile ]]; then
|
||||
curl -fsSL "$url" -o "$outfile"
|
||||
else
|
||||
curl -fsSL "$url"
|
||||
fi
|
||||
else
|
||||
>&2 echo "Either 'wget' or 'curl' needs to be on PATH!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
key="$1"
|
||||
|
|
@ -106,9 +80,9 @@ fi
|
|||
|
||||
if [[ "$version" == "" ]]; then
|
||||
if [[ "$dev_build" == "true" ]]; then
|
||||
version="$(fetch https://raw.githubusercontent.com/babashka/babashka/master/resources/BABASHKA_VERSION)"
|
||||
version="$(curl -sL https://raw.githubusercontent.com/babashka/babashka/master/resources/BABASHKA_VERSION)"
|
||||
else
|
||||
version="$(fetch https://raw.githubusercontent.com/babashka/babashka/master/resources/BABASHKA_RELEASED_VERSION)"
|
||||
version="$(curl -sL https://raw.githubusercontent.com/babashka/babashka/master/resources/BABASHKA_RELEASED_VERSION)"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
@ -170,9 +144,9 @@ download_url="https://github.com/babashka/$repo/releases/download/v$version/$fil
|
|||
|
||||
# macOS only have shasum available by default
|
||||
# Some Linux distros (RHEL-like) only have sha256sum available by default (others have both)
|
||||
if has sha256sum; then
|
||||
if command -v sha256sum >/dev/null; then
|
||||
sha256sum_cmd="sha256sum"
|
||||
elif has shasum; then
|
||||
elif command -v shasum >/dev/null; then
|
||||
sha256sum_cmd="shasum -a 256"
|
||||
else
|
||||
>&2 echo "Either 'sha256sum' or 'shasum' needs to be on PATH for '--checksum' flag!"
|
||||
|
|
@ -185,7 +159,7 @@ mkdir -p "$download_dir" && (
|
|||
cd "$download_dir"
|
||||
echo -e "Downloading $download_url to $download_dir"
|
||||
|
||||
fetch "$download_url" "$filename"
|
||||
curl -o "$filename" -sL "$download_url"
|
||||
if [[ -n "$checksum" ]]; then
|
||||
if ! echo "$checksum *$filename" | $sha256sum_cmd --check --status; then
|
||||
>&2 echo "Failed checksum on $filename"
|
||||
|
|
|
|||
2
process
2
process
|
|
@ -1 +1 @@
|
|||
Subproject commit 2058c79fb63f80ca71917432eddea73e0c58717c
|
||||
Subproject commit 5160f98666363afeeea9f728d12e7f0fd39263cd
|
||||
19
project.clj
19
project.clj
|
|
@ -22,28 +22,27 @@
|
|||
:flaky :flaky}
|
||||
:jvm-opts ["--enable-preview"]
|
||||
:dependencies [[org.clojure/clojure "1.12.0"]
|
||||
[borkdude/edamame "1.4.30"]
|
||||
[borkdude/edamame "1.4.27"]
|
||||
[borkdude/graal.locking "0.0.2"]
|
||||
[org.clojure/tools.cli "1.0.214"]
|
||||
[cheshire "6.0.0"]
|
||||
[cheshire "5.13.0"]
|
||||
[nrepl/bencode "1.2.0"]
|
||||
[borkdude/sci.impl.reflector "0.0.4"]
|
||||
[borkdude/sci.impl.reflector "0.0.3"]
|
||||
[org.babashka/sci.impl.types "0.0.2"]
|
||||
[org.babashka/babashka.impl.java "0.1.10"]
|
||||
[org.clojure/core.async "1.8.741"]
|
||||
[org.clojure/core.async "1.6.673"]
|
||||
[org.clojure/test.check "1.1.1"]
|
||||
[com.github.clj-easy/graal-build-time "0.1.0"]
|
||||
[rewrite-clj/rewrite-clj "1.1.49"]
|
||||
[rewrite-clj/rewrite-clj "1.1.48"]
|
||||
[insn/insn "0.5.2"]
|
||||
[org.babashka/cli "0.8.65"]
|
||||
[org.babashka/http-client "0.4.22"]
|
||||
[org.jsoup/jsoup "1.20.1"]
|
||||
[borkdude/graal.locking "0.0.2"]]
|
||||
[org.babashka/cli "0.8.59"]
|
||||
[org.babashka/http-client "0.4.21"]]
|
||||
:plugins [[org.kipz/lein-meta-bom "0.1.1"]]
|
||||
:metabom {:jar-name "metabom.jar"}
|
||||
:profiles {:feature/xml {:source-paths ["feature-xml"]
|
||||
:dependencies [[org.clojure/data.xml "0.2.0-alpha8"]]}
|
||||
:feature/yaml {:source-paths ["feature-yaml"]
|
||||
:dependencies [[clj-commons/clj-yaml "1.0.29"
|
||||
:dependencies [[clj-commons/clj-yaml "1.0.28"
|
||||
:exclusions [org.flatland/ordered]#_#_clj-commons/clj-yaml "0.7.110"]
|
||||
[org.flatland/ordered "1.15.12"]]}
|
||||
:feature/jdbc {:source-paths ["feature-jdbc"]
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
1.12.200
|
||||
1.12.194
|
||||
|
|
@ -1 +1 @@
|
|||
1.12.201-SNAPSHOT
|
||||
1.12.195-SNAPSHOT
|
||||
|
|
@ -25,12 +25,13 @@
|
|||
babashka/babashka.curl {:local/root "babashka.curl"}
|
||||
babashka/fs {:local/root "fs"}
|
||||
babashka/babashka.core {:local/root "babashka.core"}
|
||||
org.clojure/core.async {:mvn/version "1.8.741"},
|
||||
borkdude/graal.locking {:mvn/version "0.0.2"},
|
||||
org.clojure/core.async {:mvn/version "1.6.673"},
|
||||
org.clojure/tools.cli {:mvn/version "1.0.214"},
|
||||
org.clojure/data.csv {:mvn/version "1.0.0"},
|
||||
cheshire/cheshire {:mvn/version "6.0.0"}
|
||||
cheshire/cheshire {:mvn/version "5.13.0"}
|
||||
org.clojure/data.xml {:mvn/version "0.2.0-alpha8"}
|
||||
clj-commons/clj-yaml {:mvn/version "1.0.29"}
|
||||
clj-commons/clj-yaml {:mvn/version "1.0.28"}
|
||||
com.cognitect/transit-clj {:mvn/version "1.0.333"}
|
||||
org.clojure/test.check {:mvn/version "1.1.1"}
|
||||
nrepl/bencode {:mvn/version "1.2.0"}
|
||||
|
|
@ -42,17 +43,16 @@
|
|||
babashka/clojure-lanterna {:mvn/version "0.9.8-SNAPSHOT"}
|
||||
org.clojure/core.match {:mvn/version "1.0.0"}
|
||||
hiccup/hiccup {:mvn/version "2.0.0-RC1"}
|
||||
rewrite-clj/rewrite-clj {:mvn/version "1.1.49"}
|
||||
rewrite-clj/rewrite-clj {:mvn/version "1.1.48"}
|
||||
selmer/selmer {:mvn/version "1.12.59"}
|
||||
com.taoensso/timbre {:mvn/version "6.6.0"}
|
||||
org.clojure/tools.logging {:mvn/version "1.1.0"}
|
||||
org.clojure/data.priority-map {:mvn/version "1.1.0"}
|
||||
insn/insn {:mvn/version "0.5.2"}
|
||||
org.clojure/core.rrb-vector {:mvn/version "0.1.2"}
|
||||
org.babashka/cli {:mvn/version "0.8.65"}
|
||||
org.babashka/http-client {:mvn/version "0.4.22"}
|
||||
org.flatland/ordered {:mvn/version "1.15.12"}
|
||||
org.jsoup/jsoup {:mvn/version "1.20.1"}}
|
||||
org.babashka/cli {:mvn/version "0.8.59"}
|
||||
org.babashka/http-client {:mvn/version "0.4.21"}
|
||||
org.flatland/ordered {:mvn/version "1.15.12"}}
|
||||
:aliases {:babashka/dev
|
||||
{:main-opts ["-m" "babashka.main"]}
|
||||
:profile
|
||||
|
|
@ -172,13 +172,7 @@
|
|||
:git/sha "550dbc150a79c6ecc148d8a7e260e10bc36321c6"
|
||||
:deps/manifest :deps}
|
||||
prismatic/plumbing {:git/url "https://github.com/plumatic/plumbing",
|
||||
:git/sha "424bc704f2db422de34269c139a5494314b3a43b"}
|
||||
org.clj-commons/hickory {:git/url "https://github.com/clj-commons/hickory"
|
||||
:git/sha "9385b6708ef35f161732d8464b3a3aa57dd79f30"}
|
||||
com.potetm/fusebox {:git/url "https://github.com/potetm/fusebox"
|
||||
:git/sha "ac6d6a0a69510b009b3c1bb2247cd110fd9f7246"}
|
||||
net.sekao/odoyle-rules {:git/url "https://github.com/oakes/odoyle-rules"
|
||||
:git/sha "0b1d825ec45a998c4d3481dfb292e08ce6a47f0b"}}
|
||||
:git/sha "424bc704f2db422de34269c139a5494314b3a43b"}}
|
||||
:classpath-overrides {org.clojure/clojure nil
|
||||
org.clojure/spec.alpha nil}}
|
||||
:clj-nvd
|
||||
|
|
|
|||
863
resources/src/babashka/clojure/test.clj
Normal file
863
resources/src/babashka/clojure/test.clj
Normal file
|
|
@ -0,0 +1,863 @@
|
|||
; Copyright (c) Rich Hickey. All rights reserved.
|
||||
; The use and distribution terms for this software are covered by the
|
||||
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
||||
; which can be found in the file epl-v10.html at the root of this distribution.
|
||||
; By using this software in any fashion, you are agreeing to be bound by
|
||||
; the terms of this license.
|
||||
; You must not remove this notice, or any other, from this software.
|
||||
|
||||
;;; test.clj: test framework for Clojure
|
||||
|
||||
;; by Stuart Sierra
|
||||
;; March 28, 2009
|
||||
|
||||
;; Thanks to Chas Emerick, Allen Rohner, and Stuart Halloway for
|
||||
;; contributions and suggestions.
|
||||
|
||||
(ns
|
||||
^{:author "Stuart Sierra, with contributions and suggestions by
|
||||
Chas Emerick, Allen Rohner, and Stuart Halloway",
|
||||
:doc "A unit testing framework.
|
||||
|
||||
ASSERTIONS
|
||||
|
||||
The core of the library is the \"is\" macro, which lets you make
|
||||
assertions of any arbitrary expression:
|
||||
|
||||
(is (= 4 (+ 2 2)))
|
||||
(is (instance? Integer 256))
|
||||
(is (.startsWith \"abcde\" \"ab\"))
|
||||
|
||||
You can type an \"is\" expression directly at the REPL, which will
|
||||
print a message if it fails.
|
||||
|
||||
user> (is (= 5 (+ 2 2)))
|
||||
|
||||
FAIL in (:1)
|
||||
expected: (= 5 (+ 2 2))
|
||||
actual: (not (= 5 4))
|
||||
false
|
||||
|
||||
The \"expected:\" line shows you the original expression, and the
|
||||
\"actual:\" shows you what actually happened. In this case, it
|
||||
shows that (+ 2 2) returned 4, which is not = to 5. Finally, the
|
||||
\"false\" on the last line is the value returned from the
|
||||
expression. The \"is\" macro always returns the result of the
|
||||
inner expression.
|
||||
|
||||
There are two special assertions for testing exceptions. The
|
||||
\"(is (thrown? c ...))\" form tests if an exception of class c is
|
||||
thrown:
|
||||
|
||||
(is (thrown? ArithmeticException (/ 1 0)))
|
||||
|
||||
\"(is (thrown-with-msg? c re ...))\" does the same thing and also
|
||||
tests that the message on the exception matches the regular
|
||||
expression re:
|
||||
|
||||
(is (thrown-with-msg? ArithmeticException #\"Divide by zero\"
|
||||
(/ 1 0)))
|
||||
|
||||
DOCUMENTING TESTS
|
||||
|
||||
\"is\" takes an optional second argument, a string describing the
|
||||
assertion. This message will be included in the error report.
|
||||
|
||||
(is (= 5 (+ 2 2)) \"Crazy arithmetic\")
|
||||
|
||||
In addition, you can document groups of assertions with the
|
||||
\"testing\" macro, which takes a string followed by any number of
|
||||
assertions. The string will be included in failure reports.
|
||||
Calls to \"testing\" may be nested, and all of the strings will be
|
||||
joined together with spaces in the final report, in a style
|
||||
similar to RSpec <http://rspec.info/>
|
||||
|
||||
(testing \"Arithmetic\"
|
||||
(testing \"with positive integers\"
|
||||
(is (= 4 (+ 2 2)))
|
||||
(is (= 7 (+ 3 4))))
|
||||
(testing \"with negative integers\"
|
||||
(is (= -4 (+ -2 -2)))
|
||||
(is (= -1 (+ 3 -4)))))
|
||||
|
||||
Note that, unlike RSpec, the \"testing\" macro may only be used
|
||||
INSIDE a \"deftest\" or \"with-test\" form (see below).
|
||||
|
||||
|
||||
DEFINING TESTS
|
||||
|
||||
There are two ways to define tests. The \"with-test\" macro takes
|
||||
a defn or def form as its first argument, followed by any number
|
||||
of assertions. The tests will be stored as metadata on the
|
||||
definition.
|
||||
|
||||
(with-test
|
||||
(defn my-function [x y]
|
||||
(+ x y))
|
||||
(is (= 4 (my-function 2 2)))
|
||||
(is (= 7 (my-function 3 4))))
|
||||
|
||||
As of Clojure SVN rev. 1221, this does not work with defmacro.
|
||||
See http://code.google.com/p/clojure/issues/detail?id=51
|
||||
|
||||
The other way lets you define tests separately from the rest of
|
||||
your code, even in a different namespace:
|
||||
|
||||
(deftest addition
|
||||
(is (= 4 (+ 2 2)))
|
||||
(is (= 7 (+ 3 4))))
|
||||
|
||||
(deftest subtraction
|
||||
(is (= 1 (- 4 3)))
|
||||
(is (= 3 (- 7 4))))
|
||||
|
||||
This creates functions named \"addition\" and \"subtraction\", which
|
||||
can be called like any other function. Therefore, tests can be
|
||||
grouped and composed, in a style similar to the test framework in
|
||||
Peter Seibel's \"Practical Common Lisp\"
|
||||
<http://www.gigamonkeys.com/book/practical-building-a-unit-test-framework.html>
|
||||
|
||||
(deftest arithmetic
|
||||
(addition)
|
||||
(subtraction))
|
||||
|
||||
The names of the nested tests will be joined in a list, like
|
||||
\"(arithmetic addition)\", in failure reports. You can use nested
|
||||
tests to set up a context shared by several tests.
|
||||
|
||||
|
||||
RUNNING TESTS
|
||||
|
||||
Run tests with the function \"(run-tests namespaces...)\":
|
||||
|
||||
(run-tests 'your.namespace 'some.other.namespace)
|
||||
|
||||
If you don't specify any namespaces, the current namespace is
|
||||
used. To run all tests in all namespaces, use \"(run-all-tests)\".
|
||||
|
||||
By default, these functions will search for all tests defined in
|
||||
a namespace and run them in an undefined order. However, if you
|
||||
are composing tests, as in the \"arithmetic\" example above, you
|
||||
probably do not want the \"addition\" and \"subtraction\" tests run
|
||||
separately. In that case, you must define a special function
|
||||
named \"test-ns-hook\" that runs your tests in the correct order:
|
||||
|
||||
(defn test-ns-hook []
|
||||
(arithmetic))
|
||||
|
||||
Note: test-ns-hook prevents execution of fixtures (see below).
|
||||
|
||||
|
||||
OMITTING TESTS FROM PRODUCTION CODE
|
||||
|
||||
You can bind the variable \"*load-tests*\" to false when loading or
|
||||
compiling code in production. This will prevent any tests from
|
||||
being created by \"with-test\" or \"deftest\".
|
||||
|
||||
|
||||
FIXTURES
|
||||
|
||||
Fixtures allow you to run code before and after tests, to set up
|
||||
the context in which tests should be run.
|
||||
|
||||
A fixture is just a function that calls another function passed as
|
||||
an argument. It looks like this:
|
||||
|
||||
(defn my-fixture [f]
|
||||
Perform setup, establish bindings, whatever.
|
||||
(f) Then call the function we were passed.
|
||||
Tear-down / clean-up code here.
|
||||
)
|
||||
|
||||
Fixtures are attached to namespaces in one of two ways. \"each\"
|
||||
fixtures are run repeatedly, once for each test function created
|
||||
with \"deftest\" or \"with-test\". \"each\" fixtures are useful for
|
||||
establishing a consistent before/after state for each test, like
|
||||
clearing out database tables.
|
||||
|
||||
\"each\" fixtures can be attached to the current namespace like this:
|
||||
(use-fixtures :each fixture1 fixture2 ...)
|
||||
The fixture1, fixture2 are just functions like the example above.
|
||||
They can also be anonymous functions, like this:
|
||||
(use-fixtures :each (fn [f] setup... (f) cleanup...))
|
||||
|
||||
The other kind of fixture, a \"once\" fixture, is only run once,
|
||||
around ALL the tests in the namespace. \"once\" fixtures are useful
|
||||
for tasks that only need to be performed once, like establishing
|
||||
database connections, or for time-consuming tasks.
|
||||
|
||||
Attach \"once\" fixtures to the current namespace like this:
|
||||
(use-fixtures :once fixture1 fixture2 ...)
|
||||
|
||||
Note: Fixtures and test-ns-hook are mutually incompatible. If you
|
||||
are using test-ns-hook, fixture functions will *never* be run.
|
||||
|
||||
|
||||
SAVING TEST OUTPUT TO A FILE
|
||||
|
||||
All the test reporting functions write to the var *test-out*. By
|
||||
default, this is the same as *out*, but you can rebind it to any
|
||||
PrintWriter. For example, it could be a file opened with
|
||||
clojure.java.io/writer.
|
||||
|
||||
|
||||
EXTENDING TEST-IS (ADVANCED)
|
||||
|
||||
You can extend the behavior of the \"is\" macro by defining new
|
||||
methods for the \"assert-expr\" multimethod. These methods are
|
||||
called during expansion of the \"is\" macro, so they should return
|
||||
quoted forms to be evaluated.
|
||||
|
||||
You can plug in your own test-reporting framework by rebinding
|
||||
the \"report\" function: (report event)
|
||||
|
||||
The 'event' argument is a map. It will always have a :type key,
|
||||
whose value will be a keyword signaling the type of event being
|
||||
reported. Standard events with :type value of :pass, :fail, and
|
||||
:error are called when an assertion passes, fails, and throws an
|
||||
exception, respectively. In that case, the event will also have
|
||||
the following keys:
|
||||
|
||||
:expected The form that was expected to be true
|
||||
:actual A form representing what actually occurred
|
||||
:message The string message given as an argument to 'is'
|
||||
|
||||
The \"testing\" strings will be a list in \"*testing-contexts*\", and
|
||||
the vars being tested will be a list in \"*testing-vars*\".
|
||||
|
||||
Your \"report\" function should wrap any printing calls in the
|
||||
\"with-test-out\" macro, which rebinds *out* to the current value
|
||||
of *test-out*.
|
||||
|
||||
For additional event types, see the examples in the code.
|
||||
"}
|
||||
clojure.test
|
||||
(:require [clojure.template :as temp]
|
||||
[clojure.stacktrace :as stack]
|
||||
[clojure.string :as str]))
|
||||
|
||||
;; Nothing is marked "private" here, so you can rebind things to plug
|
||||
;; in your own testing or reporting frameworks.
|
||||
|
||||
|
||||
;;; USER-MODIFIABLE GLOBALS
|
||||
|
||||
(defonce ^:dynamic
|
||||
^{:doc "True by default. If set to false, no test functions will
|
||||
be created by deftest, set-test, or with-test. Use this to omit
|
||||
tests when compiling or loading production code."
|
||||
:added "1.1"}
|
||||
*load-tests* true)
|
||||
|
||||
(def ^:dynamic
|
||||
^{:doc "The maximum depth of stack traces to print when an Exception
|
||||
is thrown during a test. Defaults to nil, which means print the
|
||||
complete stack trace."
|
||||
:added "1.1"}
|
||||
*stack-trace-depth* nil)
|
||||
|
||||
|
||||
;;; GLOBALS USED BY THE REPORTING FUNCTIONS
|
||||
|
||||
(def ^:dynamic *report-counters* nil) ; bound to a ref of a map in test-ns
|
||||
|
||||
(def ^:dynamic *initial-report-counters* ; used to initialize *report-counters*
|
||||
{:test 0, :pass 0, :fail 0, :error 0})
|
||||
|
||||
(def ^:dynamic *testing-vars* (list)) ; bound to hierarchy of vars being tested
|
||||
|
||||
(def ^:dynamic *testing-contexts* (list)) ; bound to hierarchy of "testing" strings
|
||||
|
||||
(def ^:dynamic *test-out* *out*) ; PrintWriter for test reporting output
|
||||
|
||||
(defmacro with-test-out
|
||||
"Runs body with *out* bound to the value of *test-out*."
|
||||
{:added "1.1"}
|
||||
[& body]
|
||||
`(binding [*out* *test-out*]
|
||||
~@body))
|
||||
|
||||
;;; UTILITIES FOR REPORTING FUNCTIONS
|
||||
|
||||
(defn file-position
|
||||
"Returns a vector [filename line-number] for the nth call up the
|
||||
stack.
|
||||
|
||||
Deprecated in 1.2: The information needed for test reporting is
|
||||
now on :file and :line keys in the result map."
|
||||
{:added "1.1"
|
||||
:deprecated "1.2"}
|
||||
[n]
|
||||
(let [^StackTraceElement s (nth (.getStackTrace (new java.lang.Throwable)) n)]
|
||||
[(.getFileName s) (.getLineNumber s)]))
|
||||
|
||||
(defn testing-vars-str
|
||||
"Returns a string representation of the current test. Renders names
|
||||
in *testing-vars* as a list, then the source file and line of
|
||||
current assertion."
|
||||
{:added "1.1"}
|
||||
[m]
|
||||
(let [{:keys [file line]} (merge m (meta (first *testing-vars*)))]
|
||||
(str
|
||||
;; Uncomment to include namespace in failure report:
|
||||
;;(ns-name (:ns (meta (first *testing-vars*)))) "/ "
|
||||
(reverse (map #(:name (meta %)) *testing-vars*))
|
||||
" (" file ":" line ")")))
|
||||
|
||||
(defn testing-contexts-str
|
||||
"Returns a string representation of the current test context. Joins
|
||||
strings in *testing-contexts* with spaces."
|
||||
{:added "1.1"}
|
||||
[]
|
||||
(apply str (interpose " " (reverse *testing-contexts*))))
|
||||
|
||||
(defn inc-report-counter
|
||||
"Increments the named counter in *report-counters*, a ref to a map.
|
||||
Does nothing if *report-counters* is nil."
|
||||
{:added "1.1"}
|
||||
[name]
|
||||
(when *report-counters*
|
||||
(dosync (commute *report-counters* update-in [name] (fnil inc 0)))))
|
||||
|
||||
;;; TEST RESULT REPORTING
|
||||
|
||||
(defmulti
|
||||
^{:doc "Generic reporting function, may be overridden to plug in
|
||||
different report formats (e.g., TAP, JUnit). Assertions such as
|
||||
'is' call 'report' to indicate results. The argument given to
|
||||
'report' will be a map with a :type key. See the documentation at
|
||||
the top of test_is.clj for more information on the types of
|
||||
arguments for 'report'."
|
||||
:dynamic true
|
||||
:added "1.1"}
|
||||
report :type)
|
||||
|
||||
(defn- file-and-line
|
||||
{:deprecated "1.8"}
|
||||
[^Throwable exception depth]
|
||||
(let [stacktrace (.getStackTrace exception)]
|
||||
(if (< depth (count stacktrace))
|
||||
(let [^StackTraceElement s (nth stacktrace depth)]
|
||||
{:file (.getFileName s) :line (.getLineNumber s)})
|
||||
{:file nil :line nil})))
|
||||
|
||||
(defn- stacktrace-file-and-line
|
||||
[stacktrace]
|
||||
(if (seq stacktrace)
|
||||
(let [^StackTraceElement s (first stacktrace)]
|
||||
{:file (.getFileName s) :line (.getLineNumber s)})
|
||||
{:file nil :line nil}))
|
||||
|
||||
(defn do-report
|
||||
"Add file and line information to a test result and call report.
|
||||
If you are writing a custom assert-expr method, call this function
|
||||
to pass test results to report."
|
||||
{:added "1.2"}
|
||||
[m]
|
||||
(report
|
||||
(case
|
||||
(:type m)
|
||||
:fail (merge m #_(stacktrace-file-and-line (drop-while
|
||||
#(let [cl-name (.getClassName ^StackTraceElement %)]
|
||||
(or (str/starts-with? cl-name "java.lang.")
|
||||
(str/starts-with? cl-name "clojure.test$")
|
||||
(str/starts-with? cl-name "clojure.core$ex_info")))
|
||||
(.getStackTrace (Thread/currentThread)))) m)
|
||||
:error (do
|
||||
(merge m)) #_(merge (stacktrace-file-and-line (.getStackTrace ^Throwable (:actual m))) m)
|
||||
m)))
|
||||
|
||||
(defmethod report :default [m]
|
||||
(with-test-out (prn m)))
|
||||
|
||||
(defmethod report :pass [m]
|
||||
(with-test-out (inc-report-counter :pass)))
|
||||
|
||||
(defmethod report :fail [m]
|
||||
(with-test-out
|
||||
(inc-report-counter :fail)
|
||||
(println "\nFAIL in" (testing-vars-str m))
|
||||
(when (seq *testing-contexts*) (println (testing-contexts-str)))
|
||||
(when-let [message (:message m)] (println message))
|
||||
(println "expected:" (pr-str (:expected m)))
|
||||
(println " actual:" (pr-str (:actual m)))))
|
||||
|
||||
(defmethod report :error [m]
|
||||
(with-test-out
|
||||
(inc-report-counter :error)
|
||||
(println "\nERROR in" (testing-vars-str m))
|
||||
(when (seq *testing-contexts*) (println (testing-contexts-str)))
|
||||
(when-let [message (:message m)] (println message))
|
||||
(println "expected:" (pr-str (:expected m)))
|
||||
(println " actual:")
|
||||
(let [actual (:actual m)]
|
||||
(if (instance? Throwable actual)
|
||||
(if-let [s (:stacktrace m)]
|
||||
(run! println s)
|
||||
(stack/print-cause-trace actual *stack-trace-depth*))
|
||||
(prn actual)))))
|
||||
|
||||
(defmethod report :summary [m]
|
||||
(with-test-out
|
||||
(println "\nRan" (:test m) "tests containing"
|
||||
(+ (:pass m) (:fail m) (:error m)) "assertions.")
|
||||
(println (:fail m) "failures," (:error m) "errors.")))
|
||||
|
||||
(defmethod report :begin-test-ns [m]
|
||||
(with-test-out
|
||||
(println "\nTesting" (ns-name (:ns m)))))
|
||||
|
||||
;; Ignore these message types:
|
||||
(defmethod report :end-test-ns [m])
|
||||
(defmethod report :begin-test-var [m])
|
||||
(defmethod report :end-test-var [m])
|
||||
|
||||
|
||||
|
||||
;;; UTILITIES FOR ASSERTIONS
|
||||
|
||||
(defn get-possibly-unbound-var
|
||||
"Like var-get but returns nil if the var is unbound."
|
||||
{:added "1.1"}
|
||||
[v]
|
||||
(try (var-get v)
|
||||
(catch IllegalStateException e
|
||||
nil)))
|
||||
|
||||
(defn function?
|
||||
"Returns true if argument is a function or a symbol that resolves to
|
||||
a function (not a macro)."
|
||||
{:added "1.1"}
|
||||
[x]
|
||||
(if (symbol? x)
|
||||
(when-let [v (resolve x)]
|
||||
(when-let [value (get-possibly-unbound-var v)]
|
||||
(and (fn? value)
|
||||
(not (:macro (meta v))))))
|
||||
(fn? x)))
|
||||
|
||||
(defn assert-predicate
|
||||
"Returns generic assertion code for any functional predicate. The
|
||||
'expected' argument to 'report' will contains the original form, the
|
||||
'actual' argument will contain the form with all its sub-forms
|
||||
evaluated. If the predicate returns false, the 'actual' form will
|
||||
be wrapped in (not...)."
|
||||
{:added "1.1"}
|
||||
[msg form]
|
||||
(let [args (rest form)
|
||||
pred (first form)]
|
||||
`(let [values# (list ~@args)
|
||||
result# (apply ~pred values#)]
|
||||
(if result#
|
||||
(do-report (merge {:type :pass, :message ~msg,
|
||||
:expected '~form, :actual (cons '~pred values#)
|
||||
:file *file*}
|
||||
~(meta form)))
|
||||
(do-report (merge {:type :fail, :message ~msg,
|
||||
:expected '~form, :actual (list '~'not (cons '~pred values#))
|
||||
:file *file*}
|
||||
~(meta form))))
|
||||
result#)))
|
||||
|
||||
(defn assert-any
|
||||
"Returns generic assertion code for any test, including macros, Java
|
||||
method calls, or isolated symbols."
|
||||
{:added "1.1"}
|
||||
[msg form]
|
||||
`(let [value# ~form]
|
||||
(if value#
|
||||
(do-report (merge {:type :pass, :message ~msg,
|
||||
:expected '~form, :actual value#
|
||||
:file *file*}
|
||||
~(meta form)))
|
||||
(do-report (merge {:type :fail, :message ~msg,
|
||||
:expected '~form, :actual value#
|
||||
:file *file*}
|
||||
~(meta form))))
|
||||
value#))
|
||||
|
||||
|
||||
|
||||
;;; ASSERTION METHODS
|
||||
|
||||
;; You don't call these, but you can add methods to extend the 'is'
|
||||
;; macro. These define different kinds of tests, based on the first
|
||||
;; symbol in the test expression.
|
||||
|
||||
(defmulti assert-expr
|
||||
(fn [msg form]
|
||||
(cond
|
||||
(nil? form) :always-fail
|
||||
(seq? form) (first form)
|
||||
:else :default)))
|
||||
|
||||
(defmethod assert-expr :always-fail [msg form]
|
||||
;; nil test: always fail
|
||||
`(do-report {:type :fail, :message ~msg
|
||||
:file clojure.core/*file*
|
||||
:line ~(:line (meta form))}))
|
||||
|
||||
(defmethod assert-expr :default [msg form]
|
||||
(if (and (sequential? form) (function? (first form)))
|
||||
(assert-predicate msg form)
|
||||
(assert-any msg form)))
|
||||
|
||||
(defmethod assert-expr 'instance? [msg form]
|
||||
;; Test if x is an instance of y.
|
||||
`(let [klass# ~(nth form 1)
|
||||
object# ~(nth form 2)]
|
||||
(let [result# (instance? klass# object#)]
|
||||
(if result#
|
||||
(do-report {:type :pass, :message ~msg,
|
||||
:expected '~form, :actual (class object#)})
|
||||
(do-report {:type :fail, :message ~msg,
|
||||
:expected '~form, :actual (class object#)
|
||||
:file clojure.core/*file*
|
||||
:line ~(:line (meta form))}))
|
||||
result#)))
|
||||
|
||||
(defmethod assert-expr 'thrown? [msg form]
|
||||
;; (is (thrown? c expr))
|
||||
;; Asserts that evaluating expr throws an exception of class c.
|
||||
;; Returns the exception thrown.
|
||||
(let [klass (second form)
|
||||
body (nthnext form 2)]
|
||||
`(try ~@body
|
||||
(do-report {:type :fail, :message ~msg,
|
||||
:expected '~form, :actual nil
|
||||
:file clojure.core/*file*
|
||||
:line ~(:line (meta form))})
|
||||
(catch ~klass e#
|
||||
(do-report {:type :pass, :message ~msg,
|
||||
:expected '~form, :actual e#})
|
||||
e#))))
|
||||
|
||||
(defmethod assert-expr 'thrown-with-msg? [msg form]
|
||||
;; (is (thrown-with-msg? c re expr))
|
||||
;; Asserts that evaluating expr throws an exception of class c.
|
||||
;; Also asserts that the message string of the exception matches
|
||||
;; (with re-find) the regular expression re.
|
||||
(let [klass (nth form 1)
|
||||
re (nth form 2)
|
||||
body (nthnext form 3)]
|
||||
`(try ~@body
|
||||
(do-report {:type :fail, :message ~msg, :expected '~form, :actual nil})
|
||||
(catch ~klass e#
|
||||
(let [m# (.getMessage e#)]
|
||||
(if (re-find ~re m#)
|
||||
(do-report {:type :pass, :message ~msg,
|
||||
:expected '~form, :actual e#})
|
||||
(do-report {:type :fail, :message ~msg,
|
||||
:file clojure.core/*file*
|
||||
:line ~(:line (meta form))
|
||||
:expected '~form, :actual e#})))
|
||||
e#))))
|
||||
|
||||
(defmacro try-expr
|
||||
"Used by the 'is' macro to catch unexpected exceptions.
|
||||
You don't call this."
|
||||
{:added "1.1"}
|
||||
[msg form]
|
||||
;; (println (assert-expr msg form))
|
||||
`(try ~(assert-expr msg form)
|
||||
;; TODO: make SCI catch Throwable as well
|
||||
(catch ~(with-meta 'Exception {:sci/error true}) t#
|
||||
(let [cause# (ex-cause t#)
|
||||
exd# (ex-data t#)
|
||||
file# (:file exd#)
|
||||
line# (:line exd#)
|
||||
message# (ex-message cause#)
|
||||
stack# (-> (sci.core/stacktrace t#) (sci.core/format-stacktrace))]
|
||||
(do-report (cond-> {:file clojure.core/*file*
|
||||
:line ~(:line (meta form))
|
||||
:type :error, :message ~msg,
|
||||
:expected '~form, :actual cause#}
|
||||
file# (assoc :file file#)
|
||||
line# (assoc :line line#)
|
||||
stack# (assoc :stacktrace stack#)
|
||||
message# (assoc :message message#)))))))
|
||||
|
||||
|
||||
|
||||
;;; ASSERTION MACROS
|
||||
|
||||
;; You use these in your tests.
|
||||
|
||||
(defmacro is
|
||||
"Generic assertion macro. 'form' is any predicate test.
|
||||
'msg' is an optional message to attach to the assertion.
|
||||
|
||||
Example: (is (= 4 (+ 2 2)) \"Two plus two should be 4\")
|
||||
|
||||
Special forms:
|
||||
|
||||
(is (thrown? c body)) checks that an instance of c is thrown from
|
||||
body, fails if not; then returns the thing thrown.
|
||||
|
||||
(is (thrown-with-msg? c re body)) checks that an instance of c is
|
||||
thrown AND that the message on the exception matches (with
|
||||
re-find) the regular expression re."
|
||||
{:added "1.1"}
|
||||
([form] `(is ~form nil))
|
||||
([form msg] `(try-expr ~msg ~form)))
|
||||
|
||||
(defmacro are
|
||||
"Checks multiple assertions with a template expression.
|
||||
See clojure.template/do-template for an explanation of
|
||||
templates.
|
||||
|
||||
Example: (are [x y] (= x y)
|
||||
2 (+ 1 1)
|
||||
4 (* 2 2))
|
||||
Expands to:
|
||||
(do (is (= 2 (+ 1 1)))
|
||||
(is (= 4 (* 2 2))))
|
||||
|
||||
Note: This breaks some reporting features, such as line numbers."
|
||||
{:added "1.1"}
|
||||
[argv expr & args]
|
||||
(if (or
|
||||
;; (are [] true) is meaningless but ok
|
||||
(and (empty? argv) (empty? args))
|
||||
;; Catch wrong number of args
|
||||
(and (pos? (count argv))
|
||||
(pos? (count args))
|
||||
(zero? (mod (count args) (count argv)))))
|
||||
`(temp/do-template ~argv (is ~expr) ~@args)
|
||||
(throw (IllegalArgumentException. "The number of args doesn't match are's argv."))))
|
||||
|
||||
(defmacro testing
|
||||
"Adds a new string to the list of testing contexts. May be nested,
|
||||
but must occur inside a test function (deftest)."
|
||||
{:added "1.1"}
|
||||
[string & body]
|
||||
`(binding [*testing-contexts* (conj *testing-contexts* ~string)]
|
||||
~@body))
|
||||
|
||||
|
||||
|
||||
;;; DEFINING TESTS
|
||||
|
||||
(defmacro with-test
|
||||
"Takes any definition form (that returns a Var) as the first argument.
|
||||
Remaining body goes in the :test metadata function for that Var.
|
||||
|
||||
When *load-tests* is false, only evaluates the definition, ignoring
|
||||
the tests."
|
||||
{:added "1.1"}
|
||||
[definition & body]
|
||||
(if *load-tests*
|
||||
`(doto ~definition (alter-meta! assoc :test (fn [] ~@body)))
|
||||
definition))
|
||||
|
||||
|
||||
(defmacro deftest
|
||||
"Defines a test function with no arguments. Test functions may call
|
||||
other tests, so tests may be composed. If you compose tests, you
|
||||
should also define a function named test-ns-hook; run-tests will
|
||||
call test-ns-hook instead of testing all vars.
|
||||
|
||||
Note: Actually, the test body goes in the :test metadata on the var,
|
||||
and the real function (the value of the var) calls test-var on
|
||||
itself.
|
||||
|
||||
When *load-tests* is false, deftest is ignored."
|
||||
{:added "1.1"}
|
||||
[name & body]
|
||||
(when *load-tests*
|
||||
`(def ~(vary-meta name assoc :test `(fn [] ~@body))
|
||||
(fn [] (test-var (var ~name))))))
|
||||
|
||||
(defmacro deftest-
|
||||
"Like deftest but creates a private var."
|
||||
{:added "1.1"}
|
||||
[name & body]
|
||||
(when *load-tests*
|
||||
`(def ~(vary-meta name assoc :test `(fn [] ~@body) :private true)
|
||||
(fn [] (test-var (var ~name))))))
|
||||
|
||||
|
||||
(defmacro set-test
|
||||
"Experimental.
|
||||
Sets :test metadata of the named var to a fn with the given body.
|
||||
The var must already exist. Does not modify the value of the var.
|
||||
|
||||
When *load-tests* is false, set-test is ignored."
|
||||
{:added "1.1"}
|
||||
[name & body]
|
||||
(when *load-tests*
|
||||
`(alter-meta! (var ~name) assoc :test (fn [] ~@body))))
|
||||
|
||||
|
||||
|
||||
;;; DEFINING FIXTURES
|
||||
|
||||
(defn- add-ns-meta
|
||||
"Adds elements in coll to the current namespace metadata as the
|
||||
value of key."
|
||||
{:added "1.1"}
|
||||
[key coll]
|
||||
(alter-meta! *ns* assoc key coll))
|
||||
|
||||
(defmulti use-fixtures
|
||||
"Wrap test runs in a fixture function to perform setup and
|
||||
teardown. Using a fixture-type of :each wraps every test
|
||||
individually, while :once wraps the whole run in a single function."
|
||||
{:added "1.1"}
|
||||
(fn [fixture-type & args] fixture-type))
|
||||
|
||||
(defmethod use-fixtures :each [fixture-type & args]
|
||||
(add-ns-meta ::each-fixtures args))
|
||||
|
||||
(defmethod use-fixtures :once [fixture-type & args]
|
||||
(add-ns-meta ::once-fixtures args))
|
||||
|
||||
(defn- default-fixture
|
||||
"The default, empty, fixture function. Just calls its argument."
|
||||
{:added "1.1"}
|
||||
[f]
|
||||
(f))
|
||||
|
||||
(defn compose-fixtures
|
||||
"Composes two fixture functions, creating a new fixture function
|
||||
that combines their behavior."
|
||||
{:added "1.1"}
|
||||
[f1 f2]
|
||||
(fn [g] (f1 (fn [] (f2 g)))))
|
||||
|
||||
(defn join-fixtures
|
||||
"Composes a collection of fixtures, in order. Always returns a valid
|
||||
fixture function, even if the collection is empty."
|
||||
{:added "1.1"}
|
||||
[fixtures]
|
||||
(reduce compose-fixtures default-fixture fixtures))
|
||||
|
||||
|
||||
|
||||
|
||||
;;; RUNNING TESTS: LOW-LEVEL FUNCTIONS
|
||||
|
||||
(defn test-var
|
||||
"If v has a function in its :test metadata, calls that function,
|
||||
with *testing-vars* bound to (conj *testing-vars* v)."
|
||||
{:dynamic true, :added "1.1"}
|
||||
[v]
|
||||
(when-let [t (:test (meta v))]
|
||||
(binding [*testing-vars* (conj *testing-vars* v)]
|
||||
(do-report {:type :begin-test-var, :var v})
|
||||
(inc-report-counter :test)
|
||||
(try (t)
|
||||
(catch Throwable e
|
||||
(do-report {:type :error, :message "Uncaught exception, not in assertion."
|
||||
:expected nil, :actual e})))
|
||||
(do-report {:type :end-test-var, :var v}))))
|
||||
|
||||
(defn test-vars
|
||||
"Groups vars by their namespace and runs test-var on them with
|
||||
appropriate fixtures applied."
|
||||
{:added "1.6"}
|
||||
[vars]
|
||||
(doseq [[ns vars] (group-by (comp :ns meta) vars)]
|
||||
(let [once-fixture-fn (join-fixtures (::once-fixtures (meta ns)))
|
||||
each-fixture-fn (join-fixtures (::each-fixtures (meta ns)))]
|
||||
(once-fixture-fn
|
||||
(fn []
|
||||
(doseq [v vars]
|
||||
(when (:test (meta v))
|
||||
(each-fixture-fn (fn [] (test-var v))))))))))
|
||||
|
||||
(defn test-all-vars
|
||||
"Calls test-vars on every var interned in the namespace, with fixtures."
|
||||
{:added "1.1"}
|
||||
[ns]
|
||||
(test-vars (vals (ns-interns ns))))
|
||||
|
||||
(defn test-ns
|
||||
"If the namespace defines a function named test-ns-hook, calls that.
|
||||
Otherwise, calls test-all-vars on the namespace. 'ns' is a
|
||||
namespace object or a symbol.
|
||||
|
||||
Internally binds *report-counters* to a ref initialized to
|
||||
*initial-report-counters*. Returns the final, dereferenced state of
|
||||
*report-counters*."
|
||||
{:added "1.1"}
|
||||
[ns]
|
||||
(binding [*report-counters* (ref *initial-report-counters*)]
|
||||
(let [ns-obj (the-ns ns)]
|
||||
(do-report {:type :begin-test-ns, :ns ns-obj})
|
||||
;; If the namespace has a test-ns-hook function, call that:
|
||||
(if-let [v (find-var (symbol (str (ns-name ns-obj)) "test-ns-hook"))]
|
||||
((var-get v))
|
||||
;; Otherwise, just test every var in the namespace.
|
||||
(test-all-vars ns-obj))
|
||||
(do-report {:type :end-test-ns, :ns ns-obj}))
|
||||
@*report-counters*))
|
||||
|
||||
|
||||
|
||||
;;; RUNNING TESTS: HIGH-LEVEL FUNCTIONS
|
||||
|
||||
(defn run-tests
|
||||
"Runs all tests in the given namespaces; prints results.
|
||||
Defaults to current namespace if none given. Returns a map
|
||||
summarizing test results."
|
||||
{:added "1.1"}
|
||||
([] (run-tests *ns*))
|
||||
([& namespaces]
|
||||
(let [summary (assoc (apply merge-with + (map test-ns namespaces))
|
||||
:type :summary)]
|
||||
(do-report summary)
|
||||
summary)))
|
||||
|
||||
(defn run-all-tests
|
||||
"Runs all tests in all namespaces; prints results.
|
||||
Optional argument is a regular expression; only namespaces with
|
||||
names matching the regular expression (with re-matches) will be
|
||||
tested."
|
||||
{:added "1.1"}
|
||||
([] (apply run-tests (all-ns)))
|
||||
([re] (apply run-tests (filter #(re-matches re (name (ns-name %))) (all-ns)))))
|
||||
|
||||
(defn successful?
|
||||
"Returns true if the given test summary indicates all tests
|
||||
were successful, false otherwise."
|
||||
{:added "1.1"}
|
||||
[summary]
|
||||
(and (zero? (:fail summary 0))
|
||||
(zero? (:error summary 0))))
|
||||
|
||||
(defn run-test-var
|
||||
"Runs the tests for a single Var, with fixtures executed around the test, and summary output after."
|
||||
{:added "1.11"}
|
||||
[v]
|
||||
(binding [*report-counters* (ref *initial-report-counters*)]
|
||||
(let [ns-obj (-> v meta :ns)
|
||||
summary (do
|
||||
(do-report {:type :begin-test-ns
|
||||
:ns ns-obj})
|
||||
(test-vars [v])
|
||||
(do-report {:type :end-test-ns
|
||||
:ns ns-obj})
|
||||
(assoc @*report-counters* :type :summary))]
|
||||
(do-report summary)
|
||||
summary)))
|
||||
|
||||
(defmacro run-test
|
||||
"Runs a single test.
|
||||
|
||||
Because the intent is to run a single test, there is no check for the namespace test-ns-hook."
|
||||
{:added "1.11"}
|
||||
[test-symbol]
|
||||
(let [test-var (resolve test-symbol)]
|
||||
(cond
|
||||
(nil? test-var)
|
||||
(binding [*out* *err*]
|
||||
(println "Unable to resolve" test-symbol "to a test function."))
|
||||
|
||||
(not (-> test-var meta :test))
|
||||
(binding [*out* *err*]
|
||||
(println test-symbol "is not a test."))
|
||||
|
||||
:else
|
||||
`(run-test-var ~test-var))))
|
||||
|
||||
2
sci
2
sci
|
|
@ -1 +1 @@
|
|||
Subproject commit e85433a0214114fdceb4ca896e1b9c27b1bdf713
|
||||
Subproject commit 6d9380f55b3038769d5856fc67e7d7939ac981ef
|
||||
|
|
@ -45,6 +45,7 @@
|
|||
"appveyor.yml"
|
||||
"project.clj"
|
||||
"script/bump_graal_version.clj"
|
||||
".circleci/script/short_ci.clj"
|
||||
".cirrus.yml"
|
||||
"script/install-graalvm"])
|
||||
|
||||
|
|
@ -54,7 +55,7 @@
|
|||
;; OR
|
||||
;;
|
||||
;; We could have them as environment variables
|
||||
(def current-graal-version "24")
|
||||
(def current-graal-version "23")
|
||||
|
||||
(def cl-options
|
||||
[["-g" "--graal VERSION" "graal version"]
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ set -euo pipefail
|
|||
|
||||
INSTALL_DIR="${1:-$HOME}"
|
||||
|
||||
GRAALVM_VERSION="${GRAALVM_VERSION:-24}"
|
||||
GRAALVM_VERSION="${GRAALVM_VERSION:-23}"
|
||||
|
||||
GRAALVM_PLATFORM=$BABASHKA_PLATFORM
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ esac
|
|||
|
||||
GRAALVM_DIR_NAME="graalvm-$GRAALVM_VERSION"
|
||||
GRAALVM_FILENAME="graalvm-jdk-${GRAALVM_VERSION}_${GRAALVM_PLATFORM}-${GRAALVM_ARCH}_bin.tar.gz"
|
||||
DOWNLOAD_URL="https://download.oracle.com/graalvm/${GRAALVM_VERSION}/archive/${GRAALVM_FILENAME}"
|
||||
DOWNLOAD_URL="https://download.oracle.com/graalvm/23/archive/${GRAALVM_FILENAME}"
|
||||
|
||||
pushd "$INSTALL_DIR" >/dev/null
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
(ns aaaa-this-has-to-be-first.because-patches
|
||||
;; we need pprint loaded first, it patches pprint to not bloat the GraalVM binary
|
||||
(:require [babashka.impl.patches.datafy]
|
||||
[babashka.impl.pprint]
|
||||
))
|
||||
[babashka.impl.pprint]))
|
||||
|
||||
;; Enable this for scanning requiring usage:
|
||||
(def enable-require-scan
|
||||
|
|
|
|||
|
|
@ -1,120 +1,25 @@
|
|||
(ns babashka.impl.cheshire
|
||||
{:no-doc true}
|
||||
(:require [cheshire.core :as json]
|
||||
[cheshire.factory :as fact]
|
||||
[sci.core :as sci :refer [copy-var]]))
|
||||
|
||||
(def tns (sci/create-ns 'cheshire.core nil))
|
||||
(def fns (sci/create-ns 'cheshire.factory nil))
|
||||
|
||||
(def json-factory (sci/new-dynamic-var '*json-factory* nil {:ns fns}))
|
||||
|
||||
;; wrap cheshire fns to support `*json-factory*` dynamic var
|
||||
|
||||
(defn generate-string
|
||||
([obj]
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/generate-string obj)))
|
||||
([obj opt-map]
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/generate-string obj opt-map))))
|
||||
|
||||
(defn generate-stream
|
||||
([obj writer]
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/generate-stream obj writer)))
|
||||
([obj writer opt-map]
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/generate-stream obj writer opt-map))))
|
||||
|
||||
(defn parse-string
|
||||
([string]
|
||||
(when string
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/parse-string string))))
|
||||
([string key-fn]
|
||||
(when string
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/parse-string string key-fn))))
|
||||
([^String string key-fn array-coerce-fn]
|
||||
(when string
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/parse-string string key-fn array-coerce-fn)))))
|
||||
|
||||
(defn parse-string-strict
|
||||
([string]
|
||||
(when string
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/parse-string-strict string))))
|
||||
([string key-fn]
|
||||
(when string
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/parse-string-strict string key-fn))))
|
||||
([^String string key-fn array-coerce-fn]
|
||||
(when string
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/parse-string-strict string key-fn array-coerce-fn)))))
|
||||
|
||||
(defn parse-stream
|
||||
([rdr]
|
||||
(when rdr
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/parse-stream rdr))))
|
||||
([rdr key-fn]
|
||||
(when rdr
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/parse-stream rdr key-fn))))
|
||||
([rdr key-fn array-coerce-fn]
|
||||
(when rdr
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/parse-stream rdr key-fn array-coerce-fn)))))
|
||||
|
||||
(defn parse-stream-strict
|
||||
([rdr]
|
||||
(when rdr
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/parse-stream-strict rdr))))
|
||||
([rdr key-fn]
|
||||
(when rdr
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/parse-stream-strict rdr key-fn))))
|
||||
([rdr key-fn array-coerce-fn]
|
||||
(when rdr
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/parse-stream-strict rdr key-fn array-coerce-fn)))))
|
||||
|
||||
(defn parsed-seq
|
||||
([reader]
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/parsed-seq reader)))
|
||||
([reader key-fn]
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/parsed-seq reader key-fn)))
|
||||
([reader key-fn array-coerce-fn]
|
||||
(binding [fact/*json-factory* @json-factory]
|
||||
(json/parsed-seq reader key-fn array-coerce-fn))))
|
||||
|
||||
(def cheshire-core-namespace
|
||||
{'encode (copy-var generate-string tns)
|
||||
'generate-string (copy-var generate-string tns)
|
||||
'encode-stream (copy-var generate-stream tns)
|
||||
'generate-stream (copy-var generate-stream tns)
|
||||
{'encode (copy-var json/encode tns)
|
||||
'generate-string (copy-var json/generate-string tns)
|
||||
'encode-stream (copy-var json/encode-stream tns)
|
||||
'generate-stream (copy-var json/generate-stream tns)
|
||||
;;'encode-smile (copy-var json/encode-smile tns)
|
||||
;;'generate-smile (copy-var json/generate-smile tns)
|
||||
'decode (copy-var parse-string tns)
|
||||
'parse-string (copy-var parse-string tns)
|
||||
'parse-string-strict (copy-var parse-string-strict tns)
|
||||
'decode (copy-var json/decode tns)
|
||||
'parse-string (copy-var json/parse-string tns)
|
||||
'parse-string-strict (copy-var json/parse-string-strict tns)
|
||||
;;'parse-smile (copy-var json/parse-smile tns)
|
||||
'parse-stream (copy-var parse-stream tns)
|
||||
'parse-stream-strict (copy-var parse-stream-strict tns)
|
||||
'parsed-seq (copy-var parsed-seq tns)
|
||||
'parse-stream (copy-var json/parse-stream tns)
|
||||
'parse-stream-strict (copy-var json/parse-stream-strict tns)
|
||||
'parsed-seq (copy-var json/parsed-seq tns)
|
||||
;;'parsed-smile-seq (copy-var json/parsed-smile-seq tns)
|
||||
;;'decode-smile (copy-var json/decode-smile tns)
|
||||
'default-pretty-print-options (copy-var json/default-pretty-print-options tns)
|
||||
'create-pretty-printer (copy-var json/create-pretty-printer tns)})
|
||||
|
||||
(def cheshire-factory-namespace
|
||||
{'*json-factory* json-factory
|
||||
'default-factory-options (copy-var fact/default-factory-options fns)
|
||||
'json-factory (copy-var fact/json-factory fns)
|
||||
'make-json-factory (copy-var fact/make-json-factory fns)})
|
||||
|
|
|
|||
|
|
@ -128,7 +128,6 @@
|
|||
{:methods [{:name "aget"}
|
||||
{:name "aset"}
|
||||
{:name "aclone"}
|
||||
{:name "iter"}
|
||||
;; we expose this via the Compiler/LOADER dynamic var
|
||||
{:name "baseLoader"}]}
|
||||
clojure.lang.Compiler
|
||||
|
|
@ -224,9 +223,7 @@
|
|||
java.net.http.WebSocket$Listener
|
||||
java.security.cert.X509Certificate
|
||||
java.security.cert.CertificateFactory
|
||||
java.security.Signature
|
||||
javax.crypto.Cipher
|
||||
javax.crypto.KeyAgreement
|
||||
javax.crypto.Mac
|
||||
javax.crypto.SecretKey
|
||||
javax.crypto.SecretKeyFactory
|
||||
|
|
@ -255,10 +252,6 @@
|
|||
jdk.internal.net.http.websocket.BuilderImpl
|
||||
jdk.internal.net.http.websocket.WebSocketImpl])
|
||||
|
||||
(def thread-builder
|
||||
(try (Class/forName "java.lang.Thread$Builder")
|
||||
(catch Exception _ nil)))
|
||||
|
||||
(def classes
|
||||
`{:all [clojure.lang.ArityException
|
||||
clojure.lang.BigInt
|
||||
|
|
@ -344,8 +337,6 @@
|
|||
java.lang.Throwable
|
||||
java.lang.ThreadLocal
|
||||
java.lang.Thread$UncaughtExceptionHandler
|
||||
~@(when thread-builder
|
||||
'[java.lang.Thread$Builder])
|
||||
java.lang.UnsupportedOperationException
|
||||
java.lang.ref.WeakReference
|
||||
java.lang.ref.ReferenceQueue
|
||||
|
|
@ -414,28 +405,21 @@
|
|||
java.nio.file.attribute.BasicFileAttributes
|
||||
java.nio.file.attribute.FileAttribute
|
||||
java.nio.file.attribute.FileTime
|
||||
java.nio.file.attribute.PosixFileAttributes
|
||||
java.nio.file.attribute.PosixFilePermission
|
||||
java.nio.file.attribute.PosixFilePermissions
|
||||
java.nio.file.attribute.UserDefinedFileAttributeView])
|
||||
java.security.DigestInputStream
|
||||
java.security.KeyFactory
|
||||
java.security.KeyPairGenerator
|
||||
java.security.KeyPair
|
||||
java.security.KeyStore
|
||||
java.nio.file.attribute.PosixFilePermissions])
|
||||
java.security.spec.PKCS8EncodedKeySpec
|
||||
java.security.MessageDigest
|
||||
java.security.DigestInputStream
|
||||
java.security.Provider
|
||||
java.security.KeyFactory
|
||||
java.security.KeyStore
|
||||
java.security.SecureRandom
|
||||
java.security.Security
|
||||
java.security.spec.ECGenParameterSpec
|
||||
java.security.spec.PKCS8EncodedKeySpec
|
||||
java.security.spec.X509EncodedKeySpec
|
||||
java.sql.Date
|
||||
java.text.ParseException
|
||||
java.text.ParsePosition
|
||||
;; adds about 200kb, same functionality provided by java.time:
|
||||
java.text.SimpleDateFormat
|
||||
java.text.BreakIterator
|
||||
~@(when features/java-time?
|
||||
`[java.time.format.DateTimeFormatter
|
||||
java.time.Clock
|
||||
|
|
@ -477,12 +461,7 @@
|
|||
java.time.temporal.TemporalAccessor
|
||||
java.time.temporal.TemporalAdjuster
|
||||
java.time.temporal.TemporalQuery
|
||||
~(symbol "[Ljava.time.temporal.TemporalQuery;")
|
||||
java.time.chrono.ChronoLocalDate
|
||||
java.time.temporal.TemporalUnit
|
||||
java.time.chrono.ChronoLocalDateTime
|
||||
java.time.chrono.ChronoZonedDateTime
|
||||
java.time.chrono.Chronology])
|
||||
~(symbol "[Ljava.time.temporal.TemporalQuery;")])
|
||||
java.util.concurrent.atomic.AtomicInteger
|
||||
java.util.concurrent.atomic.AtomicLong
|
||||
java.util.concurrent.atomic.AtomicReference
|
||||
|
|
@ -512,10 +491,6 @@
|
|||
java.util.concurrent.CompletableFuture
|
||||
java.util.concurrent.Executors
|
||||
java.util.concurrent.TimeUnit
|
||||
java.util.concurrent.CompletionStage
|
||||
java.util.concurrent.locks.ReentrantLock
|
||||
java.util.concurrent.ThreadLocalRandom
|
||||
java.util.concurrent.ConcurrentHashMap
|
||||
java.util.jar.Attributes
|
||||
java.util.jar.Attributes$Name
|
||||
java.util.jar.JarFile
|
||||
|
|
@ -530,7 +505,6 @@
|
|||
java.util.Random
|
||||
java.util.regex.Matcher
|
||||
java.util.regex.Pattern
|
||||
java.util.regex.PatternSyntaxException
|
||||
java.util.ArrayDeque
|
||||
java.util.ArrayList
|
||||
java.util.Collections
|
||||
|
|
@ -592,20 +566,7 @@
|
|||
~(symbol "[Ljava.util.regex.Pattern;")
|
||||
~(symbol "[Lclojure.core$range;")])
|
||||
~@(when features/yaml? '[org.yaml.snakeyaml.error.YAMLException])
|
||||
~@(when features/hsqldb? '[org.hsqldb.jdbcDriver])
|
||||
org.jsoup.Jsoup
|
||||
org.jsoup.nodes.Attribute
|
||||
org.jsoup.nodes.Attributes
|
||||
org.jsoup.nodes.Comment
|
||||
org.jsoup.nodes.DataNode
|
||||
org.jsoup.nodes.Document
|
||||
org.jsoup.nodes.DocumentType
|
||||
org.jsoup.nodes.Element
|
||||
org.jsoup.nodes.Node
|
||||
org.jsoup.nodes.TextNode
|
||||
org.jsoup.nodes.XmlDeclaration
|
||||
org.jsoup.parser.Tag
|
||||
org.jsoup.parser.Parser]
|
||||
~@(when features/hsqldb? '[org.hsqldb.jdbcDriver])]
|
||||
:constructors [clojure.lang.Delay
|
||||
clojure.lang.DynamicClassLoader
|
||||
clojure.lang.LineNumberingPushbackReader
|
||||
|
|
@ -655,10 +616,7 @@
|
|||
clojure.lang.Named
|
||||
clojure.lang.Keyword
|
||||
clojure.lang.PersistentArrayMap
|
||||
clojure.lang.PersistentArrayMap$TransientArrayMap
|
||||
clojure.lang.PersistentHashMap$TransientHashMap
|
||||
clojure.lang.PersistentHashSet
|
||||
clojure.lang.PersistentHashSet$TransientHashSet
|
||||
clojure.lang.PersistentList
|
||||
clojure.lang.PersistentList$EmptyList
|
||||
clojure.lang.PersistentQueue
|
||||
|
|
@ -666,7 +624,6 @@
|
|||
clojure.lang.PersistentTreeMap
|
||||
clojure.lang.PersistentTreeSet
|
||||
clojure.lang.PersistentVector
|
||||
clojure.lang.PersistentVector$TransientVector
|
||||
clojure.lang.Range
|
||||
clojure.lang.Ratio
|
||||
clojure.lang.ReaderConditional
|
||||
|
|
@ -685,14 +642,10 @@
|
|||
java.lang.LinkageError
|
||||
java.lang.ThreadDeath
|
||||
java.lang.VirtualMachineError
|
||||
java.lang.NoSuchFieldException
|
||||
java.sql.Timestamp
|
||||
java.util.concurrent.TimeoutException
|
||||
java.util.Collection
|
||||
java.util.Map$Entry
|
||||
java.util.AbstractMap
|
||||
java.util.AbstractSet
|
||||
java.util.AbstractList
|
||||
~@(when features/xml? ['clojure.data.xml.node.Element])]
|
||||
:custom ~custom-map})
|
||||
|
||||
|
|
@ -778,12 +731,8 @@
|
|||
java.net.URLClassLoader
|
||||
(instance? java.lang.ClassLoader v)
|
||||
java.lang.ClassLoader
|
||||
(instance? java.nio.file.attribute.PosixFileAttributes v)
|
||||
java.nio.file.attribute.PosixFileAttributes
|
||||
(instance? java.nio.file.attribute.BasicFileAttributes v)
|
||||
java.nio.file.attribute.BasicFileAttributes
|
||||
(instance? java.nio.file.attribute.UserDefinedFileAttributeView v)
|
||||
java.nio.file.attribute.UserDefinedFileAttributeView
|
||||
(instance? java.util.concurrent.Future v)
|
||||
java.util.concurrent.Future
|
||||
(instance? java.util.concurrent.ScheduledExecutorService v)
|
||||
|
|
@ -806,29 +755,14 @@
|
|||
java.security.cert.X509Certificate
|
||||
(instance? java.io.Console v)
|
||||
java.io.Console
|
||||
(instance? java.security.KeyPairGenerator v)
|
||||
java.security.KeyPairGenerator
|
||||
(instance? java.security.Signature v)
|
||||
java.security.Signature
|
||||
(instance? java.security.Key v)
|
||||
java.security.Key
|
||||
(instance? java.util.Set v)
|
||||
java.util.Set
|
||||
(instance? java.io.Closeable v)
|
||||
java.io.Closeable
|
||||
(instance? java.util.Collection v)
|
||||
java.util.Collection
|
||||
(instance? java.lang.Throwable v)
|
||||
java.lang.Throwable
|
||||
(instance? org.jsoup.nodes.Element v)
|
||||
org.jsoup.nodes.Element
|
||||
(and thread-builder
|
||||
(instance? thread-builder v))
|
||||
thread-builder
|
||||
(instance? java.text.BreakIterator v)
|
||||
java.text.BreakIterator
|
||||
;; keep commas for merge friendliness
|
||||
,)]
|
||||
)]
|
||||
;; (prn :res res)
|
||||
res)))
|
||||
m (assoc m (list 'quote 'clojure.lang.Var) 'sci.lang.Var)
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@
|
|||
cp)))
|
||||
|
||||
(defn resource
|
||||
(^URL [path] (resource path @the-url-loader))
|
||||
(^URL [path loader]
|
||||
(^URL [path] (resource @the-url-loader path))
|
||||
(^URL [loader path]
|
||||
(if (str/starts-with? path "/") nil ;; non-relative paths always return nil
|
||||
(getResource loader [path] true))))
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
(:refer-clojure :exclude [future read+string clojure-version with-precision
|
||||
send-via send send-off sync into-array])
|
||||
(:require [babashka.impl.common :as common]
|
||||
[borkdude.graal.locking :as locking]
|
||||
[clojure.core :as c]
|
||||
[clojure.string :as str]
|
||||
[sci.core :as sci]
|
||||
|
|
@ -11,6 +12,9 @@
|
|||
[sci.impl.utils :refer [clojure-core-ns]]
|
||||
[sci.impl.vars :as vars]))
|
||||
|
||||
(defn locking* [form bindings v f & args]
|
||||
(apply @#'locking/locking form bindings v f args))
|
||||
|
||||
(defn core-dynamic-var
|
||||
([sym] (core-dynamic-var sym nil))
|
||||
([sym init-val] (sci/new-dynamic-var sym init-val {:ns clojure-core-ns})))
|
||||
|
|
@ -144,6 +148,7 @@
|
|||
'file-seq (copy-core-var file-seq)
|
||||
'promise (copy-core-var promise)
|
||||
'deliver (copy-core-var deliver)
|
||||
'locking (macrofy 'locking locking*)
|
||||
'shutdown-agents (copy-core-var shutdown-agents)
|
||||
'slurp (copy-core-var slurp)
|
||||
'spit (copy-core-var spit)
|
||||
|
|
|
|||
|
|
@ -2,39 +2,13 @@
|
|||
{:no-doc true}
|
||||
(:require [clojure.core.async :as async]
|
||||
[clojure.core.async.impl.protocols :as protocols]
|
||||
[clojure.core.async.impl.dispatch :as dispatch]
|
||||
[sci.core :as sci :refer [copy-var]]
|
||||
[sci.impl.copy-vars :refer [macrofy]]
|
||||
[sci.impl.vars :as vars])
|
||||
(:import [java.util.concurrent Executors ExecutorService ThreadFactory]))
|
||||
[sci.impl.vars :as vars]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
#_(def ^java.util.concurrent.Executor executor @#'async/thread-macro-executor)
|
||||
(def executor-for
|
||||
"Given a workload tag, returns an ExecutorService instance and memoizes the result. By
|
||||
default, core.async will defer to a user factory (if provided via sys prop) or construct
|
||||
a specialized ExecutorService instance for each tag :io, :compute, and :mixed. When
|
||||
given the tag :core-async-dispatch it will default to the executor service for :io."
|
||||
(memoize
|
||||
(fn ^ExecutorService [workload]
|
||||
(let [sysprop-factory nil #_(when-let [esf (System/getProperty "clojure.core.async.executor-factory")]
|
||||
(requiring-resolve (symbol esf)))
|
||||
sp-exec (and sysprop-factory (sysprop-factory workload))]
|
||||
(or sp-exec
|
||||
(if (= workload :core-async-dispatch)
|
||||
(executor-for :io)
|
||||
(@#'dispatch/create-default-executor workload)))))))
|
||||
|
||||
(alter-var-root #'dispatch/executor-for (constantly executor-for))
|
||||
|
||||
#_#_(defn exec
|
||||
[^Runnable r workload]
|
||||
(prn :r r :w workload)
|
||||
(let [^ExecutorService e (executor-for workload)]
|
||||
(.execute e r)))
|
||||
|
||||
(alter-var-root #'dispatch/exec (constantly exec))
|
||||
(def ^java.util.concurrent.Executor executor @#'async/thread-macro-executor)
|
||||
|
||||
(def ^java.util.concurrent.Executor virtual-executor
|
||||
(try (eval '(java.util.concurrent.Executors/newVirtualThreadPerTaskExecutor))
|
||||
|
|
@ -43,25 +17,20 @@
|
|||
(defn thread-call
|
||||
"Executes f in another thread, returning immediately to the calling
|
||||
thread. Returns a channel which will receive the result of calling
|
||||
f when completed, then close. workload is a keyword that describes
|
||||
the work performed by f, where:
|
||||
|
||||
:io - may do blocking I/O but must not do extended computation
|
||||
:compute - must not ever block
|
||||
:mixed - anything else (default)
|
||||
|
||||
when workload not supplied, defaults to :mixed"
|
||||
([f] (thread-call f :mixed))
|
||||
([f workload]
|
||||
(let [c (async/chan 1)
|
||||
returning-to-chan (fn [bf]
|
||||
#(try
|
||||
(when-some [ret (bf)]
|
||||
(async/>!! c ret))
|
||||
(finally (async/close! c))))
|
||||
f (vars/binding-conveyor-fn f)]
|
||||
(-> f #_bound-fn* returning-to-chan (dispatch/exec workload))
|
||||
c)))
|
||||
f when completed, then close."
|
||||
[f]
|
||||
(let [c (async/chan 1)]
|
||||
(let [binds (vars/get-thread-binding-frame)]
|
||||
(.execute executor
|
||||
(fn []
|
||||
(vars/reset-thread-binding-frame binds)
|
||||
(try
|
||||
(let [ret (f)]
|
||||
(when-not (nil? ret)
|
||||
(async/>!! c ret)))
|
||||
(finally
|
||||
(async/close! c))))))
|
||||
c))
|
||||
|
||||
(defn -vthread-call
|
||||
"Executes f in another virtual thread, returning immediately to the calling
|
||||
|
|
@ -69,23 +38,21 @@
|
|||
f when completed, then close."
|
||||
[f]
|
||||
(let [c (async/chan 1)]
|
||||
(let [returning-to-chan (fn [bf]
|
||||
#(try
|
||||
(when-some [ret (bf)]
|
||||
(async/>!! c ret))
|
||||
(finally (async/close! c))))
|
||||
f (vars/binding-conveyor-fn f)]
|
||||
(let [binds (vars/get-thread-binding-frame)]
|
||||
(.execute virtual-executor
|
||||
(-> f returning-to-chan)))
|
||||
(fn []
|
||||
(vars/reset-thread-binding-frame binds)
|
||||
(try
|
||||
(let [ret (f)]
|
||||
(when-not (nil? ret)
|
||||
(async/>!! c ret)))
|
||||
(finally
|
||||
(async/close! c))))))
|
||||
c))
|
||||
|
||||
(defn thread
|
||||
[_ _ & body]
|
||||
`(~'clojure.core.async/thread-call (fn [] ~@body) :mixed))
|
||||
|
||||
(defn io-thread
|
||||
[_ _ & body]
|
||||
`(~'clojure.core.async/thread-call (fn [] ~@body) :io))
|
||||
`(~'clojure.core.async/thread-call (fn [] ~@body)))
|
||||
|
||||
(defn -vthread
|
||||
[_ _ & body]
|
||||
|
|
@ -161,7 +128,6 @@
|
|||
'take! (copy-var async/take! core-async-namespace)
|
||||
'tap (copy-var async/tap core-async-namespace)
|
||||
'thread (macrofy 'thread thread core-async-namespace)
|
||||
'io-thread (macrofy 'io-thread io-thread core-async-namespace)
|
||||
'thread-call (copy-var thread-call core-async-namespace)
|
||||
'-vthread-call (copy-var -vthread-call core-async-namespace)
|
||||
'timeout (copy-var timeout core-async-namespace)
|
||||
|
|
|
|||
|
|
@ -118,9 +118,8 @@ by default when a new command-line REPL is started."} repl-requires
|
|||
:file "<repl>"
|
||||
:type :sci/error) e)))))))
|
||||
(catch Throwable e
|
||||
(let [e' (ex-cause e)]
|
||||
(caught e)
|
||||
(set! *e e')))))]
|
||||
(caught e)
|
||||
(set! *e e))))]
|
||||
(with-bindings
|
||||
(try
|
||||
(init)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
{:no-doc true}
|
||||
(:require [clojure.pprint :as pprint]
|
||||
[sci.core :as sci]
|
||||
[sci.pprint]
|
||||
[babashka.impl.clojure.core.async]))
|
||||
[sci.pprint]))
|
||||
|
||||
(defonce patched? (volatile! false))
|
||||
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@
|
|||
edn/read-string)
|
||||
deps (:deps deps)
|
||||
deps (assoc deps
|
||||
'babashka/fs {:mvn/version "0.5.25"}
|
||||
'babashka/fs {:mvn/version "0.5.22"}
|
||||
'babashka/babashka.curl {:mvn/version "0.1.2"}
|
||||
'babashka/babashka.core {:git/url "https://github.com/babashka/babashka.core"
|
||||
:git/sha "52a6037bd4b632bffffb04394fb4efd0cdab6b1e"}
|
||||
'babashka/process {:mvn/version "0.6.23"})
|
||||
'babashka/process {:mvn/version "0.5.22"})
|
||||
deps (dissoc deps
|
||||
'borkdude/sci
|
||||
'org.babashka/sci
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
"Inspired by skip-if-eol from clojure.main."
|
||||
[s]
|
||||
(let [c (r/read-char s)]
|
||||
(when-not (= \newline c )
|
||||
(when-not (= c \newline)
|
||||
(r/unread s c))))
|
||||
|
||||
(defn repl-read [sci-ctx in-stream _request-prompt request-exit]
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
(ns babashka.impl.tools.cli
|
||||
{:no-doc true}
|
||||
(:require [clojure.tools.cli :as tools.cli]
|
||||
[sci.core :as sci :refer [copy-var]]))
|
||||
[sci.core :as sci :refer [copy-var]]
|
||||
[sci.impl.utils :as sciu]))
|
||||
|
||||
(def cli-ns (sci/create-ns 'clojure.tools.cli nil))
|
||||
|
||||
(defn parse-opts [args option-specs & options]
|
||||
(prn :try sciu/*in-try*)
|
||||
(binding [sciu/*in-try* nil]
|
||||
(prn :parse-opts!)
|
||||
(apply tools.cli/parse-opts args option-specs options)))
|
||||
|
||||
(def tools-cli-namespace
|
||||
{'format-lines (copy-var tools.cli/format-lines cli-ns)
|
||||
'summarize (copy-var tools.cli/summarize cli-ns)
|
||||
'get-default-options (copy-var tools.cli/get-default-options cli-ns)
|
||||
'parse-opts (copy-var tools.cli/parse-opts cli-ns)
|
||||
'parse-opts (copy-var parse-opts #_tools.cli/parse-opts cli-ns)
|
||||
'make-summary-part (copy-var tools.cli/make-summary-part cli-ns)})
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
[babashka.deps :as bdeps]
|
||||
[babashka.fs :as fs]
|
||||
[babashka.impl.bencode :refer [bencode-namespace]]
|
||||
[babashka.impl.cheshire :refer [cheshire-core-namespace cheshire-factory-namespace]]
|
||||
[babashka.impl.cheshire :refer [cheshire-core-namespace]]
|
||||
[babashka.impl.classes :as classes :refer [classes-namespace]]
|
||||
[babashka.impl.classpath :as cp :refer [classpath-namespace]]
|
||||
[babashka.impl.cli :as cli]
|
||||
|
|
@ -53,7 +53,6 @@
|
|||
[babashka.impl.server :refer [clojure-core-server-namespace]]
|
||||
[babashka.impl.socket-repl :as socket-repl]
|
||||
[babashka.impl.tasks :as tasks :refer [tasks-namespace]]
|
||||
[babashka.impl.test :as t]
|
||||
[babashka.impl.tools.cli :refer [tools-cli-namespace]]
|
||||
[babashka.impl.uberscript :as uberscript]
|
||||
[babashka.nrepl.server :as nrepl-server]
|
||||
|
|
@ -333,20 +332,20 @@ Use bb run --help to show this help output.
|
|||
|
||||
(def aliases
|
||||
(cond->
|
||||
'{str clojure.string
|
||||
set clojure.set
|
||||
tools.cli clojure.tools.cli
|
||||
edn clojure.edn
|
||||
wait babashka.wait
|
||||
signal babashka.signal
|
||||
shell clojure.java.shell
|
||||
io clojure.java.io
|
||||
json cheshire.core
|
||||
curl babashka.curl
|
||||
fs babashka.fs
|
||||
bencode bencode.core
|
||||
deps babashka.deps
|
||||
async clojure.core.async}
|
||||
'{str clojure.string
|
||||
set clojure.set
|
||||
tools.cli clojure.tools.cli
|
||||
edn clojure.edn
|
||||
wait babashka.wait
|
||||
signal babashka.signal
|
||||
shell clojure.java.shell
|
||||
io clojure.java.io
|
||||
json cheshire.core
|
||||
curl babashka.curl
|
||||
fs babashka.fs
|
||||
bencode bencode.core
|
||||
deps babashka.deps
|
||||
async clojure.core.async}
|
||||
features/xml? (assoc 'xml 'clojure.data.xml)
|
||||
features/yaml? (assoc 'yaml 'clj-yaml.core)
|
||||
features/jdbc? (assoc 'jdbc 'next.jdbc)
|
||||
|
|
@ -366,73 +365,72 @@ Use bb run --help to show this help output.
|
|||
|
||||
(def namespaces
|
||||
(cond->
|
||||
{'user {'*input* (reify
|
||||
sci-types/Eval
|
||||
(eval [_ _ctx _bindings]
|
||||
(force @input-var)))}
|
||||
'clojure.core core-extras
|
||||
'clojure.tools.cli tools-cli-namespace
|
||||
'clojure.java.shell shell-namespace
|
||||
'babashka.core bbcore/core-namespace
|
||||
'babashka.nrepl.server nrepl-server-namespace
|
||||
'babashka.wait wait-namespace
|
||||
'babashka.signal signal-ns
|
||||
'clojure.java.io io-namespace
|
||||
'cheshire.core cheshire-core-namespace
|
||||
'cheshire.factory cheshire-factory-namespace
|
||||
'clojure.data data/data-namespace
|
||||
'clojure.instant instant/instant-namespace
|
||||
'clojure.stacktrace stacktrace-namespace
|
||||
'clojure.zip zip-namespace
|
||||
'clojure.main {:obj clojure-main-ns
|
||||
'demunge (sci/copy-var demunge clojure-main-ns)
|
||||
'repl-requires (sci/copy-var clojure-main/repl-requires clojure-main-ns)
|
||||
'repl (sci/new-var 'repl
|
||||
(fn [& opts]
|
||||
(let [opts (apply hash-map opts)]
|
||||
(repl/start-repl! (common/ctx) opts))) {:ns clojure-main-ns})
|
||||
'with-bindings (sci/copy-var clojure-main/with-bindings clojure-main-ns)
|
||||
'repl-caught (sci/copy-var repl/repl-caught clojure-main-ns)
|
||||
'with-read-known (sci/copy-var clojure-main/with-read-known clojure-main-ns)
|
||||
'main main-var}
|
||||
'clojure.test t/clojure-test-namespace
|
||||
'clojure.math math-namespace
|
||||
'clojure.java.process cjp-namespace
|
||||
'babashka.classpath classpath-namespace
|
||||
'babashka.classes classes-namespace
|
||||
'clojure.pprint pprint-namespace
|
||||
'babashka.curl curl-namespace
|
||||
'babashka.fs fs-namespace
|
||||
'babashka.pods pods/pods-namespace
|
||||
'bencode.core bencode-namespace
|
||||
'clojure.java.browse browse-namespace
|
||||
'clojure.datafy datafy-namespace
|
||||
'clojure.core.protocols protocols-namespace
|
||||
'babashka.process process-namespace
|
||||
'clojure.core.server clojure-core-server-namespace
|
||||
'babashka.deps deps-namespace
|
||||
'babashka.tasks tasks-namespace
|
||||
'clojure.tools.reader.edn edn-namespace
|
||||
'clojure.tools.reader.reader-types reader-types-namespace
|
||||
'clojure.tools.reader reader-namespace
|
||||
'clojure.core.async async-namespace
|
||||
'clojure.core.async.impl.protocols async-protocols-namespace
|
||||
'clojure.reflect reflect-namespace
|
||||
'rewrite-clj.node rewrite/node-namespace
|
||||
'rewrite-clj.paredit rewrite/paredit-namespace
|
||||
'rewrite-clj.parser rewrite/parser-namespace
|
||||
'rewrite-clj.zip rewrite/zip-namespace
|
||||
'rewrite-clj.zip.subedit rewrite/subedit-namespace
|
||||
'clojure.core.rrb-vector (if features/rrb-vector?
|
||||
@(resolve 'babashka.impl.rrb-vector/rrb-vector-namespace)
|
||||
{'catvec (sci/copy-var catvec
|
||||
(sci/create-ns 'clojure.core.rrb-vector))})
|
||||
'edamame.core edamame-namespace
|
||||
'sci.core sci-core-namespace
|
||||
'babashka.cli cli/cli-namespace
|
||||
'babashka.http-client http-client-namespace
|
||||
'babashka.http-client.websocket http-client-websocket-namespace
|
||||
'babashka.http-client.interceptors http-client-interceptors-namespace}
|
||||
{'user {'*input* (reify
|
||||
sci-types/Eval
|
||||
(eval [_ _ctx _bindings]
|
||||
(force @input-var)))}
|
||||
'clojure.core core-extras
|
||||
'clojure.tools.cli tools-cli-namespace
|
||||
'clojure.java.shell shell-namespace
|
||||
'babashka.core bbcore/core-namespace
|
||||
'babashka.nrepl.server nrepl-server-namespace
|
||||
'babashka.wait wait-namespace
|
||||
'babashka.signal signal-ns
|
||||
'clojure.java.io io-namespace
|
||||
'cheshire.core cheshire-core-namespace
|
||||
'clojure.data data/data-namespace
|
||||
'clojure.instant instant/instant-namespace
|
||||
'clojure.stacktrace stacktrace-namespace
|
||||
'clojure.zip zip-namespace
|
||||
'clojure.main {:obj clojure-main-ns
|
||||
'demunge (sci/copy-var demunge clojure-main-ns)
|
||||
'repl-requires (sci/copy-var clojure-main/repl-requires clojure-main-ns)
|
||||
'repl (sci/new-var 'repl
|
||||
(fn [& opts]
|
||||
(let [opts (apply hash-map opts)]
|
||||
(repl/start-repl! (common/ctx) opts))) {:ns clojure-main-ns})
|
||||
'with-bindings (sci/copy-var clojure-main/with-bindings clojure-main-ns)
|
||||
'repl-caught (sci/copy-var repl/repl-caught clojure-main-ns)
|
||||
'with-read-known (sci/copy-var clojure-main/with-read-known clojure-main-ns)
|
||||
'main main-var}
|
||||
;; 'clojure.test t/clojure-test-namespace
|
||||
'clojure.math math-namespace
|
||||
'clojure.java.process cjp-namespace
|
||||
'babashka.classpath classpath-namespace
|
||||
'babashka.classes classes-namespace
|
||||
'clojure.pprint pprint-namespace
|
||||
'babashka.curl curl-namespace
|
||||
'babashka.fs fs-namespace
|
||||
'babashka.pods pods/pods-namespace
|
||||
'bencode.core bencode-namespace
|
||||
'clojure.java.browse browse-namespace
|
||||
'clojure.datafy datafy-namespace
|
||||
'clojure.core.protocols protocols-namespace
|
||||
'babashka.process process-namespace
|
||||
'clojure.core.server clojure-core-server-namespace
|
||||
'babashka.deps deps-namespace
|
||||
'babashka.tasks tasks-namespace
|
||||
'clojure.tools.reader.edn edn-namespace
|
||||
'clojure.tools.reader.reader-types reader-types-namespace
|
||||
'clojure.tools.reader reader-namespace
|
||||
'clojure.core.async async-namespace
|
||||
'clojure.core.async.impl.protocols async-protocols-namespace
|
||||
'clojure.reflect reflect-namespace
|
||||
'rewrite-clj.node rewrite/node-namespace
|
||||
'rewrite-clj.paredit rewrite/paredit-namespace
|
||||
'rewrite-clj.parser rewrite/parser-namespace
|
||||
'rewrite-clj.zip rewrite/zip-namespace
|
||||
'rewrite-clj.zip.subedit rewrite/subedit-namespace
|
||||
'clojure.core.rrb-vector (if features/rrb-vector?
|
||||
@(resolve 'babashka.impl.rrb-vector/rrb-vector-namespace)
|
||||
{'catvec (sci/copy-var catvec
|
||||
(sci/create-ns 'clojure.core.rrb-vector))})
|
||||
'edamame.core edamame-namespace
|
||||
'sci.core sci-core-namespace
|
||||
'babashka.cli cli/cli-namespace
|
||||
'babashka.http-client http-client-namespace
|
||||
'babashka.http-client.websocket http-client-websocket-namespace
|
||||
'babashka.http-client.interceptors http-client-interceptors-namespace}
|
||||
features/xml? (assoc 'clojure.data.xml @(resolve 'babashka.impl.xml/xml-namespace)
|
||||
'clojure.data.xml.event @(resolve 'babashka.impl.xml/xml-event-namespace)
|
||||
'clojure.data.xml.tree @(resolve 'babashka.impl.xml/xml-tree-namespace))
|
||||
|
|
@ -470,7 +468,7 @@ Use bb run --help to show this help output.
|
|||
@(resolve 'babashka.impl.clojure.test.check/test-check-namespace)
|
||||
;; it's better to load this from source by adding the clojure.test.check dependency
|
||||
#_#_'clojure.test.check.clojure-test
|
||||
@(resolve 'babashka.impl.clojure.test.check/test-check-clojure-test-namespace))
|
||||
@(resolve 'babashka.impl.clojure.test.check/test-check-clojure-test-namespace))
|
||||
features/spec-alpha? (-> (assoc ;; spec
|
||||
'clojure.spec.alpha @(resolve 'babashka.impl.spec/spec-namespace)
|
||||
'clojure.spec.gen.alpha @(resolve 'babashka.impl.spec/gen-namespace)
|
||||
|
|
@ -893,10 +891,10 @@ Use bb run --help to show this help output.
|
|||
(let [loader @cp/the-url-loader]
|
||||
(or
|
||||
(when ;; ignore built-in namespaces when uberscripting, unless with :reload
|
||||
(and uberscript
|
||||
(not reload)
|
||||
(or (contains? namespaces namespace)
|
||||
(contains? sci-namespaces/namespaces namespace)))
|
||||
(and uberscript
|
||||
(not reload)
|
||||
(or (contains? namespaces namespace)
|
||||
(contains? sci-namespaces/namespaces namespace)))
|
||||
"")
|
||||
;; pod namespaces go before namespaces from source,
|
||||
;; unless reload is used
|
||||
|
|
@ -1026,7 +1024,7 @@ Use bb run --help to show this help output.
|
|||
(or exit-code
|
||||
(second
|
||||
(cond doc (print-doc sci-ctx command-line-args)
|
||||
repl (sci/binding [core/command-line-args command-line-args]
|
||||
repl (sci/binding [core/command-line-args command-line-args]
|
||||
[(repl/start-repl! sci-ctx) 0])
|
||||
nrepl [(start-nrepl! nrepl) 0]
|
||||
uberjar [nil 0]
|
||||
|
|
@ -1143,20 +1141,20 @@ Use bb run --help to show this help output.
|
|||
|
||||
(defn binary-invoked-as-jar []
|
||||
(and (= "executable" (System/getProperty "org.graalvm.nativeimage.kind"))
|
||||
(when-let [bin (-> (java.lang.ProcessHandle/current)
|
||||
.info
|
||||
.command
|
||||
(.orElse nil))]
|
||||
(let [fn (fs/file-name bin)]
|
||||
(if (= "bb" fn)
|
||||
(let [bin (-> (java.lang.ProcessHandle/current)
|
||||
.info
|
||||
.command
|
||||
.get)
|
||||
fn (fs/file-name bin)]
|
||||
(if (= "bb" fn)
|
||||
false
|
||||
(if (and (fs/windows?)
|
||||
(= "bb.exe" fn))
|
||||
false
|
||||
(if (and (fs/windows?)
|
||||
(= "bb.exe" fn))
|
||||
false
|
||||
(when (try (with-open [_ (java.util.zip.ZipFile. (fs/file bin))])
|
||||
true
|
||||
(catch Exception _ false))
|
||||
bin)))))))
|
||||
(when (try (with-open [_ (java.util.zip.ZipFile. (fs/file bin))])
|
||||
true
|
||||
(catch Exception _ false))
|
||||
bin))))))
|
||||
|
||||
(defn resolve-symbolic-link [f]
|
||||
(if (and f (fs/exists? f))
|
||||
|
|
@ -1190,7 +1188,7 @@ Use bb run --help to show this help output.
|
|||
(println "[babashka] WARNING: config file does not exist:" config))
|
||||
nil))
|
||||
jar (let [jar (resolve-symbolic-link jar)]
|
||||
(some->> [jar] cp/new-loader (cp/resource "META-INF/bb.edn") .toString))
|
||||
(some-> [jar] cp/new-loader (cp/resource "META-INF/bb.edn") .toString))
|
||||
:else (if (and file (fs/exists? file))
|
||||
;; file relative to bb.edn
|
||||
(let [file (abs-path file) ;; follow symlink
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
42
|
||||
|
|
@ -191,30 +191,4 @@
|
|||
prismatic/plumbing {:git-url "https://github.com/plumatic/plumbing",
|
||||
:git-sha "424bc704f2db422de34269c139a5494314b3a43b",
|
||||
:test-namespaces [plumbing.core-test],
|
||||
:test-paths ["test"]}
|
||||
org.clj-commons/hickory {:git-url "https://github.com/clj-commons/hickory"
|
||||
:git-sha "9385b6708ef35f161732d8464b3a3aa57dd79f30"
|
||||
:test-paths ["test/cljc"]
|
||||
:test-namespaces [hickory.test.core
|
||||
hickory.test.convert
|
||||
hickory.test.hiccup-utils
|
||||
hickory.test.render
|
||||
hickory.test.select
|
||||
hickory.test.zip]}
|
||||
cheshire/cheshire {:git-url "https://github.com/dakrone/cheshire", :test-namespaces [cheshire.test.core], :manually-added true}
|
||||
com.potetm/fusebox {:git-url "https://github.com/potetm/fusebox"
|
||||
:git-sha "ac6d6a0a69510b009b3c1bb2247cd110fd9f7246"
|
||||
:test-paths ["test"]
|
||||
:test-namespaces [#_com.potetm.fusebox.bulkhead-test
|
||||
com.potetm.fusebox.bulwark-test
|
||||
com.potetm.fusebox.circuit-breaker-test
|
||||
com.potetm.fusebox.fallback-test
|
||||
com.potetm.fusebox.memoize-test
|
||||
#_com.potetm.fusebox.rate-limit-test
|
||||
com.potetm.fusebox.registry-test
|
||||
com.potetm.fusebox.retry-test
|
||||
#_com.potetm.fusebox.timeout-test]}
|
||||
net.sekao/odoyle-rules {:git-url "https://github.com/oakes/odoyle-rules"
|
||||
:git-sha "0b1d825ec45a998c4d3481dfb292e08ce6a47f0b"
|
||||
:test-paths ["test"]
|
||||
:test-namespaces [odoyle.rules-test]}}
|
||||
:test-paths ["test"]}}
|
||||
|
|
|
|||
|
|
@ -1,793 +0,0 @@
|
|||
(ns cheshire.test.core
|
||||
(:require [clojure.test :refer [deftest testing is are]]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.string :as str]
|
||||
[cheshire.core :as json]
|
||||
;; BB-TEST-PATCH: bb does not include cheshire.exact
|
||||
#_[cheshire.exact :as json-exact]
|
||||
;; BB-TEST-PATCH: bb does not include cheshire.gen
|
||||
#_[cheshire.generate :as gen]
|
||||
[cheshire.factory :as fact]
|
||||
;; BB-TEST-PATCH: bb does not include cheshire.parse
|
||||
#_[cheshire.parse :as parse])
|
||||
(:import ;; BB-TEST-PATCH: tests adjusted to check for general Exception instead of specific jackson exceptions
|
||||
#_(com.fasterxml.jackson.core JsonGenerationException
|
||||
JsonParseException)
|
||||
#_(com.fasterxml.jackson.core.exc StreamConstraintsException)
|
||||
(java.io StringReader StringWriter
|
||||
BufferedReader BufferedWriter
|
||||
IOException)
|
||||
;; BB-TEST-PATCH: bb does not support creating java.sql.Timestamps
|
||||
#_(java.sql Timestamp)
|
||||
(java.util Date UUID)))
|
||||
|
||||
(defn- str-of-len
|
||||
([len]
|
||||
(str-of-len len "x"))
|
||||
([len val]
|
||||
(apply str (repeat len val))))
|
||||
|
||||
(defn- nested-map [depth]
|
||||
(reduce (fn [acc n] {(str n) acc})
|
||||
{"0" "foo"}
|
||||
(range 1 depth)))
|
||||
|
||||
(defn- encode-stream->str [obj opts]
|
||||
(let [sw (StringWriter.)
|
||||
bw (BufferedWriter. sw)]
|
||||
(json/generate-stream obj bw opts)
|
||||
(.toString sw)))
|
||||
|
||||
(def test-obj {"int" 3 "long" (long -2147483647) "boolean" true
|
||||
"LongObj" (Long/parseLong "2147483647") "double" 1.23
|
||||
"nil" nil "string" "string" "vec" [1 2 3] "map" {"a" "b"}
|
||||
"list" (list "a" "b") "short" (short 21) "byte" (byte 3)})
|
||||
|
||||
(deftest t-ratio
|
||||
(let [n 1/2]
|
||||
(is (= (double n) (:num (json/decode (json/encode {:num n}) true))))))
|
||||
|
||||
(deftest t-long-wrap-around
|
||||
(is (= 2147483648 (json/decode (json/encode 2147483648)))))
|
||||
|
||||
(deftest t-bigint
|
||||
(let [n 9223372036854775808]
|
||||
(is (= n (:num (json/decode (json/encode {:num n}) true))))))
|
||||
|
||||
(deftest t-biginteger
|
||||
(let [n (BigInteger. "42")]
|
||||
(is (= n (:num (json/decode (json/encode {:num n}) true))))))
|
||||
|
||||
(deftest t-bigdecimal
|
||||
(let [n (BigDecimal. "42.5")]
|
||||
(is (= (.doubleValue n) (:num (json/decode (json/encode {:num n}) true))))
|
||||
;; BB-TEST-PATCH:
|
||||
#_(binding [parse/*use-bigdecimals?* true]
|
||||
(is (= n (:num (json/decode (json/encode {:num n}) true)))))))
|
||||
|
||||
(deftest test-string-round-trip
|
||||
(is (= test-obj (json/decode (json/encode test-obj)))))
|
||||
|
||||
(deftest test-generate-accepts-float
|
||||
(is (= "3.14" (json/encode 3.14))))
|
||||
|
||||
(deftest test-keyword-encode
|
||||
(is (= {"key" "val"}
|
||||
(json/decode (json/encode {:key "val"})))))
|
||||
|
||||
(deftest test-generate-set
|
||||
(is (= {"set" ["a" "b"]}
|
||||
(json/decode (json/encode {"set" #{"a" "b"}})))))
|
||||
|
||||
(deftest test-generate-empty-set
|
||||
(is (= {"set" []}
|
||||
(json/decode (json/encode {"set" #{}})))))
|
||||
|
||||
(deftest test-generate-empty-array
|
||||
(is (= {"array" []}
|
||||
(json/decode (json/encode {"array" []})))))
|
||||
|
||||
(deftest test-key-coercion
|
||||
(is (= {"foo" "bar" "1" "bat" "2" "bang" "3" "biz"}
|
||||
(json/decode
|
||||
(json/encode
|
||||
{:foo "bar" 1 "bat" (long 2) "bang" (bigint 3) "biz"})))))
|
||||
|
||||
(deftest test-keywords
|
||||
(is (= {:foo "bar" :bat 1}
|
||||
(json/decode (json/encode {:foo "bar" :bat 1}) true))))
|
||||
|
||||
(deftest test-symbols
|
||||
(is (= {"foo" "clojure.core/map"}
|
||||
(json/decode (json/encode {"foo" 'clojure.core/map})))))
|
||||
|
||||
(deftest test-accepts-java-map
|
||||
(is (= {"foo" 1}
|
||||
(json/decode
|
||||
(json/encode (doto (java.util.HashMap.) (.put "foo" 1)))))))
|
||||
|
||||
(deftest test-accepts-java-list
|
||||
(is (= [1 2 3]
|
||||
(json/decode (json/encode (doto (java.util.ArrayList. 3)
|
||||
(.add 1)
|
||||
(.add 2)
|
||||
(.add 3)))))))
|
||||
|
||||
(deftest test-accepts-java-set
|
||||
(is (= {"set" [1 2 3]}
|
||||
(json/decode (json/encode {"set" (doto (java.util.HashSet. 3)
|
||||
(.add 1)
|
||||
(.add 2)
|
||||
(.add 3))})))))
|
||||
|
||||
(deftest test-accepts-empty-java-set
|
||||
(is (= {"set" []}
|
||||
(json/decode (json/encode {"set" (java.util.HashSet. 3)})))))
|
||||
|
||||
(deftest test-nil
|
||||
(is (nil? (json/decode nil true))))
|
||||
|
||||
(deftest test-parsed-seq
|
||||
(let [br (BufferedReader. (StringReader. "1\n2\n3\n"))]
|
||||
(is (= (list 1 2 3) (json/parsed-seq br)))))
|
||||
|
||||
;; BB-TEST-PATCH: bb does not support smile
|
||||
#_(deftest test-smile-round-trip
|
||||
(is (= test-obj (json/parse-smile (json/generate-smile test-obj)))))
|
||||
|
||||
(def bin-obj {"byte-array" (byte-array (map byte [1 2 3]))})
|
||||
|
||||
;; BB-TEST-PATCH: bb does not support smile/cbor
|
||||
#_(deftest test-round-trip-binary
|
||||
(doseq [[p g] {json/parse-string json/generate-string
|
||||
json/parse-smile json/generate-smile
|
||||
json/parse-cbor json/generate-cbor}]
|
||||
(is (let [roundtripped (p (g bin-obj))]
|
||||
;; test value equality
|
||||
(is (= (->> bin-obj (get "byte-array") seq)
|
||||
(->> roundtripped (get "byte-array") seq)))))))
|
||||
|
||||
;; BB-TEST-PATCH: bb does not support smile
|
||||
#_(deftest test-smile-factory
|
||||
(binding [fact/*smile-factory* (fact/make-smile-factory {})]
|
||||
(is (= {"a" 1} (-> {:a 1}
|
||||
json/generate-smile
|
||||
json/parse-smile)))))
|
||||
|
||||
;; BB-TEST-PATCH: bb does not support smile/cbor
|
||||
#_(deftest test-smile-duplicate-detection
|
||||
(let [smile-data (byte-array [0x3a 0x29 0x0a 0x01 ;; smile header
|
||||
0xFa ;; object start
|
||||
0x80 0x61 ;; key a
|
||||
0xC2 ;; value 1
|
||||
0x80 0x61 ;; key a (again)
|
||||
0xC4 ;; value 2
|
||||
0xFB ;; object end
|
||||
])]
|
||||
(binding [fact/*smile-factory* (fact/make-smile-factory {:strict-duplicate-detection false})]
|
||||
(is (= {"a" 2} (json/parse-smile smile-data))))
|
||||
(binding [fact/*smile-factory* (fact/make-smile-factory {:strict-duplicate-detection true})]
|
||||
(is (thrown? JsonParseException (json/parse-smile smile-data))))))
|
||||
|
||||
;; BB-TEST-PATCH: bb does not support cbor
|
||||
#_(deftest test-cbor-factory
|
||||
(binding [fact/*cbor-factory* (fact/make-cbor-factory {})]
|
||||
(is (= {"a" 1} (-> {:a 1}
|
||||
json/generate-cbor
|
||||
json/parse-cbor)))))
|
||||
|
||||
;; BB-TEST-PATCH: bb does not support cbor
|
||||
#_(deftest test-cbor-duplicate-detection
|
||||
(let [cbor-data (byte-array [0xbf ;; object begin
|
||||
0x61 0x61 ;; key a
|
||||
0x01 ;; value 1
|
||||
0x61 0x61 ;; key a (again)
|
||||
0x02 ;; value 2
|
||||
0xff ;; object end
|
||||
])]
|
||||
(binding [fact/*cbor-factory* (fact/make-cbor-factory {:strict-duplicate-detection false})]
|
||||
(is (= {"a" 2} (json/parse-cbor cbor-data))))
|
||||
(binding [fact/*cbor-factory* (fact/make-cbor-factory {:strict-duplicate-detection true})]
|
||||
(is (thrown? JsonParseException (json/parse-cbor cbor-data))))))
|
||||
|
||||
(deftest test-aliases
|
||||
(is (= {"foo" "bar" "1" "bat" "2" "bang" "3" "biz"}
|
||||
(json/decode
|
||||
(json/encode
|
||||
{:foo "bar" 1 "bat" (long 2) "bang" (bigint 3) "biz"})))))
|
||||
|
||||
(deftest test-date
|
||||
(is (= {"foo" "1970-01-01T00:00:00Z"}
|
||||
(json/decode (json/encode {:foo (Date. (long 0))}))))
|
||||
(is (= {"foo" "1970-01-01"}
|
||||
(json/decode (json/encode {:foo (Date. (long 0))}
|
||||
{:date-format "yyyy-MM-dd"})))
|
||||
"encode with given date format"))
|
||||
|
||||
;; BB-TEST-PATCH: bb does not support creating java.sql.Timestamps
|
||||
#_(deftest test-sql-timestamp
|
||||
(is (= {"foo" "1970-01-01T00:00:00Z"}
|
||||
(json/decode (json/encode {:foo (Timestamp. (long 0))}))))
|
||||
(is (= {"foo" "1970-01-01"}
|
||||
(json/decode (json/encode {:foo (Timestamp. (long 0))}
|
||||
{:date-format "yyyy-MM-dd"})))
|
||||
"encode with given date format"))
|
||||
|
||||
(deftest test-uuid
|
||||
(let [id (UUID/randomUUID)
|
||||
id-str (str id)]
|
||||
(is (= {"foo" id-str} (json/decode (json/encode {:foo id}))))))
|
||||
|
||||
(deftest test-char-literal
|
||||
(is (= "{\"foo\":\"a\"}" (json/encode {:foo \a}))))
|
||||
|
||||
(deftest test-streams
|
||||
(testing "parse-stream"
|
||||
(are [parsed parse parsee] (= parsed
|
||||
(parse (BufferedReader. (StringReader. parsee))))
|
||||
{"foo" "bar"} json/parse-stream "{\"foo\":\"bar\"}\n"
|
||||
{"foo" "bar"} json/parse-stream-strict "{\"foo\":\"bar\"}\n")
|
||||
|
||||
(are [parsed parse parsee] (= parsed
|
||||
(with-open [rdr (StringReader. parsee)]
|
||||
(parse rdr true)))
|
||||
{(keyword "foo baz") "bar"} json/parse-stream "{\"foo baz\":\"bar\"}\n"
|
||||
{(keyword "foo baz") "bar"} json/parse-stream-strict "{\"foo baz\":\"bar\"}\n"))
|
||||
|
||||
(testing "generate-stream"
|
||||
(let [sw (StringWriter.)
|
||||
bw (BufferedWriter. sw)]
|
||||
(json/generate-stream {"foo" "bar"} bw)
|
||||
(is (= "{\"foo\":\"bar\"}" (.toString sw))))))
|
||||
|
||||
;; BB-TEST-PATCH: bb does not include with-writer
|
||||
#_(deftest serial-writing
|
||||
(is (= "[\"foo\",\"bar\"]"
|
||||
(.toString
|
||||
(json/with-writer [(StringWriter.) nil]
|
||||
(json/write [] :start)
|
||||
(json/write "foo")
|
||||
(json/write "bar")
|
||||
(json/write [] :end)))))
|
||||
(is (= "[1,[2,3],4]"
|
||||
(.toString
|
||||
(json/with-writer [(StringWriter.) nil]
|
||||
(json/write [1 [2]] :start-inner)
|
||||
(json/write 3)
|
||||
(json/write [] :end)
|
||||
(json/write 4)
|
||||
(json/write [] :end)))))
|
||||
(is (= "{\"a\":1,\"b\":2,\"c\":3}"
|
||||
(.toString
|
||||
(json/with-writer [(StringWriter.) nil]
|
||||
(json/write {:a 1} :start)
|
||||
(json/write {:b 2} :bare)
|
||||
(json/write {:c 3} :end)))))
|
||||
(is (= (str "[\"start\",\"continue\",[\"implicitly-nested\"],"
|
||||
"[\"explicitly-nested\"],\"flatten\",\"end\"]")
|
||||
(.toString
|
||||
(json/with-writer [(StringWriter.) nil]
|
||||
(json/write ["start"] :start)
|
||||
(json/write "continue")
|
||||
(json/write ["implicitly-nested"])
|
||||
(json/write ["explicitly-nested"] :all)
|
||||
(json/write ["flatten"] :bare)
|
||||
(json/write ["end"] :end)))))
|
||||
(is (= "{\"head\":\"head info\",\"data\":[1,2,3],\"tail\":\"tail info\"}"
|
||||
(.toString
|
||||
(json/with-writer [(StringWriter.) nil]
|
||||
(json/write {:head "head info" :data []} :start-inner)
|
||||
(json/write 1)
|
||||
(json/write 2)
|
||||
(json/write 3)
|
||||
(json/write [] :end)
|
||||
(json/write {:tail "tail info"} :end))))))
|
||||
|
||||
;; BB-TEST-PATCH: modified so that json files could be found
|
||||
(deftest test-multiple-objs-in-file
|
||||
(is (= {"one" 1, "foo" "bar"}
|
||||
(first (json/parsed-seq (io/reader (io/resource "cheshire/test/multi.json"))))))
|
||||
(is (= {"two" 2, "foo" "bar"}
|
||||
(second (json/parsed-seq (io/reader (io/resource "cheshire/test/multi.json"))))))
|
||||
(with-open [r (io/reader (io/resource "cheshire/test/multi.json"))]
|
||||
(is (= [{"one" 1, "foo" "bar"} {"two" 2, "foo" "bar"}]
|
||||
(json/parsed-seq r)))))
|
||||
|
||||
(deftest test-jsondotorg-pass1
|
||||
(let [;; BB-TEST-PATCH: modified so that json files could be found
|
||||
string (slurp (io/resource "cheshire/test/pass1.json"))
|
||||
decoded-json (json/decode string)
|
||||
encoded-json (json/encode decoded-json)
|
||||
re-decoded-json (json/decode encoded-json)]
|
||||
(is (= decoded-json re-decoded-json))))
|
||||
|
||||
(deftest test-namespaced-keywords
|
||||
(is (= "{\"foo\":\"user/bar\"}"
|
||||
(json/encode {:foo :user/bar})))
|
||||
(is (= {:foo/bar "baz/eggplant"}
|
||||
(json/decode (json/encode {:foo/bar :baz/eggplant}) true))))
|
||||
|
||||
(deftest test-array-coerce-fn
|
||||
(is (= {"set" #{"a" "b"} "array" ["a" "b"] "map" {"a" 1}}
|
||||
(json/decode
|
||||
(json/encode {"set" #{"a" "b"} "array" ["a" "b"] "map" {"a" 1}}) false
|
||||
(fn [field-name] (if (= "set" field-name) #{} []))))))
|
||||
|
||||
(deftest t-symbol-encoding-for-non-resolvable-symbols
|
||||
(is (= "{\"bar\":\"clojure.core/pam\",\"foo\":\"clojure.core/map\"}"
|
||||
(json/encode (sorted-map :foo 'clojure.core/map :bar 'clojure.core/pam))))
|
||||
(is (= "{\"bar\":\"clojure.core/pam\",\"foo\":\"foo.bar/baz\"}"
|
||||
(json/encode (sorted-map :foo 'foo.bar/baz :bar 'clojure.core/pam)))))
|
||||
|
||||
(deftest t-bindable-factories-auto-close-source
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:auto-close-source false})]
|
||||
(let [br (BufferedReader. (StringReader. "123"))]
|
||||
(is (= 123 (json/parse-stream br)))
|
||||
(is (= -1 (.read br)))))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:auto-close-source true})]
|
||||
(let [br (BufferedReader. (StringReader. "123"))]
|
||||
(is (= 123 (json/parse-stream br)))
|
||||
(is (thrown? IOException (.read br))))))
|
||||
|
||||
(deftest t-bindable-factories-allow-comments
|
||||
(let [s "{\"a\": /* comment */ 1, // comment\n \"b\": 2}"]
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:allow-comments true})]
|
||||
(is (= {"a" 1 "b" 2} (json/decode s))))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:allow-comments false})]
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
(is (thrown? #_JsonParseException Exception (json/decode s))))))
|
||||
|
||||
(deftest t-bindable-factories-allow-unquoted-field-names
|
||||
(let [s "{a: 1, b: 2}"]
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:allow-unquoted-field-names true})]
|
||||
(is (= {"a" 1 "b" 2} (json/decode s))))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:allow-unquoted-field-names false})]
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
(is (thrown? #_JsonParseException Exception (json/decode s))))))
|
||||
|
||||
(deftest t-bindable-factories-allow-single-quotes
|
||||
(doseq [s ["{'a': \"one\", 'b': \"two\"}"
|
||||
"{\"a\": 'one', \"b\": 'two'}"
|
||||
"{'a': 'one', 'b': 'two'}"]]
|
||||
(testing s
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:allow-single-quotes true})]
|
||||
(is (= {"a" "one" "b" "two"} (json/decode s))))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:allow-single-quotes false})]
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
(is (thrown? #_JsonParseException Exception (json/decode s)))))))
|
||||
|
||||
(deftest t-bindable-factories-allow-unquoted-control-chars
|
||||
(let [s "{\"a\": \"one\ntwo\"}"]
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:allow-unquoted-control-chars true})]
|
||||
(is (= {"a" "one\ntwo"} (json/decode s))))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:allow-unquoted-control-chars false})]
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
(is (thrown? #_JsonParseException Exception (json/decode s))))))
|
||||
|
||||
(deftest t-bindable-factories-allow-backslash-escaping-any-char
|
||||
(let [s "{\"a\": 00000000001}"]
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:allow-numeric-leading-zeros true})]
|
||||
(is (= {"a" 1} (json/decode s))))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:allow-numeric-leading-zeros false})]
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
(is (thrown? #_JsonParseException Exception (json/decode s))))))
|
||||
|
||||
(deftest t-bindable-factories-allow-numeric-leading-zeros
|
||||
(let [s "{\"a\": \"\\o\\n\\e\"}"]
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:allow-backslash-escaping true})]
|
||||
(is (= {"a" "o\ne"} (json/decode s))))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:allow-backslash-escaping false})]
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
(is (thrown? #_JsonParseException Exception (json/decode s))))))
|
||||
|
||||
(deftest t-bindable-factories-non-numeric-numbers
|
||||
(let [s "{\"foo\":NaN}"]
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:allow-non-numeric-numbers true})]
|
||||
(is (= (type Double/NaN)
|
||||
(type (:foo (json/decode s true))))))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:allow-non-numeric-numbers false})]
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
(is (thrown? #_JsonParseException Exception (json/decode s true))))))
|
||||
|
||||
(deftest t-bindable-factories-optimization-opts
|
||||
(let [s "{\"a\": \"foo\"}"]
|
||||
(doseq [opts [{:intern-field-names true}
|
||||
{:intern-field-names false}
|
||||
{:canonicalize-field-names true}
|
||||
{:canonicalize-field-names false}]]
|
||||
(binding [fact/*json-factory* (fact/make-json-factory opts)]
|
||||
(is (= {"a" "foo"} (json/decode s)))))))
|
||||
|
||||
(deftest t-bindable-factories-escape-non-ascii
|
||||
;; includes testing legacy fn opt of same name can override factory
|
||||
(let [edn {:foo "It costs £100"}
|
||||
expected-esc "{\"foo\":\"It costs \\u00A3100\"}"
|
||||
expected-no-esc "{\"foo\":\"It costs £100\"}"
|
||||
opt-esc {:escape-non-ascii true}
|
||||
opt-no-esc {:escape-non-ascii false}]
|
||||
(testing "default factory"
|
||||
(doseq [[fn-opts expected]
|
||||
[[{} expected-no-esc]
|
||||
[opt-esc expected-esc]
|
||||
[opt-no-esc expected-no-esc]]]
|
||||
(testing fn-opts
|
||||
(is (= expected (json/encode edn fn-opts) (encode-stream->str edn fn-opts))))))
|
||||
(testing (str "factory: " opt-esc)
|
||||
(binding [fact/*json-factory* (fact/make-json-factory opt-esc)]
|
||||
(doseq [[fn-opts expected]
|
||||
[[{} expected-esc]
|
||||
[opt-esc expected-esc]
|
||||
[opt-no-esc expected-no-esc]]]
|
||||
(testing (str "fn: " fn-opts)
|
||||
(is (= expected (json/encode edn fn-opts) (encode-stream->str edn fn-opts)))))))
|
||||
(testing (str "factory: " opt-no-esc)
|
||||
(binding [fact/*json-factory* (fact/make-json-factory opt-no-esc)]
|
||||
(doseq [[fn-opts expected]
|
||||
[[{} expected-no-esc]
|
||||
[opt-esc expected-esc]
|
||||
[opt-no-esc expected-no-esc]]]
|
||||
(testing (str "fn: " fn-opts)
|
||||
(is (= expected (json/encode edn fn-opts) (encode-stream->str edn fn-opts)))))))))
|
||||
|
||||
(deftest t-bindable-factories-quoteless
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:quote-field-names true})]
|
||||
(is (= "{\"a\":\"foo\"}" (json/encode {:a "foo"}))))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:quote-field-names false})]
|
||||
(is (= "{a:\"foo\"}" (json/encode {:a "foo"})))))
|
||||
|
||||
(deftest t-bindable-factories-strict-duplicate-detection
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:strict-duplicate-detection true})]
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
(is (thrown? #_ JsonParseException Exception
|
||||
(json/decode "{\"a\": 1, \"b\": 2, \"a\": 3}"))))
|
||||
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:strict-duplicate-detection false})]
|
||||
(is (= {"a" 3 "b" 2}
|
||||
(json/decode "{\"a\": 1, \"b\": 2, \"a\": 3}")))))
|
||||
|
||||
(deftest t-bindable-factories-max-input-document-length
|
||||
(let [edn {"a" (apply str (repeat 10000 "x"))}
|
||||
sample-data (json/encode edn)]
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:max-input-document-length (count sample-data)})]
|
||||
(is (= edn (json/decode sample-data))))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
;; as per Jackson docs, limit is inexact, so dividing input length by 2 should do the trick
|
||||
{:max-input-document-length (/ (count sample-data) 2)})]
|
||||
(is (thrown-with-msg?
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
#_StreamConstraintsException Exception #"(?i)document length .* exceeds"
|
||||
(json/decode sample-data))))))
|
||||
|
||||
(deftest t-bindable-factories-max-input-token-count
|
||||
;; A token is a single unit of input, such as a number, a string, an object start or end, or an array start or end.
|
||||
(let [edn {"1" 2 "3" 4}
|
||||
sample-data (json/encode edn)]
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:max-input-token-count 6})]
|
||||
(is (= edn (json/decode sample-data))))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:max-input-token-count 5})]
|
||||
(is (thrown-with-msg?
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
#_StreamConstraintsException Exception #"(?i)token count .* exceeds"
|
||||
(json/decode sample-data))))))
|
||||
|
||||
(deftest t-bindable-factories-max-input-name-length
|
||||
(let [k "somekey"
|
||||
edn {k 1}
|
||||
sample-data (json/encode edn)]
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:max-input-name-length (count k)})]
|
||||
(is (= edn (json/decode sample-data))))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:max-input-name-length (dec (count k))})]
|
||||
(is (thrown-with-msg?
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
#_StreamConstraintsException Exception #"(?i)name .* exceeds"
|
||||
(json/decode sample-data)))))
|
||||
(let [default-limit (:max-input-name-length fact/default-factory-options)]
|
||||
(let [k (str-of-len default-limit)
|
||||
edn {k 1}
|
||||
sample-data (json/encode edn)]
|
||||
(is (= edn (json/decode sample-data))))
|
||||
(let [k (str-of-len (inc default-limit))
|
||||
sample-data (json/encode {k 1})]
|
||||
(is (thrown-with-msg?
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
#_StreamConstraintsException Exception #"(?i)name .* exceeds"
|
||||
(json/decode sample-data))))))
|
||||
|
||||
(deftest t-bindable-factories-input-nesting-depth
|
||||
(let [edn (nested-map 100)
|
||||
sample-data (json/encode edn)]
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:max-input-nesting-depth 100})]
|
||||
(is (= edn (json/decode sample-data))))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:max-input-nesting-depth 99})]
|
||||
(is (thrown-with-msg?
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
#_StreamConstraintsException Exception #"(?i)nesting depth .* exceeds"
|
||||
(json/decode sample-data))))))
|
||||
|
||||
(deftest t-bindable-factories-max-input-number-length
|
||||
(let [num 123456789
|
||||
edn {"foo" num}
|
||||
sample-data (json/encode edn)]
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:max-input-number-length (-> num str count)})]
|
||||
(is (= edn (json/decode sample-data))))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:max-input-number-length (-> num str count dec)})]
|
||||
(is (thrown-with-msg?
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
#_StreamConstraintsException Exception #"(?i)number value length .* exceeds"
|
||||
(json/decode sample-data)))))
|
||||
(let [default-limit (:max-input-number-length fact/default-factory-options)]
|
||||
(let [num (bigint (str-of-len default-limit 2))
|
||||
edn {"foo" num}
|
||||
sample-data (json/encode edn)]
|
||||
(is (= edn (json/decode sample-data))))
|
||||
(let [num (bigint (str-of-len (inc default-limit) 2))
|
||||
sample-data (json/encode {"foo" num})]
|
||||
(is (thrown-with-msg?
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
#_StreamConstraintsException Exception #"(?i)number value length .* exceeds"
|
||||
(json/decode sample-data))))))
|
||||
|
||||
(deftest t-bindable-factories-max-input-string-length
|
||||
(let [big-string (str-of-len 40000000)
|
||||
edn {"big-string" big-string}
|
||||
sample-data (json/encode edn)]
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:max-input-string-length (count big-string)})]
|
||||
(is (= edn (json/decode sample-data))))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:max-input-string-length (dec (count big-string))})]
|
||||
(is (thrown-with-msg?
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
#_StreamConstraintsException Exception #"(?i)string value length .* exceeds"
|
||||
(json/decode sample-data)))))
|
||||
(let [default-limit (:max-input-string-length fact/default-factory-options)]
|
||||
(let [big-string (str-of-len default-limit)
|
||||
edn {"big-string" big-string}
|
||||
sample-data (json/encode edn)]
|
||||
(is (= edn (json/decode sample-data))))
|
||||
(let [big-string (str-of-len (inc default-limit))
|
||||
sample-data (json/encode {"big-string" big-string})]
|
||||
(is (thrown-with-msg?
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
#_StreamConstraintsException Exception #"(?i)string value length .* exceeds"
|
||||
(json/decode sample-data))))))
|
||||
|
||||
(deftest t-bindable-factories-max-output-nesting-depth
|
||||
(let [edn (nested-map 100)]
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:max-output-nesting-depth 100})]
|
||||
(is (.contains (json/encode edn) "\"99\"")))
|
||||
(binding [fact/*json-factory* (fact/make-json-factory
|
||||
{:max-output-nesting-depth 99})]
|
||||
(is (thrown-with-msg?
|
||||
;; BB-TEST-PATCH: Generalized exception check
|
||||
#_StreamConstraintsException Exception #"(?i)nesting depth .* exceeds"
|
||||
(json/encode edn))))))
|
||||
|
||||
(deftest t-persistent-queue
|
||||
(let [q (conj clojure.lang.PersistentQueue/EMPTY 1 2 3)]
|
||||
(is (= q (json/decode (json/encode q))))))
|
||||
|
||||
(deftest t-pretty-print
|
||||
(is (= (str/join (System/lineSeparator)
|
||||
["{"
|
||||
" \"bar\" : [ {"
|
||||
" \"baz\" : 2"
|
||||
" }, \"quux\", [ 1, 2, 3 ] ],"
|
||||
" \"foo\" : 1"
|
||||
"}"])
|
||||
(json/encode (sorted-map :foo 1 :bar [{:baz 2} :quux [1 2 3]])
|
||||
{:pretty true}))))
|
||||
|
||||
(deftest t-pretty-print-custom-linebreak
|
||||
(is (= (str/join "foo"
|
||||
["{"
|
||||
" \"bar\" : [ {"
|
||||
" \"baz\" : 2"
|
||||
" }, \"quux\", [ 1, 2, 3 ] ],"
|
||||
" \"foo\" : 1"
|
||||
"}"])
|
||||
(json/encode (sorted-map :foo 1 :bar [{:baz 2} :quux [1 2 3]])
|
||||
{:pretty {:line-break "foo"}}))))
|
||||
|
||||
(deftest t-pretty-print-illegal-argument
|
||||
; just expecting this not to throw
|
||||
(json/encode {:foo "bar"}
|
||||
{:pretty []})
|
||||
(json/encode {:foo "bar"}
|
||||
{:pretty nil}))
|
||||
|
||||
(deftest t-custom-pretty-print-with-defaults
|
||||
(let [test-obj (sorted-map :foo 1 :bar {:baz [{:ulu "mulu"} {:moot "foo"} 3]} :quux :blub)
|
||||
pretty-str-default (json/encode test-obj {:pretty true})
|
||||
pretty-str-custom (json/encode test-obj {:pretty {}})]
|
||||
(is (= pretty-str-default pretty-str-custom))
|
||||
(when-not (= pretty-str-default pretty-str-custom)
|
||||
; print for easy comparison
|
||||
(println "; default pretty print")
|
||||
(println pretty-str-default)
|
||||
(println "; custom pretty print with default options")
|
||||
(println pretty-str-custom))))
|
||||
|
||||
(deftest t-custom-pretty-print-with-non-defaults
|
||||
(let [test-obj (sorted-map :foo 1 :bar {:baz [{:ulu "mulu"} {:moot "foo"} 3]} :quux :blub)
|
||||
test-opts {:pretty {:indentation 4
|
||||
:indent-arrays? false
|
||||
:before-array-values ""
|
||||
:after-array-values ""
|
||||
:object-field-value-separator ": "}}
|
||||
expected (str/join (System/lineSeparator)
|
||||
["{"
|
||||
" \"bar\": {"
|
||||
" \"baz\": [{"
|
||||
" \"ulu\": \"mulu\""
|
||||
" }, {"
|
||||
" \"moot\": \"foo\""
|
||||
" }, 3]"
|
||||
" },"
|
||||
" \"foo\": 1,"
|
||||
" \"quux\": \"blub\""
|
||||
"}"])
|
||||
pretty-str (json/encode test-obj test-opts)]
|
||||
|
||||
; just to be easy on the eyes in case of error
|
||||
(when-not (= expected pretty-str)
|
||||
(println "; pretty print with options - actual")
|
||||
(println pretty-str)
|
||||
(println "; pretty print with options - expected")
|
||||
(println expected))
|
||||
(is (= expected pretty-str))))
|
||||
|
||||
(deftest t-custom-pretty-print-with-noident-objects
|
||||
(let [test-obj [{:foo 1 :bar 2} {:foo 3 :bar 4}]
|
||||
test-opts {:pretty {:indent-objects? false}}
|
||||
expected (str "[ { \"foo\" : 1, \"bar\" : 2 }, "
|
||||
"{ \"foo\" : 3, \"bar\" : 4 } ]")
|
||||
pretty-str (json/encode test-obj test-opts)]
|
||||
; just to be easy on the eyes in case of error
|
||||
(when-not (= expected pretty-str)
|
||||
(println "; pretty print with options - actual")
|
||||
(println pretty-str)
|
||||
(println "; pretty print with options - expected")
|
||||
(println expected))
|
||||
(is (= expected pretty-str))))
|
||||
|
||||
(deftest t-custom-keyword-fn
|
||||
(is (= {:FOO "bar"} (json/decode "{\"foo\": \"bar\"}"
|
||||
(fn [k] (keyword (.toUpperCase k))))))
|
||||
(is (= {"foo" "bar"} (json/decode "{\"foo\": \"bar\"}" nil)))
|
||||
(is (= {"foo" "bar"} (json/decode "{\"foo\": \"bar\"}" false)))
|
||||
(is (= {:foo "bar"} (json/decode "{\"foo\": \"bar\"}" true))))
|
||||
|
||||
(deftest t-custom-encode-key-fn
|
||||
(is (= "{\"FOO\":\"bar\"}"
|
||||
(json/encode {:foo :bar}
|
||||
{:key-fn (fn [k] (.toUpperCase (name k)))}))))
|
||||
|
||||
;; BB-TEST-PATCH: bb does nto include cheshire.generate ns
|
||||
#_(deftest test-add-remove-encoder
|
||||
(gen/remove-encoder java.net.URL)
|
||||
(gen/add-encoder java.net.URL gen/encode-str)
|
||||
(is (= "\"http://foo.com\""
|
||||
(json/encode (java.net.URL. "http://foo.com"))))
|
||||
(gen/remove-encoder java.net.URL)
|
||||
(is (thrown? JsonGenerationException
|
||||
(json/encode (java.net.URL. "http://foo.com")))))
|
||||
|
||||
#_(defprotocol TestP
|
||||
(foo [this] "foo method"))
|
||||
|
||||
#_(defrecord TestR [state])
|
||||
|
||||
#_(extend TestR
|
||||
TestP
|
||||
{:foo (constantly "bar")})
|
||||
|
||||
#_(deftest t-custom-protocol-encoder
|
||||
(let [rec (TestR. :quux)]
|
||||
(is (= {:state "quux"} (json/decode (json/encode rec) true)))
|
||||
(gen/add-encoder cheshire.test.core.TestR
|
||||
(fn [obj jg]
|
||||
(.writeString jg (foo obj))))
|
||||
(is (= "bar" (json/decode (json/encode rec))))
|
||||
(gen/remove-encoder cheshire.test.core.TestR)
|
||||
(is (= {:state "quux"} (json/decode (json/encode rec) true)))))
|
||||
|
||||
#_(defprotocol CTestP
|
||||
(thing [this] "thing method"))
|
||||
#_(defrecord CTestR [state])
|
||||
#_(extend CTestR
|
||||
CTestP
|
||||
{:thing (constantly "thing")})
|
||||
|
||||
#_(deftest t-custom-helpers
|
||||
(let [thing (CTestR. :state)
|
||||
remove #(gen/remove-encoder CTestR)]
|
||||
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-nil nil jg)))
|
||||
(is (= nil (json/decode (json/encode thing) true)))
|
||||
(remove)
|
||||
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-str "foo" jg)))
|
||||
(is (= "foo" (json/decode (json/encode thing) true)))
|
||||
(remove)
|
||||
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-number 5 jg)))
|
||||
(is (= 5 (json/decode (json/encode thing) true)))
|
||||
(remove)
|
||||
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-long 4 jg)))
|
||||
(is (= 4 (json/decode (json/encode thing) true)))
|
||||
(remove)
|
||||
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-int 3 jg)))
|
||||
(is (= 3 (json/decode (json/encode thing) true)))
|
||||
(remove)
|
||||
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-ratio 1/2 jg)))
|
||||
(is (= 0.5 (json/decode (json/encode thing) true)))
|
||||
(remove)
|
||||
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-seq [:foo :bar] jg)))
|
||||
(is (= ["foo" "bar"] (json/decode (json/encode thing) true)))
|
||||
(remove)
|
||||
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-date (Date. (long 0)) jg)))
|
||||
(binding [gen/*date-format* "yyyy-MM-dd'T'HH:mm:ss'Z'"]
|
||||
(is (= "1970-01-01T00:00:00Z" (json/decode (json/encode thing) true))))
|
||||
(remove)
|
||||
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-bool true jg)))
|
||||
(is (= true (json/decode (json/encode thing) true)))
|
||||
(remove)
|
||||
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-named :foo jg)))
|
||||
(is (= "foo" (json/decode (json/encode thing) true)))
|
||||
(remove)
|
||||
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-map {:foo "bar"} jg)))
|
||||
(is (= {:foo "bar"} (json/decode (json/encode thing) true)))
|
||||
(remove)
|
||||
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-symbol 'foo jg)))
|
||||
(is (= "foo" (json/decode (json/encode thing) true)))
|
||||
(remove)))
|
||||
|
||||
(deftest t-float-encoding
|
||||
(is (= "{\"foo\":0.01}" (json/encode {:foo (float 0.01)}))))
|
||||
|
||||
(deftest t-non-const-bools
|
||||
(is (= {:a 1} (json/decode "{\"a\": 1}" (Boolean. true)))))
|
||||
|
||||
;; BB-TEST-PATCH: bb does not include cheshire.exact ns
|
||||
#_(deftest t-invalid-json
|
||||
(let [invalid-json-message "Invalid JSON, expected exactly one parseable object but multiple objects were found"]
|
||||
(are [x y] (= x (try
|
||||
y
|
||||
(catch Exception e
|
||||
(.getMessage e))))
|
||||
invalid-json-message (json-exact/decode "{\"foo\": 1}asdf")
|
||||
invalid-json-message (json-exact/decode "{\"foo\": 123}null")
|
||||
invalid-json-message (json-exact/decode "\"hello\" : 123}")
|
||||
{"foo" 1} (json/decode "{\"foo\": 1}")
|
||||
invalid-json-message (json-exact/decode-strict "{\"foo\": 1}asdf")
|
||||
invalid-json-message (json-exact/decode-strict "{\"foo\": 123}null")
|
||||
invalid-json-message (json-exact/decode-strict "\"hello\" : 123}")
|
||||
{"foo" 1} (json/decode-strict "{\"foo\": 1}"))))
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
{"one":1,"foo":"bar"}
|
||||
{"two":2,"foo":"bar"}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
[
|
||||
"JSON Test Pattern pass1",
|
||||
{"object with 1 member":["array with 1 element"]},
|
||||
{},
|
||||
[],
|
||||
-42,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
{
|
||||
"integer": 1234567890,
|
||||
"real": -9876.543210,
|
||||
"e": 0.123456789e-12,
|
||||
"E": 1.234567890E+34,
|
||||
"": 23456789012E66,
|
||||
"zero": 0,
|
||||
"one": 1,
|
||||
"space": " ",
|
||||
"quote": "\"",
|
||||
"backslash": "\\",
|
||||
"controls": "\b\f\n\r\t",
|
||||
"slash": "/ & \/",
|
||||
"alpha": "abcdefghijklmnopqrstuvwyz",
|
||||
"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
|
||||
"digit": "0123456789",
|
||||
"0123456789": "digit",
|
||||
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
|
||||
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
|
||||
"true": true,
|
||||
"false": false,
|
||||
"null": null,
|
||||
"array":[ ],
|
||||
"object":{ },
|
||||
"address": "50 St. James Street",
|
||||
"url": "http://www.JSON.org/",
|
||||
"comment": "// /* <!-- --",
|
||||
"# -- --> */": " ",
|
||||
" s p a c e d " :[1,2 , 3
|
||||
|
||||
,
|
||||
|
||||
4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
|
||||
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
|
||||
"quotes": "" \u0022 %22 0x22 034 "",
|
||||
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
|
||||
: "A key can be any string"
|
||||
},
|
||||
0.5 ,98.6
|
||||
,
|
||||
99.44
|
||||
,
|
||||
|
||||
1066,
|
||||
1e1,
|
||||
0.1e1,
|
||||
1e-1,
|
||||
1e00,2e+00,2e-00
|
||||
,"rosebud"]
|
||||
|
|
@ -341,7 +341,7 @@
|
|||
(is (= ::response r))))
|
||||
|
||||
(try (get "https://httpbin.org/gzip" {:timeout 1000})
|
||||
(catch Exception _
|
||||
(catch java.net.http.HttpTimeoutException _
|
||||
(doseq [v (vals (ns-publics *ns*))]
|
||||
(when (:integration (meta v))
|
||||
(println "Removing test from" v "because httpbin is slow.")
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1 +0,0 @@
|
|||
42
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
[bencode.core :as bencode]
|
||||
[clojure.test :as t :refer [deftest is testing]]
|
||||
[sci.core :as sci]
|
||||
[babashka.impl.common :as common]
|
||||
[sci.ctx-store :as ctx-store]
|
||||
[babashka.impl.classpath :as cp])
|
||||
(:import
|
||||
|
|
@ -213,8 +214,8 @@
|
|||
(deftest ^:skip-windows nrepl-server-test
|
||||
(let [proc-state (atom nil)
|
||||
server-state (atom nil)
|
||||
ctx (sci/init {:namespaces main/namespaces
|
||||
:features #{:bb}})]
|
||||
_ (main/main "-e" "nil") ;; dummy invocation to reset ctx
|
||||
ctx (common/ctx)]
|
||||
(sci.ctx-store/with-ctx ctx
|
||||
(try
|
||||
(if tu/jvm?
|
||||
|
|
|
|||
|
|
@ -26,15 +26,15 @@
|
|||
(sci/with-in-str (str expr "\n:repl/quit")
|
||||
(repl!)))) expected)))
|
||||
|
||||
(defmacro assert-repl-error [expr expected]
|
||||
`(is (str/includes?
|
||||
(tu/normalize
|
||||
(let [sw# (java.io.StringWriter.)]
|
||||
(sci/binding [sci/out (java.io.StringWriter.)
|
||||
sci/err sw#]
|
||||
(sci/with-in-str (str ~expr "\n:repl/quit")
|
||||
(repl!)))
|
||||
(str sw#))) ~expected)))
|
||||
(defn assert-repl-error [expr expected]
|
||||
(is (str/includes?
|
||||
(tu/normalize
|
||||
(let [sw (java.io.StringWriter.)]
|
||||
(sci/binding [sci/out (java.io.StringWriter.)
|
||||
sci/err sw]
|
||||
(sci/with-in-str (str expr "\n:repl/quit")
|
||||
(repl!)))
|
||||
(str sw))) expected)))
|
||||
|
||||
(deftest repl-test
|
||||
(assert-repl "1" "1")
|
||||
|
|
@ -52,9 +52,7 @@
|
|||
(assert-repl-error "(+ 1 nil)" "NullPointerException")
|
||||
(assert-repl-error "(/ 1 0) (pst 1)" "Divide by zero\n\tclojure.lang.Numbers")
|
||||
(assert-repl-error "(partition (range 5) 3)"
|
||||
"Don't know how to create ISeq from: java.lang.Long")
|
||||
(assert-repl "(throw (ex-info \"foo\" {:a (+ 1 2 3)})) (ex-data *e)"
|
||||
"{:a 6}"))
|
||||
"Don't know how to create ISeq from: java.lang.Long"))
|
||||
|
||||
;;;; Scratch
|
||||
|
||||
|
|
|
|||
|
|
@ -18,10 +18,7 @@
|
|||
(bb nil (pr-str '(do
|
||||
(def t (Thread. (fn [])))
|
||||
(def vt (Thread/startVirtualThread (fn [])))
|
||||
[(.isVirtual t) (.isVirtual vt)])))))
|
||||
(is (bb nil (pr-str '(instance?
|
||||
java.util.concurrent.Executor
|
||||
(java.util.concurrent.Executors/newThreadPerTaskExecutor (-> (Thread/ofVirtual) (.name "fusebox-thread-" 1) (.factory))))))))
|
||||
[(.isVirtual t) (.isVirtual vt)]))))))
|
||||
|
||||
(deftest domain-sockets-test
|
||||
(is (= :success (bb nil (slurp "test-resources/domain_sockets.bb")))))
|
||||
|
|
@ -51,49 +48,6 @@
|
|||
(some? (.getSubjectX500Principal cert))
|
||||
"))))
|
||||
|
||||
(deftest ECDH-test
|
||||
(is (true? (bb nil "
|
||||
(import
|
||||
'[java.security KeyPairGenerator MessageDigest]
|
||||
'[java.security.spec ECGenParameterSpec]
|
||||
'[javax.crypto KeyAgreement]
|
||||
'[javax.crypto.spec SecretKeySpec])
|
||||
|
||||
(def keypair-algo \"EC\")
|
||||
(def keypair-curve \"secp256r1\")
|
||||
(def key-agreement-algo \"ECDH\") ; Elliptic Curve Diffie-Hellman
|
||||
(def key-digest-algo \"SHA-256\")
|
||||
(def key-encryption-algo \"AES\")
|
||||
|
||||
(defn keypair
|
||||
\"Generates a new key pair with the given alias, using the keypair-algo and keypair-curve\"
|
||||
[]
|
||||
(let [keygen (KeyPairGenerator/getInstance keypair-algo)]
|
||||
(.initialize keygen (ECGenParameterSpec. keypair-curve))
|
||||
(.generateKeyPair keygen)))
|
||||
|
||||
(defn symmetric-key
|
||||
\"Generates a symmetric key using Elliptic Curve Diffie-Hellman based on a given local private and a remote public key\"
|
||||
[private-key public-key]
|
||||
; Derive shared secret
|
||||
(let [shared-secret
|
||||
(let [key-agreement (KeyAgreement/getInstance key-agreement-algo)]
|
||||
(.init key-agreement private-key)
|
||||
(.doPhase key-agreement public-key true)
|
||||
(.generateSecret key-agreement))
|
||||
symmetric-key
|
||||
(let [message-digest (MessageDigest/getInstance key-digest-algo)
|
||||
hash-bytes (.digest message-digest shared-secret)
|
||||
key-bytes (byte-array (subvec (vec hash-bytes) 0 32))] ; extracts the first 256 bits for AES key
|
||||
(SecretKeySpec. key-bytes key-encryption-algo))]
|
||||
symmetric-key))
|
||||
|
||||
(let [[kp1 kp2] [(keypair) (keypair)]
|
||||
[private public] [(.getPrivate kp1) (.getPublic kp2)]
|
||||
symmetric (symmetric-key private public)]
|
||||
(some? (.getAlgorithm symmetric)))
|
||||
"))))
|
||||
|
||||
(deftest IntStream-test
|
||||
(is (pos? (bb nil "(.count (.codePoints \"woof🐕\"))"))))
|
||||
|
||||
|
|
@ -134,135 +88,3 @@
|
|||
|
||||
(deftest clojure-1_12-array-test
|
||||
(is (true? (bb nil "(instance? Class long/1)"))))
|
||||
|
||||
(deftest keygen-test
|
||||
(is (true?
|
||||
(bb nil
|
||||
'(do (ns keygen
|
||||
(:import [java.security KeyPairGenerator Signature]))
|
||||
|
||||
(defn generate-key-pair
|
||||
"Generates a public/private key pair."
|
||||
[]
|
||||
(let [keygen (KeyPairGenerator/getInstance "RSA")]
|
||||
(.initialize keygen 2048)
|
||||
(.generateKeyPair keygen)))
|
||||
|
||||
(defn create-signature
|
||||
"Signs the given message using the private key."
|
||||
[private-key message]
|
||||
(let [signature (Signature/getInstance "SHA256withRSA")]
|
||||
(.initSign signature private-key)
|
||||
(.update signature (.getBytes message "UTF-8"))
|
||||
(.sign signature)))
|
||||
|
||||
(defn verify-signature
|
||||
"Verifies the given signed data using the public key."
|
||||
[public-key message signed-data]
|
||||
(let [signature (Signature/getInstance "SHA256withRSA")]
|
||||
(.initVerify signature public-key)
|
||||
(.update signature (.getBytes message "UTF-8"))
|
||||
(.verify signature signed-data)))
|
||||
|
||||
(let [key-pair (generate-key-pair)
|
||||
private-key (.getPrivate key-pair)
|
||||
public-key (.getPublic key-pair)
|
||||
message "This is a secret message"
|
||||
signed-data (create-signature private-key message)]
|
||||
(verify-signature public-key message signed-data))))))
|
||||
|
||||
(is (true?
|
||||
(bb nil '(do (import
|
||||
'[java.security KeyPairGenerator]
|
||||
'[java.security.spec ECGenParameterSpec])
|
||||
|
||||
(def keypair-algo "EC")
|
||||
(def keypair-curve "secp256r1")
|
||||
|
||||
(defn keypair
|
||||
"Generates a new key pair with the given alias, using the keypair-algo and keypair-curve"
|
||||
[]
|
||||
(let [keygen (KeyPairGenerator/getInstance keypair-algo)]
|
||||
(.initialize keygen (ECGenParameterSpec. keypair-curve))
|
||||
(.generateKeyPair keygen)))
|
||||
|
||||
(let [kp (keypair)
|
||||
pk (.getPublic kp)]
|
||||
(bytes? (.getEncoded pk))))))))
|
||||
|
||||
;; RT iter test
|
||||
(deftest clojure-RT-iter-test
|
||||
(is (= (iterator-seq (.iterator [1 2 3]))
|
||||
(bb nil '(do (ns test
|
||||
(:import [clojure.lang RT]))
|
||||
(iterator-seq (clojure.lang.RT/iter [1 2 3])))))))
|
||||
|
||||
(deftest posix-file-attributes
|
||||
(when-not test-utils/windows?
|
||||
(is (= 'java.util.HashSet
|
||||
(bb nil
|
||||
'(do
|
||||
(import
|
||||
[java.nio.file Files LinkOption Path]
|
||||
[java.nio.file.attribute PosixFileAttributes])
|
||||
(-> (Files/readAttributes (Path/of "test-resources/posix-file-attributes.txt"
|
||||
(into-array String []))
|
||||
PosixFileAttributes
|
||||
^"[Ljava.nio.file.LinkOption;"
|
||||
(into-array LinkOption []))
|
||||
.permissions
|
||||
type)))))))
|
||||
|
||||
(deftest extended-attributes
|
||||
(is (true?
|
||||
(bb nil
|
||||
'(do
|
||||
(import
|
||||
[java.nio.file Files LinkOption Path]
|
||||
[java.nio.file.attribute UserDefinedFileAttributeView])
|
||||
(instance? UserDefinedFileAttributeView
|
||||
(Files/getFileAttributeView (Path/of "test-resources/extended-attributes.txt"
|
||||
(into-array String []))
|
||||
UserDefinedFileAttributeView
|
||||
^"[Ljava.nio.file.LinkOption;"
|
||||
(into-array LinkOption []))))))))
|
||||
|
||||
;; exercise a sampling of the superclass resolutions from the :public-class fn in
|
||||
;; babashka.impl.classes/gen-class-map
|
||||
(deftest public-class-resolutions
|
||||
(testing "Charset"
|
||||
(is (= "UTF-8" (bb nil "(.displayName (java.nio.charset.Charset/forName \"UTF-8\"))"))))
|
||||
(testing "InputStream"
|
||||
(is (zero? (bb nil "(with-open [is (java.io.InputStream/nullInputStream)]
|
||||
(.available is))"))))
|
||||
(testing "Throwable"
|
||||
; compare output from ex-message to calling .getMessage
|
||||
(let [return-throwable "(try (yaml/parse-string \"abc: def: ghi\") (catch Exception e e))"]
|
||||
(is (= (bb nil (str "(ex-message " return-throwable ")"))
|
||||
(bb nil (str "(.getMessage " return-throwable ")"))))))
|
||||
(testing "jsoup Element"
|
||||
(is (= "form" (bb nil "(.tagName (first (.getElementsByTag (org.jsoup.Jsoup/parseBodyFragment \"<form></form>\") \"form\")))")))))
|
||||
|
||||
(deftest cached-thread-pool
|
||||
(is (= 3 (bb nil "(import '(java.util.concurrent Executors ExecutorService))
|
||||
(let [fut (.submit ^ExecutorService (Executors/newCachedThreadPool) ^Callable (fn [] 3))]
|
||||
(.get fut))")))
|
||||
(is (nil? (bb nil "(import '(java.util.concurrent Executors ExecutorService))
|
||||
(let [fut (.submit ^ExecutorService (Executors/newCachedThreadPool) ^Runnable (fn [] 3))]
|
||||
(.get fut))"))))
|
||||
|
||||
(deftest break-iterator-test
|
||||
(is (= 1 (bb nil "(ns dude
|
||||
(:import [java.text BreakIterator]))
|
||||
|
||||
(defn count-characters
|
||||
[^String text]
|
||||
(let [it (BreakIterator/getCharacterInstance)]
|
||||
(.setText it text)
|
||||
(loop [count 0]
|
||||
(if (= (.next it) BreakIterator/DONE)
|
||||
count
|
||||
(recur (inc count))))))
|
||||
|
||||
(prn
|
||||
(count-characters \"🇨🇦\"))"))))
|
||||
|
|
|
|||
|
|
@ -1,17 +1,14 @@
|
|||
(ns babashka.test-test
|
||||
(:require
|
||||
[babashka.impl.clojure.test :as test-impl]
|
||||
#_[babashka.impl.clojure.test :as test-impl]
|
||||
[babashka.test-utils :as tu]
|
||||
[clojure.edn :as edn]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.string :as str]
|
||||
[clojure.test :as t :refer [deftest is]]
|
||||
[sci.core :as sci]))
|
||||
[clojure.test :as t :refer [deftest is]]))
|
||||
|
||||
(defn bb [& args]
|
||||
(let [sw (java.io.StringWriter.)]
|
||||
(sci/binding [test-impl/test-out sw]
|
||||
(str sw (apply tu/bb nil (map str args))))))
|
||||
(str (apply tu/bb nil (map str args))))
|
||||
|
||||
(deftest deftest-test
|
||||
(is (str/includes?
|
||||
|
|
@ -83,8 +80,8 @@ true")))))
|
|||
"3.14 should be roughly 3.141592653589793")))
|
||||
|
||||
(deftest rebind-vars-test
|
||||
(is (bb "(binding [clojure.test/report (constantly true)] nil)"))
|
||||
(is (bb "(binding [clojure.test/test-var (constantly true)] nil)")))
|
||||
(is (bb "(require '[clojure.test]) (binding [clojure.test/report (constantly true)] nil)"))
|
||||
(is (bb "(require '[clojure.test]) (binding [clojure.test/test-var (constantly true)] nil)")))
|
||||
|
||||
(deftest rebind-report-test
|
||||
(let [[m1 m2 m3]
|
||||
|
|
@ -122,6 +119,6 @@ true")))))
|
|||
|
||||
(deftest testing-vars-str-test
|
||||
(is (str/includes?
|
||||
(bb "(clojure.test/testing-vars-str {:file \"x\" :line 1})")
|
||||
(bb "(require 'clojure.test) (clojure.test/testing-vars-str {:file \"x\" :line 1})")
|
||||
"() (x:1)")
|
||||
"includes explicit line number + file name in test report"))
|
||||
|
|
|
|||
Loading…
Reference in a new issue