Skip to content

Commit 6b189c6

Browse files
committed
fix: generate proper strings from contract results
Fixes: #213
1 parent 020edf9 commit 6b189c6

File tree

1 file changed

+140
-1
lines changed

1 file changed

+140
-1
lines changed

src/runnner/deno.rs

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use clarity_repl::clarity::coverage::CoverageReporter;
2+
use clarity_repl::clarity::types;
3+
use clarity_repl::clarity::util::hash;
24
use clarity_repl::prettytable::{color, format, Attr, Cell, Row, Table};
35
use clarity_repl::repl::session::CostsReport;
46
use clarity_repl::repl::Session;
@@ -35,6 +37,7 @@ use serde::Serialize;
3537
use std::collections::HashSet;
3638
use std::collections::{btree_map::Entry, BTreeMap};
3739
use std::convert::TryFrom;
40+
use std::fmt::Write;
3841
use std::ops::Index;
3942
use std::path::Path;
4043
use std::path::PathBuf;
@@ -1183,6 +1186,61 @@ struct TransferSTXArgs {
11831186
recipient: String,
11841187
}
11851188

1189+
fn value_to_string(value: &types::Value) -> String {
1190+
use clarity_repl::clarity::types::{CharType, SequenceData, Value};
1191+
1192+
match value {
1193+
Value::Tuple(tup_data) => {
1194+
let mut out = String::new();
1195+
write!(out, "{{");
1196+
for (i, (name, value)) in tup_data.data_map.iter().enumerate() {
1197+
write!(out, "{}: {}", &**name, value_to_string(value));
1198+
if i < tup_data.data_map.len() - 1 {
1199+
write!(out, ", ");
1200+
}
1201+
}
1202+
write!(out, "}}");
1203+
out
1204+
}
1205+
Value::Optional(opt_data) => match opt_data.data {
1206+
Some(ref x) => format!("(some {})", value_to_string(&**x)),
1207+
None => "none".to_string(),
1208+
},
1209+
Value::Response(res_data) => match res_data.committed {
1210+
true => format!("(ok {})", value_to_string(&*res_data.data)),
1211+
false => format!("(err {})", value_to_string(&*res_data.data)),
1212+
},
1213+
Value::Sequence(SequenceData::String(CharType::ASCII(data))) => {
1214+
format!("\"{}\"", String::from_utf8(data.data.clone()).unwrap())
1215+
}
1216+
Value::Sequence(SequenceData::String(CharType::UTF8(data))) => {
1217+
let mut result = String::new();
1218+
for c in data.data.iter() {
1219+
if c.len() > 1 {
1220+
// We escape extended charset
1221+
result.push_str(&format!("\\u{{{}}}", hash::to_hex(&c[..])));
1222+
} else {
1223+
result.push(c[0] as char)
1224+
}
1225+
}
1226+
format!("u\"{}\"", result)
1227+
}
1228+
Value::Sequence(SequenceData::List(list_data)) => {
1229+
let mut out = String::new();
1230+
write!(out, "[");
1231+
for (ix, v) in list_data.data.iter().enumerate() {
1232+
if ix > 0 {
1233+
write!(out, ", ");
1234+
}
1235+
write!(out, "{}", value_to_string(v));
1236+
}
1237+
write!(out, "]");
1238+
out
1239+
}
1240+
_ => format!("{}", value),
1241+
}
1242+
}
1243+
11861244
fn mine_block(state: &mut OpState, args: Value, _: ()) -> Result<String, AnyError> {
11871245
let args: MineBlockArgs =
11881246
serde_json::from_value(args).expect("Invalid request from JavaScript.");
@@ -1215,7 +1273,7 @@ fn mine_block(state: &mut OpState, args: Value, _: ()) -> Result<String, AnyErro
12151273
}
12161274
};
12171275
let result = match execution.result {
1218-
Some(output) => format!("{}", output),
1276+
Some(output) => value_to_string(&output),
12191277
_ => unreachable!("Value empty"),
12201278
};
12211279
receipts.push((result, execution.events));
@@ -1360,3 +1418,84 @@ fn get_assets_maps(state: &mut OpState, args: Value, _: ()) -> Result<String, An
13601418
})
13611419
.to_string())
13621420
}
1421+
1422+
#[cfg(test)]
1423+
mod tests {
1424+
use clarity_repl::clarity::representations::ClarityName;
1425+
use clarity_repl::clarity::types::{
1426+
ListTypeData, OptionalData, ResponseData, SequenceData, SequencedValue, TupleData,
1427+
};
1428+
1429+
use super::*;
1430+
1431+
#[test]
1432+
fn test_value_to_string() {
1433+
let mut s = value_to_string(&types::Value::Int(42));
1434+
assert_eq!(s, "42");
1435+
1436+
s = value_to_string(&types::Value::UInt(12345678909876));
1437+
assert_eq!(s, "u12345678909876");
1438+
1439+
s = value_to_string(&types::Value::Bool(true));
1440+
assert_eq!(s, "true");
1441+
1442+
s = value_to_string(&types::Value::buff_from(vec![1, 2, 3]).unwrap());
1443+
assert_eq!(s, "0x010203");
1444+
1445+
s = value_to_string(&types::Value::buff_from(vec![1, 2, 3]).unwrap());
1446+
assert_eq!(s, "0x010203");
1447+
1448+
s = value_to_string(&types::Value::Tuple(
1449+
TupleData::from_data(vec![(
1450+
ClarityName::try_from("foo".to_string()).unwrap(),
1451+
types::Value::Bool(true),
1452+
)])
1453+
.unwrap(),
1454+
));
1455+
assert_eq!(s, "{foo: true}");
1456+
1457+
s = value_to_string(&types::Value::Optional(OptionalData {
1458+
data: Some(Box::new(types::Value::UInt(42))),
1459+
}));
1460+
assert_eq!(s, "(some u42)");
1461+
1462+
s = value_to_string(&types::NONE);
1463+
assert_eq!(s, "none");
1464+
1465+
s = value_to_string(&types::Value::Response(ResponseData {
1466+
committed: true,
1467+
data: Box::new(types::Value::Int(-321)),
1468+
}));
1469+
assert_eq!(s, "(ok -321)");
1470+
1471+
s = value_to_string(&types::Value::Response(ResponseData {
1472+
committed: false,
1473+
data: Box::new(types::Value::Sequence(types::SequenceData::String(
1474+
types::CharType::ASCII(types::ASCIIData {
1475+
data: "'foo'".as_bytes().to_vec(),
1476+
}),
1477+
))),
1478+
}));
1479+
assert_eq!(s, "(err \"'foo'\")");
1480+
1481+
s = value_to_string(&types::Value::Sequence(types::SequenceData::String(
1482+
types::CharType::ASCII(types::ASCIIData {
1483+
data: "Hello, \"world\"\n".as_bytes().to_vec(),
1484+
}),
1485+
)));
1486+
assert_eq!(s, "\"Hello, \"world\"\n\"");
1487+
1488+
s = value_to_string(&types::UTF8Data::to_value(
1489+
&"Hello, 'world'\n".as_bytes().to_vec(),
1490+
));
1491+
assert_eq!(s, "u\"Hello, 'world'\n\"");
1492+
1493+
s = value_to_string(&types::Value::Sequence(SequenceData::List(
1494+
types::ListData {
1495+
data: vec![types::Value::Int(-321)],
1496+
type_signature: ListTypeData::new_list(types::TypeSignature::IntType, 2).unwrap(),
1497+
},
1498+
)));
1499+
assert_eq!(s, "[-321]");
1500+
}
1501+
}

0 commit comments

Comments
 (0)