RAR Test Files

Quick question. How many people realized that it’s legally impossible to create a RAR file without using WinRAR, RAR for Linux, etc., all of which are shareware?

At first, that might seem like no big deal, given that we have 7-Zip now… until you realize how difficult it is to be sure you’re legally in the clear if you have something that unpacks RAR files, or RAR-based formats like CBR and RSN and want to distribute some RAR files as part of your test suite.

Well, when Clint from Lazy Game Reviews released a video titled Registering WinRAR in 2021: How Far Back Does It Work?, I decided that I had reason enough to change that, so I bought a WinRAR license for my Windows XP retro-hobby PC (and, since the license allows a home user to share one license between all their devices, also for my Linux desktop PC and my Windows 98 retro PC).

Home users may use their single computer usage license on all computers and mobile devices (USB drive, external hard drive, etc.) which are property of the license owner.

https://www.win-rar.com/winrarlicense.html

I’m still waiting for my “WinRAR Physical Delivery on CD” (CA$ 13.94 extra) to arrive, but I’ve already used the digital delivery license key to make a nice load of test RAR and CBR files for the batch file corruption checker that I’m writing which shells out to /usr/bin/unrar t on Linux.

They contain either a testfile.txt or a PNG and a JPG, as appropriate, all made from scratch by me, and all designed to be as compact as possible while still being recognizable as the expected file formats. You’re welcome to use them for whatever you want.

P.S. Since I also have Amiga Forever 2016, I’m looking for suggestions for similar “can’t be made on Linux/Windows using 100% gratis software” formats to build up a complementary repo of Amiga test files.

So far, I’ve combined the Amiga Kickstart ROMs I paid for with the freeware’d LZX release from LZX_Y2KF.LHA to make an LZX test file that lsar -t from The Unarchiver’s command-line tools (mirror) can verify.

Posted in Geek Stuff | Leave a comment

Stripping Emoji from File And Folder Names

There’s an annoying little problem that happens sometimes when you save stuff off the web, which the popularity of emoji has brought into the spotlight: Some tools still assume Unicode code points will fit within 16 bits and break with characters outside the Basic Multilingual Plane (BMP for short).

I’ve seen this happen with git gui where I had to adjust the test suites for some Unicode-processing code to use character escapes instead but, in this case, the problem is astral characters in filenames.

If you’ve ever used something like Ctrl+S on a Tumblr page or youtube-dl on a video that uses emoji in the title, you might have discovered that CD/DVD-burning GUIs like K3b run into errors with mkisofs/genisoimage when you try to save such files onto a typical Joliet+RockRidge ISO.

It used to be just one or two, so I’d rename them away manually within K3b before burning the disc but, now, I’m starting to see a lot of them… so I wrote a quick little script that recurses through one or more folders (I forgot the usual “Is this a file? Skip os.walk and go straight to the file handler” code, so no file paths) and renames away any codepoints above 0xFFFF.

I’m not sure what Windows tools might break on non-BMP codepoints in filenames, but I habitually steer clear of anything I know will complicate making scripts portable so it should work anywhere you’ve got Python 3 installed.

Enjoy.

Posted in Geek Stuff | Leave a comment

Food For Thought

I was making food and my mind got to wandering.

“Broccoli… sounds like broccoly… same construction as shiny or smelly… what does it mean to have the characteristic of broccol?”

“Cucumber… OK, If the vegetable is a “cucumb-er”, what does the verb ‘to cucumb’ mean?”

“…and I know that broccol-y (having the characteristic of) and broccol-ish (resembling) aren’t the same thing, but where do broccol-esque and broccol-oid fit in? Hmm. This needs more thought.”

Yes, I know broccoli is an Italian loanword and cucumber is a corruption of the Old French cocombre… but that doesn’t stop my mind from getting silly and I wouldn’t want to, because being in that habit is what makes me notice the things that go into my better reviews.

Posted in Web Wandering & Opinion | Leave a comment

Fanfiction – A Quick Overview of The Whole Pureblood Pretense Series

In the wake of the final chapter of murkybluematter’s The Futile Facade, I found myself stuck dwelling on the huge cliffhanger it ends on. Enough so, that I’ve just finished a marathon re-read of the series to wear out my attraction to it for a little while… and, since I said in my review of The Pureblood Pretense that I’d review the rest some day, I suppose waiting for the final act to begin is as good a time as any for a run-down of why you should read the thing.

Given that I’m covering a series that’s 1.4 million words long and still has a whole act left to go, I’ll be focusing more on overarching themes and general trends than fine detail.

NOTE: If you feel this review is overly positive, I suggest checking out the aforementioned review of the first volume only. If anything, it’s a little too honest about flaws that I didn’t notice until the reading was done and the critical analysis had begun.

To recap, the series is a fusion of Harry Potter and Tamora Pierce’s Song of the Lioness Quartet, where a girl named Alanna of Trebond is so determined to become a knight that she trades places with her twin brother and adopts the name Alan, eventually befriending both the crown prince of the realm and the king of thieves and winding up the kingdom’s first Lady Knight and married to one of them.

I’d like to put some emphasis on that for anyone who’s only familiar with the Harry Potter side of things, because it’s important. To make this plot work, the main character is a blend of Harry Potter and Alanna of Trebond. It may introduce a backstory to help justify that but, in the end, the plot relies on certain aspects of Alanna’s character to avoid falling apart at the seams.

I’d also like to spend a moment on what makes this blend of Harry and Alanna such a compelling character. Like Harry Potter, she’s a quiet, unassuming individual who can be goaded into doing The Right Thing by fate. Like Alanna, she’s laser-focused on what she wants in life, and is determined to do whatever it takes to get what she wants. This combination of quiet introversion, a strong sense of what’s right once she’s emotionally invested, and the drive to do what she wants, come hell or high water, produces an interestingly complex hero. One who keeps doing the heroic deeds when trouble comes knocking (despite how important it is to remain unassuming) but who also spends most of the story learning to acknowledge the idea that she’s heroic and never loses that desire for the quiet, academic life that destiny stood as an obstacle to.

At the same time, there are other facets of her personality which integrate well with that. As I’ll cover in a couple of later quotes, Harriet Potter has always been a troublemaker and, though she may not want to fully accept the implications of the label, a liar. She’s a character with a history of trying to let her more boisterous cousin take the blame for childhood escapades gone wrong, and mastered her own variant of the infamous puppy-dog eyes before ever conceiving of their grand ruse. Not exactly a paragon of virtue, this reluctant hero.

(And, with a villain so entrenched in political power, she is a hero who is caught between “lying as virtue” and “lying as vice”. Without her skill and willingness to lie, she can’t accumulate the stable of allies needed to face the villain, but that same willingness to turn to deceit also makes her life harder at times, blinding her to easier choices and, as the ruse progresses, fostering self-doubt. After all, when so many others have misplaced trust in you, it is easy to start questioning your trust in yourself.)

In this series, the divergence from canon starts back when Tom Riddle didn’t become Lord Voldemort but, instead, went into politics as the charismatic and cunning Lord Riddle, leader of the right-wing Save Our World party… producing a setting where, by the time young Harriet “Harry” Potter is born, only purebloods are allowed at Hogwarts.

By age 11, Harry is an obsessive potions nerd (that I suspect to have drawn at least some inspiration from someone in the author’s life who’s on the autism spectrum), and she’s determined to study under the man who, in her eyes, is the greatest potions researcher of the age, Professor Severus Snape. At the same time, the death of Sirius Black’s wife has left him insistent on sending her honorary cousin, Arcturus Rigel “Archie” Black to Hogwarts, and left Archie wanting to study somewhere better suited to an aspiring healer… so Harriet proposes that they trade places.

