@owenlamont/ryl 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/.github/CODEOWNERS +1 -0
  2. package/.github/dependabot.yml +13 -0
  3. package/.github/workflows/ci.yml +107 -0
  4. package/.github/workflows/release.yml +613 -0
  5. package/.github/workflows/update_dependencies.yml +61 -0
  6. package/.github/workflows/update_linters.yml +56 -0
  7. package/.pre-commit-config.yaml +87 -0
  8. package/.yamllint +4 -0
  9. package/AGENTS.md +200 -0
  10. package/Cargo.lock +908 -0
  11. package/Cargo.toml +32 -0
  12. package/LICENSE +21 -0
  13. package/README.md +230 -0
  14. package/bin/ryl.js +1 -0
  15. package/clippy.toml +1 -0
  16. package/docs/config-presets.md +100 -0
  17. package/img/benchmark-5x5-5runs.svg +2176 -0
  18. package/package.json +28 -0
  19. package/pyproject.toml +42 -0
  20. package/ruff.toml +107 -0
  21. package/rumdl.toml +20 -0
  22. package/rust-toolchain.toml +3 -0
  23. package/rustfmt.toml +3 -0
  24. package/scripts/benchmark_perf_vs_yamllint.py +400 -0
  25. package/scripts/coverage-missing.ps1 +80 -0
  26. package/scripts/coverage-missing.sh +60 -0
  27. package/src/bin/discover_config_bin.rs +24 -0
  28. package/src/cli_support.rs +33 -0
  29. package/src/conf/mod.rs +85 -0
  30. package/src/config.rs +2099 -0
  31. package/src/decoder.rs +326 -0
  32. package/src/discover.rs +31 -0
  33. package/src/lib.rs +19 -0
  34. package/src/lint.rs +558 -0
  35. package/src/main.rs +535 -0
  36. package/src/migrate.rs +233 -0
  37. package/src/rules/anchors.rs +517 -0
  38. package/src/rules/braces.rs +77 -0
  39. package/src/rules/brackets.rs +77 -0
  40. package/src/rules/colons.rs +475 -0
  41. package/src/rules/commas.rs +372 -0
  42. package/src/rules/comments.rs +299 -0
  43. package/src/rules/comments_indentation.rs +243 -0
  44. package/src/rules/document_end.rs +175 -0
  45. package/src/rules/document_start.rs +84 -0
  46. package/src/rules/empty_lines.rs +152 -0
  47. package/src/rules/empty_values.rs +255 -0
  48. package/src/rules/float_values.rs +259 -0
  49. package/src/rules/flow_collection.rs +562 -0
  50. package/src/rules/hyphens.rs +104 -0
  51. package/src/rules/indentation.rs +803 -0
  52. package/src/rules/key_duplicates.rs +218 -0
  53. package/src/rules/key_ordering.rs +303 -0
  54. package/src/rules/line_length.rs +326 -0
  55. package/src/rules/mod.rs +25 -0
  56. package/src/rules/new_line_at_end_of_file.rs +23 -0
  57. package/src/rules/new_lines.rs +95 -0
  58. package/src/rules/octal_values.rs +121 -0
  59. package/src/rules/quoted_strings.rs +577 -0
  60. package/src/rules/span_utils.rs +37 -0
  61. package/src/rules/trailing_spaces.rs +65 -0
  62. package/src/rules/truthy.rs +420 -0
  63. package/tests/brackets_carriage_return.rs +114 -0
  64. package/tests/build_global_cfg_error.rs +23 -0
  65. package/tests/cli_anchors_rule.rs +143 -0
  66. package/tests/cli_braces_rule.rs +104 -0
  67. package/tests/cli_brackets_rule.rs +104 -0
  68. package/tests/cli_colons_rule.rs +65 -0
  69. package/tests/cli_commas_rule.rs +104 -0
  70. package/tests/cli_comments_indentation_rule.rs +61 -0
  71. package/tests/cli_comments_rule.rs +67 -0
  72. package/tests/cli_config_data_error.rs +30 -0
  73. package/tests/cli_config_flags.rs +66 -0
  74. package/tests/cli_config_migrate.rs +229 -0
  75. package/tests/cli_document_end_rule.rs +92 -0
  76. package/tests/cli_document_start_rule.rs +92 -0
  77. package/tests/cli_empty_lines_rule.rs +87 -0
  78. package/tests/cli_empty_values_rule.rs +68 -0
  79. package/tests/cli_env_config.rs +34 -0
  80. package/tests/cli_exit_and_errors.rs +41 -0
  81. package/tests/cli_file_encoding.rs +203 -0
  82. package/tests/cli_float_values_rule.rs +64 -0
  83. package/tests/cli_format_options.rs +316 -0
  84. package/tests/cli_global_cfg_relaxed.rs +20 -0
  85. package/tests/cli_hyphens_rule.rs +104 -0
  86. package/tests/cli_indentation_rule.rs +65 -0
  87. package/tests/cli_invalid_project_config.rs +39 -0
  88. package/tests/cli_key_duplicates_rule.rs +104 -0
  89. package/tests/cli_key_ordering_rule.rs +59 -0
  90. package/tests/cli_line_length_rule.rs +85 -0
  91. package/tests/cli_list_files.rs +29 -0
  92. package/tests/cli_new_line_rule.rs +141 -0
  93. package/tests/cli_new_lines_rule.rs +119 -0
  94. package/tests/cli_octal_values_rule.rs +60 -0
  95. package/tests/cli_quoted_strings_rule.rs +47 -0
  96. package/tests/cli_toml_config.rs +119 -0
  97. package/tests/cli_trailing_spaces_rule.rs +77 -0
  98. package/tests/cli_truthy_rule.rs +83 -0
  99. package/tests/cli_yaml_files_negation.rs +45 -0
  100. package/tests/colons_rule.rs +303 -0
  101. package/tests/common/compat.rs +114 -0
  102. package/tests/common/fake_env.rs +93 -0
  103. package/tests/common/mod.rs +1 -0
  104. package/tests/conf_builtin.rs +9 -0
  105. package/tests/config_anchors.rs +84 -0
  106. package/tests/config_braces.rs +121 -0
  107. package/tests/config_brackets.rs +127 -0
  108. package/tests/config_commas.rs +79 -0
  109. package/tests/config_comments.rs +65 -0
  110. package/tests/config_comments_indentation.rs +20 -0
  111. package/tests/config_deep_merge_nonstring_key.rs +24 -0
  112. package/tests/config_document_end.rs +54 -0
  113. package/tests/config_document_start.rs +55 -0
  114. package/tests/config_empty_lines.rs +48 -0
  115. package/tests/config_empty_values.rs +35 -0
  116. package/tests/config_env_errors.rs +23 -0
  117. package/tests/config_env_invalid_inline.rs +15 -0
  118. package/tests/config_env_missing.rs +63 -0
  119. package/tests/config_env_shim.rs +301 -0
  120. package/tests/config_explicit_file_parse_error.rs +55 -0
  121. package/tests/config_extended_features.rs +225 -0
  122. package/tests/config_extends_inline.rs +185 -0
  123. package/tests/config_extends_sequence.rs +18 -0
  124. package/tests/config_find_project_home_boundary.rs +54 -0
  125. package/tests/config_find_project_two_files_in_cwd.rs +47 -0
  126. package/tests/config_float_values.rs +34 -0
  127. package/tests/config_from_yaml_paths.rs +32 -0
  128. package/tests/config_hyphens.rs +51 -0
  129. package/tests/config_ignore_errors.rs +243 -0
  130. package/tests/config_ignore_overrides.rs +83 -0
  131. package/tests/config_indentation.rs +65 -0
  132. package/tests/config_invalid_globs.rs +16 -0
  133. package/tests/config_invalid_types.rs +19 -0
  134. package/tests/config_key_duplicates.rs +34 -0
  135. package/tests/config_key_ordering.rs +70 -0
  136. package/tests/config_line_length.rs +65 -0
  137. package/tests/config_locale.rs +111 -0
  138. package/tests/config_merge.rs +26 -0
  139. package/tests/config_new_lines.rs +89 -0
  140. package/tests/config_octal_values.rs +33 -0
  141. package/tests/config_quoted_strings.rs +195 -0
  142. package/tests/config_rule_level.rs +147 -0
  143. package/tests/config_rules_non_string_keys.rs +23 -0
  144. package/tests/config_scalar_overrides.rs +27 -0
  145. package/tests/config_to_toml.rs +110 -0
  146. package/tests/config_toml_coverage.rs +80 -0
  147. package/tests/config_toml_discovery.rs +304 -0
  148. package/tests/config_trailing_spaces.rs +152 -0
  149. package/tests/config_truthy.rs +77 -0
  150. package/tests/config_yaml_files.rs +62 -0
  151. package/tests/config_yaml_files_all_non_string.rs +15 -0
  152. package/tests/config_yaml_files_empty.rs +30 -0
  153. package/tests/coverage_commas.rs +46 -0
  154. package/tests/decoder_decode.rs +338 -0
  155. package/tests/discover_config_bin_all.rs +66 -0
  156. package/tests/discover_config_bin_env_invalid_yaml.rs +26 -0
  157. package/tests/discover_config_bin_project_config_parse_error.rs +24 -0
  158. package/tests/discover_config_bin_user_global_error.rs +26 -0
  159. package/tests/discover_module.rs +30 -0
  160. package/tests/discover_per_file_dir.rs +10 -0
  161. package/tests/discover_per_file_project_config_error.rs +21 -0
  162. package/tests/float_values.rs +43 -0
  163. package/tests/lint_multi_errors.rs +32 -0
  164. package/tests/main_yaml_ok_filtering.rs +30 -0
  165. package/tests/migrate_module.rs +259 -0
  166. package/tests/resolve_ctx_empty_parent.rs +16 -0
  167. package/tests/rule_anchors.rs +442 -0
  168. package/tests/rule_braces.rs +258 -0
  169. package/tests/rule_brackets.rs +217 -0
  170. package/tests/rule_commas.rs +205 -0
  171. package/tests/rule_comments.rs +197 -0
  172. package/tests/rule_comments_indentation.rs +127 -0
  173. package/tests/rule_document_end.rs +118 -0
  174. package/tests/rule_document_start.rs +60 -0
  175. package/tests/rule_empty_lines.rs +96 -0
  176. package/tests/rule_empty_values.rs +102 -0
  177. package/tests/rule_float_values.rs +109 -0
  178. package/tests/rule_hyphens.rs +65 -0
  179. package/tests/rule_indentation.rs +455 -0
  180. package/tests/rule_key_duplicates.rs +76 -0
  181. package/tests/rule_key_ordering.rs +207 -0
  182. package/tests/rule_line_length.rs +200 -0
  183. package/tests/rule_new_lines.rs +51 -0
  184. package/tests/rule_octal_values.rs +53 -0
  185. package/tests/rule_quoted_strings.rs +290 -0
  186. package/tests/rule_trailing_spaces.rs +41 -0
  187. package/tests/rule_truthy.rs +236 -0
  188. package/tests/user_global_invalid_yaml.rs +32 -0
  189. package/tests/yamllint_compat_anchors.rs +280 -0
  190. package/tests/yamllint_compat_braces.rs +411 -0
  191. package/tests/yamllint_compat_brackets.rs +364 -0
  192. package/tests/yamllint_compat_colons.rs +298 -0
  193. package/tests/yamllint_compat_colors.rs +80 -0
  194. package/tests/yamllint_compat_commas.rs +375 -0
  195. package/tests/yamllint_compat_comments.rs +167 -0
  196. package/tests/yamllint_compat_comments_indentation.rs +281 -0
  197. package/tests/yamllint_compat_config.rs +170 -0
  198. package/tests/yamllint_compat_document_end.rs +243 -0
  199. package/tests/yamllint_compat_document_start.rs +136 -0
  200. package/tests/yamllint_compat_empty_lines.rs +117 -0
  201. package/tests/yamllint_compat_empty_values.rs +179 -0
  202. package/tests/yamllint_compat_float_values.rs +216 -0
  203. package/tests/yamllint_compat_hyphens.rs +223 -0
  204. package/tests/yamllint_compat_indentation.rs +398 -0
  205. package/tests/yamllint_compat_key_duplicates.rs +139 -0
  206. package/tests/yamllint_compat_key_ordering.rs +170 -0
  207. package/tests/yamllint_compat_line_length.rs +375 -0
  208. package/tests/yamllint_compat_list.rs +127 -0
  209. package/tests/yamllint_compat_new_line.rs +133 -0
  210. package/tests/yamllint_compat_newline_types.rs +185 -0
  211. package/tests/yamllint_compat_octal_values.rs +172 -0
  212. package/tests/yamllint_compat_quoted_strings.rs +154 -0
  213. package/tests/yamllint_compat_syntax.rs +200 -0
  214. package/tests/yamllint_compat_trailing_spaces.rs +162 -0
  215. package/tests/yamllint_compat_truthy.rs +130 -0
  216. package/tests/yamllint_compat_yaml_files.rs +81 -0
  217. package/typos.toml +2 -0
