Rendering diffs for Go's testable examples

Featured image for sharing metadata for article

Today I've been doing an Open Source day on oapi-codegen - thanks to my employer Elastic, who gives me 4 hours a month that I can work on the project in-hours - and have been doing some work towards the OpenAPI validation middleware for net/http-compatible servers.

One of the main things we try and do for the top-level module is have 0 dependencies, and we use Go's Testable Examples as a way to do this.

Today, I've mostly been working with these tests, and I've been finding it a little painful trying to read test failures, such as:

--- FAIL: ExampleOapiRequestValidatorWithOptions_withErrorHandler (0.00s)
got:
# A request that is malformed is rejected with HTTP 400 Bad Request (with no request body), and is then logged by the ErrorHandler
ErrorHandler: An HTTP 400 was returned by the middleware with error message: request body has an error: value is required but missing
Received an HTTP 400 response. Expected HTTP 400
Response body: This was rewritten by the ErrorHandler
want:
# A request that is malformed is rejected with HTTP 400 Bad Request (with no request body), and is then logged by the ErrorHandler
  fds f ds f ds ErrorHandler: An HTTP 400 was returned by the middleware with error message: request body has an error: value is required but missing
Received an HTTP 401 response. Expected HTTP 400
Response body: This was rewritten by the ErrorHandler
FAIL
exit status 1
FAIL    github.com/oapi-codegen/nethttp-middleware      0.022s

There's no syntax or diff highlighting, so you kinda have to read it and work it out yourself.

I usually will copy-paste the text into Neovim, split it and diff it, but as I knew I'd be working with a lot of these tests today, I wanted a nicer experience.

I set about starting to write some Ruby - the scripting language I reach for - and then realised that maybe I could outsource the work, as it wasn't particularly important for me to write the code. So I asked qwen2.5-coder:32b to do it, and it came up with a reasonable solution (on the first try, with a very basic prompt πŸ‘πŸΌ) which I then modified into the below:

# adapted from code from `qwen2-5-coder:32b`
require 'tempfile'
input = ARGF.read

# Extract text between 'got:' and 'want:'
got_match = input.match(/got:\n(.*?)\nwant:/m)
got_text = got_match[1].strip if got_match

# Extract text between 'want:' and 'FAIL'
want_match = input.match(/want:\n(.*?)\nFAIL/m)
want_text = want_match[1].strip if want_match

got = Tempfile.new('got')
want = Tempfile.new('want')
got.write(got_text)
got.rewind
want.write(want_text)
want.rewind

puts `git diff --color --no-index #{want.path} #{got.path}`
puts

got.close
got.unlink
want.close
want.unlink

It ain't pretty, but it works nicely, and has made running testable examples a nice experience today, allowing me to run i.e.

go test -run 'ExampleOapiRequestValidatorWithOptions_withErrorHandlerWithOptsAndMultiError$' | ruby diff-go-example.rb

Note that it doesn't handle multiple tests - purely out of laziness - but does what it needs to!

Until Go supports this upstream, this is probably what I'll be reaching for. But as I went to check on that issue, I noticed this comment which pointed me to the gotestdiff tool which works quite well, aside from no syntax highlighting.

Written by Jamie Tanna's profile image Jamie Tanna on , and last updated on .

Content for this article is shared under the terms of the Creative Commons Attribution Non Commercial Share Alike 4.0 International, and code is shared under the Apache License 2.0.

#blogumentation #go #ruby.

πŸ€– Content in this blog post (prose or code snippets) includes code derived from the following LLMs:

  • qwen2.5-coder:32b

This post was filed under articles.

Interactions with this post

Interactions with this post

Below you can find the interactions that this page has had using WebMention.

Have you written a response to this post? Let me know the URL:

Do you not have a website set up with WebMention capabilities? You can use Comment Parade.