The first year (The Pureblood Pretense) reads like a particularly good Harry Potter A.U.. Harry may be female in this story, but I’m reluctant to use the term “femHarry”, because it dwells on her gender’s relevance to the plot even less than Effects and Side Effects. In fact, aside from making her body-shy out of fear of getting caught, and concerned about the scarcity of women in the Potioneers’ Guild, it’s not really significant to the plot outside of being a Lioness Quartet fusion.

There. Recap done.

Now, the second year (The Serpentine Subterfuge), and especially the latter half of it, is when the series really starts to graduate from being merely well writtem by fanfiction standards, to being a more satisfying, more enjoyable read than many of the professionally published novels I’ve read… a trend which kicks into even higher gear when the second act begins in year three (The Ambiguous Artifice).

In keeping with being an HP-Lioness fusion, Book 2 begins by introducing “the lower alleys” beyond Knockturn Alley. It makes them feel natural as something that could exist in Harry Potter canon but, at the same time, imbues them with a hint of the medieval fantasy feel of Tortall from Pierce’s books. It also introduces Lionel “Leo” Hurst, the counterpart to Alanna’s friend, the King of Thieves.

murkybluematter enjoys finding subtle ways to parallel elements of the Harry Potter and Lioness Quartet books while still leaving them feeling natural enough that, if you don’t know what’s being referenced, you won’t notice anything odd to suggest that a reference is being made. For example, here’s one of the more overt ones:

“What?” Sirius held a wounded hand to his heart. “I’m saying this for Harry’s sake, Prongs. Unlike the rest of us, she hasn’t dealt with these kind of snobby, tight-eyed people before. Harry, just remember that you can’t be formally charged on capital offenses until you’re seventeen, so—”

“Please don’t encourage my daughter to murder anyone,” Lily pleaded.

“Especially anyone she hasn’t met yet!” Archie said, grinning. “She might get along really well with the party nobs.”

“She’d better not,” James grimaced.

“Yeah, no schmoozing with the politicians, Harry,” Sirius said.

“I’ll just stand in a corner, make no noise, and pretend not to exist,” Harry said.

The Ambiguous Artifice, Chapter 11

(A reference to the “I’ll be in my room, making no noise and pretending that I don’t exist” phrasing used in the film version of Harry Potter and the Chamber of Secrets, when Vernon Dursley is making sure everyone remembers their roles in his little dinner party… the book is almost the same but uses “and pretending I’m not there”.)

Likewise, with “Rigel Black” being sorted into Slytherin for the amount of cunning and ambition needed to pull off such a daring ruse, Draco Malfoy winds up being the counterpart of Alanna’s friend, the crown prince. However, in general, murkybluematter just writes engaging Slytherins, period.

(I particularly like how Pansy Parkinson’s character unfolds over the course of the series, and I’m intrigued by the similarities presented between Aldon Rosier and a bored Sherlock Holmes.)

Of course, this being a Harry Potter story, and this being an author who enjoys subtle parallels to canon, it’s also a story where “Rigel Black” inevitably finds herself in the same “destined hero” role as Harry Potter from canon, prophecy or not.

All in all, the things which make this series great tend to fall into two categories:

First, the character writing. Aside from it just being enjoyable, there are some beautifully deep bits of character development. For example, when Draco ends his first year with an internal monologue on how different his friendships turned out from what he expected, and how he wouldn’t have it any other way.

That’s far too long to quote without destroying its impact, so I won’t… but I can excerpt another moment. This one is mid-way through year 2, when I was blindsided by the realization that Harry didn’t just think she didn’t need friends,… she didn’t understand why she might want friends beyond her honorary cousin.

Rigel could only conclude that friends were an incredible thing. How strange to have people who so understood and respected what she needed. How valuable to have people who made her feel so at ease and unthreatened, despite the difficult, dangerous deception she wove her life within. Surely there was nothing in the world so necessary as a friend on nights such as these.

The Serpentine Subterfuge, Chapter 11

…or the impressively poetic bit of writing in book 4 (The Futile Facade) when she muses on her fear that the real her is slowly being consumed by the masks she wears. A passage I’ll also quote because of how it so beautifully captures so much of what makes this series great:

“You’re right of course, Miss Potter. Excuse me.” Then he left, weaving his way through the crowd toward where Narcissa was standing somewhat stiffly beside her sister.

“Just Harry,” she muttered after him half-heartedly. She had never been more aware that she was not ‘just Harry.’ She was Heiress Potter. She was Harry the Lower Alley Potions Brewer. She was Rigel Black. She was highborn, lowborn, pureblood, halfblood, powerful, average, mysterious, and unassuming. She was thirteen. She was fifteen. She was fractured and whole. She was a child and a criminal, a lady and a liar. She was afraid that by the time everything was over she wouldn’t be anything anymore. Just a collection of faces that hid a hollow void where there should be something real and solid and her.

The Futile Facade, Chapter 1

Speaking of which, the story doesn’t shy away from high-society events, and murkybluematter does a beautiful job of writing satisfying banter, both high-society and family-oriented. Here’s an example:

“Who knew you were such a hopeless romantic?” Harry affected a deadpan expression that set her uncle to chuckling.

“If I’m a hopeless romantic, then you’re a cynic, my dear niece,” Sirius informed her.

“Realists are always called cynics by optimists,” Harry said, not at all insulted by his words.

Sirius fingered a talking button absently. “Sounds like something a cynic would say.”

Harry smirked sideways at him. “You would know, Uncle.”

Her godfather had to grimace at that. “Aren’t you supposed to have a rose-colored image of your role models?”

“At my age?” Harry pretended to think about it. “I think I’m supposed to be recently disillusioned and largely mistrusting, actually. Maybe I should pout.”

The Futile Facade, Chapter 4

That said, the entire story isn’t like this… it’s just hard for me to find short snippets that capture the more ordinary day-to-day atmosphere of things.

Perhaps more importantly, having a main character who lives a double life provides a very nice opportunity to show how the warmest friend can be bigoted and uncaring when presented with a different face, purely because of their upbringing.

As for the second category the story’s cleverness falls into? The plot. This is a story which makes an effort to take themes and set pieces from canon and improve upon them.

Philosopher’s Stone had Ollivander, the Sorting Hat, and Dumbledore implicitly telling Harry that he and Voldemort are light and dark reflections of each other? This explores that theme in a way that feels both more subtle and more significant.

Harry Potter has a “saving people thing”? This uses a female Harry who wasn’t raised by the Dursleys to make you realize that Harriet Potter, Hermione Granger, and Lily Potter aren’t that different in that respect… In canon, Harry is reckless, Hermione starts S.P.E.W., and Lily defied Voldemort three times and sacrificed herself to save her child. In this one? …well, just read it and see. Three women, all fitting the description of “brilliant, but scary at times”, all characterized by their drive in some sense, none of them pureblooded, and all central to saving the world in their own ways.

Speaking of Hermione, she turns up at the American school where “Harry Potter” (Archie Black) goes and they wind up best friends in the healer track. (And yes, murkybluematter is one of those rare authors who can send a character to a pre-Ilvermorny American magical school without it feeling cheap and boring.)

As for Harry, she’s still distant from her parents, but it’s because they don’t understand her, rather than because they’re dead. See, for example, this quote:

“And James still thinks you’re the responsible one.” Remus sighed.

“He’s easily bored by me,” Harry corrected the man. “And he equates boredom with rule-following and risk-aversion and maturity. That’s why it was so easy to blame Archie for everything when we were young. Sirius and James both expect troublemakers to be boisterous and emotional, because that’s how they are. They understand the kind of mischief that makes your eyes laugh and your toes tap with impatience. They don’t understand the kind of trouble you can get into quietly and methodically and carefully.”

