Unit tests for methods with trivial logic?


  • Banned

    @error a JS fan who practices defensive programming? That's new.



  • @error Consider, for example, A is something that can only happen when part of the chip is operating normally, and B is a signal that says "this part of the chip is shut down". Those are obviously and trivially exclusive. Or a state machine. A is a signal that can only be asserted (driven to a logic "true" state) when the state machine is in state FOO, and B can only be asserted in state BAR. Since it is impossible for a state machine to be in two states simultaneously, both A and B cannot be true simultaneously.

    Let's say you have some logic that depends on these two signals and some others, say X = A & C + B & D

    ABCDX
    000000
    100010
    200100
    300110
    401000
    501011
    601100
    701111
    810000
    910010
    1010101
    1110111
    1211000
    1311011
    1411101
    1511111

    The coverage tool will complain that this expression has only 75% coverage; conditions 12, 13, 14, and 15 of this expression are not covered. Well, they can't be unless there is a bug somewhere else in the design; you want 75% coverage (but you don't want the uncoverable conditions dragging down your percentage, so you tell the tool to ignore them).

    You have a counter that counts 0 to 5 before resetting to 0. Since it resets before reaching a power of 2, there may (depending on how it's coded) be expressions in the counter that can't be covered, but consider that the output is used in a case statement. The input is a 3-bit signal, so it has 8 possible values, but only 6 of them are valid; 2 of them are impossible. Linting tools will complain if there isn't a case item for each possible value of the case expression (and it's defensive coding to throw some kind of error and/or set the output to an invalid state if invalid inputs occur), so you need case items for 6, 7, and/or default, but then you take a coverage hit for those statements that should be unreachable:

    case (counter[2:0])
        0: begin
               // statement(s) to do if counter == 0
           end
        1: begin
              // statement(s) to do if counter == 1
            end
        2: begin
              // statement(s) to do if counter == 2
            end
        3: begin
              // statement(s) to do if counter == 3
            end
        4: begin
              // statement(s) to do if counter == 4
            end
        5: begin
              // statement(s) to do if counter == 5
            end
        default:
            $error("Invalid value of counter")
    endcase
    

    Obviously, the default branch of the case should never be taken (ding against branch coverage), and the $error statement should never be executed (ding against statement coverage). So you have to tell the coverage tool to exclude the default branch and $error statement from coverage.



  • @HardwareGeek said in Unit tests for methods with trivial logic?:

    Obviously, the default branch of the case should never be taken

    But you work in an environment where the backing store of the counter is not guaranteed to be zero during initialization. It could very well be 6 or 7 before it's explicitly set to anything (and I'm not even talking about fault injection, just "we haven't properly come out of reset yet". Shouldn't there be a test for how the chip behaves in those conditions?



  • I assume the counter hardware is designed so that the global reset signal clears it. Otherwise it's a known gotcha, yeah (the digital design professor I had explicitly mentioned it).


  • BINNED

    @HardwareGeek said in Unit tests for methods with trivial logic?:

    A is something that can only happen when part of the chip is operating normally, and B is a signal that says "this part of the chip is shut down". Those are obviously and trivially exclusive.

    That doesn't sound obvious at all. I mean, it does when things are working correctly, but it seems the premise here is that there's failure modes you want to deal with where the chip doesn't work correctly, so who's to say that signal B doesn't get erroneously set / not set?

    I'm sure you have an answer for this, since you know what you're talking about here and I don't, but it's not obvious to me. Of course, in my software world, the way I'd deal with hardware errors (which I couldn't detect anyway) is "LOL, sucks to be you".



  • @topspin said in Unit tests for methods with trivial logic?:

    who's to say that signal B doesn't get erroneously set / not set?

    Typically, B doesn't just indicate that it's powered-down; it causes it to be powered-down. Yes, it could be wired to the power switches incorrectly, but that's outside the scope of digital testing. There's a whole other team that handles that and has their own tests for making sure the power/reset/retention1/isolation2 sequencing works right.

    1 Some things may need to retain their state while powered-down, so they are not powered-down completely. They are connected to a super-low-power power-supply, that can supply just enough current for them to retain their logic state but not enough to operate.

    2 Outputs from a block that is powered-down will be invalid; they won't be either 0 or 1. (We call this state X. It means the logic value is unknown, and it can occur for a number of reasons. It is the state of things that have not been initialized. It is the result of wiring something incorrectly so that two gates are trying to drive it to opposite values. It may be assigned intentionally to indicate an error. And in power-aware simulations, it is the value of logic that is powered-off.) The parts of the chip that are powered-up must be isolated from the outputs of the powered-down part because, somewhat like a NaN, the result of most calculations involving X are X, and if Xs from the powered-down block are allowed to get into the rest of the logic, the whole chip is going to stop working. (In simulation (pre-silicon testing), anyway; in reality, the outputs are probably going to be ~0V, so will most likely be interpreted as logic 0, but it's best to be explicit about it, and simulation is intentionally pessimistic.) So all the outputs of a block that can be powered-down separately from the rest of the chip go through isolation gates; when the isolation signal is true, they ignore whatever is on their input and drive the output to a known, idle state (usually 0, but for specific signals it might be 1; it depends on what makes that particular output "idle"). This needs to be done before the block is powered down, and not released until after the block is powered up and, if not retaining state, a block-level reset has driven everything to a known logic level.


  • Considered Harmful

    @Gąska said in Unit tests for methods with trivial logic?:

    then don't insinuate that I code like one.

    Something something pots and kettles.


  • Banned

    @error I DID say you're a braindead idiot, though. I may be a despicable cunt, but I'm not a hypocrite.


  • Considered Harmful

    @Gąska said in Unit tests for methods with trivial logic?:

    @Grunnen said in Unit tests for methods with trivial logic?:

    @Gąska said in Unit tests for methods with trivial logic?:

    Don't tell me you've never accidentally introduced new bugs in code that used to work fine.

    Surely. And that obviously happens with code that you touched

    Don't tell me you've never made a change that affected other parts of code that you thought wouldn't be affected.

    and by your logic, any changes in code should lead to failed unit tests, and the unit tests only check if code has changed, not if code is correct. So after changing the code, you update the unittest so that it doesn't fail anymore, and that accidentally introduced bug won't get noticed.

    The idea is that you update the test in a way that makes sense. Obviously you don't encode the wrong behavior in your asserts. If you think I'm a braindead idiot, just say it. And if you don't, then don't insinuate that I code like one.

    It's perfectly easy to believe that you code less or more braindead than you idiot , you braindead idiot.


Log in to reply