[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [ProgSoc] Programming! Code!



On Fri, 2006-10-20 at 04:22 +1000, John Elliot wrote:

> I always have understood the problem that it may have seemed like I 
> discovered yesterday. My confusion arrived from the belief that the 
> requirement of full code coverage may further constrain the set of 
> potential implementations.
> 
> I remain unsatisfied on this point. I didn't get an answer to my 
> (somewhat implicit) question about the effect of a 100% code coverage 
> requirement would have on constraining possible implementations.

Apologies, I thought that it was obvious from the examples. Stated
explicitly:

- as long as you're not testing every possible case (and with a 32-bit
parameter, you're not), there are of neccessity untested cases whose
results, absent a 100% code test coverage requirement, are more or less
arbitrary.

- All that the 100% code test coverage requirement does is to require
that the unstated cases add no execution paths, it does not in itself
constrain the results of those untested cases.

- There are several ways to create a function which does not achieve the
results that you intend, without adding codepaths. The most obvious is
to push all of the "other" cases into one of the specified cases.

So, you test for

  inc(0) == 1
  inc(1) == 2
  inc(MAXINT) == error

You're looking for

  int inc(int x) { return x + 1; }

or, if you don't want to trust overflow flag checking:

  int inc(int x)
    {
    if (x == MAXINT)
      error;
    else
      return x + 1;
    }

You correctly assert that correctly implementing the test cases and
_adding_ a bogus case will yield <100% coverage:

  int inc(int x)
    {
    switch (x)
      {
      case 0 :
        return 1;

      case 1 :
        return 2;

      case MAXINT :
        error;

      default :
        return 42; // NEVER TESTED
      }
    }

but miss the option of merging the default case with one of the tested
cases:

  int inc(int x)
    {
    switch (x)
      {
      case 0 :
        return 1;

      case 1 :
        return 2;

      default :
        error;
      }
    }

or

  int inc(int x)
    {
    switch (x)
      {
      case 0 :
        return 1;

      case MAXINT :
        error;

      default :
        return 2;
      }
    }

Both of these will pass all of your tests, and your tests will achieve
100% coverage, but clearly neither is what you are looking for.

This procedure can be applied to frustrate any _finite_ set of tests
(that leaves one or more cases unspecified), which is the point both of
Carroll's original dialogue, and of the Tortoise's peculiar records.

> > > ValueType inherits from Object, but it is fundamentally different.
> > > A value type is not an 'object' (i.e. allocated an object id and
> > > managed by the GC) unless it is boxed.
> >
> > That would be too obvious. At least Meyer had the good taste to have
> > OBJECT extend ANY, and to have the value types also extend ANY, not
> > OBJECT.
> 
> Sorry to have mislead you... System.ValueType *does* inherit from 
> System.Object from a type system point of view.

I don't think that you have misled me; I was merely poking fun at the
unfortunate nomenclature.

> Value types are known as 'structs' in C#. I don't know about the 
> difference between ANSI and K&R C structs.

If memory serves, ANSI structs can be passed by value, K&R structs can
only be passed by reference (pointer).

> It's a design pattern for representing a 'null value' with a non-null 
> instance.
> 
> http://www.cs.oberlin.edu/~jwalker/nullObjPattern/

Oh yes, I've seen this before. It's certainly appropriate for optional
strategy objects, but there are many cases, in my experience, where null
references are also desirable.

- Raz


-
You are subscribed to the progsoc mailing list. To unsubscribe, send a
message containing "unsubscribe" to progsoc-request@xxxxxxxxxxxxxxxxxxx
If you are having trouble, ask owner-progsoc@xxxxxxxxxxxxxxxxxx for help.