The Futile Facade, Chapter 3

The intersection of plot and character also leads to a couple of fun running themes:

First, characters reinforcing false assumptions, simply because the truth is so outlandish… even Lord Riddle, the chessmaster villain who, in the end, gets outplayed by a teenager because of that one tiny assumption not even he could avoid making. (This manifests itself most clearly in “if only you knew how true that was” moments like Snape telling Rigel “I have never taught a student so dedicated to mastering the field”.)

Second, a theme I can only sum up as “people on the wrong side of history shouldn’t try to one-up a literary hero”, but done with sufficient skill that it doesn’t feel cheap or tacky.

All in all, for best enjoyment of these characters, I highly recommend keeping an eye out for such patterns.

For example, if you’re paying attention, you’ll notice that, under his playful jokester personality, Archie is essentially the “canon Hermione” of their little conspiracy… smart, brave, and intensely loyal, but Harry is The Hero™ because she’s the one who can’t just accept and work within society’s dictates. In fact, he’s sometimes used to illustrate just that, when, on occasion, he sees his honorary cousin through new eyes, and realizes just how much he’s underestimated some aspect of her character.

“On the contrary, it confirms my worst suspicions of your influence on my nephew.”

“Which nephew? The one you just met, or the one you thought was your nephew that you were so very proud of until you found out he was a halfblood?” Harry’s eyes were alight with something Archie had never seen in her before. It was like seeing a light bulb without a lampshade for the first time. There was something unapologetically sharp and bright and free in her eyes, and he wondered if that flame had always been there or if the events of the last 24 hours had ignited it.

The Futile Facade, Chapter 14

Speaking of the end of act 2, Lily’s perspective on Harry’s trouble-making, as has been touched on even before the end of act 1, really gives me hope for an arc between the two of them before the series ends:

”You’ve met our daughter, haven’t you? You know, Harry, the unassuming one always standing right next to Archie when something goes terribly wrong? The girl whose idea it usually was in the first place? Our daughter is capable of unimaginable trouble”

Lily Potter, The Serpentine Subterfuge, Chapter 13

(“Unimaginable trouble” almost literally, given how many ways murkybluematter finds for Harry to rise to the challenge as the series progresses. As one example, without Hermione at Hogwarts, “Rigel Black” is the exceptional student who gets the time-turner.)

At the same time, Harry herself is an interesting case, because she’s essentially built around Harry Potter’s greatest strength and weakness, seen through the lens of Alanna of Trebond… it’s not just that she doesn’t know when to give up, it’s that something in her is incapable of considering giving up. This is a girl who promised a friend she’d come to him for help if she gets in over her head, but doesn’t fall apart in his arms until after the deception has fallen and something unconscious in her sees that it’s safe to do so. She just can’t recognize that she’s in over her head until it’s too late. She’s the kind of hero who will fight until either she wins or the fight breaks her.

Likewise, she’s also an archetypal hero, in that, no matter how she tries to keep her head down, when destiny comes knocking and she has to choose between doing what’s right and what’s easy, she can’t help but take the high road. (Something that, in concert with other details, lends the series a feeling that the anticipation just builds and builds. This story is an epic and it feels like one… even if you’d usually expect a literary hero to be an ordinary person who has trouble come to them, while Harry was a decidedly not-ordinary child who sought it out.)

For that matter, she also utterly fails to hide her light under a bushel. One of the problems that crops up in a later year puts the ruse in jeopardy because Harry achieves something too distinctively tied to her particular innate talents, compromising her and Archie’s plans to remain interchangeable until their studies are finished and they’ve swapped back.

Not to spoil too much, but there’s a very interesting cyclical element when the deception finally falls and she manages to slip back into her old life temporarily. For all the progress she’s made, there’s this sense that she’s back where she started. Even knowing she needs to keep her head down, that’s just not who she is, or the story would never have started in the first place.

I will say, however, that year 1 has one of the most satisfyingly different replacements for Quirrelmort trying to get the Philosopher’s Stone, despite it being year 2 when the seeds are truly planted for Harry/Rigel to step up in the second act and consciously set herself opposite Lord Riddle. (Which touches off everything that causes the plot of the series, as well as the intrigue of the deception, to soar to dizzying heights.)

It helps that Lord Riddle is such a well-written villain. Polite, but menacing. Always composed… except for the one time we hear him (but don’t see him) in a towering rage near the beginning of the second act. A man who diverged from Lord Voldemort when he felt remorse after killing Myrtle… but at the thought of giving up a part of his very soul for his ambition. A man where the readers are never entirely sure how much of his propaganda is genuine belief and how much is merely him being wilfully blind to searching out solutions that don’t also feed his ego.

In fact, there’s another element which has its roots in earlier chapters, but comes into its own in year 3, which becomes so significant that it pains me to not say it. (Partly because I can’t talk about my favourite character without spoiling it.) …but I will say that there is a threat to the continuation of the Wizarding World that Riddle is doing horrible things to try to avert, Harry winds up on the path to a better solution, and it also ties in with several other subplots which are very satisfyingly original.

One of those other subplots also shows what makes Harry Potter not just a protagonist, but The Hero™. Harriet Potter and Lily Evans were both given a choice. Lily Evans did the same thing any other rational, reasonable, responsible human being would do (you included), and turned away… but when Harry Potter tried to be led in her mother’s footsteps, destiny refused to accept “no” for an answer, and, in doing so, forced Harry to consider alternatives that run counter to centuries (if not millennia) of conventional wisdom and discover that one of the wizarding world’s most deeply cherished beliefs is wrong.

This is related to how, for reasons that actually do get explored, Harry habitually suppresses her magical aura. This scares her new baby sister. For this and other reasons, Harry, Archie, and Hermione wind up spending a lot of time (mostly off-camera) researching the nature of magic.

Pair that with the undercurrent of Harry being misunderstood by and emotionally distant from her family, and I’m left with the sense that, aside from the big “face down Lord Riddle for the soul of the Wizarding World” bit, the final act is probably going to include the following two elements:

  • An arc where Harry finally forms a proper connection with her mother and, in the process, “the hero” “saves” Lily from that decision she made so long ago and guides her to reaching her full potential.
  • A related arc where at least Harry, Hermione, and Lily combine magical breakthroughs all three have already made or will make soon to save the Wizarding World from their self-destructive ignorance.

As for other interesting characters, well…

  • Regulus Black and his relationship with Sirius play a significant role, both personally and as the head of the Black family. I also get the impression Regulus is being set up to serve as a personification of Harry’s progress in winning the hearts and minds of Lord Riddle’s followers.
  • Remus Lupin gets a fair bit of recognition, partly because Harry asks him for self-defense training. I suspect he too will get more screen time now that the final act is likely to keep Harry closer to his usual haunts.
  • There’s a second pureblood-aligned faction that develops and a well-developed original character in Harry’s generation who I suspect might become Regulus’s counterpart in that faction now that things have come to a head. I’d say more about why the character is well-written, but then I’d risk spoiling who it is far too early.
  • Aside from just being interestingly written, Pansy Parkinson is the closest thing to a Hermione Granger that “Rigel” and Draco have, and she develops into quite the interesting character.
  • Aldon Rosier, as I mentioned previously, is an intriguing character with that air of “Sherlock Holmes, the man tormented by gnawing boredom” to him.

So, all in all, what’s my closing statement?

