Skip to content

Commit 2d2124a

Browse files
authored
chore: add tests (#100)
1 parent 648cbd4 commit 2d2124a

File tree

4 files changed

+504
-18
lines changed

4 files changed

+504
-18
lines changed

crates/deno_task_shell/src/grammar.pest

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ DOUBLE_QUOTED = @{ "\"" ~ QUOTED_PENDING_WORD ~ "\"" }
6262
SINGLE_QUOTED = @{ "'" ~ (!"'" ~ ANY)* ~ "'" }
6363

6464
NAME = ${ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
65-
ASSIGNMENT_WORD = { NAME ~ "=" ~ ASSIGNMENT_VALUE? }
65+
ASSIGNMENT_WORD = ${ NAME ~ "=" ~ ASSIGNMENT_VALUE? }
6666
ASSIGNMENT_VALUE = ${
6767
ASSIGNMENT_TILDE_PREFIX ~
6868
((":" ~ ASSIGNMENT_TILDE_PREFIX) | (!":" ~ UNQUOTED_PENDING_WORD))* |
@@ -85,8 +85,6 @@ DLESSDASH = { "<<-" }
8585
CLOBBER = { ">|" }
8686
AMPERSAND = { "&" }
8787
EXIT_STATUS = ${ "$?" }
88-
TILDE = ${ "~" }
89-
9088

9189
// Operators
9290
OPERATOR = _{

crates/deno_task_shell/src/parser.rs

Lines changed: 367 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ fn parse_shell_var(pair: Pair<Rule>) -> Result<Sequence> {
517517
let value = inner
518518
.next()
519519
.ok_or_else(|| anyhow::anyhow!("Expected variable value"))?;
520-
let value = parse_word(value)?;
520+
let value = parse_assignment_value(value)?;
521521
Ok(Sequence::ShellVar(EnvVar { name, value }))
522522
}
523523

@@ -1046,6 +1046,372 @@ mod test {
10461046

10471047
assert!(parse("echo \"foo\" > out.txt").is_ok());
10481048
}
1049+
#[test]
1050+
fn test_sequential_list() {
1051+
let parse_and_create = |input: &str| -> Result<SequentialList> {
1052+
let pairs = ShellParser::parse(Rule::complete_command, input)
1053+
.map_err(|e| anyhow::Error::msg(e.to_string()))?
1054+
.next()
1055+
.unwrap();
1056+
// println!("pairs: {:?}", pairs);
1057+
parse_complete_command(pairs)
1058+
};
1059+
1060+
// Test case 1
1061+
let input = concat!(
1062+
"Name=Value OtherVar=Other command arg1 || command2 arg12 arg13 ; ",
1063+
"command3 && command4 & command5 ; export ENV6=5 ; ",
1064+
"ENV7=other && command8 || command9 ; ",
1065+
"cmd10 && (cmd11 || cmd12)"
1066+
);
1067+
let result = parse_and_create(input).unwrap();
1068+
let expected = SequentialList {
1069+
items: vec![
1070+
SequentialListItem {
1071+
is_async: false,
1072+
sequence: Sequence::BooleanList(Box::new(BooleanList {
1073+
current: SimpleCommand {
1074+
env_vars: vec![
1075+
EnvVar::new("Name".to_string(), Word::new_word("Value")),
1076+
EnvVar::new("OtherVar".to_string(), Word::new_word("Other")),
1077+
],
1078+
args: vec![Word::new_word("command"), Word::new_word("arg1")],
1079+
}
1080+
.into(),
1081+
op: BooleanListOperator::Or,
1082+
next: SimpleCommand {
1083+
env_vars: vec![],
1084+
args: vec![
1085+
Word::new_word("command2"),
1086+
Word::new_word("arg12"),
1087+
Word::new_word("arg13"),
1088+
],
1089+
}
1090+
.into(),
1091+
})),
1092+
},
1093+
SequentialListItem {
1094+
is_async: true,
1095+
sequence: Sequence::BooleanList(Box::new(BooleanList {
1096+
current: SimpleCommand {
1097+
env_vars: vec![],
1098+
args: vec![Word::new_word("command3")],
1099+
}
1100+
.into(),
1101+
op: BooleanListOperator::And,
1102+
next: SimpleCommand {
1103+
env_vars: vec![],
1104+
args: vec![Word::new_word("command4")],
1105+
}
1106+
.into(),
1107+
})),
1108+
},
1109+
SequentialListItem {
1110+
is_async: false,
1111+
sequence: SimpleCommand {
1112+
env_vars: vec![],
1113+
args: vec![Word::new_word("command5")],
1114+
}
1115+
.into(),
1116+
},
1117+
SequentialListItem {
1118+
is_async: false,
1119+
sequence: SimpleCommand {
1120+
env_vars: vec![],
1121+
args: vec![Word::new_word("export"), Word::new_word("ENV6=5")],
1122+
}
1123+
.into(),
1124+
},
1125+
SequentialListItem {
1126+
is_async: false,
1127+
sequence: Sequence::BooleanList(Box::new(BooleanList {
1128+
current: Sequence::ShellVar(EnvVar::new(
1129+
"ENV7".to_string(),
1130+
Word::new_word("other"),
1131+
)),
1132+
op: BooleanListOperator::And,
1133+
next: Sequence::BooleanList(Box::new(BooleanList {
1134+
current: SimpleCommand {
1135+
env_vars: vec![],
1136+
args: vec![Word::new_word("command8")],
1137+
}
1138+
.into(),
1139+
op: BooleanListOperator::Or,
1140+
next: SimpleCommand {
1141+
env_vars: vec![],
1142+
args: vec![Word::new_word("command9")],
1143+
}
1144+
.into(),
1145+
})),
1146+
})),
1147+
},
1148+
SequentialListItem {
1149+
is_async: false,
1150+
sequence: Sequence::BooleanList(Box::new(BooleanList {
1151+
current: SimpleCommand {
1152+
env_vars: vec![],
1153+
args: vec![Word::new_word("cmd10")],
1154+
}
1155+
.into(),
1156+
op: BooleanListOperator::And,
1157+
next: Command {
1158+
inner: CommandInner::Subshell(Box::new(SequentialList {
1159+
items: vec![SequentialListItem {
1160+
is_async: false,
1161+
sequence: Sequence::BooleanList(Box::new(BooleanList {
1162+
current: SimpleCommand {
1163+
env_vars: vec![],
1164+
args: vec![Word::new_word("cmd11")],
1165+
}
1166+
.into(),
1167+
op: BooleanListOperator::Or,
1168+
next: SimpleCommand {
1169+
env_vars: vec![],
1170+
args: vec![Word::new_word("cmd12")],
1171+
}
1172+
.into(),
1173+
})),
1174+
}],
1175+
})),
1176+
redirect: None,
1177+
}
1178+
.into(),
1179+
})),
1180+
},
1181+
],
1182+
};
1183+
assert_eq!(result, expected);
1184+
1185+
// Test case 2
1186+
let input = "command1 ; command2 ; A='b' command3";
1187+
let result = parse_and_create(input).unwrap();
1188+
let expected = SequentialList {
1189+
items: vec![
1190+
SequentialListItem {
1191+
is_async: false,
1192+
sequence: SimpleCommand {
1193+
env_vars: vec![],
1194+
args: vec![Word::new_word("command1")],
1195+
}
1196+
.into(),
1197+
},
1198+
SequentialListItem {
1199+
is_async: false,
1200+
sequence: SimpleCommand {
1201+
env_vars: vec![],
1202+
args: vec![Word::new_word("command2")],
1203+
}
1204+
.into(),
1205+
},
1206+
SequentialListItem {
1207+
is_async: false,
1208+
sequence: SimpleCommand {
1209+
env_vars: vec![EnvVar::new("A".to_string(), Word::new_string("b"))],
1210+
args: vec![Word::new_word("command3")],
1211+
}
1212+
.into(),
1213+
},
1214+
],
1215+
};
1216+
assert_eq!(result, expected);
1217+
1218+
// Test case 3
1219+
let input = "test &&";
1220+
assert!(parse_and_create(input).is_err());
1221+
1222+
// Test case 4
1223+
let input = "command &";
1224+
let result = parse_and_create(input).unwrap();
1225+
let expected = SequentialList {
1226+
items: vec![SequentialListItem {
1227+
is_async: true,
1228+
sequence: SimpleCommand {
1229+
env_vars: vec![],
1230+
args: vec![Word::new_word("command")],
1231+
}
1232+
.into(),
1233+
}],
1234+
};
1235+
assert_eq!(result, expected);
1236+
1237+
// Test case 5
1238+
let input = "test | other";
1239+
let result = parse_and_create(input).unwrap();
1240+
let expected = SequentialList {
1241+
items: vec![SequentialListItem {
1242+
is_async: false,
1243+
sequence: PipeSequence {
1244+
current: SimpleCommand {
1245+
env_vars: vec![],
1246+
args: vec![Word::new_word("test")],
1247+
}
1248+
.into(),
1249+
op: PipeSequenceOperator::Stdout,
1250+
next: SimpleCommand {
1251+
env_vars: vec![],
1252+
args: vec![Word::new_word("other")],
1253+
}
1254+
.into(),
1255+
}
1256+
.into(),
1257+
}],
1258+
};
1259+
assert_eq!(result, expected);
1260+
1261+
// Test case 6
1262+
let input = "test |& other";
1263+
let result = parse_and_create(input).unwrap();
1264+
let expected = SequentialList {
1265+
items: vec![SequentialListItem {
1266+
is_async: false,
1267+
sequence: PipeSequence {
1268+
current: SimpleCommand {
1269+
env_vars: vec![],
1270+
args: vec![Word::new_word("test")],
1271+
}
1272+
.into(),
1273+
op: PipeSequenceOperator::StdoutStderr,
1274+
next: SimpleCommand {
1275+
env_vars: vec![],
1276+
args: vec![Word::new_word("other")],
1277+
}
1278+
.into(),
1279+
}
1280+
.into(),
1281+
}],
1282+
};
1283+
assert_eq!(result, expected);
1284+
1285+
// Test case 8
1286+
let input = "echo $MY_ENV;";
1287+
let result = parse_and_create(input).unwrap();
1288+
let expected = SequentialList {
1289+
items: vec![SequentialListItem {
1290+
is_async: false,
1291+
sequence: SimpleCommand {
1292+
env_vars: vec![],
1293+
args: vec![
1294+
Word::new_word("echo"),
1295+
Word(vec![WordPart::Variable("MY_ENV".to_string())]),
1296+
],
1297+
}
1298+
.into(),
1299+
}],
1300+
};
1301+
assert_eq!(result, expected);
1302+
1303+
// Test case 9
1304+
let input = "! cmd1 | cmd2 && cmd3";
1305+
let result = parse_and_create(input).unwrap();
1306+
let expected = SequentialList {
1307+
items: vec![SequentialListItem {
1308+
is_async: false,
1309+
sequence: Sequence::BooleanList(Box::new(BooleanList {
1310+
current: Pipeline {
1311+
negated: true,
1312+
inner: PipeSequence {
1313+
current: SimpleCommand {
1314+
args: vec![Word::new_word("cmd1")],
1315+
env_vars: vec![],
1316+
}
1317+
.into(),
1318+
op: PipeSequenceOperator::Stdout,
1319+
next: SimpleCommand {
1320+
args: vec![Word::new_word("cmd2")],
1321+
env_vars: vec![],
1322+
}
1323+
.into(),
1324+
}
1325+
.into(),
1326+
}
1327+
.into(),
1328+
op: BooleanListOperator::And,
1329+
next: SimpleCommand {
1330+
args: vec![Word::new_word("cmd3")],
1331+
env_vars: vec![],
1332+
}
1333+
.into(),
1334+
})),
1335+
}],
1336+
};
1337+
assert_eq!(result, expected);
1338+
}
1339+
1340+
#[test]
1341+
fn test_env_var() {
1342+
let parse_and_create = |input: &str| -> Result<EnvVar, anyhow::Error> {
1343+
let pairs = ShellParser::parse(Rule::ASSIGNMENT_WORD, input)
1344+
.map_err(|e| anyhow::anyhow!(e.to_string()))?
1345+
.next()
1346+
.unwrap();
1347+
parse_env_var(pairs)
1348+
};
1349+
1350+
assert_eq!(
1351+
parse_and_create("Name=Value").unwrap(),
1352+
EnvVar {
1353+
name: "Name".to_string(),
1354+
value: Word::new_word("Value"),
1355+
}
1356+
);
1357+
1358+
assert_eq!(
1359+
parse_and_create("Name='quoted value'").unwrap(),
1360+
EnvVar {
1361+
name: "Name".to_string(),
1362+
value: Word::new_string("quoted value"),
1363+
}
1364+
);
1365+
1366+
assert_eq!(
1367+
parse_and_create("Name=\"double quoted value\"").unwrap(),
1368+
EnvVar {
1369+
name: "Name".to_string(),
1370+
value: Word::new_string("double quoted value"),
1371+
}
1372+
);
1373+
1374+
assert_eq!(
1375+
parse_and_create("Name=").unwrap(),
1376+
EnvVar {
1377+
name: "Name".to_string(),
1378+
value: Word(vec![]),
1379+
}
1380+
);
1381+
1382+
assert_eq!(
1383+
parse_and_create("Name=$(test)").unwrap(),
1384+
EnvVar {
1385+
name: "Name".to_string(),
1386+
value: Word(vec![WordPart::Command(SequentialList {
1387+
items: vec![SequentialListItem {
1388+
is_async: false,
1389+
sequence: SimpleCommand {
1390+
env_vars: vec![],
1391+
args: vec![Word::new_word("test")],
1392+
}
1393+
.into(),
1394+
}],
1395+
})]),
1396+
}
1397+
);
1398+
1399+
assert_eq!(
1400+
parse_and_create("Name=$(OTHER=5)").unwrap(),
1401+
EnvVar {
1402+
name: "Name".to_string(),
1403+
value: Word(vec![WordPart::Command(SequentialList {
1404+
items: vec![SequentialListItem {
1405+
is_async: false,
1406+
sequence: Sequence::ShellVar(EnvVar {
1407+
name: "OTHER".to_string(),
1408+
value: Word::new_word("5"),
1409+
}),
1410+
}],
1411+
})]),
1412+
}
1413+
);
1414+
}
10491415

10501416
#[cfg(feature = "serialization")]
10511417
#[test]

0 commit comments

Comments
 (0)