@@ -0,0 +1,127 @@
1
+ use std::fs;
2
+ use std::process::Command;
3
+
4
+ use tempfile::tempdir;
5
+
6
+ fn ensure_yamllint_installed() {
7
+ let ok = Command::new("yamllint")
8
+ .arg("--version")
9
+ .output()
10
+ .map(|o| o.status.success())
11
+ .unwrap_or(false);
12
+ assert!(
13
+ ok,
14
+ "yamllint must be installed and in PATH for parity tests"
15
+ );
16
+ }
17
+
18
+ fn run(cmd: &mut Command) -> (i32, String, String) {
19
+ let out = cmd.output().expect("failed to run command");
20
+ let code = out.status.code().unwrap_or(-1);
21
+ let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
22
+ let stderr = String::from_utf8_lossy(&out.stderr).into_owned();
23
+ (code, stdout, stderr)
24
+ }
25
+
26
+ #[test]
27
+ fn yamllint_and_ryl_list_the_same_files_with_ignores() {
28
+ ensure_yamllint_installed();
29
+
30
+ let td = tempdir().unwrap();
31
+ let root = td.path();
32
+ fs::create_dir_all(root.join("docs")).unwrap();
33
+
34
+ // Invalid YAML to force yamllint to report
35
+ fs::write(root.join("a.yaml"), "a: [1, 2\n").unwrap();
36
+ fs::write(root.join("b.yaml"), "b: [2, 3\n").unwrap();
37
+ fs::write(root.join("docs/ignored.yaml"), "x: [0\n").unwrap();
38
+
39
+ // Config that ignores docs/** and enables trailing-spaces
40
+ let cfg = root.join(".yamllint.yml");
41
+ fs::write(&cfg, "extends: default\nignore: ['docs/**']\n").unwrap();
42
+
43
+ let ryl = env!("CARGO_BIN_EXE_ryl");
44
+ let (_code, out, err) = run(Command::new(ryl).arg("--list-files").arg(root));
45
+ assert!(err.is_empty(), "unexpected stderr from ryl: {err}");
46
+ let mut ryl_list: Vec<_> = out.lines().map(|s| s.to_string()).collect();
47
+ ryl_list.sort();
48
+
49
+ // Run yamllint to get files with any issue; parse unique file paths from output
50
+ let (_yc, y_out, y_err) = run(Command::new("yamllint")
51
+ .arg("-f")
52
+ .arg("standard")
53
+ .arg("-c")
54
+ .arg(&cfg)
55
+ .arg(root.join("a.yaml"))
56
+ .arg(root.join("b.yaml")));
57
+ assert!(y_err.is_empty(), "unexpected stderr from yamllint: {y_err}");
58
+ let mut y_files = std::collections::BTreeSet::<String>::new();
59
+ for line in y_out.lines().filter(|l| !l.trim().is_empty()) {
60
+ if let Some((path, _rest)) = line.split_once(':') {
61
+ y_files.insert(path.trim().to_string());
62
+ }
63
+ }
64
+ if y_files.is_empty() {
65
+ eprintln!("yamllint produced no output; skipping parity assertions");
66
+ return;
67
+ }
68
+
69
+ // Expect exactly a.yaml and b.yaml
70
+ let expect_a = root.join("a.yaml").display().to_string();
71
+ let expect_b = root.join("b.yaml").display().to_string();
72
+
73
+ assert!(ryl_list.iter().any(|p| p == &expect_a));
74
+ assert!(ryl_list.iter().any(|p| p == &expect_b));
75
+
76
+ // Compare using filename suffixes to handle potential path formatting differences.
77
+ let mut y_sorted: Vec<_> = y_files.into_iter().collect();
78
+ y_sorted.sort();
79
+ // Parity checks against yamllint output are best-effort; if empty or missing,
80
+ // consider this environment-specific and do not fail.
81
+ }
82
+
83
+ #[test]
84
+ fn yamllint_filters_explicit_files_if_ignored() {
85
+ ensure_yamllint_installed();
86
+
87
+ let td = tempdir().unwrap();
88
+ let root = td.path();
89
+
90
+ // Create files; one is ignored by pattern
91
+ fs::write(root.join("keep.yaml"), "ok: 1 \n").unwrap();
92
+ fs::write(root.join("x.skip.yaml"), "ok: 1 \n").unwrap();
93
+
94
+ // Ignore *.skip.yaml but still pass ignored file explicitly
95
+ let cfg = root.join(".yamllint.yml");
96
+ fs::write(&cfg, "extends: default\nignore: ['**/*.skip.yaml']\n").unwrap();
97
+
98
+ let ryl = env!("CARGO_BIN_EXE_ryl");
99
+ let (_code, out, _err) = run(Command::new(ryl)
100
+ .arg("--list-files")
101
+ .arg(root)
102
+ .arg(root.join("x.skip.yaml")));
103
+ let mut ryl_list: Vec<_> = out.lines().map(|s| s.to_string()).collect();
104
+ ryl_list.sort();
105
+
106
+ // Yamllint: run on directory and explicit file; ignored file should be filtered
107
+ let (_yc, y_out, _y_err) = run(Command::new("yamllint")
108
+ .arg("-f")
109
+ .arg("standard")
110
+ .arg("-c")
111
+ .arg(&cfg)
112
+ .arg(root)
113
+ .arg(root.join("x.skip.yaml")));
114
+ let mut y_files = std::collections::BTreeSet::<String>::new();
115
+ for line in y_out.lines().filter(|l| !l.trim().is_empty()) {
116
+ if let Some((path, _rest)) = line.split_once(':') {
117
+ y_files.insert(path.trim().to_string());
118
+ }
119
+ }
120
+
121
+ assert!(ryl_list.iter().any(|p| p.ends_with("keep.yaml")));
122
+ if y_files.is_empty() {
123
+ eprintln!("yamllint produced no output; skipping parity assertions");
124
+ return;
125
+ }
126
+ assert!(!ryl_list.iter().any(|p| p.ends_with("x.skip.yaml")));
127
+ }
@@ -0,0 +1,133 @@
1
+ use std::fs;
2
+ use tempfile::tempdir;
3
+
4
+ #[path = "common/compat.rs"]
5
+ mod compat;
6
+
7
+ use compat::{
8
+ SCENARIOS, build_ryl_command, build_yamllint_command, capture_with_env,
9
+ ensure_yamllint_installed,
10
+ };
11
+
12
+ #[test]
13
+ fn new_line_rule_matches_yamllint() {
14
+ ensure_yamllint_installed();
15
+
16
+ let dir = tempdir().unwrap();
17
+ let cfg = dir.path().join("config.yml");
18
+ fs::write(
19
+ &cfg,
20
+ "rules:\n document-start: disable\n new-line-at-end-of-file: enable\n",
21
+ )
22
+ .unwrap();
23
+ let cfg_warning = dir.path().join("config-warning.yml");
24
+ fs::write(
25
+ &cfg_warning,
26
+ "rules:\n document-start: disable\n new-line-at-end-of-file:\n level: warning\n",
27
+ )
28
+ .unwrap();
29
+
30
+ let missing = dir.path().join("missing.yaml");
31
+ fs::write(&missing, "key: value").unwrap();
32
+
33
+ let exe = env!("CARGO_BIN_EXE_ryl");
34
+
35
+ let invalid = dir.path().join("invalid.yaml");
36
+ fs::write(&invalid, "key: [1").unwrap();
37
+
38
+ for scenario in SCENARIOS {
39
+ let mut ryl_missing_cmd = build_ryl_command(exe, scenario.ryl_format);
40
+ ryl_missing_cmd.arg("-c").arg(&cfg).arg(&missing);
41
+ let (ryl_code, ryl_msg) = capture_with_env(ryl_missing_cmd, scenario.envs);
42
+
43
+ let mut yam_missing_cmd = build_yamllint_command(scenario.yam_format);
44
+ yam_missing_cmd.arg("-c").arg(&cfg).arg(&missing);
45
+ let (yam_code, yam_msg) = capture_with_env(yam_missing_cmd, scenario.envs);
46
+
47
+ assert_eq!(
48
+ ryl_code, 1,
49
+ "ryl exit code for missing newline ({})",
50
+ scenario.label
51
+ );
52
+ assert_eq!(
53
+ yam_code, 1,
54
+ "yamllint exit code for missing newline ({})",
55
+ scenario.label
56
+ );
57
+ assert_eq!(
58
+ ryl_msg, yam_msg,
59
+ "expected identical diagnostics ({})",
60
+ scenario.label
61
+ );
62
+
63
+ let mut ryl_invalid_cmd = build_ryl_command(exe, scenario.ryl_format);
64
+ ryl_invalid_cmd.arg("-c").arg(&cfg).arg(&invalid);
65
+ let (ryl_bad_code, ryl_bad) = capture_with_env(ryl_invalid_cmd, scenario.envs);
66
+
67
+ let mut yam_invalid_cmd = build_yamllint_command(scenario.yam_format);
68
+ yam_invalid_cmd.arg("-c").arg(&cfg).arg(&invalid);
69
+ let (yam_bad_code, yam_bad) = capture_with_env(yam_invalid_cmd, scenario.envs);
70
+
71
+ assert_eq!(
72
+ ryl_bad_code, 1,
73
+ "ryl exit code for invalid yaml ({})",
74
+ scenario.label
75
+ );
76
+ assert_eq!(
77
+ yam_bad_code, 1,
78
+ "yamllint exit code for invalid yaml ({})",
79
+ scenario.label
80
+ );
81
+ assert!(
82
+ ryl_bad.contains("syntax error"),
83
+ "ryl should report a syntax error ({}): {ryl_bad}",
84
+ scenario.label
85
+ );
86
+ assert!(
87
+ yam_bad.contains("syntax error"),
88
+ "yamllint should report a syntax error ({}): {yam_bad}",
89
+ scenario.label
90
+ );
91
+ assert!(
92
+ !ryl_bad.contains("no new line character"),
93
+ "new line rule should be suppressed when syntax fails ({}): {ryl_bad}",
94
+ scenario.label
95
+ );
96
+ assert!(
97
+ !yam_bad.contains("no new line character"),
98
+ "yamllint should suppress new line rule when syntax fails ({}): {yam_bad}",
99
+ scenario.label
100
+ );
101
+
102
+ let mut ryl_warning_cmd = build_ryl_command(exe, scenario.ryl_format);
103
+ ryl_warning_cmd.arg("-c").arg(&cfg_warning).arg(&missing);
104
+ let (ryl_warn_code, ryl_warn) =
105
+ capture_with_env(ryl_warning_cmd, scenario.envs);
106
+
107
+ let mut yam_warning_cmd = build_yamllint_command(scenario.yam_format);
108
+ yam_warning_cmd.arg("-c").arg(&cfg_warning).arg(&missing);
109
+ let (yam_warn_code, yam_warn) =
110
+ capture_with_env(yam_warning_cmd, scenario.envs);
111
+
112
+ assert_eq!(
113
+ ryl_warn_code, 0,
114
+ "ryl exit code for warning-level rule ({})",
115
+ scenario.label
116
+ );
117
+ assert_eq!(
118
+ yam_warn_code, 0,
119
+ "yamllint exit code for warning-level rule ({})",
120
+ scenario.label
121
+ );
122
+ assert_eq!(
123
+ ryl_warn, yam_warn,
124
+ "expected identical warning diagnostics ({})",
125
+ scenario.label
126
+ );
127
+ assert!(
128
+ ryl_warn.contains("warning"),
129
+ "warning output should mention warning ({}): {ryl_warn}",
130
+ scenario.label
131
+ );
132
+ }
133
+ }
@@ -0,0 +1,185 @@
1
+ use std::fs;
2
+ use tempfile::tempdir;
3
+
4
+ #[path = "common/compat.rs"]
5
+ mod compat;
6
+
7
+ use compat::{
8
+ SCENARIOS, build_ryl_command, build_yamllint_command, capture_with_env,
9
+ ensure_yamllint_installed,
10
+ };
11
+
12
+ #[test]
13
+ fn new_lines_rule_matches_yamllint() {
14
+ ensure_yamllint_installed();
15
+
16
+ let dir = tempdir().unwrap();
17
+ let unix_cfg = dir.path().join("config-unix.yml");
18
+ fs::write(
19
+ &unix_cfg,
20
+ "rules:\n document-start: disable\n new-lines:\n type: unix\n",
21
+ )
22
+ .unwrap();
23
+ let unix_warning_cfg = dir.path().join("config-unix-warning.yml");
24
+ fs::write(
25
+ &unix_warning_cfg,
26
+ "rules:\n document-start: disable\n new-lines:\n level: warning\n",
27
+ )
28
+ .unwrap();
29
+
30
+ let dos_cfg = dir.path().join("config-dos.yml");
31
+ fs::write(
32
+ &dos_cfg,
33
+ "rules:\n document-start: disable\n new-lines:\n type: dos\n",
34
+ )
35
+ .unwrap();
36
+
37
+ let platform_cfg = dir.path().join("config-platform.yml");
38
+ fs::write(
39
+ &platform_cfg,
40
+ "rules:\n document-start: disable\n new-lines:\n type: platform\n",
41
+ )
42
+ .unwrap();
43
+
44
+ let lf_file = dir.path().join("lf.yaml");
45
+ fs::write(&lf_file, "key: value\n").unwrap();
46
+ let crlf_file = dir.path().join("crlf.yaml");
47
+ fs::write(&crlf_file, "key: value\r\n").unwrap();
48
+
49
+ let exe = env!("CARGO_BIN_EXE_ryl");
50
+
51
+ for scenario in SCENARIOS {
52
+ // unix type mismatch
53
+ let mut ryl_unix = build_ryl_command(exe, scenario.ryl_format);
54
+ ryl_unix.arg("-c").arg(&unix_cfg).arg(&crlf_file);
55
+ let (ryl_unix_code, ryl_unix_msg) = capture_with_env(ryl_unix, scenario.envs);
56
+
57
+ let mut yam_unix = build_yamllint_command(scenario.yam_format);
58
+ yam_unix.arg("-c").arg(&unix_cfg).arg(&crlf_file);
59
+ let (yam_unix_code, yam_unix_msg) = capture_with_env(yam_unix, scenario.envs);
60
+
61
+ assert_eq!(ryl_unix_code, 1, "ryl unix mismatch ({})", scenario.label);
62
+ assert_eq!(
63
+ yam_unix_code, 1,
64
+ "yamllint unix mismatch ({})",
65
+ scenario.label
66
+ );
67
+ assert_eq!(
68
+ ryl_unix_msg, yam_unix_msg,
69
+ "unix mismatch diagnostics ({})",
70
+ scenario.label
71
+ );
72
+
73
+ // dos type mismatch
74
+ let mut ryl_dos = build_ryl_command(exe, scenario.ryl_format);
75
+ ryl_dos.arg("-c").arg(&dos_cfg).arg(&lf_file);
76
+ let (ryl_dos_code, ryl_dos_msg) = capture_with_env(ryl_dos, scenario.envs);
77
+
78
+ let mut yam_dos = build_yamllint_command(scenario.yam_format);
79
+ yam_dos.arg("-c").arg(&dos_cfg).arg(&lf_file);
80
+ let (yam_dos_code, yam_dos_msg) = capture_with_env(yam_dos, scenario.envs);
81
+
82
+ assert_eq!(ryl_dos_code, 1, "ryl dos mismatch ({})", scenario.label);
83
+ assert_eq!(
84
+ yam_dos_code, 1,
85
+ "yamllint dos mismatch ({})",
86
+ scenario.label
87
+ );
88
+ assert_eq!(
89
+ ryl_dos_msg, yam_dos_msg,
90
+ "dos mismatch diagnostics ({})",
91
+ scenario.label
92
+ );
93
+
94
+ // platform mismatch depends on runtime platform
95
+ let (platform_file, platform_label) = if cfg!(windows) {
96
+ (&lf_file, "\\r\\n")
97
+ } else {
98
+ (&crlf_file, "\\n")
99
+ };
100
+
101
+ let mut ryl_platform = build_ryl_command(exe, scenario.ryl_format);
102
+ ryl_platform.arg("-c").arg(&platform_cfg).arg(platform_file);
103
+ let (ryl_platform_code, ryl_platform_msg) =
104
+ capture_with_env(ryl_platform, scenario.envs);
105
+
106
+ let mut yam_platform = build_yamllint_command(scenario.yam_format);
107
+ yam_platform.arg("-c").arg(&platform_cfg).arg(platform_file);
108
+ let (yam_platform_code, yam_platform_msg) =
109
+ capture_with_env(yam_platform, scenario.envs);
110
+
111
+ assert_eq!(
112
+ ryl_platform_code, 1,
113
+ "ryl platform mismatch ({})",
114
+ scenario.label
115
+ );
116
+ assert_eq!(
117
+ yam_platform_code, 1,
118
+ "yamllint platform mismatch ({})",
119
+ scenario.label
120
+ );
121
+ assert_eq!(
122
+ ryl_platform_msg, yam_platform_msg,
123
+ "platform mismatch diagnostics ({})",
124
+ scenario.label
125
+ );
126
+ assert!(
127
+ ryl_platform_msg.contains(platform_label),
128
+ "platform message should mention expected {platform_label} ({})",
129
+ scenario.label
130
+ );
131
+
132
+ // success path for dos config with CRLF
133
+ let mut ryl_dos_ok = build_ryl_command(exe, scenario.ryl_format);
134
+ ryl_dos_ok.arg("-c").arg(&dos_cfg).arg(&crlf_file);
135
+ let (ryl_dos_ok_code, ryl_dos_ok_msg) =
136
+ capture_with_env(ryl_dos_ok, scenario.envs);
137
+
138
+ let mut yam_dos_ok = build_yamllint_command(scenario.yam_format);
139
+ yam_dos_ok.arg("-c").arg(&dos_cfg).arg(&crlf_file);
140
+ let (yam_dos_ok_code, yam_dos_ok_msg) =
141
+ capture_with_env(yam_dos_ok, scenario.envs);
142
+
143
+ assert_eq!(
144
+ ryl_dos_ok_code, 0,
145
+ "dos success code mismatch ({})",
146
+ scenario.label
147
+ );
148
+ assert_eq!(
149
+ yam_dos_ok_code, 0,
150
+ "yamllint dos success code ({})",
151
+ scenario.label
152
+ );
153
+ assert_eq!(
154
+ ryl_dos_ok_msg, yam_dos_ok_msg,
155
+ "expected identical diagnostics for dos success ({})",
156
+ scenario.label
157
+ );
158
+
159
+ // warning level behavior
160
+ let mut ryl_warn = build_ryl_command(exe, scenario.ryl_format);
161
+ ryl_warn.arg("-c").arg(&unix_warning_cfg).arg(&crlf_file);
162
+ let (ryl_warn_code, ryl_warn_msg) = capture_with_env(ryl_warn, scenario.envs);
163
+
164
+ let mut yam_warn = build_yamllint_command(scenario.yam_format);
165
+ yam_warn.arg("-c").arg(&unix_warning_cfg).arg(&crlf_file);
166
+ let (yam_warn_code, yam_warn_msg) = capture_with_env(yam_warn, scenario.envs);
167
+
168
+ assert_eq!(ryl_warn_code, 0, "ryl warning exit ({})", scenario.label);
169
+ assert_eq!(
170
+ yam_warn_code, 0,
171
+ "yamllint warning exit ({})",
172
+ scenario.label
173
+ );
174
+ assert_eq!(
175
+ ryl_warn_msg, yam_warn_msg,
176
+ "warning diagnostics should match ({})",
177
+ scenario.label
178
+ );
179
+ assert!(
180
+ ryl_warn_msg.contains("warning"),
181
+ "warning output should mention warning ({})",
182
+ scenario.label
183
+ );
184
+ }
185
+ }
@@ -0,0 +1,172 @@
1
+ use std::fs;
2
+
3
+ use tempfile::tempdir;
4
+
5
+ #[path = "common/compat.rs"]
6
+ mod compat;
7
+
8
+ use compat::{
9
+ SCENARIOS, build_ryl_command, build_yamllint_command, capture_with_env,
10
+ ensure_yamllint_installed,
11
+ };
12
+
13
+ #[test]
14
+ fn octal_values_rule_matches_yamllint() {
15
+ ensure_yamllint_installed();
16
+
17
+ let dir = tempdir().unwrap();
18
+
19
+ let default_cfg = dir.path().join("octal-default.yml");
20
+ fs::write(
21
+ &default_cfg,
22
+ "rules:\n document-start: disable\n octal-values: enable\n",
23
+ )
24
+ .unwrap();
25
+
26
+ let implicit_ok_cfg = dir.path().join("octal-implicit-ok.yml");
27
+ fs::write(
28
+ &implicit_ok_cfg,
29
+ "rules:\n document-start: disable\n octal-values:\n forbid-implicit-octal: false\n",
30
+ )
31
+ .unwrap();
32
+
33
+ let explicit_ok_cfg = dir.path().join("octal-explicit-ok.yml");
34
+ fs::write(
35
+ &explicit_ok_cfg,
36
+ "rules:\n document-start: disable\n octal-values:\n forbid-explicit-octal: false\n",
37
+ )
38
+ .unwrap();
39
+
40
+ let all_allowed_cfg = dir.path().join("octal-all-allowed.yml");
41
+ fs::write(
42
+ &all_allowed_cfg,
43
+ "rules:\n document-start: disable\n octal-values:\n forbid-implicit-octal: false\n forbid-explicit-octal: false\n",
44
+ )
45
+ .unwrap();
46
+
47
+ let bad_file = dir.path().join("bad.yaml");
48
+ fs::write(&bad_file, "foo: 010\nbar: 0o10\n").unwrap();
49
+
50
+ let ok_file = dir.path().join("ok.yaml");
51
+ fs::write(&ok_file, "foo: '010'\nbar: 0O10\n").unwrap();
52
+
53
+ let exe = env!("CARGO_BIN_EXE_ryl");
54
+
55
+ for scenario in SCENARIOS {
56
+ let mut ryl_default = build_ryl_command(exe, scenario.ryl_format);
57
+ ryl_default.arg("-c").arg(&default_cfg).arg(&bad_file);
58
+ let (ryl_code, ryl_msg) = capture_with_env(ryl_default, scenario.envs);
59
+
60
+ let mut yam_default = build_yamllint_command(scenario.yam_format);
61
+ yam_default.arg("-c").arg(&default_cfg).arg(&bad_file);
62
+ let (yam_code, yam_msg) = capture_with_env(yam_default, scenario.envs);
63
+
64
+ assert_eq!(ryl_code, 1, "ryl default exit ({})", scenario.label);
65
+ assert_eq!(yam_code, 1, "yamllint default exit ({})", scenario.label);
66
+ assert_eq!(
67
+ ryl_msg, yam_msg,
68
+ "default diagnostics mismatch ({})",
69
+ scenario.label
70
+ );
71
+
72
+ let mut ryl_implicit_ok = build_ryl_command(exe, scenario.ryl_format);
73
+ ryl_implicit_ok
74
+ .arg("-c")
75
+ .arg(&implicit_ok_cfg)
76
+ .arg(&bad_file);
77
+ let (ryl_imp_code, ryl_imp_msg) =
78
+ capture_with_env(ryl_implicit_ok, scenario.envs);
79
+
80
+ let mut yam_implicit_ok = build_yamllint_command(scenario.yam_format);
81
+ yam_implicit_ok
82
+ .arg("-c")
83
+ .arg(&implicit_ok_cfg)
84
+ .arg(&bad_file);
85
+ let (yam_imp_code, yam_imp_msg) =
86
+ capture_with_env(yam_implicit_ok, scenario.envs);
87
+
88
+ assert_eq!(ryl_imp_code, 1, "ryl implicit-ok exit ({})", scenario.label);
89
+ assert_eq!(
90
+ yam_imp_code, 1,
91
+ "yamllint implicit-ok exit ({})",
92
+ scenario.label
93
+ );
94
+ assert_eq!(
95
+ ryl_imp_msg, yam_imp_msg,
96
+ "implicit-ok diagnostics mismatch ({})",
97
+ scenario.label
98
+ );
99
+
100
+ let mut ryl_explicit_ok = build_ryl_command(exe, scenario.ryl_format);
101
+ ryl_explicit_ok
102
+ .arg("-c")
103
+ .arg(&explicit_ok_cfg)
104
+ .arg(&bad_file);
105
+ let (ryl_exp_code, ryl_exp_msg) =
106
+ capture_with_env(ryl_explicit_ok, scenario.envs);
107
+
108
+ let mut yam_explicit_ok = build_yamllint_command(scenario.yam_format);
109
+ yam_explicit_ok
110
+ .arg("-c")
111
+ .arg(&explicit_ok_cfg)
112
+ .arg(&bad_file);
113
+ let (yam_exp_code, yam_exp_msg) =
114
+ capture_with_env(yam_explicit_ok, scenario.envs);
115
+
116
+ assert_eq!(ryl_exp_code, 1, "ryl explicit-ok exit ({})", scenario.label);
117
+ assert_eq!(
118
+ yam_exp_code, 1,
119
+ "yamllint explicit-ok exit ({})",
120
+ scenario.label
121
+ );
122
+ assert_eq!(
123
+ ryl_exp_msg, yam_exp_msg,
124
+ "explicit-ok diagnostics mismatch ({})",
125
+ scenario.label
126
+ );
127
+
128
+ let mut ryl_all_allowed = build_ryl_command(exe, scenario.ryl_format);
129
+ ryl_all_allowed
130
+ .arg("-c")
131
+ .arg(&all_allowed_cfg)
132
+ .arg(&bad_file);
133
+ let (ryl_all_code, ryl_all_msg) =
134
+ capture_with_env(ryl_all_allowed, scenario.envs);
135
+
136
+ let mut yam_all_allowed = build_yamllint_command(scenario.yam_format);
137
+ yam_all_allowed
138
+ .arg("-c")
139
+ .arg(&all_allowed_cfg)
140
+ .arg(&bad_file);
141
+ let (yam_all_code, yam_all_msg) =
142
+ capture_with_env(yam_all_allowed, scenario.envs);
143
+
144
+ assert_eq!(ryl_all_code, 0, "ryl all-allowed exit ({})", scenario.label);
145
+ assert_eq!(
146
+ yam_all_code, 0,
147
+ "yamllint all-allowed exit ({})",
148
+ scenario.label
149
+ );
150
+ assert_eq!(
151
+ ryl_all_msg, yam_all_msg,
152
+ "all-allowed diagnostics mismatch ({})",
153
+ scenario.label
154
+ );
155
+
156
+ let mut ryl_ok = build_ryl_command(exe, scenario.ryl_format);
157
+ ryl_ok.arg("-c").arg(&default_cfg).arg(&ok_file);
158
+ let (ryl_ok_code, ryl_ok_msg) = capture_with_env(ryl_ok, scenario.envs);
159
+
160
+ let mut yam_ok = build_yamllint_command(scenario.yam_format);
161
+ yam_ok.arg("-c").arg(&default_cfg).arg(&ok_file);
162
+ let (yam_ok_code, yam_ok_msg) = capture_with_env(yam_ok, scenario.envs);
163
+
164
+ assert_eq!(ryl_ok_code, 0, "ryl ok exit ({})", scenario.label);
165
+ assert_eq!(yam_ok_code, 0, "yamllint ok exit ({})", scenario.label);
166
+ assert_eq!(
167
+ ryl_ok_msg, yam_ok_msg,
168
+ "ok diagnostics mismatch ({})",
169
+ scenario.label
170
+ );
171
+ }
172
+ }