It’s a beautifully written A.U., but an A.U. nonetheless. Harriet Potter is more OC than you may be used to, but most of it will feel familiar to anyone who’s read Song of the Lioness and the most important core elements of Harry Potter are there if you look for them. The setting gets expanded on a fair bit, but it all feels canon-compatible. There’s a lot of focus on characters who are either OCs or so under-explored in Harry Potter canon that they’re effectively OCs, but you still get to see well-written takes on familiar staples like Hermione Granger, the Weasley twins, Ron, Ginny, Severus Snape, the other professors, and so on. The plot is an elegant mix of canon and new elements that keeps it feeling familiar without feeling stale or boring, and I’ve undersold a lot of things I adore in the name of not spoiling significant plot twists.

It starts out as what I’d rate at 5 out of 5 and just keeps getting better as the series progresses, so I’d say it deserves an award (and not one of those cop-out “best of [time period]” awards either). If you’re OK with giving an A.U. like this a try, I’d recommend it as the best Harry Potter fanfic I’ve ever read.

Oh, but the chapter numbering is deceptive. Whether intentional or not, each story starts out with more normal length chapters and then they trend longer and longer as the story progresses.

Posted in Fanfiction | 3 Comments

Fanfiction – Loopholes

I decided that this story is so different from the usual Zero no Tsukaima/Familiar of Zero fare that it deserves a full review of its own.

Loopholes by DschingisKhan

The basic plot is that Louise summons Tabitha from across the field (after she summons Sylphid, though that’s not really emphasized much) instead of Saito from another world.

Naturally, this throws the canon dynamic completely out the window even before Kirche invites herself into the group and it’s the feel and focus that makes this story so noteworthy. It focuses a lot on the characters’ thoughts and emotions.

For example, when the tone swings light, like the the time Kirche grabs the suspicious cloaked figure coming to Louise’s room, only to discover she’s just molested the princess, the overall dynamic actually feels like what I might come up with if I were to try to take the feel I enjoyed in harem romantic comedy anime like Ai Yori Aoshi and then stir in a liberal dose of what I’ve seen in shoujo manga. A lot more focus on their thoughts and feelings and minimal tacky fanservice-y stuff aside from Kirche occasionally being too Kirche. With no male protagonist, there’s instead hints at a possible future intent to blur the line between friendship and romantic interest between multiple female characters.

When the tone swings more serious, we get to see Kirche showing her more serious, more competent side… and her emotional baggage. Not for too long at a time, of course. Kirche wouldn’t be Kirche otherwise.

With her familiar being female, a fellow noble and mage, and not someone who irritates her, Louise has little provocation to act her canonical tsundere self and, combined with the amount of focus spent on seeing things from her perspective, I actually spent the first couple of chapters double-checking that she was sufficiently in-character because it’s such a departure from the norm.

That said, It does feel like there’s room for improvement in the writing style at the beginning. There were parts that felt like they were missing something they needed to connect. Given other evidence, like the short length of the early chapters and one of the examples I was able to put my finger on, I think it’s that the writing style was too brief and didn’t have enough flow.

On a couple of occasions when I’d stayed up late reading, I found the process grinding to a halt. I’d slipped into skim-reading, and the style made it too easy to miss an important detail which completely changed the mental picture for the following few pages.

For example, in chapter 6, in the “under ordinary circumstances” sequence, I somehow missed the fact that Tabitha had whistled for Sylphid and taken Louise airborne and didn’t realize something didn’t match up until a whole screenful of text later, at which point my befuddled mind had to read backwards up the page to figure out what I missed. It’s very rare that I run into something where the implications of such a major change don’t flow into the prose after, providing a supporting cue that I was about to skim over something very consequential to the mental imagery.

I’m still not sure about the later chapters to be honest. It’s just such an alien feeling to see Louise knuckling down and being that reliably serious and competent.

That aside, once it gets over its teething problems, it’s a very pleasing read and I like how it takes proper advantage of the opportunity to address canon events differently. For example, with Tabitha managing to get Fouquet/Mathilda’s story out of her, recognizing a kindred soul, and insisting that she come back with them so they can try to help her… which then flows into a very significant divergence from how canon events unfold.

Overall, it’s definitely worth a read and I’ll give it a tentative 4.5 out of 5 despite its flaws. Given how significant a divergence from canon and shift in tone it makes so close to the end of the chapters which have been written, I don’t yet have enough information on the author’s strengths and weaknesses to guess whether it’ll maintain that rating going forward.

Posted in Fanfiction | Leave a comment

Platformer Design Trends: Then and Now

I started playing Celeste a couple of days ago and, while I was playing it, I started tallying up some of the ways that the average modern platformer, retro-styled or not, differs from its counterparts in the 80s and 90s.

This isn’t an exhaustive list… just what came to mind while I was playing or while I was writing this.

Retired Arcade Mechanics

These are the archaic mechanics which are so overtly unhelpful that I can’t think of a single modern platformer in my collection that gets them wrong.

No Time Limit

In the early days of home platformers, they were still drawing a lot of influence from arcade machines, where the goal was to maximize the number of quarters machines took in per hour.

In that environment, a time limit makes sense to set an upper bound on how much time a player can spend on a single payment without also paying in skill. (Of course, earning more time with skill was allowed because it motivates player engagement.)

In home games, that rationale is absent, and you want to encourage the player to recognize and enjoy all the effort you put into building the game, so modern games usually solve this problem by tracking how long you take but not imposing a limit… which is even more useful to competitive players who actually care about the time taken.

A notable exception is Sonic The Hedgehog for Sega Genesis, which feels ahead of its time in this respect, but not far enough. It has a timer that ticks up, allowing you to easily note down your completion time for each stage, but, when it hits 10 minutes, you unexpectedly die with a “TIME OVER” message. (Granted, you should never even discover that time limit exists unless you’re exhaustively exploring the level… but why have it in the first place?)

As someone who enjoys platformers with an exploration component to their mechanics, like Super Mario World, I say good riddance to arbitrary time limits in games. (I’ll touch on time limits that are integral to the mechanics later.)

No Life Counter

It’s pretty obvious that lives were a means to milk more quarters out of players which then got adapted to home consoles as a way to artificially lengthen the game.

Yes, they increase the challenge, but it’s very frustrating to lose large amounts of progress and be forced to replay earlier areas to practice later ones.

(After ruining Warcraft 2 for myself when I was a little kid by cheating too liberally, I decided that “infinite lives” is the only cheat code I’ll use when playing older games… a rule I still follow.)

Having a limited number of lives also penalizes player experimentation, which is never a good thing because it makes them less likely to discover less obvious game content or mechanics.

No Score Counter

This is another mechanic which developed in the arcades and was already pretty useless and ignored by the time Super Mario World incorporated one. If you don’t have a high score list in a public place, there’s no reason to have a score counter.

For modern platformers, the mechanic that replaced this is some blend of public achievements and public leaderboards.

(In the interest of fairness, I will say that neither of those are my thing because I prefer to play only what I can archive to re-experience later, and the online social aspect of gaming isn’t as reproduceable as inviting some friends over for local multiplayer. If a game doesn’t offer offline achievements, I don’t bother collecting them.)

Less Simplistic Mechanical Changes

Tighter Controls and Agility-Oriented Gameplay

If you go back to play a platformer game from the 1980s or 1990s, they tend to feel a little stiff and sluggish until you get used to them.

Whether because they don’t have multiple movement speeds, like Super Castlevania IV, or because their long acceleration curves make the character feel heavy (slow to start and slow to stop) like NES and SNES Mario games. Even the best ones usually do this.

I’ve noticed that, ever since the Nintendo 64 introduced the analog stick and Super Mario 64 incorporated the wall-jumping mechanic originally found in games like Ninja Gaiden, the popularity of agility-oriented gameplay has skyrocketed among developers.

