Sleepy Tests

Last night, just before I passed out into comatose sleep after being up all “Wednursday” (Wednesday + Thursday ;)) again, I wrote code to also export arrays and annotations, i.e. data with structure inside, as XML that reflects the structure. Before, I was just dumping it out as a string. I also tested it, but I really wasn’t sure I could trust my coding OR testing skills after being up that long, so I just revisited it, and the code seems to be good.

You may ask why I’m putting so much importance on correctly exporting these annotations to an XML format. Right now, I don’t have code that imports that XML data back, in fact, I don’t even have the code that inserts the runtime checks. So why bother with exporting?

Looking at the XML is just the easiest way for me to make sure that I am gathering the data correctly and that I’m putting it together the right way. Yeah, writing this code took some time too, but it’s a convenient and reassuring stop on the way to what I need to do, and since importing the XML will be important later, this effort isn’t even wasted.

Here’s an example of XML generated from predicate annotations:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<method sig="foo()V">
  <predicate type="Ledu/rice/cs/cunit/threadCheck/predicates/OnlyEventThread;"/>
</method>
<method sig="bar()V">
  <predicate type="Ledu/rice/cs/cunit/threadCheck/predicates/OnlyThreadWithName;">
    <arg name="value" type="s" value="auxThread"/>
    <arg name="regex" type="Z" value="0"/>
  </predicate>
</method>
<method sig="arr()V">
  <predicate type="LTCTest2$ArrayTest;">
    <arg name="value" type="[" value="2">
      <element type="s" value="abc"/>
      <element type="s" value="xyz"/>
    </arg>
  </predicate>
</method>
<method sig="arr2()V">
  <predicate type="LTCTest2$ArrayTest;">
    <arg name="value" type="[" value="2">
      <element type="s" value="foo"/>
      <element type="s" value="bar"/>
    </arg>
  </predicate>
</method>
<method sig="ann()V" value="Ledu/rice/cs/cunit/threadCheck/PredicateLink;">
  <predicate type="LTCTest2$AnnotTest;">
    <arg name="value" type="@">
      <arg name="value" type="c" value="LTCTest2;"/>
    </arg>
  </predicate>
</method>
<method sig="ann2()V">
  <predicate type="LAnnotTest;">
    <arg name="value" type="@" value="Ledu/rice/cs/cunit/threadCheck/PredicateLink;">
      <arg name="value" type="c" value="Ljava/lang/Object;"/>
    </arg>
  </predicate>
</method>
<method sig="enu()V">
  <predicate type="LEnumTest;">
    <arg name="value" type="e" value="Ljava/lang/annotation/RetentionPolicy;.SOURCE"/>
  </predicate>
</method>
<method sig="enu2()V">
  <predicate type="LEnumTest;">
    <arg name="value" type="e" value="Ljava/lang/annotation/RetentionPolicy;.RUNTIME"/>
  </predicate>
</method>
<method sig="arrAnn()V">
  <predicate type="LArrayAnnotTest;">
    <arg name="value" type="[" value="3">
      <element type="@" value="Ledu/rice/cs/cunit/threadCheck/PredicateLink;">
        <arg name="value" type="c" value="LTCTest2;"/>
      </element>
      <element type="@" value="Ledu/rice/cs/cunit/threadCheck/PredicateLink;">
        <arg name="value" type="c" value="LTCTest2;"/>
      </element>
      <element type="@" value="Ledu/rice/cs/cunit/threadCheck/PredicateLink;">
        <arg name="value" type="c" value="LTCTest2;"/>
      </element>
    </arg>
  </predicate>
</method>
<method sig="arrAnn2()V">
  <predicate type="LArrayAnnotTest;">
    <arg name="value" type="[" value="2">
      <element type="@" value="Ledu/rice/cs/cunit/threadCheck/PredicateLink;">
        <arg name="value" type="c" value="Ljava/lang/Object;"/>
      </element>
      <element type="@" value="Ledu/rice/cs/cunit/threadCheck/PredicateLink;">
        <arg name="value" type="c" value="Ljava/lang/String;"/>
        <arg name="method" type="s" value="foo"/>
      </element>
    </arg>
  </predicate>
</method>

