New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
p5.Camera unit tests #3083
p5.Camera unit tests #3083
Conversation
hey @AidanNelson, instead of replicating the ortho/perspective/etc functions in the unit tests, what you'll do instead is determine the expected values for each entry of the matrix and hard code them. in theory, the 'expected' values are generally known ahead of time and not computed—things that are easily unit-testable have predictable results. this feels hard for me to explain, somehow—if this doesn't make sense, we can set up some time on google hangouts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Aidan, this is a good start. I think the ideas/goals of unit testing take a bit of practice to set in, and seeing this gives me a good idea of where you're at and where to go next. I've left some comments in line and thought it would be good to share some general comments, too:
in some cases, because the camera is a complex object, you may want to check that additional values are set
for most functions, you'll want to test them with a variety of inputs, especially if there are any edge cases in the code or you can think of some possible gotchas in the matrix math. the tests in math/calculation.js have some good examples for this—the distance function is an especially good one to look at.
test/unit/webgl/p5.Camera.js
Outdated
}); | ||
|
||
test('SetPosition() should set eyeXYZ', function() { | ||
var pos = Math.random(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
generally speaking, unit tests should be deterministic. a known value should be applied as an argument to a function, then hardcoded values should be tested. instead of testing a true random set of numbers, it's good to be systematic about what types of numbers you're testing.
some things we might consider here:
- are any or all of the values positive? covers a case where the code might have special cases for >0 or <0
- are any or all of the values negative?
- are any or all of the values 0? all 0s is a good case to test with matrix math because it means the magnitude of the supplied vector is 0, which can be trouble in some calculations
- is there a mix positive/negative/0?
- are all the values the same, or is each one different? as written, this test would not find a bug where the first argument is accidentally applied for all three (this is something I have done before!)
- what if a non-number value is passed as one of the arguments?
- are any other values updated as a result of
setPosition
that should be checked in their own assertions as part of this test? the assertions will let you provide some more detail in an error message, so you can figure out what if any conditions are not met.
test/unit/webgl/p5.Camera.js
Outdated
myCam.lookAt(23, 23, 23); | ||
assert.strictEqual(myCam.centerX, 23); | ||
assert.strictEqual(myCam.centerY, 23); | ||
assert.strictEqual(myCam.centerZ, 23); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are other values (up, eye) expected to change here? if so, we should test their values.
test/unit/webgl/p5.Camera.js
Outdated
myCam.projMatrix.mat4[i], | ||
myp5._renderer.uPMatrix.mat4[i] | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in the same test, we should check if the expected values are in the matrix with additional assertions. you can add an argument to the assert call to print a more helpful error so it's obvious if the error was that the matrices didn't match or that they didn't have the expected values (applies to next test, too)
test/unit/webgl/p5.Camera.js
Outdated
0, -1, 0, 0, | ||
0, 0, -3, -1, | ||
0, 0, -40, 0]; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool. another good value to test is the default! you may want to write a helper function that iterates over two arrays or matrices to check their values—or maybe there's already a chai function that already handles arrays?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, switched to using chai's deepEqual assertion.
test/unit/webgl/p5.Camera.js
Outdated
test('copy() returns a new p5.Camera object', function() { | ||
var newCam = myCam.copy(); | ||
assert.instanceOf(newCam, p5.Camera); | ||
assert.notDeepEqual(newCam, myCam); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should check that the values for both are the same here, to ensure that the copy worked
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a test for this.
test/unit/webgl/p5.Camera.js
Outdated
for (let j = 0; j < 3; j++) { | ||
assert.typeOf(local.x[j], 'number'); | ||
assert.typeOf(local.y[j], 'number'); | ||
assert.typeOf(local.z[j], 'number'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great. are there any other conditions that should be true here? should the axes be normalized? should they be orthogonal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, those checks are added.
test/unit/webgl/p5.Camera.js
Outdated
}); | ||
|
||
test('perspective() sets renderer uPMatrix', function() { | ||
myCam.perspective(Math.PI / 3.0, 1, 1, 100); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is a negative value for the field of view allowed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but the view will be reversed! I wasn't sure whether / how to check for this (and a few other) edge cases which produce valid matrices but unexpected views.
Ok, @kjhollen I added several unit tests and updated them throughout to ...
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job, Aidan! This is looking much better. One thing I was thinking while I read through this was, is there some way you can test this on values you are likely to encounter using orbitControl? especially for the camera() method!
test/unit/webgl/p5.Camera.js
Outdated
var delta = 0.001; | ||
|
||
// copy of p5.Vector.prototype.angleBetween... | ||
var angleBetween = function(a1, a2, a3, b1, b2, b3) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, I think it ought to be ok to just use the vector version (and make some vectors) when you need this? unless I'm missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. I was trying to keep it isolated, but not for any particular reason!
Ok! Once #3088 is merged, I could add a unit test for orbitControl using the |
cool! a nice bonus is that using p5.Vector made the test more legible too :) |
This adds unit tests for the p5.Camera object as added in #3080.
I wasn't quite sure how to create tests for projection matrices without simply recreating the ortho() and perspective() functions in the test, so any feedback on that would be appreciated!