|
4 | 4 | use std::str::Chars; |
5 | 5 | use std::ops::Range; |
6 | 6 |
|
| 7 | +#[cfg(test)] |
| 8 | +mod tests; |
| 9 | + |
7 | 10 | #[derive(Debug, PartialEq, Eq)] |
8 | 11 | pub enum EscapeError { |
9 | 12 | ZeroChars, |
@@ -320,283 +323,3 @@ fn byte_from_char(c: char) -> u8 { |
320 | 323 | fn is_ascii(x: u32) -> bool { |
321 | 324 | x <= 0x7F |
322 | 325 | } |
323 | | - |
324 | | -#[cfg(test)] |
325 | | -mod tests { |
326 | | - use super::*; |
327 | | - |
328 | | - #[test] |
329 | | - fn test_unescape_char_bad() { |
330 | | - fn check(literal_text: &str, expected_error: EscapeError) { |
331 | | - let actual_result = unescape_char(literal_text).map_err(|(_offset, err)| err); |
332 | | - assert_eq!(actual_result, Err(expected_error)); |
333 | | - } |
334 | | - |
335 | | - check("", EscapeError::ZeroChars); |
336 | | - check(r"\", EscapeError::LoneSlash); |
337 | | - |
338 | | - check("\n", EscapeError::EscapeOnlyChar); |
339 | | - check("\r\n", EscapeError::EscapeOnlyChar); |
340 | | - check("\t", EscapeError::EscapeOnlyChar); |
341 | | - check("'", EscapeError::EscapeOnlyChar); |
342 | | - check("\r", EscapeError::BareCarriageReturn); |
343 | | - |
344 | | - check("spam", EscapeError::MoreThanOneChar); |
345 | | - check(r"\x0ff", EscapeError::MoreThanOneChar); |
346 | | - check(r#"\"a"#, EscapeError::MoreThanOneChar); |
347 | | - check(r"\na", EscapeError::MoreThanOneChar); |
348 | | - check(r"\ra", EscapeError::MoreThanOneChar); |
349 | | - check(r"\ta", EscapeError::MoreThanOneChar); |
350 | | - check(r"\\a", EscapeError::MoreThanOneChar); |
351 | | - check(r"\'a", EscapeError::MoreThanOneChar); |
352 | | - check(r"\0a", EscapeError::MoreThanOneChar); |
353 | | - check(r"\u{0}x", EscapeError::MoreThanOneChar); |
354 | | - check(r"\u{1F63b}}", EscapeError::MoreThanOneChar); |
355 | | - |
356 | | - check(r"\v", EscapeError::InvalidEscape); |
357 | | - check(r"\💩", EscapeError::InvalidEscape); |
358 | | - check(r"\●", EscapeError::InvalidEscape); |
359 | | - |
360 | | - check(r"\x", EscapeError::TooShortHexEscape); |
361 | | - check(r"\x0", EscapeError::TooShortHexEscape); |
362 | | - check(r"\xf", EscapeError::TooShortHexEscape); |
363 | | - check(r"\xa", EscapeError::TooShortHexEscape); |
364 | | - check(r"\xx", EscapeError::InvalidCharInHexEscape); |
365 | | - check(r"\xы", EscapeError::InvalidCharInHexEscape); |
366 | | - check(r"\x🦀", EscapeError::InvalidCharInHexEscape); |
367 | | - check(r"\xtt", EscapeError::InvalidCharInHexEscape); |
368 | | - check(r"\xff", EscapeError::OutOfRangeHexEscape); |
369 | | - check(r"\xFF", EscapeError::OutOfRangeHexEscape); |
370 | | - check(r"\x80", EscapeError::OutOfRangeHexEscape); |
371 | | - |
372 | | - check(r"\u", EscapeError::NoBraceInUnicodeEscape); |
373 | | - check(r"\u[0123]", EscapeError::NoBraceInUnicodeEscape); |
374 | | - check(r"\u{0x}", EscapeError::InvalidCharInUnicodeEscape); |
375 | | - check(r"\u{", EscapeError::UnclosedUnicodeEscape); |
376 | | - check(r"\u{0000", EscapeError::UnclosedUnicodeEscape); |
377 | | - check(r"\u{}", EscapeError::EmptyUnicodeEscape); |
378 | | - check(r"\u{_0000}", EscapeError::LeadingUnderscoreUnicodeEscape); |
379 | | - check(r"\u{0000000}", EscapeError::OverlongUnicodeEscape); |
380 | | - check(r"\u{FFFFFF}", EscapeError::OutOfRangeUnicodeEscape); |
381 | | - check(r"\u{ffffff}", EscapeError::OutOfRangeUnicodeEscape); |
382 | | - check(r"\u{ffffff}", EscapeError::OutOfRangeUnicodeEscape); |
383 | | - |
384 | | - check(r"\u{DC00}", EscapeError::LoneSurrogateUnicodeEscape); |
385 | | - check(r"\u{DDDD}", EscapeError::LoneSurrogateUnicodeEscape); |
386 | | - check(r"\u{DFFF}", EscapeError::LoneSurrogateUnicodeEscape); |
387 | | - |
388 | | - check(r"\u{D800}", EscapeError::LoneSurrogateUnicodeEscape); |
389 | | - check(r"\u{DAAA}", EscapeError::LoneSurrogateUnicodeEscape); |
390 | | - check(r"\u{DBFF}", EscapeError::LoneSurrogateUnicodeEscape); |
391 | | - } |
392 | | - |
393 | | - #[test] |
394 | | - fn test_unescape_char_good() { |
395 | | - fn check(literal_text: &str, expected_char: char) { |
396 | | - let actual_result = unescape_char(literal_text); |
397 | | - assert_eq!(actual_result, Ok(expected_char)); |
398 | | - } |
399 | | - |
400 | | - check("a", 'a'); |
401 | | - check("ы", 'ы'); |
402 | | - check("🦀", '🦀'); |
403 | | - |
404 | | - check(r#"\""#, '"'); |
405 | | - check(r"\n", '\n'); |
406 | | - check(r"\r", '\r'); |
407 | | - check(r"\t", '\t'); |
408 | | - check(r"\\", '\\'); |
409 | | - check(r"\'", '\''); |
410 | | - check(r"\0", '\0'); |
411 | | - |
412 | | - check(r"\x00", '\0'); |
413 | | - check(r"\x5a", 'Z'); |
414 | | - check(r"\x5A", 'Z'); |
415 | | - check(r"\x7f", 127 as char); |
416 | | - |
417 | | - check(r"\u{0}", '\0'); |
418 | | - check(r"\u{000000}", '\0'); |
419 | | - check(r"\u{41}", 'A'); |
420 | | - check(r"\u{0041}", 'A'); |
421 | | - check(r"\u{00_41}", 'A'); |
422 | | - check(r"\u{4__1__}", 'A'); |
423 | | - check(r"\u{1F63b}", '😻'); |
424 | | - } |
425 | | - |
426 | | - #[test] |
427 | | - fn test_unescape_str_good() { |
428 | | - fn check(literal_text: &str, expected: &str) { |
429 | | - let mut buf = Ok(String::with_capacity(literal_text.len())); |
430 | | - unescape_str(literal_text, &mut |range, c| { |
431 | | - if let Ok(b) = &mut buf { |
432 | | - match c { |
433 | | - Ok(c) => b.push(c), |
434 | | - Err(e) => buf = Err((range, e)), |
435 | | - } |
436 | | - } |
437 | | - }); |
438 | | - let buf = buf.as_ref().map(|it| it.as_ref()); |
439 | | - assert_eq!(buf, Ok(expected)) |
440 | | - } |
441 | | - |
442 | | - check("foo", "foo"); |
443 | | - check("", ""); |
444 | | - check(" \t\n\r\n", " \t\n\n"); |
445 | | - |
446 | | - check("hello \\\n world", "hello world"); |
447 | | - check("hello \\\r\n world", "hello world"); |
448 | | - check("thread's", "thread's") |
449 | | - } |
450 | | - |
451 | | - #[test] |
452 | | - fn test_unescape_byte_bad() { |
453 | | - fn check(literal_text: &str, expected_error: EscapeError) { |
454 | | - let actual_result = unescape_byte(literal_text).map_err(|(_offset, err)| err); |
455 | | - assert_eq!(actual_result, Err(expected_error)); |
456 | | - } |
457 | | - |
458 | | - check("", EscapeError::ZeroChars); |
459 | | - check(r"\", EscapeError::LoneSlash); |
460 | | - |
461 | | - check("\n", EscapeError::EscapeOnlyChar); |
462 | | - check("\r\n", EscapeError::EscapeOnlyChar); |
463 | | - check("\t", EscapeError::EscapeOnlyChar); |
464 | | - check("'", EscapeError::EscapeOnlyChar); |
465 | | - check("\r", EscapeError::BareCarriageReturn); |
466 | | - |
467 | | - check("spam", EscapeError::MoreThanOneChar); |
468 | | - check(r"\x0ff", EscapeError::MoreThanOneChar); |
469 | | - check(r#"\"a"#, EscapeError::MoreThanOneChar); |
470 | | - check(r"\na", EscapeError::MoreThanOneChar); |
471 | | - check(r"\ra", EscapeError::MoreThanOneChar); |
472 | | - check(r"\ta", EscapeError::MoreThanOneChar); |
473 | | - check(r"\\a", EscapeError::MoreThanOneChar); |
474 | | - check(r"\'a", EscapeError::MoreThanOneChar); |
475 | | - check(r"\0a", EscapeError::MoreThanOneChar); |
476 | | - |
477 | | - check(r"\v", EscapeError::InvalidEscape); |
478 | | - check(r"\💩", EscapeError::InvalidEscape); |
479 | | - check(r"\●", EscapeError::InvalidEscape); |
480 | | - |
481 | | - check(r"\x", EscapeError::TooShortHexEscape); |
482 | | - check(r"\x0", EscapeError::TooShortHexEscape); |
483 | | - check(r"\xa", EscapeError::TooShortHexEscape); |
484 | | - check(r"\xf", EscapeError::TooShortHexEscape); |
485 | | - check(r"\xx", EscapeError::InvalidCharInHexEscape); |
486 | | - check(r"\xы", EscapeError::InvalidCharInHexEscape); |
487 | | - check(r"\x🦀", EscapeError::InvalidCharInHexEscape); |
488 | | - check(r"\xtt", EscapeError::InvalidCharInHexEscape); |
489 | | - |
490 | | - check(r"\u", EscapeError::NoBraceInUnicodeEscape); |
491 | | - check(r"\u[0123]", EscapeError::NoBraceInUnicodeEscape); |
492 | | - check(r"\u{0x}", EscapeError::InvalidCharInUnicodeEscape); |
493 | | - check(r"\u{", EscapeError::UnclosedUnicodeEscape); |
494 | | - check(r"\u{0000", EscapeError::UnclosedUnicodeEscape); |
495 | | - check(r"\u{}", EscapeError::EmptyUnicodeEscape); |
496 | | - check(r"\u{_0000}", EscapeError::LeadingUnderscoreUnicodeEscape); |
497 | | - check(r"\u{0000000}", EscapeError::OverlongUnicodeEscape); |
498 | | - |
499 | | - check("ы", EscapeError::NonAsciiCharInByte); |
500 | | - check("🦀", EscapeError::NonAsciiCharInByte); |
501 | | - |
502 | | - check(r"\u{0}", EscapeError::UnicodeEscapeInByte); |
503 | | - check(r"\u{000000}", EscapeError::UnicodeEscapeInByte); |
504 | | - check(r"\u{41}", EscapeError::UnicodeEscapeInByte); |
505 | | - check(r"\u{0041}", EscapeError::UnicodeEscapeInByte); |
506 | | - check(r"\u{00_41}", EscapeError::UnicodeEscapeInByte); |
507 | | - check(r"\u{4__1__}", EscapeError::UnicodeEscapeInByte); |
508 | | - check(r"\u{1F63b}", EscapeError::UnicodeEscapeInByte); |
509 | | - check(r"\u{0}x", EscapeError::UnicodeEscapeInByte); |
510 | | - check(r"\u{1F63b}}", EscapeError::UnicodeEscapeInByte); |
511 | | - check(r"\u{FFFFFF}", EscapeError::UnicodeEscapeInByte); |
512 | | - check(r"\u{ffffff}", EscapeError::UnicodeEscapeInByte); |
513 | | - check(r"\u{ffffff}", EscapeError::UnicodeEscapeInByte); |
514 | | - check(r"\u{DC00}", EscapeError::UnicodeEscapeInByte); |
515 | | - check(r"\u{DDDD}", EscapeError::UnicodeEscapeInByte); |
516 | | - check(r"\u{DFFF}", EscapeError::UnicodeEscapeInByte); |
517 | | - check(r"\u{D800}", EscapeError::UnicodeEscapeInByte); |
518 | | - check(r"\u{DAAA}", EscapeError::UnicodeEscapeInByte); |
519 | | - check(r"\u{DBFF}", EscapeError::UnicodeEscapeInByte); |
520 | | - } |
521 | | - |
522 | | - #[test] |
523 | | - fn test_unescape_byte_good() { |
524 | | - fn check(literal_text: &str, expected_byte: u8) { |
525 | | - let actual_result = unescape_byte(literal_text); |
526 | | - assert_eq!(actual_result, Ok(expected_byte)); |
527 | | - } |
528 | | - |
529 | | - check("a", b'a'); |
530 | | - |
531 | | - check(r#"\""#, b'"'); |
532 | | - check(r"\n", b'\n'); |
533 | | - check(r"\r", b'\r'); |
534 | | - check(r"\t", b'\t'); |
535 | | - check(r"\\", b'\\'); |
536 | | - check(r"\'", b'\''); |
537 | | - check(r"\0", b'\0'); |
538 | | - |
539 | | - check(r"\x00", b'\0'); |
540 | | - check(r"\x5a", b'Z'); |
541 | | - check(r"\x5A", b'Z'); |
542 | | - check(r"\x7f", 127); |
543 | | - check(r"\x80", 128); |
544 | | - check(r"\xff", 255); |
545 | | - check(r"\xFF", 255); |
546 | | - } |
547 | | - |
548 | | - #[test] |
549 | | - fn test_unescape_byte_str_good() { |
550 | | - fn check(literal_text: &str, expected: &[u8]) { |
551 | | - let mut buf = Ok(Vec::with_capacity(literal_text.len())); |
552 | | - unescape_byte_str(literal_text, &mut |range, c| { |
553 | | - if let Ok(b) = &mut buf { |
554 | | - match c { |
555 | | - Ok(c) => b.push(c), |
556 | | - Err(e) => buf = Err((range, e)), |
557 | | - } |
558 | | - } |
559 | | - }); |
560 | | - let buf = buf.as_ref().map(|it| it.as_ref()); |
561 | | - assert_eq!(buf, Ok(expected)) |
562 | | - } |
563 | | - |
564 | | - check("foo", b"foo"); |
565 | | - check("", b""); |
566 | | - check(" \t\n\r\n", b" \t\n\n"); |
567 | | - |
568 | | - check("hello \\\n world", b"hello world"); |
569 | | - check("hello \\\r\n world", b"hello world"); |
570 | | - check("thread's", b"thread's") |
571 | | - } |
572 | | - |
573 | | - #[test] |
574 | | - fn test_unescape_raw_str() { |
575 | | - fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) { |
576 | | - let mut unescaped = Vec::with_capacity(literal.len()); |
577 | | - unescape_raw_str(literal, &mut |range, res| unescaped.push((range, res))); |
578 | | - assert_eq!(unescaped, expected); |
579 | | - } |
580 | | - |
581 | | - check("\r\n", &[(0..2, Ok('\n'))]); |
582 | | - check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]); |
583 | | - check("\rx", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString)), (1..2, Ok('x'))]); |
584 | | - } |
585 | | - |
586 | | - #[test] |
587 | | - fn test_unescape_raw_byte_str() { |
588 | | - fn check(literal: &str, expected: &[(Range<usize>, Result<u8, EscapeError>)]) { |
589 | | - let mut unescaped = Vec::with_capacity(literal.len()); |
590 | | - unescape_raw_byte_str(literal, &mut |range, res| unescaped.push((range, res))); |
591 | | - assert_eq!(unescaped, expected); |
592 | | - } |
593 | | - |
594 | | - check("\r\n", &[(0..2, Ok(byte_from_char('\n')))]); |
595 | | - check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]); |
596 | | - check("🦀", &[(0..4, Err(EscapeError::NonAsciiCharInByteString))]); |
597 | | - check( |
598 | | - "🦀a", |
599 | | - &[(0..4, Err(EscapeError::NonAsciiCharInByteString)), (4..5, Ok(byte_from_char('a')))], |
600 | | - ); |
601 | | - } |
602 | | -} |
0 commit comments