import Foundation import Testing @testable import Hutch struct ReadmeViewTests { @Test func sanitizedReadmeLinkURLStringRejectsUnexpectedSchemes() { #expect(sanitizedReadmeLinkURLString("javascript:alert(1)") == nil) #expect(sanitizedReadmeLinkURLString("file:///tmp/readme") == nil) #expect(sanitizedReadmeLinkURLString("data:text/html;base64,SGVsbG8=") == nil) } @Test func processInlineDropsUnsafeMarkdownLinks() { let rendered = processInline("[click me](javascript:alert)") #expect(rendered == "click me") #expect(!rendered.contains("href=")) #expect(!rendered.contains("javascript:")) } @Test func sanitizedReadmeLinkURLStringAllowsExpectedDestinations() { #expect(sanitizedReadmeLinkURLString("https://example.com/docs?q=1") == "https://example.com/docs?q=1") #expect(sanitizedReadmeLinkURLString("mailto:test@example.com") == "mailto:test@example.com") #expect(sanitizedReadmeLinkURLString("#readme") == "#readme") } } struct MarkdownRenderingTests { @Test func markdownOrderedList() { let html = markdownToHTML("1. First\n2. Second\n3. Third") #expect(html.contains("
    ")) #expect(html.contains("
  1. First
  2. ")) #expect(html.contains("
  3. Third
  4. ")) #expect(html.contains("
")) } @Test func markdownBlockquote() { let html = markdownToHTML("> This is a quote") #expect(html.contains("
")) #expect(html.contains("This is a quote")) #expect(html.contains("
")) } @Test func markdownTable() { let input = "| A | B |\n|---|---|\n| 1 | 2 |" let html = markdownToHTML(input) #expect(html.contains("")) #expect(html.contains("
")) #expect(html.contains("")) } @Test func markdownHorizontalRule() { let html = markdownToHTML("---") #expect(html.contains("
")) } @Test func markdownDeepHeadings() { let html = markdownToHTML("#### Level 4\n##### Level 5\n###### Level 6") #expect(html.contains("

")) #expect(html.contains("

")) #expect(html.contains("
")) } @Test func markdownStrikethrough() { let html = markdownToHTML("~~deleted~~") #expect(html.contains("deleted")) } @Test func markdownInlineCodeEscaping() { let html = processInline("``") #expect(html.contains("")) #expect(html.contains("<b>")) #expect(!html.contains("")) } @Test func markdownWrappedBulletNormalizesLines() { let html = markdownToHTML("- First line\n continues here") #expect(html.contains("
  • First line continues here
  • ")) } @Test func markdownPlainEmailAutolinks() { let html = processInline("Contact hello@cleberg.net") #expect(html.contains(#"href="mailto:hello@cleberg.net""#)) #expect(html.contains(">hello@cleberg.net")) } @Test func markdownListContinuesAfterCodeBlock() { let html = markdownToHTML(""" 1. Clone the repository: ```sh git clone https://git.sr.ht/~ccleberg/Hutch ``` 2. Open the project in Xcode. """) #expect(html.contains("
      ")) #expect(html.contains("
      "))
              #expect(html.contains("
    1. Clone the repository:

      ")) #expect(html.contains("
    2. Open the project in Xcode.
    3. ")) #expect(html.contains("
    ")) } @Test func markdownListContinuesAfterBlankLineIndentedCodeBlock() { let html = markdownToHTML(""" 1. Clone the repository: ```sh git clone https://git.sr.ht/~ccleberg/Hutch ``` 2. Open the project in Xcode. """) #expect(html.contains("
  • Clone the repository:

    ")) #expect(html.contains("
    git clone https://git.sr.ht/~ccleberg/Hutch
    ")) #expect(html.contains("
  • Open the project in Xcode.
  • ")) #expect(!html.contains("
      \n
    1. Open the project in Xcode.
    2. \n
    \n
      ")) #expect(html.firstRange(of: "

      Clone the repository:

      ")!.lowerBound < html.firstRange(of: "
      git clone https://git.sr.ht/~ccleberg/Hutch
      ")!.lowerBound) } @Test func markdownImageQueryStringPreservesAmpersands() { let html = processInline("![badge](https://sonarcloud.io/api/project_badges/measure?project=ccleberg_Hutch&metric=security_rating)") #expect(html.contains("metric=security_rating")) #expect(!html.contains("amp;metric")) #expect(html.contains("Bold Link"#) #expect(html.contains("Bold")) #expect(html.contains(#"Link"#)) } @Test func markdownProtectedTokensDoNotLeak() { let html = processInline(#"Back to top `yoshi [ARG] `"#) #expect(!html.contains("ZZPROTECTED")) #expect(html.contains(#"Back to top"#)) #expect(html.contains("yoshi [ARG] <FILE>")) } } struct OrgRenderingTests { @Test func orgDeepHeading() { let html = orgToHTML("**** Level 4 Heading") #expect(html.contains("

      ")) } @Test func orgCommentLinesIgnored() { let html = orgToHTML("# This is a comment\nNormal text") #expect(!html.contains("This is a comment")) #expect(html.contains("Normal text")) } @Test func orgStrikethrough() { let html = orgToHTML("+deleted text+") #expect(html.contains("")) } @Test func orgExampleBlock() { let html = orgToHTML("#+begin_example\nhello world\n#+end_example") #expect(html.contains("
      "))
              #expect(html.contains("hello world"))
          }
      
          @Test
          func orgTitleKeyword() {
              let html = orgToHTML("#+TITLE: My Document\nBody text")
      
              #expect(html.contains("org-title"))
              #expect(html.contains("My Document"))
          }
      
          @Test
          func orgItalicDoesNotMatchURLPaths() {
              let html = orgToHTML("[[https://example.com/path/to/file]]")
      
              #expect(!html.contains(""))
          }
      
          @Test
          func orgWrappedBulletNormalizesLines() {
              let html = orgToHTML("- First line\n  continues here")
      
              #expect(html.contains("
    1. First line continues here
    2. ")) } } struct RepositoryAssetURLTests { @Test func repositoryAssetURLPercentEncodesImagePaths() { let url = resolveRepositoryAssetURL( "images/My Logo.png", owner: "~ccleberg", repositoryName: "Hutch", readmePath: "README.md" ) #expect(url == "https://git.sr.ht/~ccleberg/Hutch/blob/HEAD/images/My%20Logo.png") } }