Ozcode’s export object(s) feature, a first review (part 1)

Nearly half a year ago, in November 2015 I wrote a first article about a feature of the OzCode, an awesome debugging tool that plugs into Visual Studio and enhances it by many features in the debugging field I don’t want to miss again.

Recently Version 2.0 of OzCode has been published and today I finally found the time to test it in more depth. The whole article is based on OzCode version 2.0.0.1413.

For testing I wrote a very small test project with some XUnit tests. Unit testing as such is not necessary in this case, but these tests are easy to run as a single, separated piece of code, so it was the easiest way to go. The test project is published on GitHub as ozcode-export-test.

When OzCode 2.0 was announced on twitter and I asked for a test version, they finally answered (fixed the link here that was a wrong shortlink on Twitter due to missing space):

@jongleur1983 Wait is over http://o.oz-code.com/announcing-ozcode-v2.1-beta. Doesn’t address the issues you mentioned in your post yet, but we will be looking into that.

So I do not expect any issue mentioned in my first post to be addressed, but nevertheless the feature might be quite useful, so let’s give it a try.

As this article get’s lengthy again and it’s past midnight, I decided to split it, so this post is about single-object exports only for now, I’ll try to write a next one about exporting object graphs assembled from more than one object.

What is this Feature I’m talking about?

OzCode hooks (among other things) into the debugging process of Visual Studio. Whenever you break code, automatically on thrown exceptions or manually on a breakpoint or stepping through code starting from a breakpoint, ozCode augments the available options by more sophisticated features.

This article concentrates on the Export-Feature: While debugging any object that is inspected (so you look into the actual values of that object) can be exported to XML, JSON or C# code.

I’m especially interested in exporting to C# code. My major use case is to get test instances from a complex model to create unit tests. Consider a program to run and while debugging you find some error. One thing is to reproduce the error in the application – this might be hard enough, but it may only require to repeat the same input that lead to the error to reproduce it. A common way to proceed is to isolate the buggy input and actions and write a unit tests. This test should cover the problem, but as less additional code as possible. For a complex model setting up the model itself may take hundrets of lines of code, so I was excited to hear, ozCode should provide a way to export the C# code from a running program while debugging.

To a certain degree this feature is available now, still with some bugs, and my concerns from the initial article have not yet been addressed, but anything has to start somewhere, I’m fine with that.

The test cases

My boss at work sometimes sounds ambivalent when I again point on a special corner case nobody considered yet, so I might be good at this, but for testing these cornercases are what I’m most interested in, at least, wherever I trust the developers to have some coding skills (which I definitly do for the OzCode team).

So the majority of the following test cases of corner cases for a general export feature, but I was right to test them as they show some bugs.

Simple export: Different properties and fields

At first I tried to export a simple object, using different property types. The following is the test method:

[Fact]
public void ExportsWithDifferentPropertyTypes()
{
  var objectToExport = new DifferentExportableItems("first sample object")
  {
    EnumProperty = SampleEnum.SecondOption,
    DateTimePropertyExpectingHighPrecision = new DateTime(2000, 12, 31, 23, 59, 59, 987),
    IntegerProperty = 42,
    InternalStringProperty = "this string is internal, how is it exported?",
    NullableIntegerProperty = 23,
    PublicStringField = "a field is not a property. probably bad style, but perfectly valid code"
  };

  Assert.Equal(23, objectToExport.NullableIntegerProperty);
}

It starts creating a single object. For the definition of the object, see [github… ]. The properties and fields of that object are set by an object initializer. The Assertion afterwards isn’t required for what to show, but it provides a good way to set a breakpoint in that line as the objectToExport is completely defined.

Breaking there we can export the object. By default we get the following C# code:

new DifferentExportableItems
{
    PublicStringField = "a field is not a property. probably bad style, but perfectly valid code",
    IntegerProperty = 42,
    DateTimePropertyExpectingHighPrecision = new DateTime(631139039999870000L) { },
    NullableIntegerProperty = 23,
    InternalStringProperty = "this string is internal, how is it exported?",
    EnumProperty = "SecondOption",
    BooleanProperty = "false"
}