The Java code below contains the methods and some of the annotations and predicates. It demonstrates how different kinds of data are processed:

  • The method void foo() is annotated with just a marker annotation; the XML for it simply has a <predicate> tag that specifies the class of the annotation.
  • The method void bar() has an annotation with a string and a boolean, but boolean has a default value, so it’s not specified in the Java code. In the XML, in addition to the <predicate> tag, there are two nested <arg> tags that hold name-type-value triples for both the string and the boolean.
  • The methods void arr() and void arr2() both have annotations with an array of strings, but void arr2() uses the default value. For arrays, I’ve decided that there will still be nested <arg> tags that hold name-type-value triples, but the value is the size of the array, and the actual elements are stored in nested <element> tags.
  • The methods void ann()</code and <code inline="true" escaped="true">void ann2() have an annotation that itself has an annotation as member; void ann2() again uses the default value. For annotations, the value attribute of the <arg> tag contains the class name of the annotation, and then the data of the members is placed in <arg> tags that are themselves nested in the <arg> tag of the annotation.
  • The methods void enu()</code and <code inline="true" escaped="true">void enu2() are pretty simple, but they have an annotation with an enum as member, and enums print out a little funny. I guess I could split it up into a class-value pair.
  • The last two methods, void arrAnn()</code and <code inline="true" escaped="true">void arrAnn2(), finally have an annotation that contains an array of annotations. The XML they generate is a result of what has been explained above, I just wanted to make sure it works correctly. At this time I also noticed that arrays with more than one dimension (like String[][]) aren’t allowed inside annotations; that was another case I was worried about.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// class with predicate methods for structured data
class Checks {
    public static boolean checkArray(Object thisObject, String[] value) {
        return true;
    }
    public static boolean checkAnnot(Object thisObject, PredicateLink value /*???*/) {
        return true;
    }
    public static boolean checkEnum(Object thisObject, RetentionPolicy value) {
        return true;
    }
}

// calls Checks.checkArrayObject thisObject, String[] value)
@PredicateLink(value=Checks.class, method="checkArray")
@interface ArrayTest {
    String[] value() default {"foo", "bar"};
}

// calls Checks.checkAnnot(Object thisObject, PredicateLink???)
@PredicateLink(value=Checks.class, method="checkAnnot")
@interface AnnotTest {
    PredicateLink value();
}

// calls Checks.checkEnum(Object thisObject, RetentionPolicy)
@PredicateLink(value=Checks.class, method="checkEnum")
@interface EnumTest {
    RetentionPolicy value() default RetentionPolicy.RUNTIME;
}

// calls Checks.checkArrayAnnot(Object thisObject, PredicateLink[] value)
@PredicateLink(value=Checks.class, method="checkArrayAnnot")
@interface ArrayAnnotTest {
    PredicateLink[] value() default {
        @PredicateLink(Object.class),
        @PredicateLink(value=String.class, method="foo")};
}

public class TCTest2 {    
    @OnlyEventThread
    public void foo() {
        // only allowed to be run by event thread
    }
   
    @OnlyThreadWithName("auxThread")
    public void bar() {
        // only allowed to be run by thread with name "auxThread"
    }

    @ArrayTest({"abc", "xyz"})
    public void arr() {

    }
    @ArrayTest()
    public void arr2() { }

    @AnnotTest(@PredicateLink(TCTest2.class))
    public void ann() { }

    @AnnotTest
    public void ann2() { }

    @EnumTest(RetentionPolicy.SOURCE)
    public void enu() { }

    @EnumTest
    public void enu2() { }

    @ArrayAnnotTest({
        @PredicateLink(TCTest2.class),
        @PredicateLink(TCTest2.class),
        @PredicateLink(TCTest2.class)})
    public void arrAnn() { }

    @ArrayAnnotTest
    public void arrAnn2() { }
}

Of course, the annotations @ArrayTest, @AnnotTest, @EnumTest and @ArrayAnnotTest don’t have any meaning when it comes to concurrency testing. They’re just there so I can test how arrays, annotations and enums as member values get dealt with.

There’s still one thing where I don’t quite know if what I did was right: The @AnnotTest annotation has a member that is an annotation itself, PredicateLink. According to the conventions for the predicates, the predicate method Checks.checkAnnot has to accept an Object for this and one argument for each value in the annotation. But what is the correct type for this annotation? Is it PredicateLink? How do I call that method? Checks.checkAnnotation(this, @PredicateLink(Object.class)); doesn’t work, and neither does Checks.checkAnnotation(this, new PredicateLink(Object.class));, because PredicateLink is an interface.

This is something that I have to figure out when I write the code that actually calls the predicates. I also think that I may want to change the way default values are exported. After thinking about it a little, I don’t think default values should appear in the XML for members whose values aren’t specified. The XML should correspond exactly to what’s written in the source code. It’s either that, or all default values should appear, and currently they don’t get exported when an annotation is a member value.

I need to get going, COMP 311 and my office hours are ahead of me…. We promised to send out the grades on Wednesday, but not all students have been graded. On Thursday night, I finally decided to send out the grades we have and not wait for consistency as planned. So now the ones that don’t have their grades yet will probably complain to me, and the ones that did get their grades will complain about certain deductions. Yay.

Share

About Mathias

Software development engineer. Principal developer of DrJava. Recent Ph.D. graduate from the Department of Computer Science at Rice University.
This entry was posted in Concurrent Unit Testing. Bookmark the permalink.

Leave a Reply