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.

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.