Some obvious errors are visible at the first glance – when you know I used speaking names, so let’s go through the different items exported:

  1. PublicStringField: this is a field, not a property. It has public as an access modifier, so good to see it is included.
  2. IntegerProperty: it’s an int, and it is exported as int – looks fine.
  3. DateTimePropertyExpectingHighPrecision: DateTime is exported using the ticks overload of the constructor. This is both, good and bad. On the positive side this allows arbitrary precision in contrast to the other constructors, that take the individual components of the dateTime (year, month, day, hour, minute, second, millisecond). The big drawback is readability: It’s impossible to read what is the meaning of that number.
    As a small enhancement idea: It would be great to provide the component-wise meaning as a end-of-line comment behind DateTime properties. Whenever there’s no ticks value given and the value can be expressed by components up to milliseconds, using the other constructor would be much more readable.
  4. NullableIntegerProperty: is exported correctly as 23 – but when it is null it is not included in the export at all, which I consider to be a bug. Whenever a property is default-initialized to some non-null value, omitting the value produces a wrong result.
  5. InternalStringProperty: this property is defined as internal. As such it cannot be set from code that runs outside the same assembly. The exported code in this case therefore is not wrong, but it would not compile whenever it is run in another assembly than the classes definition. For test projects this is nearly always the case. Enhancement: I would have expected a warning here at least, and in contrast to private and protected properties, internals cannot be omitted optionally.
  6. EnumProperty: Is exported by Name, not by value (usually a number in C#), which is good, but it’s exported as a string, a bug again. It should be SecondOption without quotation marks instead.
  7. BooleanProperty: Obviously a similar problem as with the Enum.

For the last two point’s I asked via twitter today, and I expect the fix to be in the next version, as they answered nearly immediately:

@jongleur1983 Another known issue – that’s actually true of all primitives, and enums as well. Working on a fix as we speak.

Properties with Asymmetric setter and getter

A property in C# under the hood is not more than a private field and two methods, one to set it, one to get the value back. There are automatic properties where both are completely generated, but it’s common use to add sanity checking logic or to trigger other updates whenever the value is set.

Something, that makes code less easy to read and usually is a sign for bad style are properties where getter and setter do something different. For this test I wrote a class with the following three properties:

public bool UseFallbackValue { get; set; }
public int FallbackValue => -1;

public int TheNumber
{
  get
  {
    if (UseFallbackValue)
    {
      return this.FallbackValue;
    }
    else
    {
      return theNumber;
    }
  }
  set
  {
    this.theNumber = value;
  }
}

The clean pattern would be to add a third property or a function for the calculated number using the fallback if appropriate, but that’s not the point.

My test method initializes an object of the corresponding class like this:

var objectToExport = new AsymmetricalSetterAndGetter()
  {
    TheNumber = 1773,
    UseFallbackValue = false
  };

The correct output would produce the same or something equivalent, but as the property getter of TheNumber returns -1 due to UseFallbackValue=true, the export looks as follows:

new OzCodeExportReview.SampleClasses.AsymmetricalSetterAndGetter
{
  theNumber = 1773,
  UseFallbackValue = "true",
  FallbackValue = -1,
  TheNumber = -1
}

Besides the wrong bool export again, the private backing field theNumber and the public property FallbackValue are both exported (the private field is optional, but I included it here). Nevertheless due to the order of the assignments in the object initializer the result will be wrong when this code is executed: The setter of the FallbackValue property will overwrite the value of the field theNumber.

I am not sure how easy it is to solve that, and if I can consider it a bug or not. If fields were exported after properties, property setters could not overwrite fields afterwards, the result in this example would be correct. Nevertheless multiple property setters could (in theory) set the private fields subsequently to different values, so even the order within the same type could matter.

Integration into the Visual Studio User Interface

OzCode usually integrates quite nice into Visual Studio. The Export option itself is a context menu inside the debugging window, which is good. On pressing it a dialog appears that enables to export in different formats and with several options to take. Unfortunately this dialog is modal, so that it’s impossible to switch between files in Visual Studio, or to use bug trackers integrated to visual studio without closing the dialog. I understand part of why that might be necessary: As it’s possible to enhance the depth of export (see the followup post not yet written) the debugger should not be able to change as long as the window is open, but nevertheless it would be great to use at least some tooling in combination with the exported tool, however that should work.

The options of the C# export contain two bool flags: „Include fully qualified type names“ and „Include private and protected members“. A bug here is, that these both are inverted compared with the outcome, and as an enhancement I would propose to order by type (as explained above), and probably to export the accessibility level as a comment – probably optional. A second bug within these options is the missing support for internal, again as explained above.

About the inverted properties @oz_code answered quite fast again via Twitter:

Thanks! Yeah, that’s a known issue. Already fixed and fix will be deployed as part of an update that’s coming soon.

I hope to get the next article online within the next week, but this feature which looks like a tiny one is – as often – far more complex than it looks at the first glance, so I found more to write about than I expected.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.