deprecated.rs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // Copyright 2013-2014 The rust-url developers.
  2. //
  3. // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
  4. // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
  5. // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
  6. // option. This file may not be copied, modified, or distributed
  7. // except according to those terms.
  8. #![allow(clippy::assigning_clones)]
  9. #![allow(deprecated)]
  10. use crate::test::TestFn;
  11. use std::char;
  12. use std::fmt::Write;
  13. use idna::Errors;
  14. pub fn collect_tests<F: FnMut(String, TestFn)>(add_test: &mut F) {
  15. // https://www.unicode.org/Public/idna/13.0.0/IdnaTestV2.txt
  16. for (i, line) in include_str!("IdnaTestV2.txt").lines().enumerate() {
  17. if line.is_empty() || line.starts_with('#') {
  18. continue;
  19. }
  20. // Remove comments
  21. let line = match line.find('#') {
  22. Some(index) => &line[0..index],
  23. None => line,
  24. };
  25. let mut pieces = line.split(';').map(|x| x.trim()).collect::<Vec<&str>>();
  26. let source = unescape(pieces.remove(0));
  27. // ToUnicode
  28. let mut to_unicode = unescape(pieces.remove(0));
  29. if to_unicode.is_empty() {
  30. to_unicode = source.clone();
  31. }
  32. let to_unicode_status = status(pieces.remove(0));
  33. // ToAsciiN
  34. let to_ascii_n = pieces.remove(0);
  35. let to_ascii_n = if to_ascii_n.is_empty() {
  36. to_unicode.clone()
  37. } else {
  38. to_ascii_n.to_owned()
  39. };
  40. let to_ascii_n_status = pieces.remove(0);
  41. let to_ascii_n_status = if to_ascii_n_status.is_empty() {
  42. to_unicode_status.clone()
  43. } else {
  44. status(to_ascii_n_status)
  45. };
  46. // ToAsciiT
  47. let to_ascii_t = pieces.remove(0);
  48. let to_ascii_t = if to_ascii_t.is_empty() {
  49. to_ascii_n.clone()
  50. } else {
  51. to_ascii_t.to_owned()
  52. };
  53. let to_ascii_t_status = pieces.remove(0);
  54. let to_ascii_t_status = if to_ascii_t_status.is_empty() {
  55. to_ascii_n_status.clone()
  56. } else {
  57. status(to_ascii_t_status)
  58. };
  59. let test_name = format!("UTS #46 (deprecated API) line {}", i + 1);
  60. add_test(
  61. test_name,
  62. TestFn::DynTestFn(Box::new(move || {
  63. let config = idna::Config::default()
  64. .use_std3_ascii_rules(true)
  65. .verify_dns_length(true)
  66. .check_hyphens(true);
  67. // http://unicode.org/reports/tr46/#Deviations
  68. // applications that perform IDNA2008 lookup are not required to check
  69. // for these contexts, so we skip all tests annotated with C*
  70. // Everybody ignores V2
  71. // https://github.com/servo/rust-url/pull/240
  72. // https://github.com/whatwg/url/issues/53#issuecomment-181528158
  73. // http://www.unicode.org/review/pri317/
  74. // "The special error codes X3 and X4_2 are now returned where a toASCII error code
  75. // was formerly being generated in toUnicode due to an empty label."
  76. // This is not implemented yet, so we skip toUnicode X4_2 tests for now, too.
  77. let (to_unicode_value, to_unicode_result) =
  78. config.transitional_processing(false).to_unicode(&source);
  79. let to_unicode_result = to_unicode_result.map(|()| to_unicode_value);
  80. check(
  81. &source,
  82. (&to_unicode, &to_unicode_status),
  83. to_unicode_result,
  84. |e| e == "X4_2" || e == "V2",
  85. );
  86. let to_ascii_n_result = config.transitional_processing(false).to_ascii(&source);
  87. check(
  88. &source,
  89. (&to_ascii_n, &to_ascii_n_status),
  90. to_ascii_n_result,
  91. |e| e == "V2",
  92. );
  93. let to_ascii_t_result = config.transitional_processing(true).to_ascii(&source);
  94. check(
  95. &source,
  96. (&to_ascii_t, &to_ascii_t_status),
  97. to_ascii_t_result,
  98. |e| e == "V2",
  99. );
  100. })),
  101. )
  102. }
  103. }
  104. #[allow(clippy::redundant_clone)]
  105. fn check<F>(source: &str, expected: (&str, &[&str]), actual: Result<String, Errors>, ignore: F)
  106. where
  107. F: Fn(&str) -> bool,
  108. {
  109. if !expected.1.is_empty() {
  110. if !expected.1.iter().copied().any(ignore) {
  111. let res = actual.ok();
  112. assert_eq!(
  113. res.clone(),
  114. None,
  115. "Expected error {:?}. result: {} | source: {}",
  116. expected.1,
  117. res.unwrap(),
  118. source,
  119. );
  120. }
  121. } else {
  122. assert!(
  123. actual.is_ok(),
  124. "Couldn't parse {} | error: {:?}",
  125. source,
  126. actual.err().unwrap(),
  127. );
  128. assert_eq!(actual.unwrap(), expected.0, "source: {}", source);
  129. }
  130. }
  131. fn unescape(input: &str) -> String {
  132. let mut output = String::new();
  133. let mut chars = input.chars();
  134. loop {
  135. match chars.next() {
  136. None => return output,
  137. Some(c) => {
  138. if c == '\\' {
  139. match chars.next().unwrap() {
  140. '\\' => output.push('\\'),
  141. 'u' => {
  142. let c1 = chars.next().unwrap().to_digit(16).unwrap();
  143. let c2 = chars.next().unwrap().to_digit(16).unwrap();
  144. let c3 = chars.next().unwrap().to_digit(16).unwrap();
  145. let c4 = chars.next().unwrap().to_digit(16).unwrap();
  146. match char::from_u32(((c1 * 16 + c2) * 16 + c3) * 16 + c4) {
  147. Some(c) => output.push(c),
  148. None => {
  149. write!(&mut output, "\\u{:X}{:X}{:X}{:X}", c1, c2, c3, c4)
  150. .expect("Could not write to output");
  151. }
  152. };
  153. }
  154. _ => panic!("Invalid test data input"),
  155. }
  156. } else {
  157. output.push(c);
  158. }
  159. }
  160. }
  161. }
  162. }
  163. fn status(status: &str) -> Vec<&str> {
  164. if status.is_empty() || status == "[]" {
  165. return Vec::new();
  166. }
  167. let mut result = status.split(", ").collect::<Vec<_>>();
  168. assert!(result[0].starts_with('['));
  169. result[0] = &result[0][1..];
  170. let idx = result.len() - 1;
  171. let last = &mut result[idx];
  172. assert!(last.ends_with(']'));
  173. *last = &last[..last.len() - 1];
  174. result
  175. }