Loading ...
Sorry, an error occurred while loading the content.

Re: Test Design / Architecture interaction

Expand Messages
  • thpr
    ... Not particularly. Helpful for debugging issues, but not LITERALLY required. ... This is _exactly_ what I want to be able to test. ... It s not .equals and
    Message 1 of 10 , Oct 21, 2010
    • 0 Attachment
      --- In pcgen_developers@yahoogroups.com, Martijn Verburg <martijnverburg@...> wrote:
      > Do we need to know exactly what parts of the PlayerCharacter are not equal?

      Not particularly. Helpful for debugging issues, but not LITERALLY required.

      > Or do we just need to know that something was changed on one of the
      > PlayerCharacter objects and therefore it cannot be equal to another
      > PlayerCharacter, e.g. Something like the isDirty flag.

      Other than that I don't terribly trust isDirty, it isn't sufficient for the reason you specify:

      > I guess you do
      > have the case where you change PC1 (it's now different!) which makes PC2 and
      > then change PC2 (Was that the reverse change I just made to PC1? Are they
      > now 'equal' again?).

      This is _exactly_ what I want to be able to test.

      > Some would argue that equals() and hashCode() (despite being
      > time-consuming to maintain) are fundamental methods you should
      > implement in your domain model. Â Forcing developers to adhere to
      > that standard is no bad thing.

      It's not .equals and hashcode. It's a method called .areEqual(CharID c1, CharID c2). While perhaps a similar concept, it isn't .equals and .hashCode since they are never reusable outside of the equality test. This reduces the value of implementation. Perhaps you could assert it is simply a boilerplate set of code of fetching 2 cache items and then doing a literal .equals on them, but forcing every facet to have the *exact* same biolerplate code (or to share a single class in their parent) is an option I am not fond of, when a much simpler option (putting the logic in FacetCache) exists.

      > So I think you're talking about maintaining a subset of Facets for PCs in
      > order to determine their equality? e.g. Using the minimum number of Facets
      > to uniquely identify a PC once it starts changing? So we add Facets to this
      > cache if their details change (like an extended isDirty), so:

      I think it should be able to test outside of our infrastructure (meaning if someone adds a facet/actor, it shouldn't require tons of new code to build a test for that new facet/actor), so I don't want to do a minimum number of facets. I want a test that is passively exhaustive (meaning it's exhaustive even when new things are added and doesn't require new test code or facets to implement a certain interface - so as to avoid fragility)

      The key is also that you're not adding new constructs. The Facet structure is already set up in a way that they should not store state (all open PCs share the same facets, and the facets are all given a CharID to identify which PC is being modified/queried/etc. - think of it as a session key if you're a web person). All of the facet state is stored in the FacetCache. Therefore, in theory at least, any state test can go do one centralized place (the FacetCache) to get ALL state for a PlayerCharacter if we go fully to facets (hence the acceleration proposal). The only 'contract' it places on a developer is that they should use FacetCache if the facet stores state. Since we already have the "facets can't store internal state" contract, changing that to "facets can't store internal state and must store external state in FacetCache" isn't a very big change and is rationally what would have been done anyway given the existing infrastructure... so I think it's a safe one to force on the devs.

      > PlayerCharacter1 has 49 facets, 4 of which change at runtime and are
      > therefore stored in the FacetCache as we know they've changed and therefore
      > need to be fully compared with equals() and hashCode() when we compare it
      > against PlayerCharacter2.

      PC1 has N facets, none of which change or store internal state. 4 of which store external state in the FacetCache (indexed by CharID). Those objects stored in the FacetCache (not the facets themselves) are tested using the traditional .equals and .hashCode. (so now we are on your devil's advocate point that equals and hashcode are not bad things - I agree)

      > Are we doing extra work here? If you add item C to character B (creating
      > B1) and then remove item C from B (creating B2) can't we at that stage say
      > that the net effect is that B hasn't changed? I'm probably missing
      > something fundamental here (not having written any PCGen code in a couple of
      > years :|).

      Yes, we are doing extra work, because I think it may be the easiest option to have the tests do a bit of extra work...

      In a "raw" PC (B0) the list of templates might be null.
      When something is added to the PC (B1), it might be an ArrayList with "Foo"
      When something is removed from the PC (B2), it might be an empty ArrayList.
      Effectively this empty list is "equivalent" to null, but not _literally_ equal in the == or .equals sense.

      There are 4 options I can think of:
      (1) Force all facets to implement a method that allows them to initialize all of their state, so that the lists and other objects placed info the FacetCache are present (and not null). I _really_ don't like this because of the added overhead on the facets (new method, uses memory in facets that would otherwise remain untouched for a given PC [e.g. spellcasting in a Fighter])
      (2) Have all facet stored items implement isEmpty() so that they can be compared to null by FacetCache. (and have FacetCache understand to test isEmpty when it encounters null on a PC). The problem here is that there can't be a common interface for isEmpty(), since we use ArrayList, for example, so it will have to be fully done through reflection (ick). Again, this is a unique demand (isEmpty) that could be fragile when facets are changed.
      (3) Force facets to "clean up" when they are empty and clear out the FacetCache (e.g. no empty lists allowed, must set the FacetCache to null). Per my earlier comment, this is not CPU or memory efficient, since it forces reconstruction of lists and stored items. Open to discussion if this is something we should be worried about...
      (4) Run the weird test cycle I originally proposed so that we never have to test null vs. an empty list.

      > I wonder if that's something we'd could log/profile, e.g. See how often
      > users keep Characters open and change them _without_ persisting them to the
      > PCG file to get us back to a starting state.

      It's not just about persisting to PCG. It's about the datasets and how they are built. Any time a PRExxx is involved, things can appear/disappear from a PC. even during load from a PCG.

      I also think the infrastructure to log/profile at an end-user is a huge infrastructure that has already been controversial, so from an implementation time-frame, I'm not sure how much of an option that is for us...

      TP.
    • Martijn Verburg
      Hi Tom, As I thought I had some of the code design completely wrong (that s what you get when you don t actually look at the code). Hopefully my blind
      Message 2 of 10 , Oct 22, 2010
      • 0 Attachment
        Hi Tom,

        As I thought I had some of the code design completely wrong (that's what you get when you don't actually look at the code).  Hopefully my blind wanderings are clarifying some thoughts for you anyhow :).  More inline below.

        > Some would argue that equals() and hashCode() (despite being 
        > time-consuming to maintain) are fundamental methods you should
        > implement in your domain model. Forcing developers to adhere to
        > that standard is no bad thing.

        It's not .equals and hashcode. It's a method called .areEqual(CharID c1, CharID c2). While perhaps a similar concept, it isn't .equals and .hashCode since they are never reusable outside of the equality test. This reduces the value of implementation. Perhaps you could assert it is simply a boilerplate set of code of fetching 2 cache items and then doing a literal .equals on them, but forcing every facet to have the *exact* same biolerplate code (or to share a single class in their parent) is an option I am not fond of, when a much simpler option (putting the logic in FacetCache) exists.

        OK, that now makes sense, I had the logic flipped around in my head (didn't look at the code and didn't realise how the Facet structure hung together) .

        > So I think you're talking about maintaining a subset of Facets for PCs in
        > order to determine their equality? e.g. Using the minimum number of Facets
        > to uniquely identify a PC once it starts changing? So we add Facets to this
        > cache if their details change (like an extended isDirty), so:

        I think it should be able to test outside of our infrastructure (meaning if someone adds a facet/actor, it shouldn't require tons of new code to build a test for that new facet/actor), so I don't want to do a minimum number of facets. I want a test that is passively exhaustive (meaning it's exhaustive even when new things are added and doesn't require new test code or facets to implement a certain interface - so as to avoid fragility)

        The key is also that you're not adding new constructs. The Facet structure is already set up in a way that they should not store state (all open PCs share the same facets, and the facets are all given a CharID to identify which PC is being modified/queried/etc. - think of it as a session key if you're a web person). All of the facet state is stored in the FacetCache. Therefore, in theory at least, any state test can go do one centralized place (the FacetCache) to get ALL state for a PlayerCharacter if we go fully to facets (hence the acceleration proposal). The only 'contract' it places on a developer is that they should use FacetCache if the facet stores state. Since we already have the "facets can't store internal state" contract, changing that to "facets can't store internal state and must store external state in FacetCache" isn't a very big change and is rationally what would have been done anyway given the existing infrastructure... so I think it's a safe one to force on the devs.

        Gotcha.
         
        > PlayerCharacter1 has 49 facets, 4 of which change at runtime and are
        > therefore stored in the FacetCache as we know they've changed and therefore
        > need to be fully compared with equals() and hashCode() when we compare it
        > against PlayerCharacter2.

        PC1 has N facets, none of which change or store internal state. 4 of which store external state in the FacetCache (indexed by CharID). Those objects stored in the FacetCache (not the facets themselves) are tested using the traditional .equals and .hashCode. (so now we are on your devil's advocate point that equals and hashcode are not bad things - I agree)

        OK, this makes sense and you're only testing equality for that set of 'facet' objects in the cache as opposed to all facets (which is a good thing).  I guess one useful developer reminder would be a Hudson report checking that .equals() and .hashcode() are implemented for a Facet implementation (I understand most do, but we need to catch up on the others in that case).
         
        > Are we doing extra work here? If you add item C to character B (creating
        > B1) and then remove item C from B (creating B2) can't we at that stage say
        > that the net effect is that B hasn't changed? I'm probably missing
        > something fundamental here (not having written any PCGen code in a couple of
        > years :|).

        Yes, we are doing extra work, because I think it may be the easiest option to have the tests do a bit of extra work...

        In a "raw" PC (B0) the list of templates might be null.
        When something is added to the PC (B1), it might be an ArrayList with "Foo"
        When something is removed from the PC (B2), it might be an empty ArrayList.
        Effectively this empty list is "equivalent" to null, but not _literally_ equal in the == or .equals sense.

        There are 4 options I can think of:
        (1) Force all facets to implement a method that allows them to initialize all of their state, so that the lists and other objects placed info the FacetCache are present (and not null). I _really_ don't like this because of the added overhead on the facets (new method, uses memory in facets that would otherwise remain untouched for a given PC [e.g. spellcasting in a Fighter])
        (2) Have all facet stored items implement isEmpty() so that they can be compared to null by FacetCache. (and have FacetCache understand to test isEmpty when it encounters null on a PC). The problem here is that there can't be a common interface for isEmpty(), since we use ArrayList, for example, so it will have to be fully done through reflection (ick). Again, this is a unique demand (isEmpty) that could be fragile when facets are changed.
        (3) Force facets to "clean up" when they are empty and clear out the FacetCache (e.g. no empty lists allowed, must set the FacetCache to null). Per my earlier comment, this is not CPU or memory efficient, since it forces reconstruction of lists and stored items. Open to discussion if this is something we should be worried about...
        (4) Run the weird test cycle I originally proposed so that we never have to test null vs. an empty list.

        Would getting the remove(X) method (in the removal from B2 case) to check to see if X the last item in a Collection and if it is then setting that Collection to null an option?  I guess that's similar to option (3) really, but shifts the responsibility a little.

        Also, is it just a null vs empty Collection issue?  Is this a case where we could standardise on always having an empty collection as a starting point (hmm, that's probably a bad idea, resource overkill for one).
         
        > I wonder if that's something we'd could log/profile, e.g. See how often
        > users keep Characters open and change them _without_ persisting them to the
        > PCG file to get us back to a starting state.

        It's not just about persisting to PCG. It's about the datasets and how they are built. Any time a PRExxx is involved, things can appear/disappear from a PC. even during load from a PCG.

        I also think the infrastructure to log/profile at an end-user is a huge infrastructure that has already been controversial, so from an implementation time-frame, I'm not sure how much of an option that is for us...

        Fair points!

        K
      • Andrew Wilson
        ... Don t like this option, as you ve said it s not testing real code. ... This seems the better option, but the fact that you re mentioning it makes me wonder
        Message 3 of 10 , Oct 22, 2010
        • 0 Attachment
          On 21 October 2010 01:40, thpr <thpr@...> wrote:
          > There are a few ways to go about having the ability to test this:
          >
          > (A) Have a class that overrides PlayerCharacter to replace methods so the
          > PlayerCharacter is more "transparent". This has a few issues, tha main
          > problem being: It doesn't test real code.  In addition, it is fragile since
          > it overrides some (hopefully all) but doesn't force an override of all
          > methods (could be solved by making PlayerCharacter an interface, but that is
          > a hugely complex interface and is ugly to have running around)

          Don't like this option, as you've said it's not testing real code.

          > (B) Accelerate moves out of PlayerCharacter into Facets and don't let
          > PlayerCharacter store any information.  Then have something do a compare in
          > the facets.

          This seems the better option, but the fact that you're mentioning it makes me
          wonder if we are planning to have stuff not moved out to Facets? Will all
          of the permanent state of a Player Character be in Facets for 6.0?
          If not, what is the time scale for that, or is it not on the cards at all?

          > <snip>
          >
          > Forcing facets to implement .equals is a tiny bit less error prone than a
          > full equals in PlayerCharacter, but still not ideal.  It makes it very
          > difficult to extend the system with new facets without placing a potential
          > burden on those facets to participate in our process (this is a contract on
          > the developer that I don't like).  It also requires a full list of all Facets
          > in the system to be maintained somewhere, so that they can be incremented
          > across and tested for equality between two CharIDs.  Oh, and we probably need
          > an interface to identify the method to be called.
          >
          > A better solution seems to be to have FacetCache be able to perform a
          > comparison between two CharIDs, based on all of the information stored in the
          > FacetCache.  This at least centralizes the equality testing, and therefore
          > doesn't impact every facet.  It also guarantees that new facets don't bear
          > any burden beyond "use FacetCache!", which while it's a contract, seems like
          > a pretty reasonable one!

          I agree this sounds like the best option that you've suggested.

          > This does force all objects used in a Facet to properly implement .hashCode
          > and .equals, but since many of them do already (many of them are storing
          > collections or other simple objects), that seems like less of a burden.  It
          > also isn't technically required of the Facets unless they something we ship
          > and would therefore be in our test cycle.

          I think you're missing some words from that last sentence and I can't
          figure out what you're saying.

          > The challenge comes from the fact that the first add/remove may not be
          > symmetric.  For example, initially the cache contents for a list of Templates
          > would be "null". After an add/remove cycle, it could be either "null" or an
          > empty list. (Today's code produces an empty list).  Therefore the test cycle
          > could be:
          >
          > Create PlayerCharacter A
          > Create PlayerCharacter B
          > Add item C to B, creating character B1
          > ensure A!=B1
          > Remove item C from B, creating character B2
          > ensure B1!=B2
          > Add item C to B, creating character B3
          > ensure B1==B3
          > ensure B2!=B3
          > Remove item C from B, creating character B4
          > ensure B2==B4
          >
          > This probably has some corner case error situation that could sneak through,
          > but it may be good enough for testing purposes.  Any ideas on a common case
          > where this would break?  Other thoughts on being able to test the reactions
          > to a CHOOSE application (a %LIST item) in a round-robin add/remove?

          I don't understand how we make a new PlayerCharacter object, here for instance:

          Add item C to B, creating character B1

          How does that work?

          > Should we just get strict about things and force the facets to clean up after
          > themselves if they are "empty" (and reset the FacetCache to null?) I'm
          > concerned that adds additional code in the facets for  little value, and
          > depending on how often that code needs to be called, could add up to a decent
          > amount of CPU cycles being spent on cleaning up things that would otherwise
          > only have to be constructed once per PlayerCharacter (so we're actually
          > un-optimizing the runtime performance)

          We definitely shouldn't be unoptimising general case runtime code to benefit
          the tests.

          I don't think that your convoluted series of tests is that bad. If we can pass
          the add and remove operations through reflection then we could write code
          that takes the add and remove operations and does that series of tests, and
          that's not onerous at all. It's only onerous if someone has to sit and code
          every instance of it by hand.

          andrew
        • thpr
          ... Well, except that it s not for the Facet. The Facet doens t store itself, it stores another object. So the code to go in and establish exactly what each
          Message 4 of 10 , Oct 22, 2010
          • 0 Attachment
            --- In pcgen_developers@yahoogroups.com, Martijn Verburg <martijnverburg@...> wrote:
            > OK, this makes sense and you're only testing equality for that set of
            > 'facet' objects in the cache as opposed to all facets (which is a good
            > thing). I guess one useful developer reminder would be a Hudson report
            > checking that .equals() and .hashcode() are implemented for a Facet
            > implementation (I understand most do, but we need to catch up on the others
            > in that case).

            Well, except that it's not for the Facet. The Facet doens't store itself, it stores another object. So the code to go in and establish exactly what each facet is storing would be reasonably complicated use of reflection or analyzing java bytecode (not impossible, but a bit of a pain in the neck to write)... so I'm not sure an automated check is that feasible vs. just waiting for tests to break (breakage would happen quickly anyway if something didn't implement .equals())

            > Would getting the remove(X) method (in the removal from B2 case) to check to
            > see if X the last item in a Collection and if it is then setting that
            > Collection to null an option? I guess that's similar to option (3) really,
            > but shifts the responsibility a little.

            This is exactly #3, not a shift in responsibility to what I suggest. You can't shift the responsibility to the FacetCache because it doesn't know when items in it are modified, and you can't transfer responsibility to PlayerCharacter because it doesn't know what types of objects the facets are storing. Also, it has to be done in the Facet (and custom for each Facet) as it's not as simple as Collections and null, as some of the facets store more complicated classes than a Collection. Note this also goes back to the churn issue where eliminating a list every time it becomes empty, only to reconstuct the list the next time something is added could potentially be a lot of creation and destruction of objects.

            > Also, is it just a null vs empty Collection issue? Is this a case where we
            > could standardise on always having an empty collection as a starting point
            > (hmm, that's probably a bad idea, resource overkill for one).

            This is #1 (initializing everything), and I think it's a bad idea due to the extra resources it would demand and the additional delay when a new PC is opened.

            TP.
          • Martijn Verburg
            Hey Tom, Points understood, that s me out of ideas (until I ever get back to looking at the code base properly) for now. Sorry I couldn t come up with
            Message 5 of 10 , Oct 22, 2010
            • 0 Attachment
              Hey Tom,

              Points understood, that's me out of ideas (until I ever get back to looking at the code base properly) for now.  Sorry I couldn't come up with anything new :(.  I'll post back if I get a Eureka moment!

              K

              On Fri, Oct 22, 2010 at 2:32 PM, thpr <thpr@...> wrote:
               


              --- In pcgen_developers@yahoogroups.com, Martijn Verburg <martijnverburg@...> wrote:
              > OK, this makes sense and you're only testing equality for that set of
              > 'facet' objects in the cache as opposed to all facets (which is a good
              > thing). I guess one useful developer reminder would be a Hudson report
              > checking that .equals() and .hashcode() are implemented for a Facet
              > implementation (I understand most do, but we need to catch up on the others
              > in that case).

              Well, except that it's not for the Facet. The Facet doens't store itself, it stores another object. So the code to go in and establish exactly what each facet is storing would be reasonably complicated use of reflection or analyzing java bytecode (not impossible, but a bit of a pain in the neck to write)... so I'm not sure an automated check is that feasible vs. just waiting for tests to break (breakage would happen quickly anyway if something didn't implement .equals())


              > Would getting the remove(X) method (in the removal from B2 case) to check to
              > see if X the last item in a Collection and if it is then setting that
              > Collection to null an option? I guess that's similar to option (3) really,
              > but shifts the responsibility a little.

              This is exactly #3, not a shift in responsibility to what I suggest. You can't shift the responsibility to the FacetCache because it doesn't know when items in it are modified, and you can't transfer responsibility to PlayerCharacter because it doesn't know what types of objects the facets are storing. Also, it has to be done in the Facet (and custom for each Facet) as it's not as simple as Collections and null, as some of the facets store more complicated classes than a Collection. Note this also goes back to the churn issue where eliminating a list every time it becomes empty, only to reconstuct the list the next time something is added could potentially be a lot of creation and destruction of objects.


              > Also, is it just a null vs empty Collection issue? Is this a case where we
              > could standardise on always having an empty collection as a starting point
              > (hmm, that's probably a bad idea, resource overkill for one).

              This is #1 (initializing everything), and I think it's a bad idea due to the extra resources it would demand and the additional delay when a new PC is opened.

              TP.


            • thpr
              ... It s more that my next step was to finish the ability items to be able to drive type safety into the CHOOSE items. What I m finding is that to build the
              Message 6 of 10 , Oct 22, 2010
              • 0 Attachment
                --- In pcgen_developers@yahoogroups.com, Andrew Wilson <andrew@...> wrote:
                > This seems the better option, but the fact that you're mentioning it makes me
                > wonder if we are planning to have stuff not moved out to Facets? Will all
                > of the permanent state of a Player Character be in Facets for 6.0?
                > If not, what is the time scale for that, or is it not on the cards at all?

                It's more that my next step was to finish the ability items to be able to drive type safety into the CHOOSE items. What I'm finding is that to build the tests I want to do that transition, I may have to go focus on tearing everything out of PlayerCharacter first. That's not necessarily bad... and it's not necessarily a change in what ships in 6.0, just a change in what order I'm doing things and what my priorities are on the arch side.

                > > This does force all objects used in a Facet to properly implement .hashCode
                > > and .equals, but since many of them do already (many of them are storing
                > > collections or other simple objects), that seems like less of a burden. It
                > > also isn't technically required of the Facets unless they something we ship
                > > and would therefore be in our test cycle.
                >
                > I think you're missing some words from that last sentence and I can't
                > figure out what you're saying.

                Implementing .equals and .hashcode for what is stored in FacetCache isn't technically required of the Facets unless the Facet is something we ship and would therefore be in our test cycle. In other words, the contract is only on our developers, not on anyone attempting to write code for PCGen (in case anyone goes down that path)

                > I don't understand how we make a new PlayerCharacter object, here for instance:
                >
                > Add item C to B, creating character B1
                >
                > How does that work?

                Unfortunately, it's probably
                Create PlayerCharacter A
                Create PlayerCharacter B
                Create PlayerCharacter C
                Create PlayerCharacter D
                Create PlayerCharacter E
                Add item I to B, C, D, E
                ensure A!=B
                Remove item C from C, D, E
                ensure B!=C
                Add item I to D, E
                ensure B==D
                ensure C!=D
                Remove item I from E
                ensure C==E

                > I don't think that your convoluted series of tests is that bad. If we can pass
                > the add and remove operations through reflection then we could write code
                > that takes the add and remove operations and does that series of tests, and
                > that's not onerous at all. It's only onerous if someone has to sit and code
                > every instance of it by hand.

                Between the facets themselves and the ChooseSelectionActors, I think the tests will be distributed across multiple places and won't require reflection

                TP.
              • Andrew Wilson
                ... Yuck! Hmm ... Ok, but you really don t need A. Or rather, A can become E if you delay adding I to it before you do the A!=B check. ... Ok, now you ve lost
                Message 7 of 10 , Oct 22, 2010
                • 0 Attachment
                  On 22 October 2010 14:50, thpr <thpr@...> wrote:
                  >> I think you're missing some words from that last sentence and I can't figure
                  >> out what you're saying.
                  >
                  > Implementing .equals and .hashcode for what is stored in FacetCache isn't
                  > technically required of the Facets unless the Facet is something we ship and
                  > would therefore be in our test cycle.  In other words, the contract is only
                  > on our developers, not on anyone attempting to write code for PCGen (in case
                  > anyone goes down that path)
                  >
                  >> I don't understand how we make a new PlayerCharacter object, here for
                  >> instance:
                  >>
                  >>     Add item C to B, creating character B1
                  >>
                  >> How does that work?
                  >
                  > Unfortunately, it's probably
                  > Create PlayerCharacter A
                  > Create PlayerCharacter B
                  > Create PlayerCharacter C
                  > Create PlayerCharacter D
                  > Create PlayerCharacter E

                  > Add item I to B, C, D, E
                  > ensure A!=B
                  > Remove item C from C, D, E
                  > ensure B!=C
                  > Add item I to D, E
                  > ensure B==D
                  > ensure C!=D
                  > Remove item I from E
                  > ensure C==E

                  Yuck!

                  Hmm ... Ok, but you really don't need A. Or rather, A can become E if
                  you delay adding I to it before you do the A!=B check.

                  >> I don't think that your convoluted series of tests is that bad.  If we can
                  >> pass the add and remove operations through reflection then we could write
                  >> code that takes the add and remove operations and does that series of tests,
                  >> and that's not onerous at all. It's only onerous if someone has to sit and
                  >> code every instance of it by hand.
                  >
                  > Between the facets themselves and the ChooseSelectionActors, I think the
                  > tests will be distributed across multiple places and won't require reflection

                  Ok, now you've lost me. I don't see why the tests will be distributed, or
                  rather I don't see why that would be better than centralising all the "add one
                  of these and remove it again" tests in one place.

                  andrew
                • thpr
                  ... True. I haven t done that for now, but it is a reasonable simplification. ... Both due to some challenges on implementation (esp wrt PlayerCharacter) as
                  Message 8 of 10 , Nov 6, 2010
                  • 0 Attachment
                    --- In pcgen_developers@yahoogroups.com, Andrew Wilson <andrew@...> wrote:
                    > Hmm ... Ok, but you really don't need A. Or rather, A can become E if
                    > you delay adding I to it before you do the A!=B check.

                    True. I haven't done that for now, but it is a reasonable simplification.

                    > Ok, now you've lost me. I don't see why the tests will be distributed, or
                    > rather I don't see why that would be better than centralising all the "add one
                    > of these and remove it again" tests in one place.

                    Both due to some challenges on implementation (esp wrt PlayerCharacter) as well as to try to provide a framework for explanation, I have submitted a patch that shows the structure and some tests that use the structure to http://jira.pcgen.org/browse/CODE-375

                    TP.
                  Your message has been successfully submitted and would be delivered to recipients shortly.