Orestis Papadopoulos

Orestis Papadopoulos

Software, Sound, Swift

Jekyll: Testing Swift Code Blocks

Reading through last week’s iOSDevWeekly I came across Doctest, an exciting new project that aims to make Swift documentation testable.

The idea is, you can run swift-doctest giving it a bunch of .swift files and then it evaluates code blocks in your documentation, returning test results for the given conditions.

It turns out that you can run swift-doctest on Markdown files too. What if, we could inject a nice little swift-doctest every time jekyll renders our static website? That way we can test codeblocks in blog posts and even get it done automatically on every build.

Install DocTest

Via Homebrew:

$ brew install swiftdocorg/formulae/swift-doctest

Or Manually:

$ git clone https://github.com/SwiftDocOrg/DocTest
$ cd DocTest
$ make install

Jekyll Hook

note: these are my first 6 lines of Ruby, please be gentle with me

# Put this in a file called swift-doctest.rb on a _plugins folder in your blog root foolder
Jekyll::Hooks.register :posts, :pre_render do |post|
	if post.data['doctest'] == true
		value = %x( echo;echo 'swift-doctest for #{post.path}';swift-doctest #{post.path}; echo;)
		puts value
	end
end

This Jekyl Hook runs every time your site is built, before the .md files get rendered to .html files. I put it at this point so that I can do something more sophisticated in the future by probably injecting some html to show me the failed test results.

In order to enable swift-doctest for a post, add doctest: true to the post’s front matter.

Take it for a spin

Start a codeblock with ```swift doctest and then, add an annotation in the format => (Type) = (Value), to test the expected type and value of the expression:

struct User {
	let name: String
}

let user = User(name: "Foo")
let anotherUser = User(name: "Bar")
user.name == anotherUser.name // => Bool = true

Now if you run bundle exec jekyll serve to build and serve your site, the terminal will print a failed test in the TAP format

...

swift-doctest for <path_to_your_blog>/_posts/<blog_post_filename>.md
TAP version 13
1..2
not ok 1 - `user.name == anotherUser.name` produces `Bool = false`, expected `Bool = true`
  ---
  column: 37
  file: <path_to_your_blog>/_posts/<blog_post_filename>.md
  line: 6
  ...
  
...

Nice! If you just change the example to:

struct User {
	let name: String
}

let user = User(name: "Foo")
let anotherUser = User(name: "Bar")
user.name == anotherUser.name // => Bool = false

And just save the file, you will see:

...

swift-doctest for <path_to_your_blog>/_posts/<blog_post_filename>.md
TAP version 13
1..1
ok 1 - `user.name == anotherUser.name` produces `Bool = false`
  ---
  column: 36
  file: <path_to_your_blog>/_posts/<blog_post_filename>.md
  line: 6
  ...
  
...

Conclusion

That’s all you need in order to enable testing for Swift codeblocks in your Jekyll site!

Keep your eyes peeled for further updates to the very promising Doctest since it’s still on its early days.

Feel free to contact me or tweet to me on Twitter if you have any additional tips or feedback.

Thanks!