Now, keep in mind that agility-oriented gameplay doesn’t require analog controls. Guacamelee! has so many moves that the pause menu has a reference chart and it still only has the digital stop/go movement you’d expect on a platform without analog sticks.

Hollow Knight takes it even further by giving you perfect air control (no horizontal movement inertia in any circumstances I could identify) but the game is tuned so that I didn’t even notice the character has no movement physics beyond basic gravity until I was writing this post. (The level design never makes you want to precision-platform at a speed less than the run you’re stuck at, the lack of a deceleration curve keeps the character from feeling slippery, and character and camera animation are used to keep the instant response to control inputs from feeling cheap and lazy.)

Don’t get me wrong, I’m not saying every platformer should be about agility, but, all else about a game’s input response being equal, an agile character certainly helps to reinforce the sense that, if you fail, it’s because of genuine challenge, not bad controls.

Even with its ledge-hanging and double-jump mechanics, Odallus: The Dark Call makes a good example of this principle. While it keeps the restricted color palette, limited animation, and limited attack mechanics of NES action platformers, the character responds instantly to all inputs, and the way the camera follows him has a distinctly modern polish to it.

I should also make it clear that responsiveness doesn’t imply fancy movement mechanics and vice-versa. Dustforce is an example of a game which annoys me because, for something with so many agility-based mechanics (double-jumping, wall-jumping, wall-running, dashing, etc.), the controls are sluggish by design (I e-mailed the developers) to enable the kinds of fancy animation dynamics they wanted.

Reduced Death Penalty

You’re gonna die. Failure is part of learning and, in 80s and 90s platformers, you couldn’t get this more wrong than the “one life, no continues” games James Rolfe has done send-ups of in The Angry Video Game Nerd… but even without that, most games still made dying a pretty punishing experience.

Whether it’s giving you a limited number of continues or making you sit through an annoyingly long Game Over cutscene in Castlevania: Symphony of the Night, the implication was “players need to be Skinner Box‘d into not dying”.

That said, given how long it took for PC games to recognize that the mantra of “save early, save often” was just code for “make the player implement checkpointing manually without a solid reason”, I won’t hold it against them too much.

Modern games, on the other hand, vary widely in how frequently they checkpoint you. (I found Celeste’s checkpoints to be mildly annoying at times, such as the moment during the fight with your alter ego where you have to get through three or four screens of precision platforming before it’ll checkpoint.)

Super Meat Boy is probably the purest example of the direction platformers have moved in this respect. Not only is there no life counter, and frequent checkpointing (in the form of small levels), the game goes out of its way to optimize for a death-heavy play style. From the beginning of your death animation to when you can start moving after respawning is less than two seconds, and, after you finish the level, it shows a simultaneous replay of all your attempts, making your deaths more worthy of a smile than a groan.

For larger levels, true checkpointing becomes more important and Shovel Knight does a beautiful job of this by providing an in-universe way for the player to dial in on their preferred difficulty in fine detail: By breaking checkpoints to get more loot. In fact, I want to say a little more about this…

Difficulty Selection

Traditionally, if a game wanted to have multiple difficulty levels, you’d choose from a difficulty selector beforehand. This has two problems: First, you don’t know how your estimation of your skill compares to the developers until you try it and, second, you can’t change your mind without restarting.

Some older games, like Double Dragon II add insult to injury on this front by not telling you that the true ending is only available on the hardest difficulty until you’ve struggled all the way through a lower difficulty level.

Modern design instead favours a more organic approach to difficulty, where the player can fine-tune the challenge as they play, and the game mechanic incrementally encourages the player to take on greater challenges.

The crudest, simplest way to accomplish this is replacing a difficulty selector with some form of system for skipping levels that you’re struggling with, but I’d argue that it’s better for difficulty to be additive instead of subtractive (optional extra challenges) and to not break the immersion the way a “skip” option does.

I especially don’t like how Nintendo does this in recent Mario games with its Assist Blocks, where, if you fail a level too many times, it shoves the offer of a cheat code in your face. Sure, offer a “skip” mechanic, but don’t shove it in our faces when we’re trying to “git gud”. Instead, do something like Goblins Quest 3 where there’s help if you go looking for it, but it’s just an always-present toolbar option like any other.

Shovel Knight does this sort of thing much better with its “break checkpoints for extra money” mechanic. Not only does it give you fine-grained control over what’s easy and what’s hard, it’s also very organic, it gives you an incentive to challenge yourself, and it ensures the devs can’t be tempted to make the easy mode patronizingly easy because the easy mode is the default everyone will see.

A more common approach is what you see in games like Celeste, Super Meat Boy, VVVVVV, and New Super Mario Bros. where you have a system of collectables and possibly hidden challenge levels which aren’t required to beat the game. (Be very careful about requiring players to get all of a level’s collectables in a single run, though… it can easily lead in the same direction as the “no checkpoints, limited lives” paradigm of 80s games because the underlying problem is the same. “I have to do all that over again because of one tiny little mistake!?”)

Personally, I prefer the Shovel Knight approach because the collectable-based approaches tend to leave you feeling that you haven’t beaten the game without “getting the true ending” while the Shovel Knight approach is more of a “play at your own difficulty level” mechanic.

I read that the Switch Palaces in Super Mario World were meant to be this, but they still have that flaw that, once you’ve lowered the difficulty level, you have to start a new game to raise it again.

Skippable Cutscenes

A lot of old games force you to just mash buttons to rush through cutscenes, while modern games generally provide a “skip cutscene” option somewhere.

Why did it take until the 80s generation grew up and became game developers to recognize that we don’t want to sit through stuff we’ve already seen?

Sadly, this is still a change in progress since modern developers generally don’t get that we also don’t want to sit through the on-startup logos.

(In the worst cases of this, it makes me want to install the game in a virtual machine that has suitably good 3D guest drivers and “suspend to disk” the whole virtual machine instead of quitting the game.)

Going Above and Beyond In The Name Of Fun

This is probably the least obvious difference. In fact, it’s one I had to be told in Game Maker’s Toolkit’s video, Why Does Celeste Feel So Good to Play?.

In short, a modern game knows when to cheat in your favour.

In an NES or SNES game, if you press Jump a split second too late when walking off a ledge, you’ll fall. This is technically accurate and fair, but it feels needlessly frustrating when the core purpose of a game is entertainment.

In Celeste, by contrast, you can still initiate a jump for a few frames after you leave a ledge. This is referred to as coyote time by game developers. It’s one of several ways the game goes out of its way to fudge reality to match expectations, and is akin to how the Parthenon‘s architecture isn’t actually made of straight lines [2] but, instead, of curves that compensate for the effects of optical illusions.

An example that’s easier for the player to notice, but still welcome, is erring on the side of small hitboxes. “Nobody ever complained that their character’s hitbox was too small”.

This sort of “deceiving the player to improve their enjoyment” is common in game design, an important part of tuning the play experience, and it makes perfect sense that 30-40 years of progress would have turned up more ways to do it.

It also applies to stuff that is mechanically the same, but looks different. For example, it feels much better to be killed by something in-universe, like the pursuing monster in Castlevania: Rondo of Blood and its remake, and to retain the ability to move the camera normally, than to have a traditional self-scrolling level where you can be crushed between the edge of the screen and an on-screen object. Speaking of which…

Keep the Player In Control

The biggest thing that Trine got right about storytelling was overlaying character dialogue on top the beginning of the levels. The biggest thing it got wrong was aborting the pre-level narration when you start the level.

Whether it’s cutscenes, forced or otherwise, or a self-scrolling camera in an old-school self-scrolling level, players don’t like having their illusion of control broken. As Rebecca Heineman said in an interview I watched, “I don’t want to watch a movie. I want to play a game.”

The more you can keep the player in control, the more satisfying it will be. Tight controls, playing narration or dialogue over active gameplay instead of using cutscenes, using in-level hazards instead of scrolling cameras, simplifying the traditional SCUMM UI’s unnecessarily diverse choices for actions in Monkey Island 3… anything that breaks down that sense that the player has had control arbitrarily taken away from them is good.

The remake of Castlevania: Rondo of Blood (Castlevania: The Dracula X Chronicles) is actually a step backward in that respect because they pause the gameplay and move the camera to make the arrival of the pursuing monster more “cinematic” before returning control to you so you can run away from it. (Luckily, you can unlock the original version of the game so you can experience it as it was meant to be.)

Automapping and Objectives

Look at a classic game, like Metroid …or even Super Metroid and you quickly realize that, if you haven’t been playing it for a while, you’ve probably forgotten what you need to do next. Good interface design isn’t just about having an automapper in a non-linear platformer, but about minimizing the drudgework of keeping track of player progress.

I won’t say much about games from the 80s and 90s, since, so often, they didn’t even have the system resources for an automapper, let alone a proper objective tracker. Instead, I’ll focus on what is still being learned today.

Celeste is actually a game that could use some improvement on this front. It may be linear between levels, and it does get you used to the idea that moving from one scene to another could trap you in the new scene, but the levels feel a little Metroid-like at times, with it being unclear which branch will take you to a collectable and which branch will take past a one-way boundary and then to the end of the level.

That said, for a full open-world or Metroidvania game, the problem is usually insufficient mapping or objective-tracking support. Take, for example, the freeware Treasure Adventure Game. I put it down for too long and now I’m reluctant to pick it up again, because I have no idea how much wandering around I’ll need to do in order to get back on track.

A much better example would be Aquaria. Yes, it distinguishes discovered regions and visited segments of them in the automapper and marks permanent points of interest, like Super Metroid, but it also allows you to put pushpins on the automap in two different colors and type a description into each pin. I’m surprised this isn’t standard in every Metroidvania. It’s not perfect, lacking auto-filling of quest markers, but I’m not sure I’ve seen a perfect automapper yet.

Hollow Knight approaches this from the opposite direction, with an automapper that does automatically fill in quest markers, but doesn’t let you type a description into your arbitrary markers, gives you a limited number of them, and you have to buy them.

…but hey, progress is progress, right?

Narrative and Diversity

Now we get to the part that’s about what story is being told, instead of how it’s told.

First, I want to remind readers that I’m not saying all games need to have these aspects… just that the market had a dearth of them back in the glory days of 2D consoles.

Like with the Bechdel Test, these are about the market meeting the diverse demands of the customer base, not mandatory changes for individual games. (Because a lot of people don’t realize that. The Bechdel Test isn’t about any specific movie but about “If 50% of customers are women, it stands to reason that about 50% of movies should easily pass this test.”)

So, with that said, what’s happened in the last 30-40 years?

Well, in early platformers, there was an overwhelming preponderance of “man being the hero” plaformers, whether it was Mario rescuing Princess Peach, Bill and Lance saving humanity from Red Falcon in Contra, or less iconic things in the same vein like the adaptations of countless action movies.

That still happens. For example, Super Meat Boy is an over-the-top caricatured love letter to those days with its gratuitous gore, gratuitous difficulty, and a gratuitously “rescue your kidnapped girlfriend” plot. (Seriously, you’re up against a fetus in a mecha suit dressed like Professor Fate from The Great Race (and countless stereotypical “girl on traintracks” moustache-twirling villains) and he ties her back up and spirits her away again at the end of every level.) It’s one of my favourite modern platformers, but I wouldn’t want every game to be Super Meat Boy, just as I wouldn’t want every book on my bookshelf to be sci-fi, no matter how much I enjoy it.

So, with that said…

Rich Storytelling

It’s true that gameplay is the most important thing in any game, and storytelling is optional. Just look at a puzzle game I’ve sunk countless hours into, like the Hexcells trilogy. However, people will always experiment with any new medium as a way to tell stories, and, if you’re trying to tell stories, you might as well give it your all.

Whether for technical reasons or not, old games tended to have little narrative in the game, relying on varying amounts of narrative in the manual and your imagination to find the story if you cared. (Wasteland being an extreme example of the former. It’s an RPG, the original story-heavy genre, but the game keeps referring you to the manual because the text couldn’t fit on the disk. Modern re-releases resolve this inconvenience and fold the text into the game itself.)

Modern games, on the other hand, tend to go too far in the opposite direction, being so obsessed with telling a story that it detracts from the gameplay experience. I’ve lost count of the number of games I’ve played where I was watching a cutscene or paging through dialogue windows and all I could think is “Yeah, yeah. The game hasn’t even started yet. Just let me play!”

I mentioned Trine before, because I love how it manages to demonstrate one way to resolve this conflict. If pressing the start button after loading a level finishes didn’t cancel out of the narration, it’d be perfect.

Reduced Gender Stereotyping

I’m not stupid enough to try to argue that gender stereotyping has been banished from games, but this difference should be pretty obvious.

In the 80s, it was just taken for granted that non-puzzle games were primarily about manly men doing manly things, rescuing damsels and so on, and you were a lot more likely to see artwork inspired by the “bikini-plate barbarian” aesthetic meant to draw men to fantasy novel covers.

There’s nothing wrong with a game about a hero and, if a guy wants to look at some scantily-clad ladies, more power to him… but the market seems to have grown a bit more taste since then on the “scantily clad women” front, and I don’t think Super Princess Peach would have felt as cringe-y if it came out back in the 80s instead of in 2005.

(It’s a Mario platformer where the player’s secondary abilities are emotion-based, with Peach crying on plants to grow them and so on. If you remember the hullabaloo about Metroid: Other M, Super Princess Peach just reinforces what a skewed perspective on women Japanese game designers have.)

Not Every Conflict Is About Heroic Intent Or Proving Yourself to Someone Else

Maybe it’s because fighting games had so much prominence in arcades, but it feels like, once arcade narratives grew beyond Missile Command and Defender, every game had something to do with either racing, rescuing a damsel (eg. Double Dragon), proving your might (eg. Mortal Kombat), or some other heroic or manly activity.

If the gameplay is good, I’ll play it, but if you look at modern platformers, they seem to have bifurcated into two groups:

  • Games which intentionally keep the story minimal or nonexistent, like You Have To Win The Game or Towerfall: Ascension.
  • Games which embrace the storytelling and are made by people who’ve grown tired of the old clichés.

Celeste is one example of the latter, being a story of a girl named Madeline who’s decided that climbing Celeste mountain will help her to work through her psychological issues, but another great example would be Thomas Was Alone… a puzzle platformer about several pieces of data in a computer which really made me feel for them.

Outside of the technical aspects, I’d argue that this “we’ve grown tired of telling the same story over and over again” element is the biggest change from the 1980s. (Probably due mostly to how much technological progress has reduced the barrier to entry, allowing individuals to show the industry that demand exists for a wider range of stories.)

Female Leads

Outside of Samus Aran from Metroid, who you didn’t know was female until you beat the game, “let’s get some hot chicks in skintight outfits jumping around” characters like Cammy White from Street Fighter, and Ms. Pac-Man, how often can you remember 80s games having female leads?

Granted, the stereotypes of the period were against women playing video games, so you can’t just say “Bechdel Test”, but go a level deeper and the problem is pretty obvious. We’re all human, with fundamentally the same psychology, so, if that social pressure is omitted, the same “50% of the customers, 50% of the media” relation still applies… I’m just glad we’re finally seeing that kind of equality coming to pass.

Aside from just being fair, the average man and the average woman do get socialized differently.

Look at Knytt Stories, where it feels much more obvious to have an atmospheric, Hobbit-like approach to the “Save the World”-style plot of the first episode without the cultural baggage of a male hero. I think this is what Hayao Miyazaki is getting at when he tries to explain why he prefers female leads in his movies. Especially in Japan, there’s a lot less cultural baggage about what a female hero’s motivations should be.

Let’s go a step further. Look at Ittle Dew. A charming, tongue-in-cheek game that I just can’t see being made in the 80s or early 90s, because part of the humour and charm comes from the type of tomboyishness the heroine manages to exude. (An organic sense of being female, yet expressing that same facet of humanity that makes little boys “act gross”.)

In the end, I think proper progress in storytelling is intrinsically tied to society relaxing, so storytellers feel comfortable telling all the stories.

Posted in Web Wandering & Opinion | Leave a comment

Automated Testing for Open Watcom C/C++ and DOS

UPDATE 2022-10-21: Added update on 86Box’s porting status

One of the hobby projects I’ve been poking at again is written for DOS using Open Watcom C/C++ (v2 fork), and, being as averse to drudgework (and spoiled by modern tooling) as I am, I wanted some automated testing… so I wound up doing another blog-worthy survey of the field.

Unit Testing

Funny enough, there are actually several easy-to-use unit test frameworks that will build perfectly well with Open Watcom C/C++ v1.9 inside DOSBox… and that is the first test. There’s no point testing anything further if it’s not compatible in the first place.

TL;DR: greatest is the greatest.

greatest (ISC License) (My Recommendation)

This is probably the best bang for your buck if you want a simple test harness for your DOS projects. Just drop greatest.h into your project, add a few GREATEST_MAIN_* macro invocations to your test .c file, and start using RUN_TEST or RUN_SUITE and ASSERT_* macros.

#include "greatest.h"

TEST test_func(/* arguments */) {
    ASSERTm("Test string must not be empty", strlen(some_arg));
	
    /* ... */
    ASSERT(foo);
    ASSERT_EQ(bar, other_arg);
	
    /* ... */
    ASSERT_STR_EQ(baz, some_arg);
    PASS();
}

GREATEST_MAIN_DEFS();

int main(int argc, char **argv) {
    GREATEST_MAIN_BEGIN();

    RUN_TESTp(test_func, /* args */);
    greatest_set_test_suffix("other_args");
    RUN_TESTp(test_func, /* other args */);
    /* ... */

    GREATEST_MAIN_END();
}
screenshot

It’s also surprisingly featureful for something so simple:

  • It claims to work with any C89 compiler, does no dynamic allocation, and I had no problem building and running a real-mode executable from it inside DOSBox.
  • It supports passing a userdata argument to a test function with RUN_TEST1, so you can define your test once and then feed it various different inputs.
  • If you’ve got a compiler which supports the requisite C99 feature, you can use RUN_TESTp to invoke a test function with an arbitrary number of arguments (And I did use RUN_TESTp in my real-mode test .exe)
  • It provides SET_SETUP and SET_TEARDOWN macros which accept userdata arguments.
  • It’ll handle --help for you, but can also be invoked as a library for integration into a larger executable.
  • It’ll give you the familiar “one period per successful test, but verbose output for failing tests” output by default but there are also contrib scripts for colourizing the output or converting to TAP format.
  • It supports filtering which tests get run and listing registered tests from the command line.
  • It supports macros to randomly shuffle the order of tests or test suites to reveal hidden data dependencies.

For something that works with Open Watcom C/C++ v1.9, the experience is surprisingly reminiscent of Python’s standard library unittest module.

While it lacks some “check this and show the values if they fail” assertions I would have preferred, such as greater/less than comparisons (ironic for a library named “greatest”), there’s a PR which would add them that you can grab instead and the author is considering them for the next version. (Version 1.5.0 added ASSERT_GT, ASSERT_GTE, ASSERT_LT, and ASSERT_LTE.)

The only wart I noticed is how the assertion macros interact with helper functions. (The assertion macros work by returning enum values, so helper functions which use them have to have a return type of enum greatest_test_res and you have to wrap calls to them in CALL() to conditionally propagate the return.) That said, that’s a minor problem and I am a fan of making good use of return values to avoid hidden control flow and unnecessary side-effects.

All in all, a very nice little harness to choose for retro-C projects… or for any C projects that don’t need something fancier, really.

Unity (MIT License)

This is the next step up the complexity ladder but it’s primarily designed for embedded development, so its features are more poorly aligned for desktop development.

  • It’s split into three files (two headers and a .c file)
  • It doesn’t handle argument parsing (No --help, no test filtering)
  • The introductory documentation has a lot of “Here’s how to do this with microcontrollers and your favourite non-Watcom build system” content that can get you side-tracked if you’re not careful.
  • Because it’s designed to make microcontrollers first-class citizens, it’s got a lot of ASSERT macros which are just more specialized versions of what greatest offers. (eg. TEST_ASSERT_EQUAL_HEX8)
  • It expects you to have one setup and teardown function per file, rather than providing a macro to register them with arguments to pass in, so you may have more code duplication.
  • I couldn’t find any evidence that it provides an equivalent to greater’s RUN_TESTp for calling a template function with varying arguments.
  • The assertion macros are more verbose. (TEST_ASSERT_TRUE_MESSAGE instead of TEST_ASSERTm)
  • Its default configuration depends on more of the standard library, so I had to remove some of my compiler flags intended for size optimization to get it to build.

Going from greatest to this reminds me of going from POSIX to Java or Windows APIs.

On the plus side, it does have some advantages:

  • It comes with a lot of documentation, including a printable cheat sheet for the assert macros.
  • If you don’t mind the lack of “develop DOS software on DOS” purity, it includes some ruby scripts to generate test boilerplate for you.
  • It has a few “automatically pretty-print on failure” assertions that greater is missing, like array and bitfield equality tests.

…but still no less/greater than pretty-print macros!

Once you ignore the flood of details in the introduction that are irrelevant to DOS retro-hobby development, it becomes pretty clear that writing a Unity test suite is almost identical to writing a greatest test suite.

Drop the three Unity files somewhere your compiler can find them, tweak your makefile to also build and link unity.c, and then write a little test program:

#include "unity.h"

void setUp(void) {}     /* Required or it'll fail to link */
void tearDown(void) {}  /* Required or it'll fail to link */

void test_a(void) {
    TEST_ASSERT_TRUE_MESSAGE(strlen(some_arg), "Test string must not be empty");
	
    /* ... */
    TEST_ASSERT_TRUE(foo);
    TEST_ASSERT_EQUAL_UINT(bar, other_arg);
	
    /* ... */
    TEST_ASSERT_EQUAL_STRING(baz, some_arg);
}

int main(void) {
    UNITY_BEGIN();

    RUN_TEST(test_a);
    /* ... */

    return UNITY_END();
}
screenshot

Final verdict: It’s certainly nicer than JTN002 – MinUnit (Heck, I could write something better than that) and it’s probably the best choice for testing embedded C, but it’s not for DOS retro-computing.

Minctest (Zlib License)

For the most part, this is unarguably a worse choice than the previous two options, having fewer assertion types than either, less supporting documentation, no support for parameterized tests, and no helper for command-line options… but it does do two things which I think are valuable:

  • It shows pass/fail counts for individual assertions within a test case.
  • It lets you easily and obviously set custom display names for tests.

Again, it’s a fairly simple API. One minctest.h file to include, and then you write tests like this:

#include "minctest.h"

void test_a() {
    lok(1 == 1);

    /* ... */
    lsequal("foo", "foo");

    /* ... */
    lequal(2, 2);
    lfequal(3.0, 3.0);
}

int main(int argc, char *argv[]) {
    lrun("Test A", test_a);

    /* ... */
    lresults();
    return lfails != 0;
}

In the end, it’s not something I’d use for anything when greatest and Unity exist, but it’s a good data point for test suite UI design.

Others…

CuTest (zlib/libpng License)

CuTest (zlib/libpng License) does pass my initial triage question of “Does this cross-build from the Linux version of Open Watcom C/C++ 1.9 and run as a real-mode EXE under DOSBox?” …but that’s it.

First, it’s the only option that worked, but failed with a Stack Overflow error until I raised Open Watcom’s notoriously small default stack size with the OPTION STACK linker directive.

Second, and most damningly, the documentation and distribution archive front-load too much complexity… especially when, from what I can tell, it still produces a worse overall experience than greatest.

For that reason, I only ran the example provided in cutest-1.5.zip and this is what it looks like in DOSBox:

I checked µnit, µTest, utest.h, FCTX, and siu’s MinUnit but they all failed the “Will the distributed source build for real-mode DOS with Open Watcom 1.9 without patching?” test.

I also checked Labrat, CUnit, Check, Embedded Unit, and cmocka, but they were even more complex than CuTest to get going, so I didn’t even bother checking whether they would compile.

(It also doesn’t help that some of these rejected options are under the Unlicense, which multiple parties have criticized, and which doesn’t reliably account for “when in doubt, protect the rightsholder from their own ignorance” provisions in jurisdictions like Germany the way CC0 would. See this review of the CC0 for details.)

Snapshot Testing

If you’re testing something like a wrapper for the int 10h Video BIOS APIs, the simplest way to assert the correct results is:

  1. Clear the screen
  2. Assert that the screen buffer is in the expected state
  3. Do some drawing
  4. Check that screen buffer’s contents match a saved copy of what it should look like

Not only does this allow testing on real hardware without setting up some kind of fancy VGA capture setup, it also makes the test more generally applicable.

  • There are rendering differences between VGA and earlier color graphics adapters, but, because EGA and VGA achieve the default 80×25 color text mode by emulating CGA text mode, the data your test reads out of the screen buffer will be the same regardless.
  • DOSBox uses different fonts when you switch the machine= setting between different graphics adapters.
  • Screenshotting is affected by things like the aspect and scaler settings in your DOSBox configuration.
  • Taking a screenshot of an emulator window requires different APIs on different host platforms if the emulator wasn’t specifically built to be scriptable in that way.
  • Comparing VGA output on real hardware is even more difficult because producing and then capturing VGA output is a digital-to-analog-to-digital conversion.

On the other hand, reading the screen buffer is just a matter of synthesizing a pointer to the right memory address, and then reading out the correct number of bytes. (For CGA text mode or an emulation of it like EGA and VGA do, the address is B800:0000 and, for the default 80×25 text mode, the length is 4000 bytes.)

Doing it this way allows you to run your testing entirely within DOS by writing a simple harness around your code which sets up the screen before and dumps the memory to file after, ready to be compared like any other “Are these null-containing buffers equal?” check. (Which means you can easily run the test in any DOS environment. Great for portability testing.)

I haven’t had time to try this yet, but, if you’re running on EGA or later, where 80×25 text mode has access to four different display pages, it may even be possible to do it right inside one of the unit test runners I examined above without interfering with the test runner output, by switching away from the default page before running the test and back after to prevent it from erasing the runner’s status output.

(The main thing I need to check is whether B0000h gets remapped to the active page. If it doesn’t, then the utility of using page flipping to run the snapshot tests inside the unit test hardness would be limited to int 10h APIs that follow the active page.)

I’ll probably put up some sample code once I get to writing this part of the testing infrastructure for my project.

Functional Testing

Concept

Functional testing for a DOS program is complicated, because there is so little abstraction from the underlying platform. In fact, I think that, in the general case, it’s only worth the trouble if you run the test driver outside the DOS system under test.

This means one of two things:

  1. Run the program under test in an emulator, with the functional test harness running on the host operating system.
  2. Run the program under test on real hardware, with the functional test harness running on another machine.

To support both cases, and to avoid the needless complexity and potential for mistakes that would come from using a TSR, the solution I’ve chosen is to instrument the program to be tested with a simple serial console. Then, the same mechanism can work with real DOS machines (just use a null modem cable and, if your development machine is modern, a USB-Serial adapter) or with any DOS emulator that provides a means to connect an emulated serial port to the host system.

The serial console needn’t be complicated. Just log messages which the test harness can assert for correctness, and add a means to substitute input that would usually be provided by the user.

For additional testing, I’ll probably implement some kind of way to have the program under test stop at a machine-readable prompt to continue, so the harness can deterministically capture screenshots and complement the snapshot unit testing above with snapshot integration testing.

With DOSBox, it’s also easy for the test harness to assert for the presence, absence, and/or contents of on-disk files without having to mount or otherwise interact with an emulator’s disk images.

Research

The emulators which look to be capable of bidirectional COM port redirection to the host OS include DOSBox, QEMU, VirtualBox, and Bochs.

PCjs has some kind of serial console support but I haven’t had time to figure out whether it can be exposed to a separate process in the way I need.

I haven’t been in a hurry to investigate DOSEMU compatibility, since it’s more like Wine for DOS programs than a full-blown emulator and, aside from being especially thorough in my compatibility testing, I don’t see testing in it gaining anything if I’m already testing with DOSBox.

Either way, DOSBox should do well for quick and dirty testing, akin to testing a Windows program under Wine, and QEMU or VirtualBox should work for testing real DOS on fake hardware, but testing how software interacts with quirky hardware is another story.

Unfortunately, I’m still looking for a way to make this work with the emulators most suitable for that. PCem and its derivatives, 86Box and VARCem, are currently the state of the art in trying to accurately reproduce vintage hardware via emulation, but none of them have serial port pass-through support.

  • PCem’s developer has stated a lack of time to implement serial port pass-through but is willing to accept patches. It supports emulating an NE2000 network adaptor, but the only TSR I’ve yet found for redirecting COM ports over a network socket is paid proprietary software. (Though this TSR may be something I can MacGyver into doing the job. If I can, I’ll have to contact the author to ask for clarification on the license though.)
  • 86Box was forked before the frontend was rewritten to be cross-platform, the developers are still soliciting an experienced contributor to port over PCem’s new SDL+wxWidgets frontend, and I don’t know if it was forked before or after the NE2000 support landed. 86Box is now cross-platform and easily available to Linux users on Flathub. Its SLiRP networking option functions equivalently to the NAT option in VirtualBox and supports emulating 12 vintage NICs including the NE2000.
  • VARCem doesn’t offer non-Windows binaries and it was apparently forked from 86Box, so all the same caveats probably apply.

Finding any information on whether serial support has been added to 86Box or VARCem since the fork is complicated by how PCem-lineage emulators provide dummy/unconnected serial and parallel ports to emulated OSes to ensure that the observed behaviour of the hardware for a selected system is 100% accurate.

So far, my best hope for testing handling of hardware quirks is that a half-functional test harness could be rigged up by running 86Box inside Wine (assuming it works in Wine), using its LPT-to-file support and inotify to handle sending data from the program under test to the harness (assuming 86Box doesn’t force block-wise buffering on it), and using XTestFakeKeyEvent to send control inputs from the harness to the program under test. (Obviously, this would only work on X11-based desktops capable of using Wine to run x86-based Windows applications.)

Whatever I come up with, if it’s easy enough to generalize, I hope to release it as a reusable test framework once I’ve got something useful.

Posted in Retrocomputing | 2 Comments