Skip to content
Snippets Groups Projects
Commit 3608e95a authored by STEVAN Antoine's avatar STEVAN Antoine 🦀
Browse files

refactor repo architecture (dragoon/komodo!161)

## changelog
- `src/main.rs` has been moved to a new crate: `bins/saclin` which stands for **S**emi-**A**VID **CLI** in **N**ushell
- dependencies of `komodo` have been fixed
- Nushell and Rust tests have been split in the Makefile: by default, only Rust tests will run locally and Nushell tests and examples can be run manually if desired. The CI will still run everything.
- the README has been updated
- test images have been moved to `assets/`
- the majority of the old `./nu-utils/` module have been moved to internals of `./benchmarks/` and imports have been fixed
- `cargo.nu` has been moved to `./bins/` and a new `./bins/README.md` mentions it
- `./bins/saclin/` has been created and should be a self-contained Rust crate + Nushell module
parent 0977677f
No related branches found
No related tags found
1 merge request!161refactor repo architecture
Pipeline #5727 passed
use std log
use error.nu "error throw"
def "error throw" [err: record<
err: string,
label: string,
span: record<start: int, end: int>,
# help: string?,
>] {
error make {
msg: $"(ansi red_bold)($err.err)(ansi reset)",
label: {
text: $err.label,
span: $err.span,
},
help: $err.help?,
}
}
def get-workspace-bins []: nothing -> table<name: string, toml: path> {
open Cargo.toml
......
[package]
name = "saclin"
version = "0.3.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.81"
ark-bls12-381 = "0.4.0"
ark-ec = "0.4.2"
ark-ff = "0.4.2"
ark-poly = "0.4.2"
ark-serialize = "0.4.2"
ark-std = "0.4.0"
komodo = { path = "../../" }
rand = "0.8.5"
tracing = "0.1.40"
tracing-subscriber = "0.3.17"
## CLI app using Semi-AVID
File moved
#!/usr/bin/env nu
use ../komodo.nu [
"komodo build",
"komodo setup",
"komodo prove",
"komodo verify",
"komodo reconstruct",
"komodo ls",
use .. [
"saclin build",
"saclin setup",
"saclin prove",
"saclin verify",
"saclin reconstruct",
"saclin ls",
]
use ../nu-utils binary [ "bytes from_int" ]
use ../binary.nu [ "bytes from_int" ]
use std assert
const BYTES = "tests/dragoon_32x32.png"
const BYTES = "assets/dragoon_32x32.png"
const FEC_PARAMS = { k: 3, n: 5 }
const BLOCKS_TO_VERIFY = [0, 1]
const BLOCKS_TO_RECONSTRUCT = [0, 2, 3]
def main [] {
komodo build
saclin build
komodo setup (open $BYTES | into binary | bytes length)
komodo prove $BYTES --fec-params $FEC_PARAMS
saclin setup (open $BYTES | into binary | bytes length)
saclin prove $BYTES --fec-params $FEC_PARAMS
let blocks = komodo ls
let blocks = saclin ls
komodo verify ...($BLOCKS_TO_VERIFY | each {|i| $blocks | get $i })
saclin verify ...($BLOCKS_TO_VERIFY | each {|i| $blocks | get $i })
let actual = komodo reconstruct ...($BLOCKS_TO_RECONSTRUCT | each {|i| $blocks | get $i })
let actual = saclin reconstruct ...($BLOCKS_TO_RECONSTRUCT | each {|i| $blocks | get $i })
let expected = open $BYTES | bytes from_int
assert equal $actual $expected
......
# Welcome to Komodo, a tool to encode and prove data.
# Welcome to SACLIN (**S**emi-**A**VID **CLI** in **N**ushell), a tool to encode and prove data.
#
# please run `komodo --help` or `komodo <tab>` to have a look at more information
# please run `saclin --help` or `saclin <tab>` to have a look at more information
use nu-utils binary ["bytes from_int"]
module binary.nu
const KOMODO_BINARY = "./target/release/komodo"
use binary ["bytes from_int"]
const BIN = "./target/release/saclin"
const DEFAULT_LOG_LEVEL = "INFO"
def home-dir []: nothing -> path {
$env.KOMODO_HOME? | default (
$env.XDG_DATA_HOME? | default "~/.local/share" | path join "komodo"
$env.SACLIN_HOME? | default (
$env.XDG_DATA_HOME? | default "~/.local/share" | path join "saclin"
) | path expand
}
......@@ -34,7 +36,7 @@ def "nu-complete encoding-methods" []: nothing -> list<string> {
]
}
def run-komodo [
def run-saclin [
--input: path = "",
--nb-bytes: int = 0,
-k: int = 0,
......@@ -59,7 +61,7 @@ def run-komodo [
with-env {RUST_LOG: $log_level} {
let res = do {
^$KOMODO_BINARY ...([
^$BIN ...([
$input
$k
$n
......@@ -90,9 +92,9 @@ def list-blocks []: nothing -> list<string> {
}
}
# build Komodo from source, updating the application
export def "komodo build" []: nothing -> nothing {
^cargo build --package komodo --release
# build SACLIN from source, updating the application
export def "saclin build" []: nothing -> nothing {
^cargo build --release --manifest-path bins/saclin/Cargo.toml
}
# create a random trusted setup for a given amount of data
......@@ -100,19 +102,19 @@ export def "komodo build" []: nothing -> nothing {
# # Examples
# ```nushell
# # create a trusted setup well suited for a file called `my_target_file.txt`
# komodo setup (open my_target_file.txt | into binary | bytes length)
# saclin setup (open my_target_file.txt | into binary | bytes length)
# ```
# ---
# ```nushell
# # create a trusted setup for 50k bytes and make sure the setup has been created
# komodo setup 50_000
# use std assert; assert ("~/.local/share/komodo/powers" | path exists)
export def "komodo setup" [
# saclin setup 50_000
# use std assert; assert ("~/.local/share/saclin/powers" | path exists)
export def "saclin setup" [
nb_bytes: int, # the size of the biggest expected data during the lifetime of the application
--log-level: string@"nu-complete log-levels" = $DEFAULT_LOG_LEVEL # change the log level
]: nothing -> nothing {
(
run-komodo
run-saclin
--log-level $log_level
--nb-bytes $nb_bytes
--generate-powers
......@@ -123,8 +125,8 @@ export def "komodo setup" [
#
# # Examples
# ```nushell
# # encode and prove `tests/dragoon_32x32.png` with a _3 x 5_ Vandermonde encoding
# komodo prove tests/dragoon_32x32.png --fec-params {k: 3, n: 5} --encoding-method vandermonde
# # encode and prove `assets/dragoon_32x32.png` with a _3 x 5_ Vandermonde encoding
# saclin prove assets/dragoon_32x32.png --fec-params {k: 3, n: 5} --encoding-method vandermonde
# ```
# ```
# ─┬────────────────────────────────────────────────────────────────
......@@ -135,7 +137,7 @@ export def "komodo setup" [
# 4│7aa698f338605462205c5ff46b5463720d073de92a19f897cc4ae6c286ab87
# ─┴────────────────────────────────────────────────────────────────
# ```
export def "komodo prove" [
export def "saclin prove" [
input: path, # the path to the input file to encode and prove
--fec-params: record<k: int, n: int>, # the parameters of the encoding
--encoding-method: string@"nu-complete encoding-methods" = "random", # the encoding method, e.g. _random_ or _vandermonde_
......@@ -145,7 +147,7 @@ export def "komodo prove" [
# a bug on the Nushell side
if $fec_params == null {
error make --unspanned {
msg: "`komodo prove` requires `--fec-params` to be given"
msg: "`saclin prove` requires `--fec-params` to be given"
}
}
......@@ -162,7 +164,7 @@ export def "komodo prove" [
}
(
run-komodo
run-saclin
--log-level $log_level
--input $input
-k $fec_params.k
......@@ -177,10 +179,10 @@ export def "komodo prove" [
# ```nushell
# # verify the integrity of two blocks (note the use of the spread operator introduced in Nushell 0.89.0)
# # > **Note**
# # > file: `tests/dragoon_32x32.png`
# # > file: `assets/dragoon_32x32.png`
# # > parameters: k = 3 and n = 5
# # > method: vandermonde
# komodo verify ...[
# saclin verify ...[
# 44614daf1f5ebb86f1c69293b82c7795a5a35b4d12718b551648223441028e3,
# 7aa698f338605462205c5ff46b5463720d073de92a19f897cc4ae6c286ab87,
# ]
......@@ -191,16 +193,16 @@ export def "komodo prove" [
# 1│7aa698f338605462205c5ff46b5463720d073de92a19f897cc4ae6c286ab87 │true
# ─┴───────────────────────────────────────────────────────────────┴──────
# ```
export def "komodo verify" [
export def "saclin verify" [
...blocks: string@"list-blocks", # the list of blocks to verify
--log-level: string@"nu-complete log-levels" = $DEFAULT_LOG_LEVEL # change the log level
]: nothing -> table<block: string, status: int> {
run-komodo --log-level $log_level --verify ...$blocks
run-saclin --log-level $log_level --verify ...$blocks
}
# reconstruct the original data from a subset of blocks
#
# `komodo reconstruct` might throw an error in some cases
# `saclin reconstruct` might throw an error in some cases
# - when there are too few blocks
# - when the blocks are linearly dependant, and thus the decoding cannot be applied
# - when the blocks belong to different data
......@@ -209,10 +211,10 @@ export def "komodo verify" [
# ```nushell
# # applying a valid reconstruction
# # > **Note**
# # > file: `tests/dragoon_32x32.png`
# # > file: `assets/dragoon_32x32.png`
# # > parameters: k = 3 and n = 5
# # > method: vandermonde
# let bytes = komodo reconstruct ...[
# let bytes = saclin reconstruct ...[
# 44614daf1f5ebb86f1c69293b82c7795a5a35b4d12718b551648223441028e3,
# 7aa698f338605462205c5ff46b5463720d073de92a19f897cc4ae6c286ab87,
# 8be575889246fbc49f4c748ac2dc1cd8a4ef71d16e91c9343660a5f79f086,
......@@ -227,10 +229,10 @@ export def "komodo verify" [
# ```nushell
# # giving too few blocks
# # > **Note**
# # > file: `tests/dragoon_32x32.png`
# # > file: `assets/dragoon_32x32.png`
# # > parameters: k = 3 and n = 5
# # > method: vandermonde
# komodo reconstruct ...[
# saclin reconstruct ...[
# 44614daf1f5ebb86f1c69293b82c7795a5a35b4d12718b551648223441028e3,
# 7aa698f338605462205c5ff46b5463720d073de92a19f897cc4ae6c286ab87,
# ]
......@@ -240,13 +242,13 @@ export def "komodo verify" [
# ```
# ---
# ```nushell
# # after combining _44614d_ and _6de9fd_ (see [`komodo combine`]), try to decode with linear dependencies
# # after combining _44614d_ and _6de9fd_ (see [`saclin combine`]), try to decode with linear dependencies
# # > **Note**
# # > file: `tests/dragoon_32x32.png`
# # > file: `assets/dragoon_32x32.png`
# # > parameters: k = 3 and n = 5
# # > method: vandermonde
# # > recoding: _44614d_ <+> _6de9fd_ => _86cdd1_
# komodo reconstruct ...[
# saclin reconstruct ...[
# 44614daf1f5ebb86f1c69293b82c7795a5a35b4d12718b551648223441028e3,
# 6de9fd5fdfe8c08b3132e0d527b14a2a4e4be9a543af1f13d2c397bd113846e4,
# 86cdd1b7ed79618696ab82d848833cbe448719a513b850207936e4dce6294,
......@@ -255,22 +257,22 @@ export def "komodo verify" [
# ```
# Error: × could not decode: Matrix is not invertible at row 2 (1)
# ```
export def "komodo reconstruct" [
export def "saclin reconstruct" [
...blocks: string@"list-blocks", # the blocks that should be used to reconstruct the original data
--log-level: string@"nu-complete log-levels" = $DEFAULT_LOG_LEVEL # change the log level
]: nothing -> binary {
run-komodo --log-level $log_level --reconstruct ...$blocks | bytes from_int
run-saclin --log-level $log_level --reconstruct ...$blocks | bytes from_int
}
# combine two blocks by computing a random linear combination
#
# # Examples
# # > **Note**
# # > file: `tests/dragoon_133x133.png`
# # > file: `assets/dragoon_133x133.png`
# # > parameters: k = 7 and n = 23
# # > method: random
# ```nushell
# komodo combine ...[
# saclin combine ...[
# 1b112a11cd89dad619aadc18cb2c15c315453e177f1117c79d4ae4e219922,
# 31c9bfe2845cc430d666413d8b8b51aee0d010aa89275a8c7d9d9ca1c9e05c,
# ]
......@@ -282,10 +284,10 @@ export def "komodo reconstruct" [
# ```nushell
# # not giving exactly 2 blocks
# # > **Note**
# # > file: `tests/dragoon_133x133.png`
# # > file: `assets/dragoon_133x133.png`
# # > parameters: k = 7 and n = 23
# # > method: random
# komodo combine ...[
# saclin combine ...[
# c22fe3c72cbc52fc55b46a3f9783f5c9a1e5fb59875f736332cf1b970b8,
# 1b112a11cd89dad619aadc18cb2c15c315453e177f1117c79d4ae4e219922,
# f3f423df47cd7538accd38abe9ad6670b894243647af98fbfa9776e9cf7ff8e,
......@@ -294,11 +296,11 @@ export def "komodo reconstruct" [
# ```
# Error: × expected exactly 2 blocks, found 3 (1)
# ```
export def "komodo combine" [
export def "saclin combine" [
...blocks: string@"list-blocks", # the blocks to combine, should contain two hashes
--log-level: string@"nu-complete log-levels" = $DEFAULT_LOG_LEVEL # change the log level
]: nothing -> string {
run-komodo --log-level $log_level --combine ...$blocks | get 0
run-saclin --log-level $log_level --combine ...$blocks | get 0
}
# open one or more blocks and inspect their content
......@@ -307,12 +309,12 @@ export def "komodo combine" [
# ```nushell
# # inspect a single block
# # # > **Note**
# # # > file: `tests/dragoon_133x133.png`
# # # > file: `assets/dragoon_133x133.png`
# # # > parameters: k = 7 and n = 23
# # # > method: random
# # # >
# # # > `$.commits` and `$shard.bytes` have been truncated for readability
# komodo inspect 374f23fd1f25ae4050c414bc169550bdd10f49f775e2af71d2aee8a87dc
# saclin inspect 374f23fd1f25ae4050c414bc169550bdd10f49f775e2af71d2aee8a87dc
# | into record
# | update commits { parse --regex '\((?<f>\d{7})\d+, (?<s>\d{7})\d+\)' }
# | update shard.bytes { length }
......@@ -346,20 +348,20 @@ export def "komodo combine" [
# m │89
# ───────┴──────────────────────────────────────────────────────────────────────
# ```
export def "komodo inspect" [
export def "saclin inspect" [
...blocks: string@"list-blocks", # the blocks to inspect
--log-level: string@"nu-complete log-levels" = $DEFAULT_LOG_LEVEL # change the log level
]: nothing -> table<shard: record<k: int, comb: list<any>, bytes: list<string>, hash: string, size: int>, commits: list<string>, m: int> {
run-komodo --log-level $log_level --inspect ...$blocks
run-saclin --log-level $log_level --inspect ...$blocks
}
# list all the blocks that are currently in the store
export def "komodo ls" []: nothing -> list<string> {
export def "saclin ls" []: nothing -> list<string> {
list-blocks
}
# clean the Komodo home from all blocks and trusted setup
export def "komodo clean" []: nothing -> nothing {
# clean the SACLIN home from all blocks and trusted setup
export def "saclin clean" []: nothing -> nothing {
rm --force --recursive (home-dir)
}
......@@ -367,12 +369,12 @@ def pretty-code []: string -> string {
$"`(ansi default_dimmed)($in)(ansi reset)`"
}
# the main entry point of Komodo, will only print some help
# the main entry point of SACLIN, will only print some help
export def main []: nothing -> nothing {
let help = [
$"the location of the files generated by Komodo can be configured via ("$env.KOMODO_HOME" | pretty-code) which will default to",
$"- ("$env.XDG_DATA_HOME/komodo" | pretty-code) if ("$env.XDG_DATA_HOME" | pretty-code) is set",
$"- ("~/.local/share/komodo/" | pretty-code) otherwise"
$"the location of the files generated by SACLIN can be configured via ("$env.SACLIN_HOME" | pretty-code) which will default to",
$"- ("$env.XDG_DATA_HOME/saclin" | pretty-code) if ("$env.XDG_DATA_HOME" | pretty-code) is set",
$"- ("~/.local/share/saclin/" | pretty-code) otherwise"
]
print ($help | str join "\n")
......
File moved
use ../nu-utils binary [ "bytes from_int", "bytes to_int" ]
use ../binary.nu [ "bytes from_int", "bytes to_int" ]
use std assert
......
use ../komodo.nu [
"komodo build",
"komodo setup",
"komodo prove",
"komodo verify",
"komodo reconstruct",
"komodo ls",
"komodo clean",
use .. [
"saclin build",
"saclin setup",
"saclin prove",
"saclin verify",
"saclin reconstruct",
"saclin ls",
"saclin clean",
]
use ../nu-utils binary [ "bytes from_int" ]
use ../binary.nu [ "bytes from_int" ]
use std assert
......@@ -120,12 +120,12 @@ module math {
use math
const FILE = "tests/dragoon_32x32.png"
const FILE = "assets/dragoon_32x32.png"
const FEC_PARAMS = {k: 3, n: 5}
def test [blocks: list<int>, --fail] {
let actual = try {
komodo reconstruct ...(komodo ls)
saclin reconstruct ...(saclin ls)
} catch {
if not $fail {
error make --unspanned { msg: "woopsie" }
......@@ -139,14 +139,14 @@ def test [blocks: list<int>, --fail] {
}
def main [] {
komodo build
saclin build
komodo clean
saclin clean
komodo setup (open $FILE | into binary | bytes length)
komodo prove $FILE --fec-params $FEC_PARAMS
saclin setup (open $FILE | into binary | bytes length)
saclin prove $FILE --fec-params $FEC_PARAMS
komodo verify ...(komodo ls)
saclin verify ...(saclin ls)
let all_k_choose_n_permutations = seq 1 $FEC_PARAMS.n
| each {|ki|
......
use error.nu "error throw"
export const WHITE = { r: 1.0, g: 1.0, b: 1.0 }
export const BLACK = { r: 0.0, g: 0.0, b: 0.0 }
export const RED = { r: 1.0, g: 0.0, b: 0.0 }
export const GREEN = { r: 0.0, g: 1.0, b: 0.0 }
export const BLUE = { r: 0.0, g: 0.0, b: 1.0 }
export def "color from-floats" [
r: float,
g: float,
b: float
]: nothing -> record<r: float, g: float, b: float> {
if $r < 0.0 or $r > 1.0 {
error throw {
err: "invalid RGB channel",
label: $"should be between 0 and 1, found ($r)",
span: (metadata $r).span,
}
}
if $g < 0.0 or $g > 1.0 {
error throw {
err: "invalid RGB channel",
label: $"should be between 0 and 1, found ($g)",
span: (metadata $g).span,
}
}
if $b < 0.0 or $b > 1.0 {
error throw {
err: "invalid RGB channel",
label: $"should be between 0 and 1, found ($b)",
span: (metadata $b).span,
}
}
{ r: $r, g: $g, b: $b }
}
export def "color from-ints" [
r: int,
g: int,
b: int
]: nothing -> record<r: float, g: float, b: float> {
if $r < 0 or $r > 255 {
error throw {
err: "invalid RGB channel",
label: $"should be between 0 and 255, found ($r)",
span: (metadata $r).span,
}
}
if $g < 0 or $g > 255 {
error throw {
err: "invalid RGB channel",
label: $"should be between 0 and 255, found ($g)",
span: (metadata $g).span,
}
}
if $b < 0 or $b > 255 {
error throw {
err: "invalid RGB channel",
label: $"should be between 0 and 255, found ($b)",
span: (metadata $b).span,
}
}
{ r: ($r / 255 | into float), g: ($g / 255 | into float), b: ($b / 255 | into float) }
}
def try-string-to-int []: string -> int {
let s = $in
try {
$"0x($s)" | into int
} catch { |e|
let err = $e.debug
| parse --regex 'CantConvert { to_type: "(?<to>.*)", from_type: "(?<from>.*)", span: Span { (?<span>.*) }, help: Some\("(?<help>.*)"\) }'
| into record
let msg = $err.help | str replace --all '\"' '"'
error make --unspanned { msg: $"($msg), found ($s)" }
}
}
export def "color from-string" [s: string]: nothing -> record<r: float, g: float, b: float> {
let res = $s
| parse --regex '^#(?<r>..)(?<g>..)(?<b>..)$'
| into record
if $res == {} {
error throw {
err: "invalid HEX color format",
label: $"format should be '#RRGGBB', found ($s)",
span: (metadata $s).span,
}
}
{
r: ($res.r | try-string-to-int | $in / 255),
g: ($res.g | try-string-to-int | $in / 255),
b: ($res.b | try-string-to-int | $in / 255),
}
}
export def "color mix" [
c1: record<r: float, g: float, b: float>,
c2: record<r: float, g: float, b: float>,
c: float,
]: nothing -> record<r: float, g: float, b: float> {
{
r: ($c * $c1.r + (1 - $c) * $c2.r),
g: ($c * $c1.g + (1 - $c) * $c2.g),
b: ($c * $c1.b + (1 - $c) * $c2.b),
}
}
def float-to-u8-hex []: float -> string {
$in * 255
| math round --precision 0
| into int
| fmt
| get lowerhex
| parse "0x{n}"
| into record
| get n
| into string
| fill --alignment "right" --character '0' --width 2
}
export def "color to-hex" []: record<r: float, g: float, b: float> -> string {
$"#($in.r | float-to-u8-hex)($in.g | float-to-u8-hex)($in.b | float-to-u8-hex)"
}
export def "error throw" [err: record<
err: string,
label: string,
span: record<start: int, end: int>,
# help: string?,
>] {
error make {
msg: $"(ansi red_bold)($err.err)(ansi reset)",
label: {
text: $err.label,
span: $err.span,
},
help: $err.help?,
}
}
......@@ -235,7 +235,7 @@ mod tests {
type LCExclusion = Vec<usize>;
fn bytes() -> Vec<u8> {
include_bytes!("../tests/dragoon_32x32.png").to_vec()
include_bytes!("../assets/dragoon_32x32.png").to_vec()
}
fn to_curve<F: PrimeField>(n: u128) -> F {
......
......@@ -42,7 +42,7 @@ mod tests {
use crate::field::{self, merge_elements_into_bytes};
fn bytes() -> Vec<u8> {
include_bytes!("../tests/dragoon_32x32.png").to_vec()
include_bytes!("../assets/dragoon_32x32.png").to_vec()
}
fn split_data_template<F: PrimeField>(
......
......@@ -206,7 +206,7 @@ mod tests {
use super::{build, prove, recode, verify};
fn bytes() -> Vec<u8> {
include_bytes!("../tests/dragoon_133x133.png").to_vec()
include_bytes!("../assets/dragoon_133x133.png").to_vec()
}
macro_rules! full {
......
use ../nu-utils color [
"color from-floats",
"color from-ints",
"color from-string",
"color mix",
"color to-hex",
RED,
GREEN,
]
use std assert
def "assert error" [code: closure, --msg: string, --body: string] {
try {
do $code
} catch { |e|
if $msg != null and ($e.msg | ansi strip) != $msg {
error make {
msg: $"(ansi red_bold)assertion: bad error message(ansi reset)",
label: {
text: $"error should have message '($msg)'",
span: (metadata $code).span,
},
help: $"actual: ($e.msg | ansi strip)",
}
}
if $body != null and not ($e.debug | ansi strip | str contains $body) {
let actual = $e.debug | ansi strip | parse "{foo}text: {text}, span: {bar}" | into record | get text
error make {
msg: $"(ansi red_bold)assertion: bad error body(ansi reset)",
label: {
text: $"error should contain '($body)'",
span: (metadata $code).span,
},
help: $"actual: ($actual)",
}
}
return
}
error make --unspanned { msg: "should error" }
}
assert error { || color from-floats 2 1 1 } --msg "invalid RGB channel" --body "should be between 0 and 1, found 2"
assert error { || color from-floats 1 (-2 | into float) 1 } --msg "invalid RGB channel" --body "should be between 0 and 1, found -2"
assert error { || color from-floats 1 1 3.4 } --msg "invalid RGB channel" --body "should be between 0 and 1, found 3.4"
assert error { || color from-ints 256 0 0 } --msg "invalid RGB channel" --body "should be between 0 and 255, found 256"
assert error { || color from-ints 0 256 0 } --msg "invalid RGB channel" --body "should be between 0 and 255, found 256"
assert error { || color from-ints 0 0 256 } --msg "invalid RGB channel" --body "should be between 0 and 255, found 256"
assert error { || color from-string "foo" } --msg "invalid HEX color format" --body "format should be '#RRGGBB', found foo"
assert error { || color from-string "#foo" } --msg "invalid HEX color format" --body "format should be '#RRGGBB', found #foo"
assert error { || color from-string "#xxxxxx" } --msg "hexadecimal digits following \"0x\" should be in 0-9, a-f, or A-F, found xx"
assert error { || color from-string "#0123yy" } --msg "hexadecimal digits following \"0x\" should be in 0-9, a-f, or A-F, found yy"
assert equal (color from-floats 0.1 0.2 0.3) { r: 0.1, g: 0.2, b: 0.3 }
assert equal (color from-ints 1 2 3) { r: (1 / 255), g: (2 / 255), b: (3 / 255) }
assert equal (color from-string "#010203") { r: (1 / 255), g: (2 / 255), b: (3 / 255) }
assert equal (color from-string "#010203" | color to-hex) "#010203"
assert equal (color mix $RED $GREEN 0.5) (color from-floats 0.5 0.5 0.0)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment