Semantic Versioning implementation

As Scott suggested, I implemented the basics of Semanting Versioning as two SuperCollider classes :

The repository is not a Quark. The Quark folder is inside the repo instead, because I think it needs discussions and improvements before being implemented.

Most notably :

  • It only implements the basics
  • I tested things manually because I don’t know how to automate such process
  • pre-release comparisons is not fully implemented, because it would need a proper set of rules to be doable
  • documentation is full of syntax and grammar mistakes, maybe poorly written. Ain’t no native English speaker.

Any feedback / review / help would be appreciated,
Regards, Simon

2 Likes

So the goal is to have a semver module/checker in the class library?

I glanced over the code and it mostly makes sense to me, thanks for writing it (:

I would definitely recommend adding automated tests, I wrote a guide for doing this a long time ago: Unit Testing Guide · supercollider/supercollider Wiki · GitHub. For your classes it should be pretty easy and you could take something like https://github.com/supercollider/supercollider/blob/develop/testsuite/classlibrary/TestString.sc as an example.

2 Likes

Yes indeed. This was proposed as a first step to ease class library dependencies management, and I think it will also be useful if people share software they wrote using SuperCollider.


Turns out moons are aligned, I just read your guide yesterday :slight_smile: . So first, thank you very much. You took time to organize it, and to go into details, with pedagogy. That’s a really good document !

Next step for me is to actually read current SuperCollider tests (as you pointed out).

But since we’re here, I have a naïve question. I understand that when code is deeply intricate, one part of the software could render an other part unusable when modified.

But regarding the example :

test_addingTwoNumbers_producesSum() {
	var calc = Calculator();
	var result = calc.add(3, 8);
	this.assertEquals(result, 11);
}

I have the feeling that this test only makes sense if the Calculator’s add method was modified right? Which in turn would only happen if arithmetic rules were modified, which is unlikely to happen (would be fun, tho). So in this example, would the test be somehow ‘too much’, because it’s unlikely to be changed, or are there some hidden complex things I’m missing about this?

I’m glad it’s helpful for you (:

The example is meant to be easily understood so naturally, the functionality it tests is also very easily understood. You wouldn’t normally see a “calculator” object like this anyway in a programming language which has arithmetic operators built in.

The line between what is and isn’t helpful to test is a matter of taste, experience, and team conventions. That’s why I point to existing tests as a starting point.

I’m completely new to this subject, I never wrote a single unit test. But I have some friends of mine, working for big corporations, who can complain for hours about having to write tons of them. So I have this newbie idea that I need to understand them to get better at programming.

To ‘rephrase’ my question, when do we use unit tests ?

As an example : maybe we indeed have a calculator implemented in a language, for some reason, and it is not supposed to be modified. But at some point, we run the test and the test fails : the function wasn’t modified, but it turns out it was stored in an isolated file, and some changes to the project removed the symbolic link pointing to the file. So thanks to the unit test, we know something broke and we can diagnose it ? Is that the kind of concrete application it also provides (beside indicating when the function was modified and doesn’t work as intended anymore) ?

(edit : I don’t have the time right now, but it will be more clear when I read current SC’s unit tests)

Yes, that’s pretty much the idea. My explanation would be that unit tests serve three main purposes –

  1. Verify correctness: generally people want to know that their code does what it intends. This is a way to make that guarantee with automatation and transparency, at some level from “better than nothing” to “fully correct”.
  2. Document behavior: for some people it is easiest to understand an object by seeing how it behaves in the small, example-like blocks that test code provides.
  3. Diagnose incorrect behavior: when you make a change and a unit test breaks as a result, this information helps pinpoint which part of the code is at fault.

A major benefit comes when the tests are run regularly under the same conditions – this allows you to find issues earlier and with greater precision. It also helps to run tests under a variety of different conditions to catch any unexpected behavior.

A lot of unit tests will run correctly for their entire lives, that’s the nature of it. It’s sort of like casting a fishing net, each knot in the net is unimportant on its own but without the whole weave of knots the fish will just swim through the holes.

There are more flavors of test which I tried to also document a bit in that guide.

3 Likes