From ba3bc6634e22db14970b91fb7fc7cbb8ce703fea Mon Sep 17 00:00:00 2001 From: Shawn Date: Tue, 21 Mar 2023 22:09:32 -0400 Subject: [PATCH] Migration of resource reports to use plugin data based construction and support serialization. --- .../reports/support/PeriodicReport.java | 3 +- .../reports/PersonResourceReport.java | 201 +++-- .../PersonResourceReportPluginData.java | 343 ++++++++ .../reports/ResourcePropertyReport.java | 11 +- .../ResourcePropertyReportPluginData.java | 185 +++++ .../resources/reports/ResourceReport.java | 207 +++-- .../reports/ResourceReportPluginData.java | 307 +++++++ .../reports/AT_PersonResourceReport.java | 46 +- .../AT_PersonResourceReportPluginData.java | 752 ++++++++++++++++++ .../reports/AT_ResourcePropertyReport.java | 2 +- .../AT_ResourcePropertyReportPluginData.java | 365 +++++++++ .../reports/AT_ResourceReportPluginData.java | 655 +++++++++++++++ .../src/main/java/lesson/Example_18.java | 14 +- 13 files changed, 2931 insertions(+), 160 deletions(-) create mode 100644 gcm4/src/main/java/plugins/resources/reports/PersonResourceReportPluginData.java create mode 100644 gcm4/src/main/java/plugins/resources/reports/ResourcePropertyReportPluginData.java create mode 100644 gcm4/src/main/java/plugins/resources/reports/ResourceReportPluginData.java create mode 100644 gcm4/src/test/java/plugins/resources/reports/AT_PersonResourceReportPluginData.java create mode 100644 gcm4/src/test/java/plugins/resources/reports/AT_ResourcePropertyReportPluginData.java create mode 100644 gcm4/src/test/java/plugins/resources/reports/AT_ResourceReportPluginData.java diff --git a/gcm4/src/main/java/plugins/reports/support/PeriodicReport.java b/gcm4/src/main/java/plugins/reports/support/PeriodicReport.java index e080ab4ce..457034438 100644 --- a/gcm4/src/main/java/plugins/reports/support/PeriodicReport.java +++ b/gcm4/src/main/java/plugins/reports/support/PeriodicReport.java @@ -17,7 +17,8 @@ public abstract class PeriodicReport { * Creates the periodic report from the given report period * * @throws ContractException - *
  • if the report period is null
  • + *
  • {@linkplain ReportError#NULL_REPORT_PERIOD} if the report period is null
  • + *
  • {@linkplain ReportError.NULL_REPORT_LABEL} if the report period is null
  • */ public PeriodicReport(ReportLabel reportLabel, ReportPeriod reportPeriod) { if (reportPeriod == null) { diff --git a/gcm4/src/main/java/plugins/resources/reports/PersonResourceReport.java b/gcm4/src/main/java/plugins/resources/reports/PersonResourceReport.java index 1206ef59c..c35fcaa97 100644 --- a/gcm4/src/main/java/plugins/resources/reports/PersonResourceReport.java +++ b/gcm4/src/main/java/plugins/resources/reports/PersonResourceReport.java @@ -6,6 +6,7 @@ import java.util.Set; import nucleus.ReportContext; +import nucleus.SimulationStateContext; import plugins.people.datamanagers.PeopleDataManager; import plugins.people.events.PersonAdditionEvent; import plugins.people.events.PersonImminentRemovalEvent; @@ -17,8 +18,6 @@ import plugins.reports.support.PeriodicReport; import plugins.reports.support.ReportHeader; import plugins.reports.support.ReportItem; -import plugins.reports.support.ReportLabel; -import plugins.reports.support.ReportPeriod; import plugins.resources.datamanagers.ResourcesDataManager; import plugins.resources.events.PersonResourceUpdateEvent; import plugins.resources.events.ResourceIdAdditionEvent; @@ -35,7 +34,7 @@ * * region -- the region identifier * - * Resource -- the resource identifier + * resource -- the resource identifier * * people_with_resource -- the number of people in the region who have at least * one unit of the given resource @@ -46,13 +45,13 @@ * */ public final class PersonResourceReport extends PeriodicReport { - public PersonResourceReport(ReportLabel reportLabel, ReportPeriod reportPeriod, boolean reportPeopleWithoutResources, boolean reportZeroPopulations, ResourceId... resourceIds) { - super(reportLabel, reportPeriod); - this.reportPeopleWithoutResources = reportPeopleWithoutResources; - this.reportZeroPopulations = reportZeroPopulations; - for (ResourceId resourceId : resourceIds) { - this.resourceIds.add(resourceId); - } + public PersonResourceReport(PersonResourceReportPluginData personResourceReportPluginData) { + super(personResourceReportPluginData.getReportLabel(), personResourceReportPluginData.getReportPeriod()); + this.reportPeopleWithoutResources = personResourceReportPluginData.getReportPeopleWithoutResources(); + this.reportZeroPopulations = personResourceReportPluginData.getReportZeroPopulations(); + this.includedResourceIds.addAll(personResourceReportPluginData.getIncludedResourceIds()); + this.excludedResourceIds.addAll(personResourceReportPluginData.getExcludedResourceIds()); + this.includeNewResourceIds = personResourceReportPluginData.getDefaultInclusionPolicy(); } /** @@ -69,19 +68,23 @@ private static enum InventoryType { * The resources that will be used in this report. They are derived from the * values passed in the init() method. */ - private Set resourceIds = new LinkedHashSet<>(); + private final boolean includeNewResourceIds; + + private final Set includedResourceIds = new LinkedHashSet<>(); + private final Set currentResourceIds = new LinkedHashSet<>(); + private final Set excludedResourceIds = new LinkedHashSet<>(); /* * Boolean for controlling the reporting of people with out resources. Set * in the init() method. */ - private boolean reportPeopleWithoutResources; + private final boolean reportPeopleWithoutResources; /* * Boolean for controlling the reporting of people with out resources. Set * in the init() method. */ - private boolean reportZeroPopulations; + private final boolean reportZeroPopulations; // Mapping of the (regionId, resource Id, InventoryType) to // sets of person id. Maintained via the processing of events. @@ -120,7 +123,7 @@ protected void flush(ReportContext reportContext) { final ReportItem.Builder reportItemBuilder = ReportItem.builder(); for (final RegionId regionId : regionMap.keySet()) { final Map>> resourceMap = regionMap.get(regionId); - for (final ResourceId resourceId : resourceIds) { + for (final ResourceId resourceId : currentResourceIds) { final Map> inventoryMap = resourceMap.get(resourceId); final int positiveCount = inventoryMap.get(InventoryType.POSITIVE).size(); @@ -153,7 +156,7 @@ private void handlePersonAdditionEvent(ReportContext reportContext, PersonAdditi PersonId personId = personAdditionEvent.personId(); final RegionId regionId = regionsDataManager.getPersonRegion(personId); - for (final ResourceId resourceId : resourceIds) { + for (final ResourceId resourceId : currentResourceIds) { final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId); if (personResourceLevel > 0) { add(regionId, resourceId, InventoryType.POSITIVE, personId); @@ -171,7 +174,7 @@ private void handlePersonImminentRemovalEvent(ReportContext reportContext, Perso RegionId regionId = regionsDataManager.getPersonRegion(personId); - for (ResourceId resourceId : resourceIds) { + for (ResourceId resourceId : currentResourceIds) { Long amount = resourcesDataManager.getPersonResourceLevel(resourceId, personId); if (amount > 0) { remove(regionId, resourceId, InventoryType.POSITIVE, personId); @@ -185,39 +188,37 @@ private void handlePersonImminentRemovalEvent(ReportContext reportContext, Perso private void handlePersonResourceUpdateEvent(ReportContext reportContext, PersonResourceUpdateEvent personResourceUpdateEvent) { ResourceId resourceId = personResourceUpdateEvent.resourceId(); - if (!resourceIds.contains(resourceId)) { - return; - } - PersonId personId = personResourceUpdateEvent.personId(); - long currentLevel = personResourceUpdateEvent.currentResourceLevel(); - long previousLevel = personResourceUpdateEvent.previousResourceLevel(); - long amount = currentLevel - previousLevel; - - if (amount == 0) { - return; - } - if (amount > 0) { - final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId); - if (personResourceLevel == amount) { - final RegionId regionId = regionsDataManager.getPersonRegion(personId); + if (isCurrentProperty(resourceId)) { + PersonId personId = personResourceUpdateEvent.personId(); + long currentLevel = personResourceUpdateEvent.currentResourceLevel(); + long previousLevel = personResourceUpdateEvent.previousResourceLevel(); + long amount = currentLevel - previousLevel; + + if (amount == 0) { + return; + } + if (amount > 0) { + final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId); + if (personResourceLevel == amount) { + final RegionId regionId = regionsDataManager.getPersonRegion(personId); - if (reportPeopleWithoutResources) { - remove(regionId, resourceId, InventoryType.ZERO, personId); + if (reportPeopleWithoutResources) { + remove(regionId, resourceId, InventoryType.ZERO, personId); + } + add(regionId, resourceId, InventoryType.POSITIVE, personId); } - add(regionId, resourceId, InventoryType.POSITIVE, personId); - } - } else { - amount = -amount; - final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId); - if (personResourceLevel == 0) { - final RegionId regionId = regionsDataManager.getPersonRegion(personId); - remove(regionId, resourceId, InventoryType.POSITIVE, personId); - if (reportPeopleWithoutResources) { - add(regionId, resourceId, InventoryType.ZERO, personId); + } else { + amount = -amount; + final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId); + if (personResourceLevel == 0) { + final RegionId regionId = regionsDataManager.getPersonRegion(personId); + remove(regionId, resourceId, InventoryType.POSITIVE, personId); + if (reportPeopleWithoutResources) { + add(regionId, resourceId, InventoryType.ZERO, personId); + } } } } - } private void handlePersonRegionUpdateEvent(ReportContext reportContext, PersonRegionUpdateEvent personRegionUpdateEvent) { @@ -225,7 +226,7 @@ private void handlePersonRegionUpdateEvent(ReportContext reportContext, PersonRe RegionId previousRegionId = personRegionUpdateEvent.previousRegionId(); RegionId currentRegionId = personRegionUpdateEvent.currentRegionId(); - for (final ResourceId resourceId : resourceIds) { + for (final ResourceId resourceId : currentResourceIds) { final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId); if (personResourceLevel > 0) { remove(previousRegionId, resourceId, InventoryType.POSITIVE, personId); @@ -242,6 +243,66 @@ private void handlePersonRegionUpdateEvent(ReportContext reportContext, PersonRe private RegionsDataManager regionsDataManager; private ResourcesDataManager resourcesDataManager; + private boolean isCurrentProperty(ResourceId resourceId) { + return currentResourceIds.contains(resourceId); + } + + private boolean addToCurrentResourceIds(ResourceId resourceId) { + + // There are eight possibilities: + + /* + * P -- the default inclusion policy + * + * I -- the property is explicitly included + * + * X -- the property is explicitly excluded + * + * C -- the property should be on the current properties + * + * + * P I X C Table + * + * TRUE TRUE FALSE TRUE + * + * TRUE FALSE FALSE TRUE + * + * FALSE TRUE FALSE TRUE + * + * FALSE FALSE FALSE FALSE + * + * TRUE TRUE TRUE FALSE -- not possible + * + * TRUE FALSE TRUE FALSE + * + * FALSE TRUE TRUE FALSE -- not possible + * + * FALSE FALSE TRUE FALSE + * + * + * Two of the cases above are contradictory since a property cannot be + * both explicitly included and explicitly excluded + * + */ + + // if X is true then we don't add the property + if (excludedResourceIds.contains(resourceId)) { + return false; + } + + // if both P and I are false we don't add the property + boolean included = includedResourceIds.contains(resourceId); + + if (!included && !includeNewResourceIds) { + return false; + } + + // we have failed to reject the property + currentResourceIds.add(resourceId); + + return true; + } + /** * * @throws ContractException @@ -260,26 +321,13 @@ protected void prepare(final ReportContext reportContext) { reportContext.subscribe(PersonImminentRemovalEvent.class, this::handlePersonImminentRemovalEvent); reportContext.subscribe(PersonRegionUpdateEvent.class, this::handlePersonRegionUpdateEvent); reportContext.subscribe(RegionAdditionEvent.class, this::handleRegionAdditionEvent); - - /* - * If no resources were selected, then assume that all are desired. - */ - if (resourceIds.size() == 0) { - resourceIds.addAll(resourcesDataManager.getResourceIds()); - } - - /* - * Ensure that the resources are valid - */ - final Set validResourceIds = resourcesDataManager.getResourceIds(); - for (final ResourceId resourceId : resourceIds) { - if (!validResourceIds.contains(resourceId)) { - throw new ContractException(ResourceError.UNKNOWN_RESOURCE_ID, resourceId); - } - } - reportContext.subscribe(PersonResourceUpdateEvent.class, this::handlePersonResourceUpdateEvent); reportContext.subscribe(ResourceIdAdditionEvent.class, this::handleResourceIdAdditionEvent); + reportContext.subscribeToSimulationState(this::recordSimulationState); + + for (final ResourceId resourceId : resourcesDataManager.getResourceIds()) { + addToCurrentResourceIds(resourceId); + } /* * Build the tuple map to empty sets of people in preparation for people @@ -291,7 +339,7 @@ protected void prepare(final ReportContext reportContext) { final Map>> resourceMap = new LinkedHashMap<>(); regionMap.put(regionId, resourceMap); - for (final ResourceId resourceId : resourceIds) { + for (final ResourceId resourceId : currentResourceIds) { final Map> inventoryMap = new LinkedHashMap<>(); resourceMap.put(resourceId, inventoryMap); for (final InventoryType inventoryType : InventoryType.values()) { @@ -306,7 +354,7 @@ protected void prepare(final ReportContext reportContext) { * Place the initial population in the mapping */ for (final PersonId personId : peopleDataManager.getPeople()) { - for (final ResourceId resourceId : resourceIds) { + for (final ResourceId resourceId : currentResourceIds) { final RegionId regionId = regionsDataManager.getPersonRegion(personId); final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId); @@ -322,6 +370,22 @@ protected void prepare(final ReportContext reportContext) { } + private void recordSimulationState(ReportContext reportContext, SimulationStateContext simulationStateContext) { + PersonResourceReportPluginData.Builder builder = simulationStateContext.get(PersonResourceReportPluginData.Builder.class); + for (ResourceId resourceId : includedResourceIds) { + builder.includeResourceId(resourceId); + } + for (ResourceId resourceId : excludedResourceIds) { + builder.excludeResourceId(resourceId); + } + builder.setDefaultInclusion(includeNewResourceIds); + builder.setReportLabel(getReportLabel()); + builder.setReportPeriod(getReportPeriod()); + builder.setReportPeopleWithoutResources(reportPeopleWithoutResources); + builder.setReportZeroPopulations(reportZeroPopulations); + + } + private void handleRegionAdditionEvent(ReportContext reportContext, RegionAdditionEvent regionAdditionEvent) { RegionId regionId = regionAdditionEvent.getRegionId(); @@ -330,7 +394,7 @@ private void handleRegionAdditionEvent(ReportContext reportContext, RegionAdditi final Map>> resourceMap = new LinkedHashMap<>(); regionMap.put(regionId, resourceMap); - for (final ResourceId resourceId : resourceIds) { + for (final ResourceId resourceId : currentResourceIds) { final Map> inventoryMap = new LinkedHashMap<>(); resourceMap.put(resourceId, inventoryMap); for (final InventoryType inventoryType : InventoryType.values()) { @@ -346,7 +410,7 @@ private void handleRegionAdditionEvent(ReportContext reportContext, RegionAdditi * Removes a person to the set of people associated with the given tuple */ private void remove(final RegionId regionId, final ResourceId resourceId, final InventoryType inventoryType, final PersonId personId) { - if (resourceIds.contains(resourceId)) { + if (currentResourceIds.contains(resourceId)) { final Set people = regionMap.get(regionId).get(resourceId).get(inventoryType); people.remove(personId); } @@ -354,8 +418,7 @@ private void remove(final RegionId regionId, final ResourceId resourceId, final private void handleResourceIdAdditionEvent(ReportContext reportContext, ResourceIdAdditionEvent resourceIdAdditionEvent) { ResourceId resourceId = resourceIdAdditionEvent.resourceId(); - if (!resourceIds.contains(resourceId)) { - resourceIds.add(resourceId); + if (addToCurrentResourceIds(resourceId)) { for (RegionId regionID : regionMap.keySet()) { Map>> map = regionMap.get(regionID); Map> invMap = new LinkedHashMap<>(); diff --git a/gcm4/src/main/java/plugins/resources/reports/PersonResourceReportPluginData.java b/gcm4/src/main/java/plugins/resources/reports/PersonResourceReportPluginData.java new file mode 100644 index 000000000..33f977635 --- /dev/null +++ b/gcm4/src/main/java/plugins/resources/reports/PersonResourceReportPluginData.java @@ -0,0 +1,343 @@ +package plugins.resources.reports; + +import java.util.LinkedHashSet; +import java.util.Set; + +import net.jcip.annotations.ThreadSafe; +import nucleus.PluginData; +import nucleus.PluginDataBuilder; +import plugins.reports.support.ReportError; +import plugins.reports.support.ReportLabel; +import plugins.reports.support.ReportPeriod; +import plugins.resources.support.ResourceError; +import plugins.resources.support.ResourceId; +import util.errors.ContractException; + +/** + * A PluginData class supporting PersonResourceReport construction. + */ +@ThreadSafe +public final class PersonResourceReportPluginData implements PluginData { + + /* + * Data class for collecting the inputs to the report + */ + private static class Data { + private ReportLabel reportLabel; + private ReportPeriod reportPeriod; + private boolean reportPeopleWithoutResources; + private boolean reportZeroPopulations; + + private Set includedResourceIds = new LinkedHashSet<>(); + private Set excludedResourceIds = new LinkedHashSet<>(); + private boolean defaultInclusionPolicy = true; + + private boolean locked; + + private Data() { + } + + private Data(Data data) { + reportLabel = data.reportLabel; + reportPeriod = data.reportPeriod; + reportPeopleWithoutResources = data.reportPeopleWithoutResources; + reportZeroPopulations = data.reportZeroPopulations; + includedResourceIds.addAll(data.includedResourceIds); + excludedResourceIds.addAll(data.excludedResourceIds); + defaultInclusionPolicy = data.defaultInclusionPolicy; + locked = data.locked; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (defaultInclusionPolicy ? 1231 : 1237); + result = prime * result + ((excludedResourceIds == null) ? 0 : excludedResourceIds.hashCode()); + result = prime * result + ((includedResourceIds == null) ? 0 : includedResourceIds.hashCode()); + result = prime * result + ((reportLabel == null) ? 0 : reportLabel.hashCode()); + result = prime * result + (reportPeopleWithoutResources ? 1231 : 1237); + result = prime * result + ((reportPeriod == null) ? 0 : reportPeriod.hashCode()); + result = prime * result + (reportZeroPopulations ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Data)) { + return false; + } + Data other = (Data) obj; + if (defaultInclusionPolicy != other.defaultInclusionPolicy) { + return false; + } + if (excludedResourceIds == null) { + if (other.excludedResourceIds != null) { + return false; + } + } else if (!excludedResourceIds.equals(other.excludedResourceIds)) { + return false; + } + if (includedResourceIds == null) { + if (other.includedResourceIds != null) { + return false; + } + } else if (!includedResourceIds.equals(other.includedResourceIds)) { + return false; + } + if (reportLabel == null) { + if (other.reportLabel != null) { + return false; + } + } else if (!reportLabel.equals(other.reportLabel)) { + return false; + } + if (reportPeopleWithoutResources != other.reportPeopleWithoutResources) { + return false; + } + if (reportPeriod != other.reportPeriod) { + return false; + } + if (reportZeroPopulations != other.reportZeroPopulations) { + return false; + } + return true; + } + } + + /** + * Returns a new instance of the builder class + */ + public static Builder builder() { + return new Builder(new Data()); + } + + /** + * Builder class for the report + * + * + */ + public final static class Builder implements PluginDataBuilder { + private Builder(Data data) { + this.data = data; + } + + private void ensureDataMutability() { + if (data.locked) { + data = new Data(data); + data.locked = false; + } + } + + private void ensureImmutability() { + if (!data.locked) { + data.locked = true; + } + } + + private void validateData() { + if (data.reportLabel == null) { + throw new ContractException(ReportError.NULL_REPORT_LABEL); + } + if (data.reportPeriod == null) { + throw new ContractException(ReportError.NULL_REPORT_PERIOD); + } + } + + private Data data; + + /** + * Returns a PersonPropertyReportPluginData created from the collected + * inputs + * + * @throws ContractException + *
  • {@linkplain ReportError#NULL_REPORT_LABEL} if the + * report label is not assigned
  • + *
  • {@linkplain ReportError#NULL_REPORT_PERIOD} if the + * report period is not assigned
  • + * + * + */ + public PersonResourceReportPluginData build() { + + if (!data.locked) { + validateData(); + } + ensureImmutability(); + return new PersonResourceReportPluginData(data); + + } + + /** + * Sets the default policy for inclusion of person properties in the + * report. This policy is used when a person property has not been + * explicitly included or excluded. Defaulted to true. + */ + public Builder setDefaultInclusion(boolean include) { + ensureDataMutability(); + data.defaultInclusionPolicy = include; + return this; + } + + /** + * Sets the policy for reporting people without resources. Defaulted to false. + */ + public Builder setReportPeopleWithoutResources(boolean reportPeopleWithoutResources) { + ensureDataMutability(); + data.reportPeopleWithoutResources = reportPeopleWithoutResources; + return this; + } + + /** + * Sets the policy for reporting resources without assigned people. Defaulted to false. + */ + public Builder setReportZeroPopulations(boolean reportZeroPopulations) { + ensureDataMutability(); + data.reportZeroPopulations = reportZeroPopulations; + return this; + } + + /** + * Selects the given resource id to be included in the report. + * + * @throws ContractException + *
  • {@linkplain ResourceError#NULL_RESOURCE_ID} if the + * resource id is null
  • + */ + public Builder includeResourceId(ResourceId resourceId) { + ensureDataMutability(); + if (resourceId == null) { + throw new ContractException(ResourceError.NULL_RESOURCE_ID); + } + data.includedResourceIds.add(resourceId); + data.excludedResourceIds.remove(resourceId); + return this; + } + + /** + * Selects the given resource id to be excluded from the report + * + * @throws ContractException + *
  • {@linkplain ResourceError#NULL_RESOURCE_ID} if the + * resource id is null
  • + */ + public Builder excludeResourceId(ResourceId resourceId) { + ensureDataMutability(); + if (resourceId == null) { + throw new ContractException(ResourceError.NULL_RESOURCE_ID); + } + data.includedResourceIds.remove(resourceId); + data.excludedResourceIds.add(resourceId); + return this; + } + + /** + * Sets the report label + * + * @throws ContractException + *
  • {@linkplain ReportError#NULL_REPORT_LABEL} if the + * report label is null
  • + */ + public Builder setReportLabel(ReportLabel reportLabel) { + ensureDataMutability(); + if (reportLabel == null) { + throw new ContractException(ReportError.NULL_REPORT_LABEL); + } + data.reportLabel = reportLabel; + return this; + } + + /** + * Sets the report period id + * + * @throws ContractException + *
  • {@linkplain ReportError#NULL_REPORT_PERIOD} if the + * report period is null
  • + */ + public Builder setReportPeriod(ReportPeriod reportPeriod) { + ensureDataMutability(); + if (reportPeriod == null) { + throw new ContractException(ReportError.NULL_REPORT_PERIOD); + } + data.reportPeriod = reportPeriod; + return this; + } + + } + + private final Data data; + + private PersonResourceReportPluginData(Data data) { + this.data = data; + } + + @Override + public Builder getCloneBuilder() { + return new Builder(data); + } + + @Override + public Builder getEmptyBuilder() { + return builder(); + } + + public ReportLabel getReportLabel() { + return data.reportLabel; + } + + public ReportPeriod getReportPeriod() { + return data.reportPeriod; + } + + public Set getIncludedResourceIds() { + return new LinkedHashSet<>(data.includedResourceIds); + } + + public Set getExcludedResourceIds() { + return new LinkedHashSet<>(data.excludedResourceIds); + } + + public boolean getDefaultInclusionPolicy() { + return data.defaultInclusionPolicy; + } + + public boolean getReportPeopleWithoutResources() { + return data.reportPeopleWithoutResources; + } + public boolean getReportZeroPopulations() { + return data.reportZeroPopulations; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((data == null) ? 0 : data.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof PersonResourceReportPluginData)) { + return false; + } + PersonResourceReportPluginData other = (PersonResourceReportPluginData) obj; + if (data == null) { + if (other.data != null) { + return false; + } + } else if (!data.equals(other.data)) { + return false; + } + return true; + } + + + +} \ No newline at end of file diff --git a/gcm4/src/main/java/plugins/resources/reports/ResourcePropertyReport.java b/gcm4/src/main/java/plugins/resources/reports/ResourcePropertyReport.java index 027096231..7a24e4c97 100644 --- a/gcm4/src/main/java/plugins/resources/reports/ResourcePropertyReport.java +++ b/gcm4/src/main/java/plugins/resources/reports/ResourcePropertyReport.java @@ -1,6 +1,7 @@ package plugins.resources.reports; import nucleus.ReportContext; +import nucleus.SimulationStateContext; import plugins.reports.support.ReportHeader; import plugins.reports.support.ReportItem; import plugins.reports.support.ReportLabel; @@ -29,8 +30,8 @@ public final class ResourcePropertyReport { private final ReportLabel reportLabel; - public ResourcePropertyReport(ReportLabel reportLabel) { - this.reportLabel = reportLabel; + public ResourcePropertyReport(ResourcePropertyReportPluginData resourcePropertyReportPluginData) { + this.reportLabel = resourcePropertyReportPluginData.getReportLabel(); } private ReportHeader reportHeader; @@ -58,6 +59,7 @@ public void init(final ReportContext reportContext) { reportContext.subscribe(ResourcePropertyUpdateEvent.class, this::handleResourcePropertyUpdateEvent); reportContext.subscribe(ResourcePropertyDefinitionEvent.class, this::handleResourcePropertyAdditionEvent); + reportContext.subscribeToSimulationState(this::recordSimulationState); ResourcesDataManager resourcesDataManager = reportContext.getDataManager(ResourcesDataManager.class); for (final ResourceId resourceId : resourcesDataManager.getResourceIds()) { @@ -67,6 +69,11 @@ public void init(final ReportContext reportContext) { } } } + + private void recordSimulationState(ReportContext reportContext, SimulationStateContext simulationStateContext) { + ResourcePropertyReportPluginData.Builder builder = simulationStateContext.get(ResourcePropertyReportPluginData.Builder.class); + builder.setReportLabel(reportLabel); + } private void handleResourcePropertyAdditionEvent(ReportContext reportContext, ResourcePropertyDefinitionEvent resourcePropertyDefinitionEvent) { ResourceId resourceId = resourcePropertyDefinitionEvent.resourceId(); diff --git a/gcm4/src/main/java/plugins/resources/reports/ResourcePropertyReportPluginData.java b/gcm4/src/main/java/plugins/resources/reports/ResourcePropertyReportPluginData.java new file mode 100644 index 000000000..e1cf830c5 --- /dev/null +++ b/gcm4/src/main/java/plugins/resources/reports/ResourcePropertyReportPluginData.java @@ -0,0 +1,185 @@ +package plugins.resources.reports; + +import net.jcip.annotations.ThreadSafe; +import nucleus.PluginData; +import nucleus.PluginDataBuilder; +import plugins.reports.support.ReportError; +import plugins.reports.support.ReportLabel; +import util.errors.ContractException; + +/** + * A PluginData class supporting PersonResourceReport construction. + */ +@ThreadSafe +public final class ResourcePropertyReportPluginData implements PluginData { + + /* + * Data class for collecting the inputs to the report + */ + private static class Data { + private ReportLabel reportLabel; + + private boolean locked; + + private Data() { + } + + private Data(Data data) { + reportLabel = data.reportLabel; + locked = data.locked; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((reportLabel == null) ? 0 : reportLabel.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Data)) { + return false; + } + Data other = (Data) obj; + if (reportLabel == null) { + if (other.reportLabel != null) { + return false; + } + } else if (!reportLabel.equals(other.reportLabel)) { + return false; + } + return true; + } + + + } + + /** + * Returns a new instance of the builder class + */ + public static Builder builder() { + return new Builder(new Data()); + } + + /** + * Builder class for the report + * + * + */ + public final static class Builder implements PluginDataBuilder { + private Builder(Data data) { + this.data = data; + } + + private void ensureDataMutability() { + if (data.locked) { + data = new Data(data); + data.locked = false; + } + } + + private void ensureImmutability() { + if (!data.locked) { + data.locked = true; + } + } + + private void validateData() { + if (data.reportLabel == null) { + throw new ContractException(ReportError.NULL_REPORT_LABEL); + } + } + + private Data data; + + /** + * Returns a PersonPropertyReportPluginData created from the collected + * inputs + * + * @throws ContractException + *
  • {@linkplain ReportError#NULL_REPORT_LABEL} if the + * report label is not assigned
  • + */ + public ResourcePropertyReportPluginData build() { + + if (!data.locked) { + validateData(); + } + ensureImmutability(); + return new ResourcePropertyReportPluginData(data); + + } + + /** + * Sets the report label + * + * @throws ContractException + *
  • {@linkplain ReportError#NULL_REPORT_LABEL} if the + * report label is null
  • + */ + public Builder setReportLabel(ReportLabel reportLabel) { + ensureDataMutability(); + if (reportLabel == null) { + throw new ContractException(ReportError.NULL_REPORT_LABEL); + } + data.reportLabel = reportLabel; + return this; + } + + } + + private final Data data; + + private ResourcePropertyReportPluginData(Data data) { + this.data = data; + } + + @Override + public Builder getCloneBuilder() { + return new Builder(data); + } + + @Override + public Builder getEmptyBuilder() { + return builder(); + } + + public ReportLabel getReportLabel() { + return data.reportLabel; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((data == null) ? 0 : data.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ResourcePropertyReportPluginData)) { + return false; + } + ResourcePropertyReportPluginData other = (ResourcePropertyReportPluginData) obj; + if (data == null) { + if (other.data != null) { + return false; + } + } else if (!data.equals(other.data)) { + return false; + } + return true; + } + + + +} \ No newline at end of file diff --git a/gcm4/src/main/java/plugins/resources/reports/ResourceReport.java b/gcm4/src/main/java/plugins/resources/reports/ResourceReport.java index 18b2a129f..33460c539 100644 --- a/gcm4/src/main/java/plugins/resources/reports/ResourceReport.java +++ b/gcm4/src/main/java/plugins/resources/reports/ResourceReport.java @@ -1,12 +1,12 @@ package plugins.resources.reports; -import java.util.ArrayList; import java.util.LinkedHashMap; -import java.util.List; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import nucleus.ReportContext; +import nucleus.SimulationStateContext; import plugins.people.datamanagers.PeopleDataManager; import plugins.people.events.PersonAdditionEvent; import plugins.people.events.PersonImminentRemovalEvent; @@ -18,8 +18,6 @@ import plugins.reports.support.PeriodicReport; import plugins.reports.support.ReportHeader; import plugins.reports.support.ReportItem; -import plugins.reports.support.ReportLabel; -import plugins.reports.support.ReportPeriod; import plugins.resources.datamanagers.ResourcesDataManager; import plugins.resources.events.PersonResourceUpdateEvent; import plugins.resources.events.RegionResourceUpdateEvent; @@ -90,12 +88,17 @@ * */ public final class ResourceReport extends PeriodicReport { + private final boolean includeNewResourceIds; - public ResourceReport(ReportLabel reportLabel, ReportPeriod reportPeriod, ResourceId... resourceIds) { - super(reportLabel, reportPeriod); - for (ResourceId resourceId : resourceIds) { - this.resourceIds.add(resourceId); - } + private final Set includedResourceIds = new LinkedHashSet<>(); + private final Set currentResourceIds = new LinkedHashSet<>(); + private final Set excludedResourceIds = new LinkedHashSet<>(); + + public ResourceReport(ResourceReportPluginData resourceReportPluginData) { + super(resourceReportPluginData.getReportLabel(), resourceReportPluginData.getReportPeriod()); + this.includedResourceIds.addAll(resourceReportPluginData.getIncludedResourceIds()); + this.excludedResourceIds.addAll(resourceReportPluginData.getExcludedResourceIds()); + this.includeNewResourceIds = resourceReportPluginData.getDefaultInclusionPolicy(); } @@ -131,13 +134,6 @@ private void reset() { } } - /* - * The resource covered by this report. Determined in the init() method. - */ - private final List resourceIds = new ArrayList<>(); - - private boolean subscribedToAllResources; - /* * The mapping of (Region, Resource, Activity) tuples to counters that * record the number of actions and the number of items handled across those @@ -195,7 +191,7 @@ protected void flush(ReportContext reportContext) { private void handlePersonAdditionEvent(ReportContext reportContext, PersonAdditionEvent personAdditionEvent) { PersonId personId = personAdditionEvent.personId(); final RegionId regionId = regionsDataManager.getPersonRegion(personId); - for (final ResourceId resourceId : resourceIds) { + for (final ResourceId resourceId : currentResourceIds) { final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId); if (personResourceLevel > 0) { increment(regionId, resourceId, Activity.PERSON_ARRIVAL, personResourceLevel); @@ -208,7 +204,7 @@ private void handlePersonImminentRemovalEvent(ReportContext reportContext, Perso PersonId personId = personImminentRemovalEvent.personId(); RegionId regionId = regionsDataManager.getPersonRegion(personId); - for (ResourceId resourceId : resourceIds) { + for (ResourceId resourceId : currentResourceIds) { final Long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId); if (personResourceLevel > 0) { increment(regionId, resourceId, Activity.PERSON_DEPARTURE, personResourceLevel); @@ -222,17 +218,17 @@ private void handlePersonResourceUpdateEvent(ReportContext reportContext, Person final ResourceId resourceId = personResourceUpdateEvent.resourceId(); final long previousLevel = personResourceUpdateEvent.previousResourceLevel(); final long currentLevel = personResourceUpdateEvent.currentResourceLevel(); - if (!resourceIds.contains(resourceId)) { - return; - } - long amount = currentLevel - previousLevel; - if (amount > 0) { - final RegionId regionId = regionsDataManager.getPersonRegion(personId); - increment(regionId, resourceId, Activity.PERSON_RESOURCE_ADDITION, amount); - } else { - amount = -amount; - final RegionId regionId = regionsDataManager.getPersonRegion(personId); - increment(regionId, resourceId, Activity.REMOVE_RESOURCE_FROM_PERSON, amount); + if (isCurrentProperty(resourceId)) { + + long amount = currentLevel - previousLevel; + if (amount > 0) { + final RegionId regionId = regionsDataManager.getPersonRegion(personId); + increment(regionId, resourceId, Activity.PERSON_RESOURCE_ADDITION, amount); + } else { + amount = -amount; + final RegionId regionId = regionsDataManager.getPersonRegion(personId); + increment(regionId, resourceId, Activity.REMOVE_RESOURCE_FROM_PERSON, amount); + } } } @@ -241,7 +237,7 @@ private void handlePersonRegionUpdateEvent(ReportContext reportContext, PersonRe RegionId previousRegionId = personRegionUpdateEvent.previousRegionId(); RegionId currentRegionId = personRegionUpdateEvent.currentRegionId(); - for (final ResourceId resourceId : resourceIds) { + for (final ResourceId resourceId : currentResourceIds) { final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId); if (personResourceLevel > 0) { increment(currentRegionId, resourceId, Activity.PERSON_REGION_ARRIVAL, personResourceLevel); @@ -251,19 +247,16 @@ private void handlePersonRegionUpdateEvent(ReportContext reportContext, PersonRe } private void handleResourceIdAdditionEvent(ReportContext reportContext, ResourceIdAdditionEvent resourceIdAdditionEvent) { - - if (subscribedToAllResources) { - ResourceId resourceId = resourceIdAdditionEvent.resourceId(); - if (resourceId != null && !resourceIds.contains(resourceId)) { - resourceIds.add(resourceId); - for (RegionId regionId : regionMap.keySet()) { - Map> map = regionMap.get(regionId); - Map activityMap = new LinkedHashMap<>(); - for (Activity activity : Activity.values()) { - activityMap.put(activity, new Counter()); - } - map.put(resourceId, activityMap); + ResourceId resourceId = resourceIdAdditionEvent.resourceId(); + + if (addToCurrentResourceIds(resourceId)) { + for (RegionId regionId : regionMap.keySet()) { + Map> map = regionMap.get(regionId); + Map activityMap = new LinkedHashMap<>(); + for (Activity activity : Activity.values()) { + activityMap.put(activity, new Counter()); } + map.put(resourceId, activityMap); } } } @@ -271,18 +264,17 @@ private void handleResourceIdAdditionEvent(ReportContext reportContext, Resource private void handleRegionResourceUpdateEvent(ReportContext reportContext, RegionResourceUpdateEvent regionResourceUpdateEvent) { ResourceId resourceId = regionResourceUpdateEvent.resourceId(); - if (!resourceIds.contains(resourceId)) { - return; - } - RegionId regionId = regionResourceUpdateEvent.regionId(); - long previousResourceLevel = regionResourceUpdateEvent.previousResourceLevel(); - long currentResourceLevel = regionResourceUpdateEvent.currentResourceLevel(); - long amount = currentResourceLevel - previousResourceLevel; - if (amount > 0) { - increment(regionId, resourceId, Activity.REGION_RESOURCE_ADDITION, amount); - } else { - amount = -amount; - increment(regionId, resourceId, Activity.REGION_RESOURCE_REMOVAL, amount); + if (isCurrentProperty(resourceId)) { + RegionId regionId = regionResourceUpdateEvent.regionId(); + long previousResourceLevel = regionResourceUpdateEvent.previousResourceLevel(); + long currentResourceLevel = regionResourceUpdateEvent.currentResourceLevel(); + long amount = currentResourceLevel - previousResourceLevel; + if (amount > 0) { + increment(regionId, resourceId, Activity.REGION_RESOURCE_ADDITION, amount); + } else { + amount = -amount; + increment(regionId, resourceId, Activity.REGION_RESOURCE_REMOVAL, amount); + } } } @@ -300,6 +292,66 @@ private void increment(final RegionId regionId, final ResourceId resourceId, fin private RegionsDataManager regionsDataManager; private ResourcesDataManager resourcesDataManager; + private boolean isCurrentProperty(ResourceId resourceId) { + return currentResourceIds.contains(resourceId); + } + + private boolean addToCurrentResourceIds(ResourceId resourceId) { + + // There are eight possibilities: + + /* + * P -- the default inclusion policy + * + * I -- the property is explicitly included + * + * X -- the property is explicitly excluded + * + * C -- the property should be on the current properties + * + * + * P I X C Table + * + * TRUE TRUE FALSE TRUE + * + * TRUE FALSE FALSE TRUE + * + * FALSE TRUE FALSE TRUE + * + * FALSE FALSE FALSE FALSE + * + * TRUE TRUE TRUE FALSE -- not possible + * + * TRUE FALSE TRUE FALSE + * + * FALSE TRUE TRUE FALSE -- not possible + * + * FALSE FALSE TRUE FALSE + * + * + * Two of the cases above are contradictory since a property cannot be + * both explicitly included and explicitly excluded + * + */ + + // if X is true then we don't add the property + if (excludedResourceIds.contains(resourceId)) { + return false; + } + + // if both P and I are false we don't add the property + boolean included = includedResourceIds.contains(resourceId); + + if (!included && !includeNewResourceIds) { + return false; + } + + // we have failed to reject the property + currentResourceIds.add(resourceId); + + return true; + } + /** * @throws ContractException *
  • {@linkplain ResourceError#UNKNOWN_RESOURCE_ID} if a @@ -318,24 +370,13 @@ protected void prepare(final ReportContext reportContext) { reportContext.subscribe(PersonRegionUpdateEvent.class, this::handlePersonRegionUpdateEvent); reportContext.subscribe(RegionResourceUpdateEvent.class, this::handleRegionResourceUpdateEvent); reportContext.subscribe(RegionAdditionEvent.class, this::handleRegionAdditionEvent); - - if (resourceIds.size() == 0) { - resourceIds.addAll(resourcesDataManager.getResourceIds()); - } - /* - * Ensure that every client supplied resource identifier is valid - */ - final Set validResourceIds = resourcesDataManager.getResourceIds(); - for (final ResourceId resourceId : resourceIds) { - if (!validResourceIds.contains(resourceId)) { - throw new ContractException(ResourceError.UNKNOWN_RESOURCE_ID, resourceId); - } - } - reportContext.subscribe(PersonResourceUpdateEvent.class, this::handlePersonResourceUpdateEvent); - subscribedToAllResources = true; - reportContext.subscribe(ResourceIdAdditionEvent.class, this::handleResourceIdAdditionEvent); + reportContext.subscribeToSimulationState(this::recordSimulationState); + + for (final ResourceId resourceId : resourcesDataManager.getResourceIds()) { + addToCurrentResourceIds(resourceId); + } /* * Filling the region map with empty counters @@ -343,7 +384,7 @@ protected void prepare(final ReportContext reportContext) { for (final RegionId regionId : regionsDataManager.getRegionIds()) { final Map> resourceMap = new LinkedHashMap<>(); regionMap.put(regionId, resourceMap); - for (final ResourceId resourceId : resourceIds) { + for (final ResourceId resourceId : currentResourceIds) { final Map activityMap = new LinkedHashMap<>(); resourceMap.put(resourceId, activityMap); for (final Activity activity : Activity.values()) { @@ -356,7 +397,7 @@ protected void prepare(final ReportContext reportContext) { for (PersonId personId : peopleDataManager.getPeople()) { final RegionId regionId = regionsDataManager.getPersonRegion(personId); - for (final ResourceId resourceId : resourceIds) { + for (final ResourceId resourceId : currentResourceIds) { final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId); if (personResourceLevel > 0) { increment(regionId, resourceId, Activity.PERSON_ARRIVAL, personResourceLevel); @@ -365,21 +406,33 @@ protected void prepare(final ReportContext reportContext) { } for (RegionId regionId : regionsDataManager.getRegionIds()) { - for (ResourceId resourceId : resourcesDataManager.getResourceIds()) { + for (ResourceId resourceId : currentResourceIds) { long regionResourceLevel = resourcesDataManager.getRegionResourceLevel(regionId, resourceId); - if (resourceIds.contains(resourceId)) { - increment(regionId, resourceId, Activity.REGION_RESOURCE_ADDITION, regionResourceLevel); - } + increment(regionId, resourceId, Activity.REGION_RESOURCE_ADDITION, regionResourceLevel); } } } + + + private void recordSimulationState(ReportContext reportContext, SimulationStateContext simulationStateContext) { + ResourceReportPluginData.Builder builder = simulationStateContext.get(ResourceReportPluginData.Builder.class); + for (ResourceId resourceId : includedResourceIds) { + builder.includeResourceId(resourceId); + } + for (ResourceId resourceId : excludedResourceIds) { + builder.excludeResourceId(resourceId); + } + builder.setDefaultInclusion(includeNewResourceIds); + builder.setReportLabel(getReportLabel()); + builder.setReportPeriod(getReportPeriod()); + } private void handleRegionAdditionEvent(ReportContext reportContext, RegionAdditionEvent regionAdditionEvent) { RegionId regionId = regionAdditionEvent.getRegionId(); final Map> resourceMap = new LinkedHashMap<>(); regionMap.put(regionId, resourceMap); - for (final ResourceId resourceId : resourceIds) { + for (final ResourceId resourceId : currentResourceIds) { final Map activityMap = new LinkedHashMap<>(); resourceMap.put(resourceId, activityMap); for (final Activity activity : Activity.values()) { diff --git a/gcm4/src/main/java/plugins/resources/reports/ResourceReportPluginData.java b/gcm4/src/main/java/plugins/resources/reports/ResourceReportPluginData.java new file mode 100644 index 000000000..7701a76dc --- /dev/null +++ b/gcm4/src/main/java/plugins/resources/reports/ResourceReportPluginData.java @@ -0,0 +1,307 @@ +package plugins.resources.reports; + +import java.util.LinkedHashSet; +import java.util.Set; + +import net.jcip.annotations.ThreadSafe; +import nucleus.PluginData; +import nucleus.PluginDataBuilder; +import plugins.reports.support.ReportError; +import plugins.reports.support.ReportLabel; +import plugins.reports.support.ReportPeriod; +import plugins.resources.support.ResourceError; +import plugins.resources.support.ResourceId; +import util.errors.ContractException; + +/** + * A PluginData class supporting PersonResourceReport construction. + */ +@ThreadSafe +public final class ResourceReportPluginData implements PluginData { + + /* + * Data class for collecting the inputs to the report + */ + private static class Data { + private ReportLabel reportLabel; + private ReportPeriod reportPeriod; + + private Set includedResourceIds = new LinkedHashSet<>(); + private Set excludedResourceIds = new LinkedHashSet<>(); + private boolean defaultInclusionPolicy = true; + + private boolean locked; + + private Data() { + } + + private Data(Data data) { + reportLabel = data.reportLabel; + reportPeriod = data.reportPeriod; + includedResourceIds.addAll(data.includedResourceIds); + excludedResourceIds.addAll(data.excludedResourceIds); + defaultInclusionPolicy = data.defaultInclusionPolicy; + locked = data.locked; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (defaultInclusionPolicy ? 1231 : 1237); + result = prime * result + ((excludedResourceIds == null) ? 0 : excludedResourceIds.hashCode()); + result = prime * result + ((includedResourceIds == null) ? 0 : includedResourceIds.hashCode()); + result = prime * result + ((reportLabel == null) ? 0 : reportLabel.hashCode()); + result = prime * result + ((reportPeriod == null) ? 0 : reportPeriod.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Data)) { + return false; + } + Data other = (Data) obj; + if (defaultInclusionPolicy != other.defaultInclusionPolicy) { + return false; + } + if (excludedResourceIds == null) { + if (other.excludedResourceIds != null) { + return false; + } + } else if (!excludedResourceIds.equals(other.excludedResourceIds)) { + return false; + } + if (includedResourceIds == null) { + if (other.includedResourceIds != null) { + return false; + } + } else if (!includedResourceIds.equals(other.includedResourceIds)) { + return false; + } + if (reportLabel == null) { + if (other.reportLabel != null) { + return false; + } + } else if (!reportLabel.equals(other.reportLabel)) { + return false; + } + + if (reportPeriod != other.reportPeriod) { + return false; + } + + return true; + } + } + + /** + * Returns a new instance of the builder class + */ + public static Builder builder() { + return new Builder(new Data()); + } + + /** + * Builder class for the report + * + * + */ + public final static class Builder implements PluginDataBuilder { + private Builder(Data data) { + this.data = data; + } + + private void ensureDataMutability() { + if (data.locked) { + data = new Data(data); + data.locked = false; + } + } + + private void ensureImmutability() { + if (!data.locked) { + data.locked = true; + } + } + + private void validateData() { + if (data.reportLabel == null) { + throw new ContractException(ReportError.NULL_REPORT_LABEL); + } + if (data.reportPeriod == null) { + throw new ContractException(ReportError.NULL_REPORT_PERIOD); + } + } + + private Data data; + + /** + * Returns a PersonPropertyReportPluginData created from the collected + * inputs + * + * @throws ContractException + *
  • {@linkplain ReportError#NULL_REPORT_LABEL} if the + * report label is not assigned
  • + *
  • {@linkplain ReportError#NULL_REPORT_PERIOD} if the + * report period is not assigned
  • + * + * + */ + public ResourceReportPluginData build() { + + if (!data.locked) { + validateData(); + } + ensureImmutability(); + return new ResourceReportPluginData(data); + + } + + /** + * Sets the default policy for inclusion of person properties in the + * report. This policy is used when a person property has not been + * explicitly included or excluded. Defaulted to true. + */ + public Builder setDefaultInclusion(boolean include) { + ensureDataMutability(); + data.defaultInclusionPolicy = include; + return this; + } + + + /** + * Selects the given resource id to be included in the report. + * + * @throws ContractException + *
  • {@linkplain ResourceError#NULL_RESOURCE_ID} if the + * resource id is null
  • + */ + public Builder includeResourceId(ResourceId resourceId) { + ensureDataMutability(); + if (resourceId == null) { + throw new ContractException(ResourceError.NULL_RESOURCE_ID); + } + data.includedResourceIds.add(resourceId); + data.excludedResourceIds.remove(resourceId); + return this; + } + + /** + * Selects the given resource id to be excluded from the report + * + * @throws ContractException + *
  • {@linkplain ResourceError#NULL_RESOURCE_ID} if the + * resource id is null
  • + */ + public Builder excludeResourceId(ResourceId resourceId) { + ensureDataMutability(); + if (resourceId == null) { + throw new ContractException(ResourceError.NULL_RESOURCE_ID); + } + data.includedResourceIds.remove(resourceId); + data.excludedResourceIds.add(resourceId); + return this; + } + + /** + * Sets the report label + * + * @throws ContractException + *
  • {@linkplain ReportError#NULL_REPORT_LABEL} if the + * report label is null
  • + */ + public Builder setReportLabel(ReportLabel reportLabel) { + ensureDataMutability(); + if (reportLabel == null) { + throw new ContractException(ReportError.NULL_REPORT_LABEL); + } + data.reportLabel = reportLabel; + return this; + } + + /** + * Sets the report period id + * + * @throws ContractException + *
  • {@linkplain ReportError#NULL_REPORT_PERIOD} if the + * report period is null
  • + */ + public Builder setReportPeriod(ReportPeriod reportPeriod) { + ensureDataMutability(); + if (reportPeriod == null) { + throw new ContractException(ReportError.NULL_REPORT_PERIOD); + } + data.reportPeriod = reportPeriod; + return this; + } + + } + + private final Data data; + + private ResourceReportPluginData(Data data) { + this.data = data; + } + + @Override + public Builder getCloneBuilder() { + return new Builder(data); + } + + @Override + public Builder getEmptyBuilder() { + return builder(); + } + + public ReportLabel getReportLabel() { + return data.reportLabel; + } + + public ReportPeriod getReportPeriod() { + return data.reportPeriod; + } + + public Set getIncludedResourceIds() { + return new LinkedHashSet<>(data.includedResourceIds); + } + + public Set getExcludedResourceIds() { + return new LinkedHashSet<>(data.excludedResourceIds); + } + + public boolean getDefaultInclusionPolicy() { + return data.defaultInclusionPolicy; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((data == null) ? 0 : data.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ResourceReportPluginData)) { + return false; + } + ResourceReportPluginData other = (ResourceReportPluginData) obj; + if (data == null) { + if (other.data != null) { + return false; + } + } else if (!data.equals(other.data)) { + return false; + } + return true; + } + +} \ No newline at end of file diff --git a/gcm4/src/test/java/plugins/resources/reports/AT_PersonResourceReport.java b/gcm4/src/test/java/plugins/resources/reports/AT_PersonResourceReport.java index 22ee587c6..6977f533a 100644 --- a/gcm4/src/test/java/plugins/resources/reports/AT_PersonResourceReport.java +++ b/gcm4/src/test/java/plugins/resources/reports/AT_PersonResourceReport.java @@ -1,11 +1,17 @@ package plugins.resources.reports; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.List; + import org.junit.jupiter.api.Test; +import nucleus.Plugin; import nucleus.ReportContext; -import plugins.reports.support.ReportLabel; -import plugins.reports.support.ReportPeriod; -import plugins.resources.support.ResourceId; +import nucleus.testsupport.testplugin.TestActorPlan; +import nucleus.testsupport.testplugin.TestPluginData; +import nucleus.testsupport.testplugin.TestSimulation; +import plugins.resources.testsupport.ResourcesTestPluginFactory; import util.annotations.UnitTag; import util.annotations.UnitTestConstructor; import util.annotations.UnitTestMethod; @@ -13,15 +19,43 @@ public class AT_PersonResourceReport { @Test - @UnitTestConstructor(target = PersonResourceReport.class, args = { ReportLabel.class, ReportPeriod.class, boolean.class, boolean.class, ResourceId[].class }) + @UnitTestConstructor(target = PersonResourceReport.class, args = { PersonResourceReportPluginData.class }) public void testConstructor() { - // nothing to test + /* + * Nothing to test. The PersonResourceReportPluginData guarantees that + * the report lable and report period will not be null. The super + * constructor of the PersonResourceReport prevents the use of a + * ContractException for null PersonResourceReportPluginData instances. + */ + assertThrows(NullPointerException.class, () -> new PersonResourceReport(null)); + } @Test @UnitTestMethod(target = PersonResourceReport.class, name = "init", args = { ReportContext.class }, tags = UnitTag.INCOMPLETE) public void testInit() { - // test incomplete + + //excluded properties + //included properties + //new non existing + +// reportContext.subscribe(PersonAdditionEvent.class, this::handlePersonAdditionEvent); +// reportContext.subscribe(PersonImminentRemovalEvent.class, this::handlePersonImminentRemovalEvent); +// reportContext.subscribe(PersonRegionUpdateEvent.class, this::handlePersonRegionUpdateEvent); +// reportContext.subscribe(RegionAdditionEvent.class, this::handleRegionAdditionEvent); +// reportContext.subscribe(PersonResourceUpdateEvent.class, this::handlePersonResourceUpdateEvent); +// reportContext.subscribe(ResourceIdAdditionEvent.class, this::handleResourceIdAdditionEvent); + + + TestPluginData.Builder pluginDataBuilder = TestPluginData.builder(); + pluginDataBuilder.addTestActorPlan("actor", new TestActorPlan(0,(c)->{})); + TestPluginData testPluginData = pluginDataBuilder.build(); + + List plugins = ResourcesTestPluginFactory// + .factory(5, 5884216992159063226L, testPluginData)// + .getPlugins(); + + TestSimulation.executeSimulation(plugins); } } \ No newline at end of file diff --git a/gcm4/src/test/java/plugins/resources/reports/AT_PersonResourceReportPluginData.java b/gcm4/src/test/java/plugins/resources/reports/AT_PersonResourceReportPluginData.java new file mode 100644 index 000000000..76ff749f0 --- /dev/null +++ b/gcm4/src/test/java/plugins/resources/reports/AT_PersonResourceReportPluginData.java @@ -0,0 +1,752 @@ +package plugins.resources.reports; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.apache.commons.math3.random.RandomGenerator; +import org.junit.jupiter.api.Test; + +import plugins.reports.support.ReportError; +import plugins.reports.support.ReportLabel; +import plugins.reports.support.ReportPeriod; +import plugins.reports.support.SimpleReportLabel; +import plugins.resources.support.ResourceError; +import plugins.resources.support.ResourceId; +import plugins.resources.testsupport.TestResourceId; +import util.annotations.UnitTestMethod; +import util.errors.ContractException; +import util.random.RandomGeneratorProvider; + +public class AT_PersonResourceReportPluginData { + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "builder", args = {}) + public void testBuilder() { + PersonResourceReportPluginData.Builder builder = PersonResourceReportPluginData.builder(); + assertNotNull(builder); + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.Builder.class, name = "build", args = {}) + public void testBuild() { + // the specific capabilities are covered elsewhere + + // precondition test: if the report period is not assigned + ContractException contractException = assertThrows(ContractException.class, () -> // + PersonResourceReportPluginData .builder()// + .setReportLabel(new SimpleReportLabel(getClass()))// + .build()); + assertEquals(ReportError.NULL_REPORT_PERIOD, contractException.getErrorType()); + + // precondition test: if the report label is not assigned + contractException = assertThrows(ContractException.class, () -> // + PersonResourceReportPluginData .builder()// + .setReportPeriod(ReportPeriod.DAILY)// + .build()); + assertEquals(ReportError.NULL_REPORT_LABEL, contractException.getErrorType()); + + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.Builder.class, name = "setReportLabel", args = { ReportLabel.class }) + public void testSetReportLabel() { + + for (int i = 0; i < 30; i++) { + ReportLabel expectedReportLabel = new SimpleReportLabel(i); + PersonResourceReportPluginData personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(ReportPeriod.DAILY)// + .setReportLabel(expectedReportLabel)// + .build(); + + assertEquals(expectedReportLabel, personResourceReportPluginData.getReportLabel()); + } + + // precondition: if the report label is null + ContractException contractException = assertThrows(ContractException.class, () -> { + PersonResourceReportPluginData.builder().setReportLabel(null); + }); + assertEquals(ReportError.NULL_REPORT_LABEL, contractException.getErrorType()); + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.Builder.class, name = "setReportPeriod", args = { ReportPeriod.class }) + public void testSetReportPeriod() { + + ReportLabel reportLabel = new SimpleReportLabel("report label"); + for (ReportPeriod reportPeriod : ReportPeriod.values()) { + + PersonResourceReportPluginData personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + + assertEquals(reportPeriod, personResourceReportPluginData.getReportPeriod()); + } + + // precondition: if the report period is null + ContractException contractException = assertThrows(ContractException.class, () -> { + PersonResourceReportPluginData.builder().setReportPeriod(null); + }); + assertEquals(ReportError.NULL_REPORT_PERIOD, contractException.getErrorType()); + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.Builder.class, name = "setReportPeopleWithoutResources(boolean)", args = { boolean.class }) + public void testSetReportPeopleWithoutResources() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + // show the default value is false + PersonResourceReportPluginData personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + assertEquals(false, personResourceReportPluginData.getReportPeopleWithoutResources()); + + personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .setReportPeopleWithoutResources(true)// + .build(); + assertEquals(true, personResourceReportPluginData.getReportPeopleWithoutResources()); + + personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .setReportPeopleWithoutResources(false)// + .build(); + assertEquals(false, personResourceReportPluginData.getReportPeopleWithoutResources()); + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.Builder.class, name = "setReportZeroPopulations(boolean)", args = { boolean.class }) + public void testSetReportZeroPopulations() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + // show the default value is false + PersonResourceReportPluginData personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + assertEquals(false, personResourceReportPluginData.getReportZeroPopulations()); + + personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .setReportZeroPopulations(true)// + .build(); + assertEquals(true, personResourceReportPluginData.getReportZeroPopulations()); + + personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .setReportZeroPopulations(false)// + .build(); + assertEquals(false, personResourceReportPluginData.getReportZeroPopulations()); + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.Builder.class, name = "setDefaultInclusion", args = { boolean.class }) + public void testSetDefaultInclusion() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + // show the default value is true + PersonResourceReportPluginData personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + assertEquals(true, personResourceReportPluginData.getDefaultInclusionPolicy()); + + personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .setDefaultInclusion(true)// + .build(); + assertEquals(true, personResourceReportPluginData.getDefaultInclusionPolicy()); + + personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .setDefaultInclusion(false)// + .build(); + assertEquals(false, personResourceReportPluginData.getDefaultInclusionPolicy()); + + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.Builder.class, name = "includeResourceId", args = { ResourceId.class }) + public void testIncludeResourceId() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + PersonResourceReportPluginData personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + assertTrue(personResourceReportPluginData.getIncludedResourceIds().isEmpty()); + + // show that inclusion alone works + Set expectedResourceIds = new LinkedHashSet<>(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + PersonResourceReportPluginData.Builder builder = PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.includeResourceId(resourceId); + } + + personResourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, personResourceReportPluginData.getIncludedResourceIds()); + + // show that inclusion will override exclusion + expectedResourceIds.clear(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + builder = PersonResourceReportPluginData.builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.excludeResourceId(resourceId); + builder.includeResourceId(resourceId); + } + + personResourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, personResourceReportPluginData.getIncludedResourceIds()); + + // precondition: if the person property id is null + ContractException contractException = assertThrows(ContractException.class, () -> { + PersonResourceReportPluginData.builder().includeResourceId(null); + }); + assertEquals(ResourceError.NULL_RESOURCE_ID, contractException.getErrorType()); + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.Builder.class, name = "excludeResourceId", args = { ResourceId.class }) + public void testExcludeResourceId() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + // show the default is non-exclusion + PersonResourceReportPluginData personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + assertTrue(personResourceReportPluginData.getExcludedResourceIds().isEmpty()); + + // show that exclusion alone works + Set expectedResourceIds = new LinkedHashSet<>(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + PersonResourceReportPluginData.Builder builder = PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.excludeResourceId(resourceId); + } + + personResourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, personResourceReportPluginData.getExcludedResourceIds()); + + // show that exclusion will override inclusion + expectedResourceIds.clear(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + builder = PersonResourceReportPluginData.builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.includeResourceId(resourceId); + builder.excludeResourceId(resourceId); + } + + personResourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, personResourceReportPluginData.getExcludedResourceIds()); + + // precondition: if the person property id is null + ContractException contractException = assertThrows(ContractException.class, () -> { + PersonResourceReportPluginData.builder().excludeResourceId(null); + }); + assertEquals(ResourceError.NULL_RESOURCE_ID, contractException.getErrorType()); + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "getReportLabel", args = {}) + public void testGetReportLabel() { + for (int i = 0; i < 30; i++) { + ReportLabel expectedReportLabel = new SimpleReportLabel(i); + PersonResourceReportPluginData personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(ReportPeriod.DAILY)// + .setReportLabel(expectedReportLabel)// + .build(); + + assertEquals(expectedReportLabel, personResourceReportPluginData.getReportLabel()); + } + + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "getReportPeriod", args = {}) + public void testGetReportPeriod() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + for (ReportPeriod reportPeriod : ReportPeriod.values()) { + + PersonResourceReportPluginData personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + + assertEquals(reportPeriod, personResourceReportPluginData.getReportPeriod()); + } + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "getIncludedResourceIds", args = {}) + public void testGetIncludedResourceIds() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + // show the default is non-inclusion + PersonResourceReportPluginData personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + assertTrue(personResourceReportPluginData.getIncludedResourceIds().isEmpty()); + + // show that inclusion alone works + Set expectedResourceIds = new LinkedHashSet<>(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + PersonResourceReportPluginData.Builder builder = PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.includeResourceId(resourceId); + } + + personResourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, personResourceReportPluginData.getIncludedResourceIds()); + + // show that inclusion will override exclusion + expectedResourceIds.clear(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + builder = PersonResourceReportPluginData.builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.excludeResourceId(resourceId); + builder.includeResourceId(resourceId); + } + + personResourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, personResourceReportPluginData.getIncludedResourceIds()); + + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "getExcludedResourceIds", args = {}) + public void testGetExcludedResourceIds() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + // show the default is non-exclusion + PersonResourceReportPluginData personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + assertTrue(personResourceReportPluginData.getExcludedResourceIds().isEmpty()); + + // show that exclusion alone works + Set expectedResourceIds = new LinkedHashSet<>(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + PersonResourceReportPluginData.Builder builder = PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.excludeResourceId(resourceId); + } + + personResourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, personResourceReportPluginData.getExcludedResourceIds()); + + // show that exclusion will override inclusion + expectedResourceIds.clear(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + builder = PersonResourceReportPluginData.builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.includeResourceId(resourceId); + builder.excludeResourceId(resourceId); + } + + personResourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, personResourceReportPluginData.getExcludedResourceIds()); + + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "getDefaultInclusionPolicy", args = {}) + public void testGetDefaultInclusionPolicy() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + // show the default value is true + PersonResourceReportPluginData personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + assertEquals(true, personResourceReportPluginData.getDefaultInclusionPolicy()); + + personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .setDefaultInclusion(true)// + .build(); + assertEquals(true, personResourceReportPluginData.getDefaultInclusionPolicy()); + + personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .setDefaultInclusion(false)// + .build(); + assertEquals(false, personResourceReportPluginData.getDefaultInclusionPolicy()); + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "getEmptyBuilder", args = {}) + public void testGetEmptyBuilder() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + // show the default value is true + PersonResourceReportPluginData filledPersonResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .setReportPeopleWithoutResources(true)// + .setReportZeroPopulations(true)// + .includeResourceId(TestResourceId.RESOURCE_1).excludeResourceId(TestResourceId.RESOURCE_2)// + .setDefaultInclusion(false)// + .build(); + + // show that the empty builder is indeed empty + + // the report label is not set + ContractException contractException = assertThrows(ContractException.class, () -> { + filledPersonResourceReportPluginData.getEmptyBuilder().build(); + }); + assertEquals(ReportError.NULL_REPORT_LABEL, contractException.getErrorType()); + + // the report period is not set + contractException = assertThrows(ContractException.class, () -> { + filledPersonResourceReportPluginData.getEmptyBuilder()// + .setReportLabel(new SimpleReportLabel("report label"))// + .build(); + }); + assertEquals(ReportError.NULL_REPORT_PERIOD, contractException.getErrorType()); + + // After filling the report label and report period we should get the + // same results as if starting from an empty builder + reportLabel = new SimpleReportLabel("another label"); + reportPeriod = ReportPeriod.END_OF_SIMULATION; + + PersonResourceReportPluginData personResourceReportPluginData1 = // + filledPersonResourceReportPluginData.getEmptyBuilder()// + .setReportLabel(reportLabel)// + .setReportPeriod(reportPeriod)// + .build(); + PersonResourceReportPluginData personResourceReportPluginData2 = // + PersonResourceReportPluginData .builder()// + .setReportLabel(reportLabel)// + .setReportPeriod(reportPeriod)// + .build(); + + assertEquals(personResourceReportPluginData1, personResourceReportPluginData2); + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "getCloneBuilder", args = {}) + public void testGetCloneBuilder() { + + RandomGenerator randomGenerator = RandomGeneratorProvider.getRandomGenerator(8951274294108578550L); + for (int i = 0; i < 10; i++) { + + // build a PersonResourceReportPluginData from random inputs + ReportLabel reportLabel = new SimpleReportLabel(randomGenerator.nextInt()); + ReportPeriod reportPeriod = ReportPeriod.values()[randomGenerator.nextInt(ReportPeriod.values().length)]; + + PersonResourceReportPluginData.Builder builder = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel); + + for (int j = 0; j < 10; j++) { + TestResourceId testResourceId = TestResourceId.getRandomResourceId(randomGenerator); + if (randomGenerator.nextBoolean()) { + builder.includeResourceId(testResourceId); + } else { + builder.excludeResourceId(testResourceId); + } + } + + builder.setReportPeopleWithoutResources(randomGenerator.nextBoolean()); + builder.setReportZeroPopulations(randomGenerator.nextBoolean()); + + builder.setDefaultInclusion(randomGenerator.nextBoolean()).build(); + + PersonResourceReportPluginData personResourceReportPluginData = builder.build(); + + // create the clone builder and have it build + PersonResourceReportPluginData clonePersonResourceReportPluginData = personResourceReportPluginData.getCloneBuilder().build(); + + // the result should equal the original if the clone builder was + // initialized with the correct state + assertEquals(personResourceReportPluginData, clonePersonResourceReportPluginData); + + } + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "equals", args = { Object.class }) + public void testEquals() { + + RandomGenerator randomGenerator = RandomGeneratorProvider.getRandomGenerator(7759639255438669162L); + for (int i = 0; i < 10; i++) { + // build a PersonResourceReportPluginData from the same random + // inputs + PersonResourceReportPluginData.Builder builder1 = PersonResourceReportPluginData.builder(); + PersonResourceReportPluginData.Builder builder2 = PersonResourceReportPluginData.builder(); + + ReportLabel reportLabel = new SimpleReportLabel(randomGenerator.nextInt(100)); + builder1.setReportLabel(reportLabel); + builder2.setReportLabel(reportLabel); + + ReportPeriod reportPeriod = ReportPeriod.values()[randomGenerator.nextInt(ReportPeriod.values().length)]; + builder1.setReportPeriod(reportPeriod); + builder2.setReportPeriod(reportPeriod); + + boolean reportPeopleWithoutResources = randomGenerator.nextBoolean(); + builder1.setReportPeopleWithoutResources(reportPeopleWithoutResources);// + builder2.setReportPeopleWithoutResources(reportPeopleWithoutResources);// + + boolean reportZeroPopulations = randomGenerator.nextBoolean(); + builder1.setReportZeroPopulations(reportZeroPopulations);// + builder2.setReportZeroPopulations(reportZeroPopulations); + + for (int j = 0; j < 10; j++) { + TestResourceId testResourceId = TestResourceId.getRandomResourceId(randomGenerator); + if (randomGenerator.nextBoolean()) { + builder1.includeResourceId(testResourceId); + builder2.includeResourceId(testResourceId); + } else { + builder1.excludeResourceId(testResourceId); + builder2.excludeResourceId(testResourceId); + } + } + + boolean defaultInclusion = randomGenerator.nextBoolean(); + builder1.setDefaultInclusion(defaultInclusion).build(); + builder2.setDefaultInclusion(defaultInclusion).build(); + + PersonResourceReportPluginData personResourceReportPluginData1 = builder1.build(); + PersonResourceReportPluginData personResourceReportPluginData2 = builder2.build(); + + assertEquals(personResourceReportPluginData1, personResourceReportPluginData2); + + // show that plugin datas with different inputs are not equal + + // change the default inclusion + personResourceReportPluginData2 = // + personResourceReportPluginData1 .getCloneBuilder()// + .setDefaultInclusion(!defaultInclusion)// + .build(); + assertNotEquals(personResourceReportPluginData2, personResourceReportPluginData1); + + // change the reportPeopleWithoutResources + personResourceReportPluginData2 = // + personResourceReportPluginData1 .getCloneBuilder()// + .setReportPeopleWithoutResources(!reportPeopleWithoutResources)// + .build(); + assertNotEquals(personResourceReportPluginData2, personResourceReportPluginData1); + + // change the reportZeroPopulations + personResourceReportPluginData2 = // + personResourceReportPluginData1 .getCloneBuilder()// + .setReportZeroPopulations(!reportZeroPopulations)// + .build(); + assertNotEquals(personResourceReportPluginData2, personResourceReportPluginData1); + + // change the report period + int ord = reportPeriod.ordinal() + 1; + ord = ord % ReportPeriod.values().length; + reportPeriod = ReportPeriod.values()[ord]; + personResourceReportPluginData2 = // + personResourceReportPluginData1 .getCloneBuilder()// + .setReportPeriod(reportPeriod)// + .build(); + assertNotEquals(personResourceReportPluginData2, personResourceReportPluginData1); + + // change the report label + reportLabel = new SimpleReportLabel(1000); + personResourceReportPluginData2 = // + personResourceReportPluginData1 .getCloneBuilder()// + .setReportLabel(reportLabel)// + .build(); + assertNotEquals(personResourceReportPluginData2, personResourceReportPluginData1); + + // change an included property id + if (!personResourceReportPluginData1.getIncludedResourceIds().isEmpty()) { + ResourceId resourceId = personResourceReportPluginData1.getIncludedResourceIds().iterator().next(); + personResourceReportPluginData2 = // + personResourceReportPluginData1 .getCloneBuilder()// + .excludeResourceId(resourceId)// + .build(); + assertNotEquals(personResourceReportPluginData2, personResourceReportPluginData1); + } + // change an excluded property id + if (!personResourceReportPluginData1.getExcludedResourceIds().isEmpty()) { + ResourceId resourceId = personResourceReportPluginData1.getExcludedResourceIds().iterator().next(); + personResourceReportPluginData2 = // + personResourceReportPluginData1 .getCloneBuilder()// + .includeResourceId(resourceId)// + .build(); + assertNotEquals(personResourceReportPluginData2, personResourceReportPluginData1); + } + + } + + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "hashCode", args = {}) + public void testHashCode() { + RandomGenerator randomGenerator = RandomGeneratorProvider.getRandomGenerator(9079768427072825406L); + + Set observedHashCodes = new LinkedHashSet<>(); + for (int i = 0; i < 50; i++) { + // build a PersonResourceReportPluginData from the same random + // inputs + PersonResourceReportPluginData.Builder builder1 = PersonResourceReportPluginData.builder(); + PersonResourceReportPluginData.Builder builder2 = PersonResourceReportPluginData.builder(); + + ReportLabel reportLabel = new SimpleReportLabel(randomGenerator.nextInt(100)); + builder1.setReportLabel(reportLabel); + builder2.setReportLabel(reportLabel); + + ReportPeriod reportPeriod = ReportPeriod.values()[randomGenerator.nextInt(ReportPeriod.values().length)]; + builder1.setReportPeriod(reportPeriod); + builder2.setReportPeriod(reportPeriod); + + for (int j = 0; j < 10; j++) { + TestResourceId testResourceId = TestResourceId.getRandomResourceId(randomGenerator); + if (randomGenerator.nextBoolean()) { + builder1.includeResourceId(testResourceId); + builder2.includeResourceId(testResourceId); + } else { + builder1.excludeResourceId(testResourceId); + builder2.excludeResourceId(testResourceId); + } + } + + boolean defaultInclusion = randomGenerator.nextBoolean(); + builder1.setDefaultInclusion(defaultInclusion).build(); + builder2.setDefaultInclusion(defaultInclusion).build(); + + boolean reportPeopleWithoutResources = randomGenerator.nextBoolean(); + builder1.setReportPeopleWithoutResources(reportPeopleWithoutResources);// + builder2.setReportPeopleWithoutResources(reportPeopleWithoutResources);// + + boolean reportZeroPopulations = randomGenerator.nextBoolean(); + builder1.setReportZeroPopulations(reportZeroPopulations);// + builder2.setReportZeroPopulations(reportZeroPopulations); + + PersonResourceReportPluginData personResourceReportPluginData1 = builder1.build(); + PersonResourceReportPluginData personResourceReportPluginData2 = builder2.build(); + + // show that the hash code is stable + int hashCode = personResourceReportPluginData1.hashCode(); + assertEquals(hashCode, personResourceReportPluginData1.hashCode()); + assertEquals(hashCode, personResourceReportPluginData1.hashCode()); + assertEquals(hashCode, personResourceReportPluginData1.hashCode()); + assertEquals(hashCode, personResourceReportPluginData1.hashCode()); + + // show that equal objects have equal hash codes + assertEquals(personResourceReportPluginData1.hashCode(), personResourceReportPluginData2.hashCode()); + + // collect the hashcode + observedHashCodes.add(personResourceReportPluginData1.hashCode()); + } + + /* + * The hash codes should be dispersed -- we only show that they are + * unique values -- this is dependent on the random seed + */ + assertEquals(50, observedHashCodes.size()); + + } + +} diff --git a/gcm4/src/test/java/plugins/resources/reports/AT_ResourcePropertyReport.java b/gcm4/src/test/java/plugins/resources/reports/AT_ResourcePropertyReport.java index 1cc79e8e8..b4571b0e1 100644 --- a/gcm4/src/test/java/plugins/resources/reports/AT_ResourcePropertyReport.java +++ b/gcm4/src/test/java/plugins/resources/reports/AT_ResourcePropertyReport.java @@ -192,7 +192,7 @@ public void testInit() { TestOutputConsumer outputConsumer = new TestOutputConsumer(); List pluginsToAdd = ResourcesTestPluginFactory.factory(initialPopulation, 8914112012010329946L, testPluginData).getPlugins(); - pluginsToAdd.add(ReportsTestPluginFactory.getPluginFromReport(new ResourcePropertyReport(REPORT_LABEL)::init)); + pluginsToAdd.add(ReportsTestPluginFactory.getPluginFromReport(new ResourcePropertyReport(ResourcePropertyReportPluginData.builder().setReportLabel(REPORT_LABEL).build())::init)); TestSimulation.executeSimulation(pluginsToAdd, outputConsumer); diff --git a/gcm4/src/test/java/plugins/resources/reports/AT_ResourcePropertyReportPluginData.java b/gcm4/src/test/java/plugins/resources/reports/AT_ResourcePropertyReportPluginData.java new file mode 100644 index 000000000..068dd75bd --- /dev/null +++ b/gcm4/src/test/java/plugins/resources/reports/AT_ResourcePropertyReportPluginData.java @@ -0,0 +1,365 @@ +package plugins.resources.reports; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.apache.commons.math3.random.RandomGenerator; +import org.junit.jupiter.api.Test; + +import plugins.reports.support.ReportError; +import plugins.reports.support.ReportLabel; +import plugins.reports.support.ReportPeriod; +import plugins.reports.support.SimpleReportLabel; +import plugins.resources.support.ResourceId; +import plugins.resources.testsupport.TestResourceId; +import util.annotations.UnitTestMethod; +import util.errors.ContractException; +import util.random.RandomGeneratorProvider; + +public class AT_ResourcePropertyReportPluginData { + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "builder", args = {}) + public void testBuilder() { + PersonResourceReportPluginData.Builder builder = PersonResourceReportPluginData.builder(); + assertNotNull(builder); + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.Builder.class, name = "build", args = {}) + public void testBuild() { + // the specific capabilities are covered elsewhere + + // precondition test: if the report period is not assigned + ContractException contractException = assertThrows(ContractException.class, () -> // + PersonResourceReportPluginData .builder()// + .setReportLabel(new SimpleReportLabel(getClass()))// + .build()); + assertEquals(ReportError.NULL_REPORT_PERIOD, contractException.getErrorType()); + + // precondition test: if the report label is not assigned + contractException = assertThrows(ContractException.class, () -> // + PersonResourceReportPluginData .builder()// + .setReportPeriod(ReportPeriod.DAILY)// + .build()); + assertEquals(ReportError.NULL_REPORT_LABEL, contractException.getErrorType()); + + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.Builder.class, name = "setReportLabel", args = { ReportLabel.class }) + public void testSetReportLabel() { + + for (int i = 0; i < 30; i++) { + ReportLabel expectedReportLabel = new SimpleReportLabel(i); + PersonResourceReportPluginData personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(ReportPeriod.DAILY)// + .setReportLabel(expectedReportLabel)// + .build(); + + assertEquals(expectedReportLabel, personResourceReportPluginData.getReportLabel()); + } + + // precondition: if the report label is null + ContractException contractException = assertThrows(ContractException.class, () -> { + PersonResourceReportPluginData.builder().setReportLabel(null); + }); + assertEquals(ReportError.NULL_REPORT_LABEL, contractException.getErrorType()); + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "getReportLabel", args = {}) + public void testGetReportLabel() { + for (int i = 0; i < 30; i++) { + ReportLabel expectedReportLabel = new SimpleReportLabel(i); + PersonResourceReportPluginData personResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(ReportPeriod.DAILY)// + .setReportLabel(expectedReportLabel)// + .build(); + + assertEquals(expectedReportLabel, personResourceReportPluginData.getReportLabel()); + } + + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "getEmptyBuilder", args = {}) + public void testGetEmptyBuilder() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + // show the default value is true + PersonResourceReportPluginData filledPersonResourceReportPluginData = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .setReportPeopleWithoutResources(true)// + .setReportZeroPopulations(true)// + .includeResourceId(TestResourceId.RESOURCE_1).excludeResourceId(TestResourceId.RESOURCE_2)// + .setDefaultInclusion(false)// + .build(); + + // show that the empty builder is indeed empty + + // the report label is not set + ContractException contractException = assertThrows(ContractException.class, () -> { + filledPersonResourceReportPluginData.getEmptyBuilder().build(); + }); + assertEquals(ReportError.NULL_REPORT_LABEL, contractException.getErrorType()); + + // the report period is not set + contractException = assertThrows(ContractException.class, () -> { + filledPersonResourceReportPluginData.getEmptyBuilder()// + .setReportLabel(new SimpleReportLabel("report label"))// + .build(); + }); + assertEquals(ReportError.NULL_REPORT_PERIOD, contractException.getErrorType()); + + // After filling the report label and report period we should get the + // same results as if starting from an empty builder + reportLabel = new SimpleReportLabel("another label"); + reportPeriod = ReportPeriod.END_OF_SIMULATION; + + PersonResourceReportPluginData personResourceReportPluginData1 = // + filledPersonResourceReportPluginData.getEmptyBuilder()// + .setReportLabel(reportLabel)// + .setReportPeriod(reportPeriod)// + .build(); + PersonResourceReportPluginData personResourceReportPluginData2 = // + PersonResourceReportPluginData .builder()// + .setReportLabel(reportLabel)// + .setReportPeriod(reportPeriod)// + .build(); + + assertEquals(personResourceReportPluginData1, personResourceReportPluginData2); + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "getCloneBuilder", args = {}) + public void testGetCloneBuilder() { + + RandomGenerator randomGenerator = RandomGeneratorProvider.getRandomGenerator(8951274294108578550L); + for (int i = 0; i < 10; i++) { + + // build a PersonResourceReportPluginData from random inputs + ReportLabel reportLabel = new SimpleReportLabel(randomGenerator.nextInt()); + ReportPeriod reportPeriod = ReportPeriod.values()[randomGenerator.nextInt(ReportPeriod.values().length)]; + + PersonResourceReportPluginData.Builder builder = // + PersonResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel); + + for (int j = 0; j < 10; j++) { + TestResourceId testResourceId = TestResourceId.getRandomResourceId(randomGenerator); + if (randomGenerator.nextBoolean()) { + builder.includeResourceId(testResourceId); + } else { + builder.excludeResourceId(testResourceId); + } + } + + builder.setReportPeopleWithoutResources(randomGenerator.nextBoolean()); + builder.setReportZeroPopulations(randomGenerator.nextBoolean()); + + builder.setDefaultInclusion(randomGenerator.nextBoolean()).build(); + + PersonResourceReportPluginData personResourceReportPluginData = builder.build(); + + // create the clone builder and have it build + PersonResourceReportPluginData clonePersonResourceReportPluginData = personResourceReportPluginData.getCloneBuilder().build(); + + // the result should equal the original if the clone builder was + // initialized with the correct state + assertEquals(personResourceReportPluginData, clonePersonResourceReportPluginData); + + } + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "equals", args = { Object.class }) + public void testEquals() { + + RandomGenerator randomGenerator = RandomGeneratorProvider.getRandomGenerator(7759639255438669162L); + for (int i = 0; i < 10; i++) { + // build a PersonResourceReportPluginData from the same random + // inputs + PersonResourceReportPluginData.Builder builder1 = PersonResourceReportPluginData.builder(); + PersonResourceReportPluginData.Builder builder2 = PersonResourceReportPluginData.builder(); + + ReportLabel reportLabel = new SimpleReportLabel(randomGenerator.nextInt(100)); + builder1.setReportLabel(reportLabel); + builder2.setReportLabel(reportLabel); + + ReportPeriod reportPeriod = ReportPeriod.values()[randomGenerator.nextInt(ReportPeriod.values().length)]; + builder1.setReportPeriod(reportPeriod); + builder2.setReportPeriod(reportPeriod); + + boolean reportPeopleWithoutResources = randomGenerator.nextBoolean(); + builder1.setReportPeopleWithoutResources(reportPeopleWithoutResources);// + builder2.setReportPeopleWithoutResources(reportPeopleWithoutResources);// + + boolean reportZeroPopulations = randomGenerator.nextBoolean(); + builder1.setReportZeroPopulations(reportZeroPopulations);// + builder2.setReportZeroPopulations(reportZeroPopulations); + + for (int j = 0; j < 10; j++) { + TestResourceId testResourceId = TestResourceId.getRandomResourceId(randomGenerator); + if (randomGenerator.nextBoolean()) { + builder1.includeResourceId(testResourceId); + builder2.includeResourceId(testResourceId); + } else { + builder1.excludeResourceId(testResourceId); + builder2.excludeResourceId(testResourceId); + } + } + + boolean defaultInclusion = randomGenerator.nextBoolean(); + builder1.setDefaultInclusion(defaultInclusion).build(); + builder2.setDefaultInclusion(defaultInclusion).build(); + + PersonResourceReportPluginData personResourceReportPluginData1 = builder1.build(); + PersonResourceReportPluginData personResourceReportPluginData2 = builder2.build(); + + assertEquals(personResourceReportPluginData1, personResourceReportPluginData2); + + // show that plugin datas with different inputs are not equal + + // change the default inclusion + personResourceReportPluginData2 = // + personResourceReportPluginData1 .getCloneBuilder()// + .setDefaultInclusion(!defaultInclusion)// + .build(); + assertNotEquals(personResourceReportPluginData2, personResourceReportPluginData1); + + // change the reportPeopleWithoutResources + personResourceReportPluginData2 = // + personResourceReportPluginData1 .getCloneBuilder()// + .setReportPeopleWithoutResources(!reportPeopleWithoutResources)// + .build(); + assertNotEquals(personResourceReportPluginData2, personResourceReportPluginData1); + + // change the reportZeroPopulations + personResourceReportPluginData2 = // + personResourceReportPluginData1 .getCloneBuilder()// + .setReportZeroPopulations(!reportZeroPopulations)// + .build(); + assertNotEquals(personResourceReportPluginData2, personResourceReportPluginData1); + + // change the report period + int ord = reportPeriod.ordinal() + 1; + ord = ord % ReportPeriod.values().length; + reportPeriod = ReportPeriod.values()[ord]; + personResourceReportPluginData2 = // + personResourceReportPluginData1 .getCloneBuilder()// + .setReportPeriod(reportPeriod)// + .build(); + assertNotEquals(personResourceReportPluginData2, personResourceReportPluginData1); + + // change the report label + reportLabel = new SimpleReportLabel(1000); + personResourceReportPluginData2 = // + personResourceReportPluginData1 .getCloneBuilder()// + .setReportLabel(reportLabel)// + .build(); + assertNotEquals(personResourceReportPluginData2, personResourceReportPluginData1); + + // change an included property id + if (!personResourceReportPluginData1.getIncludedResourceIds().isEmpty()) { + ResourceId resourceId = personResourceReportPluginData1.getIncludedResourceIds().iterator().next(); + personResourceReportPluginData2 = // + personResourceReportPluginData1 .getCloneBuilder()// + .excludeResourceId(resourceId)// + .build(); + assertNotEquals(personResourceReportPluginData2, personResourceReportPluginData1); + } + // change an excluded property id + if (!personResourceReportPluginData1.getExcludedResourceIds().isEmpty()) { + ResourceId resourceId = personResourceReportPluginData1.getExcludedResourceIds().iterator().next(); + personResourceReportPluginData2 = // + personResourceReportPluginData1 .getCloneBuilder()// + .includeResourceId(resourceId)// + .build(); + assertNotEquals(personResourceReportPluginData2, personResourceReportPluginData1); + } + + } + + } + + @Test + @UnitTestMethod(target = PersonResourceReportPluginData.class, name = "hashCode", args = {}) + public void testHashCode() { + RandomGenerator randomGenerator = RandomGeneratorProvider.getRandomGenerator(9079768427072825406L); + + Set observedHashCodes = new LinkedHashSet<>(); + for (int i = 0; i < 50; i++) { + // build a PersonResourceReportPluginData from the same random + // inputs + PersonResourceReportPluginData.Builder builder1 = PersonResourceReportPluginData.builder(); + PersonResourceReportPluginData.Builder builder2 = PersonResourceReportPluginData.builder(); + + ReportLabel reportLabel = new SimpleReportLabel(randomGenerator.nextInt(100)); + builder1.setReportLabel(reportLabel); + builder2.setReportLabel(reportLabel); + + ReportPeriod reportPeriod = ReportPeriod.values()[randomGenerator.nextInt(ReportPeriod.values().length)]; + builder1.setReportPeriod(reportPeriod); + builder2.setReportPeriod(reportPeriod); + + for (int j = 0; j < 10; j++) { + TestResourceId testResourceId = TestResourceId.getRandomResourceId(randomGenerator); + if (randomGenerator.nextBoolean()) { + builder1.includeResourceId(testResourceId); + builder2.includeResourceId(testResourceId); + } else { + builder1.excludeResourceId(testResourceId); + builder2.excludeResourceId(testResourceId); + } + } + + boolean defaultInclusion = randomGenerator.nextBoolean(); + builder1.setDefaultInclusion(defaultInclusion).build(); + builder2.setDefaultInclusion(defaultInclusion).build(); + + boolean reportPeopleWithoutResources = randomGenerator.nextBoolean(); + builder1.setReportPeopleWithoutResources(reportPeopleWithoutResources);// + builder2.setReportPeopleWithoutResources(reportPeopleWithoutResources);// + + boolean reportZeroPopulations = randomGenerator.nextBoolean(); + builder1.setReportZeroPopulations(reportZeroPopulations);// + builder2.setReportZeroPopulations(reportZeroPopulations); + + PersonResourceReportPluginData personResourceReportPluginData1 = builder1.build(); + PersonResourceReportPluginData personResourceReportPluginData2 = builder2.build(); + + // show that the hash code is stable + int hashCode = personResourceReportPluginData1.hashCode(); + assertEquals(hashCode, personResourceReportPluginData1.hashCode()); + assertEquals(hashCode, personResourceReportPluginData1.hashCode()); + assertEquals(hashCode, personResourceReportPluginData1.hashCode()); + assertEquals(hashCode, personResourceReportPluginData1.hashCode()); + + // show that equal objects have equal hash codes + assertEquals(personResourceReportPluginData1.hashCode(), personResourceReportPluginData2.hashCode()); + + // collect the hashcode + observedHashCodes.add(personResourceReportPluginData1.hashCode()); + } + + /* + * The hash codes should be dispersed -- we only show that they are + * unique values -- this is dependent on the random seed + */ + assertEquals(50, observedHashCodes.size()); + + } + +} diff --git a/gcm4/src/test/java/plugins/resources/reports/AT_ResourceReportPluginData.java b/gcm4/src/test/java/plugins/resources/reports/AT_ResourceReportPluginData.java new file mode 100644 index 000000000..65f97bc75 --- /dev/null +++ b/gcm4/src/test/java/plugins/resources/reports/AT_ResourceReportPluginData.java @@ -0,0 +1,655 @@ +package plugins.resources.reports; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.apache.commons.math3.random.RandomGenerator; +import org.junit.jupiter.api.Test; + +import plugins.reports.support.ReportError; +import plugins.reports.support.ReportLabel; +import plugins.reports.support.ReportPeriod; +import plugins.reports.support.SimpleReportLabel; +import plugins.resources.support.ResourceError; +import plugins.resources.support.ResourceId; +import plugins.resources.testsupport.TestResourceId; +import util.annotations.UnitTestMethod; +import util.errors.ContractException; +import util.random.RandomGeneratorProvider; + +public class AT_ResourceReportPluginData { + + @Test + @UnitTestMethod(target = ResourceReportPluginData.class, name = "builder", args = {}) + public void testBuilder() { + ResourceReportPluginData.Builder builder = ResourceReportPluginData.builder(); + assertNotNull(builder); + } + + @Test + @UnitTestMethod(target = ResourceReportPluginData.Builder.class, name = "build", args = {}) + public void testBuild() { + // the specific capabilities are covered elsewhere + + // precondition test: if the report period is not assigned + ContractException contractException = assertThrows(ContractException.class, () -> // + ResourceReportPluginData .builder()// + .setReportLabel(new SimpleReportLabel(getClass()))// + .build()); + assertEquals(ReportError.NULL_REPORT_PERIOD, contractException.getErrorType()); + + // precondition test: if the report label is not assigned + contractException = assertThrows(ContractException.class, () -> // + ResourceReportPluginData .builder()// + .setReportPeriod(ReportPeriod.DAILY)// + .build()); + assertEquals(ReportError.NULL_REPORT_LABEL, contractException.getErrorType()); + + } + + @Test + @UnitTestMethod(target = ResourceReportPluginData.Builder.class, name = "setReportLabel", args = { ReportLabel.class }) + public void testSetReportLabel() { + + for (int i = 0; i < 30; i++) { + ReportLabel expectedReportLabel = new SimpleReportLabel(i); + ResourceReportPluginData resourceReportPluginData = // + ResourceReportPluginData .builder()// + .setReportPeriod(ReportPeriod.DAILY)// + .setReportLabel(expectedReportLabel)// + .build(); + + assertEquals(expectedReportLabel, resourceReportPluginData.getReportLabel()); + } + + // precondition: if the report label is null + ContractException contractException = assertThrows(ContractException.class, () -> { + ResourceReportPluginData.builder().setReportLabel(null); + }); + assertEquals(ReportError.NULL_REPORT_LABEL, contractException.getErrorType()); + } + + @Test + @UnitTestMethod(target = ResourceReportPluginData.Builder.class, name = "setReportPeriod", args = { ReportPeriod.class }) + public void testSetReportPeriod() { + + ReportLabel reportLabel = new SimpleReportLabel("report label"); + for (ReportPeriod reportPeriod : ReportPeriod.values()) { + + ResourceReportPluginData resourceReportPluginData = // + ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + + assertEquals(reportPeriod, resourceReportPluginData.getReportPeriod()); + } + + // precondition: if the report period is null + ContractException contractException = assertThrows(ContractException.class, () -> { + ResourceReportPluginData.builder().setReportPeriod(null); + }); + assertEquals(ReportError.NULL_REPORT_PERIOD, contractException.getErrorType()); + } + + @Test + @UnitTestMethod(target = ResourceReportPluginData.Builder.class, name = "setDefaultInclusion", args = { boolean.class }) + public void testSetDefaultInclusion() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + // show the default value is true + ResourceReportPluginData resourceReportPluginData = // + ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + assertEquals(true, resourceReportPluginData.getDefaultInclusionPolicy()); + + resourceReportPluginData = // + ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .setDefaultInclusion(true)// + .build(); + assertEquals(true, resourceReportPluginData.getDefaultInclusionPolicy()); + + resourceReportPluginData = // + ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .setDefaultInclusion(false)// + .build(); + assertEquals(false, resourceReportPluginData.getDefaultInclusionPolicy()); + + } + + @Test + @UnitTestMethod(target = ResourceReportPluginData.Builder.class, name = "includeResourceId", args = { ResourceId.class }) + public void testIncludeResourceId() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + ResourceReportPluginData resourceReportPluginData = // + ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + assertTrue(resourceReportPluginData.getIncludedResourceIds().isEmpty()); + + // show that inclusion alone works + Set expectedResourceIds = new LinkedHashSet<>(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + ResourceReportPluginData.Builder builder = ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.includeResourceId(resourceId); + } + + resourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, resourceReportPluginData.getIncludedResourceIds()); + + // show that inclusion will override exclusion + expectedResourceIds.clear(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + builder = ResourceReportPluginData.builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.excludeResourceId(resourceId); + builder.includeResourceId(resourceId); + } + + resourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, resourceReportPluginData.getIncludedResourceIds()); + + // precondition: if the person property id is null + ContractException contractException = assertThrows(ContractException.class, () -> { + ResourceReportPluginData.builder().includeResourceId(null); + }); + assertEquals(ResourceError.NULL_RESOURCE_ID, contractException.getErrorType()); + } + + @Test + @UnitTestMethod(target = ResourceReportPluginData.Builder.class, name = "excludeResourceId", args = { ResourceId.class }) + public void testExcludeResourceId() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + // show the default is non-exclusion + ResourceReportPluginData resourceReportPluginData = // + ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + assertTrue(resourceReportPluginData.getExcludedResourceIds().isEmpty()); + + // show that exclusion alone works + Set expectedResourceIds = new LinkedHashSet<>(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + ResourceReportPluginData.Builder builder = ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.excludeResourceId(resourceId); + } + + resourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, resourceReportPluginData.getExcludedResourceIds()); + + // show that exclusion will override inclusion + expectedResourceIds.clear(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + builder = ResourceReportPluginData.builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.includeResourceId(resourceId); + builder.excludeResourceId(resourceId); + } + + resourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, resourceReportPluginData.getExcludedResourceIds()); + + // precondition: if the person property id is null + ContractException contractException = assertThrows(ContractException.class, () -> { + ResourceReportPluginData.builder().excludeResourceId(null); + }); + assertEquals(ResourceError.NULL_RESOURCE_ID, contractException.getErrorType()); + } + + @Test + @UnitTestMethod(target = ResourceReportPluginData.class, name = "getReportLabel", args = {}) + public void testGetReportLabel() { + for (int i = 0; i < 30; i++) { + ReportLabel expectedReportLabel = new SimpleReportLabel(i); + ResourceReportPluginData resourceReportPluginData = // + ResourceReportPluginData .builder()// + .setReportPeriod(ReportPeriod.DAILY)// + .setReportLabel(expectedReportLabel)// + .build(); + + assertEquals(expectedReportLabel, resourceReportPluginData.getReportLabel()); + } + + } + + @Test + @UnitTestMethod(target = ResourceReportPluginData.class, name = "getReportPeriod", args = {}) + public void testGetReportPeriod() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + for (ReportPeriod reportPeriod : ReportPeriod.values()) { + + ResourceReportPluginData resourceReportPluginData = // + ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + + assertEquals(reportPeriod, resourceReportPluginData.getReportPeriod()); + } + } + + @Test + @UnitTestMethod(target = ResourceReportPluginData.class, name = "getIncludedResourceIds", args = {}) + public void testGetIncludedResourceIds() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + // show the default is non-inclusion + ResourceReportPluginData resourceReportPluginData = // + ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + assertTrue(resourceReportPluginData.getIncludedResourceIds().isEmpty()); + + // show that inclusion alone works + Set expectedResourceIds = new LinkedHashSet<>(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + ResourceReportPluginData.Builder builder = ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.includeResourceId(resourceId); + } + + resourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, resourceReportPluginData.getIncludedResourceIds()); + + // show that inclusion will override exclusion + expectedResourceIds.clear(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + builder = ResourceReportPluginData.builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.excludeResourceId(resourceId); + builder.includeResourceId(resourceId); + } + + resourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, resourceReportPluginData.getIncludedResourceIds()); + + } + + @Test + @UnitTestMethod(target = ResourceReportPluginData.class, name = "getExcludedResourceIds", args = {}) + public void testGetExcludedResourceIds() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + // show the default is non-exclusion + ResourceReportPluginData resourceReportPluginData = // + ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + assertTrue(resourceReportPluginData.getExcludedResourceIds().isEmpty()); + + // show that exclusion alone works + Set expectedResourceIds = new LinkedHashSet<>(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + ResourceReportPluginData.Builder builder = ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.excludeResourceId(resourceId); + } + + resourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, resourceReportPluginData.getExcludedResourceIds()); + + // show that exclusion will override inclusion + expectedResourceIds.clear(); + + expectedResourceIds.add(TestResourceId.RESOURCE_1); + expectedResourceIds.add(TestResourceId.RESOURCE_4); + expectedResourceIds.add(TestResourceId.RESOURCE_2); + + builder = ResourceReportPluginData.builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel);// + + for (ResourceId resourceId : expectedResourceIds) { + builder.includeResourceId(resourceId); + builder.excludeResourceId(resourceId); + } + + resourceReportPluginData = builder.build(); + assertEquals(expectedResourceIds, resourceReportPluginData.getExcludedResourceIds()); + + } + + @Test + @UnitTestMethod(target = ResourceReportPluginData.class, name = "getDefaultInclusionPolicy", args = {}) + public void testGetDefaultInclusionPolicy() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + // show the default value is true + ResourceReportPluginData resourceReportPluginData = // + ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .build(); + assertEquals(true, resourceReportPluginData.getDefaultInclusionPolicy()); + + resourceReportPluginData = // + ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .setDefaultInclusion(true)// + .build(); + assertEquals(true, resourceReportPluginData.getDefaultInclusionPolicy()); + + resourceReportPluginData = // + ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .setDefaultInclusion(false)// + .build(); + assertEquals(false, resourceReportPluginData.getDefaultInclusionPolicy()); + } + + @Test + @UnitTestMethod(target = ResourceReportPluginData.class, name = "getEmptyBuilder", args = {}) + public void testGetEmptyBuilder() { + ReportLabel reportLabel = new SimpleReportLabel("report label"); + ReportPeriod reportPeriod = ReportPeriod.DAILY; + + // show the default value is true + ResourceReportPluginData filledResourceReportPluginData = // + ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel)// + .includeResourceId(TestResourceId.RESOURCE_1).excludeResourceId(TestResourceId.RESOURCE_2)// + .setDefaultInclusion(false)// + .build(); + + // show that the empty builder is indeed empty + + // the report label is not set + ContractException contractException = assertThrows(ContractException.class, () -> { + filledResourceReportPluginData.getEmptyBuilder().build(); + }); + assertEquals(ReportError.NULL_REPORT_LABEL, contractException.getErrorType()); + + // the report period is not set + contractException = assertThrows(ContractException.class, () -> { + filledResourceReportPluginData.getEmptyBuilder()// + .setReportLabel(new SimpleReportLabel("report label"))// + .build(); + }); + assertEquals(ReportError.NULL_REPORT_PERIOD, contractException.getErrorType()); + + // After filling the report label and report period we should get the + // same results as if starting from an empty builder + reportLabel = new SimpleReportLabel("another label"); + reportPeriod = ReportPeriod.END_OF_SIMULATION; + + ResourceReportPluginData resourceReportPluginData1 = // + filledResourceReportPluginData.getEmptyBuilder()// + .setReportLabel(reportLabel)// + .setReportPeriod(reportPeriod)// + .build(); + ResourceReportPluginData resourceReportPluginData2 = // + ResourceReportPluginData .builder()// + .setReportLabel(reportLabel)// + .setReportPeriod(reportPeriod)// + .build(); + + assertEquals(resourceReportPluginData1, resourceReportPluginData2); + } + + @Test + @UnitTestMethod(target = ResourceReportPluginData.class, name = "getCloneBuilder", args = {}) + public void testGetCloneBuilder() { + + RandomGenerator randomGenerator = RandomGeneratorProvider.getRandomGenerator(8951274294108578550L); + for (int i = 0; i < 10; i++) { + + // build a ResourceReportPluginData from random inputs + ReportLabel reportLabel = new SimpleReportLabel(randomGenerator.nextInt()); + ReportPeriod reportPeriod = ReportPeriod.values()[randomGenerator.nextInt(ReportPeriod.values().length)]; + + ResourceReportPluginData.Builder builder = // + ResourceReportPluginData .builder()// + .setReportPeriod(reportPeriod)// + .setReportLabel(reportLabel); + + for (int j = 0; j < 10; j++) { + TestResourceId testResourceId = TestResourceId.getRandomResourceId(randomGenerator); + if (randomGenerator.nextBoolean()) { + builder.includeResourceId(testResourceId); + } else { + builder.excludeResourceId(testResourceId); + } + } + + builder.setDefaultInclusion(randomGenerator.nextBoolean()).build(); + + ResourceReportPluginData resourceReportPluginData = builder.build(); + + // create the clone builder and have it build + ResourceReportPluginData cloneResourceReportPluginData = resourceReportPluginData.getCloneBuilder().build(); + + // the result should equal the original if the clone builder was + // initialized with the correct state + assertEquals(resourceReportPluginData, cloneResourceReportPluginData); + + } + } + + @Test + @UnitTestMethod(target = ResourceReportPluginData.class, name = "equals", args = { Object.class }) + public void testEquals() { + + RandomGenerator randomGenerator = RandomGeneratorProvider.getRandomGenerator(7759639255438669162L); + for (int i = 0; i < 10; i++) { + // build a ResourceReportPluginData from the same random + // inputs + ResourceReportPluginData.Builder builder1 = ResourceReportPluginData.builder(); + ResourceReportPluginData.Builder builder2 = ResourceReportPluginData.builder(); + + ReportLabel reportLabel = new SimpleReportLabel(randomGenerator.nextInt(100)); + builder1.setReportLabel(reportLabel); + builder2.setReportLabel(reportLabel); + + ReportPeriod reportPeriod = ReportPeriod.values()[randomGenerator.nextInt(ReportPeriod.values().length)]; + builder1.setReportPeriod(reportPeriod); + builder2.setReportPeriod(reportPeriod); + + for (int j = 0; j < 10; j++) { + TestResourceId testResourceId = TestResourceId.getRandomResourceId(randomGenerator); + if (randomGenerator.nextBoolean()) { + builder1.includeResourceId(testResourceId); + builder2.includeResourceId(testResourceId); + } else { + builder1.excludeResourceId(testResourceId); + builder2.excludeResourceId(testResourceId); + } + } + + boolean defaultInclusion = randomGenerator.nextBoolean(); + builder1.setDefaultInclusion(defaultInclusion).build(); + builder2.setDefaultInclusion(defaultInclusion).build(); + + ResourceReportPluginData resourceReportPluginData1 = builder1.build(); + ResourceReportPluginData resourceReportPluginData2 = builder2.build(); + + assertEquals(resourceReportPluginData1, resourceReportPluginData2); + + // show that plugin datas with different inputs are not equal + + // change the default inclusion + resourceReportPluginData2 = // + resourceReportPluginData1 .getCloneBuilder()// + .setDefaultInclusion(!defaultInclusion)// + .build(); + assertNotEquals(resourceReportPluginData2, resourceReportPluginData1); + + // change the report period + int ord = reportPeriod.ordinal() + 1; + ord = ord % ReportPeriod.values().length; + reportPeriod = ReportPeriod.values()[ord]; + resourceReportPluginData2 = // + resourceReportPluginData1 .getCloneBuilder()// + .setReportPeriod(reportPeriod)// + .build(); + assertNotEquals(resourceReportPluginData2, resourceReportPluginData1); + + // change the report label + reportLabel = new SimpleReportLabel(1000); + resourceReportPluginData2 = // + resourceReportPluginData1 .getCloneBuilder()// + .setReportLabel(reportLabel)// + .build(); + assertNotEquals(resourceReportPluginData2, resourceReportPluginData1); + + // change an included property id + if (!resourceReportPluginData1.getIncludedResourceIds().isEmpty()) { + ResourceId resourceId = resourceReportPluginData1.getIncludedResourceIds().iterator().next(); + resourceReportPluginData2 = // + resourceReportPluginData1 .getCloneBuilder()// + .excludeResourceId(resourceId)// + .build(); + assertNotEquals(resourceReportPluginData2, resourceReportPluginData1); + } + // change an excluded property id + if (!resourceReportPluginData1.getExcludedResourceIds().isEmpty()) { + ResourceId resourceId = resourceReportPluginData1.getExcludedResourceIds().iterator().next(); + resourceReportPluginData2 = // + resourceReportPluginData1 .getCloneBuilder()// + .includeResourceId(resourceId)// + .build(); + assertNotEquals(resourceReportPluginData2, resourceReportPluginData1); + } + + } + + } + + @Test + @UnitTestMethod(target = ResourceReportPluginData.class, name = "hashCode", args = {}) + public void testHashCode() { + RandomGenerator randomGenerator = RandomGeneratorProvider.getRandomGenerator(9079768427072825406L); + + Set observedHashCodes = new LinkedHashSet<>(); + for (int i = 0; i < 50; i++) { + // build a ResourceReportPluginData from the same random + // inputs + ResourceReportPluginData.Builder builder1 = ResourceReportPluginData.builder(); + ResourceReportPluginData.Builder builder2 = ResourceReportPluginData.builder(); + + ReportLabel reportLabel = new SimpleReportLabel(randomGenerator.nextInt(100)); + builder1.setReportLabel(reportLabel); + builder2.setReportLabel(reportLabel); + + ReportPeriod reportPeriod = ReportPeriod.values()[randomGenerator.nextInt(ReportPeriod.values().length)]; + builder1.setReportPeriod(reportPeriod); + builder2.setReportPeriod(reportPeriod); + + for (int j = 0; j < 10; j++) { + TestResourceId testResourceId = TestResourceId.getRandomResourceId(randomGenerator); + if (randomGenerator.nextBoolean()) { + builder1.includeResourceId(testResourceId); + builder2.includeResourceId(testResourceId); + } else { + builder1.excludeResourceId(testResourceId); + builder2.excludeResourceId(testResourceId); + } + } + + boolean defaultInclusion = randomGenerator.nextBoolean(); + builder1.setDefaultInclusion(defaultInclusion).build(); + builder2.setDefaultInclusion(defaultInclusion).build(); + + ResourceReportPluginData resourceReportPluginData1 = builder1.build(); + ResourceReportPluginData resourceReportPluginData2 = builder2.build(); + + // show that the hash code is stable + int hashCode = resourceReportPluginData1.hashCode(); + assertEquals(hashCode, resourceReportPluginData1.hashCode()); + assertEquals(hashCode, resourceReportPluginData1.hashCode()); + assertEquals(hashCode, resourceReportPluginData1.hashCode()); + assertEquals(hashCode, resourceReportPluginData1.hashCode()); + + // show that equal objects have equal hash codes + assertEquals(resourceReportPluginData1.hashCode(), resourceReportPluginData2.hashCode()); + + // collect the hashcode + observedHashCodes.add(resourceReportPluginData1.hashCode()); + } + + /* + * The hash codes should be dispersed -- we only show that they are + * unique values -- this is dependent on the random seed + */ + assertEquals(50, observedHashCodes.size()); + + } + +} diff --git a/tutorials/plugins/gcm4_lesson_18_resources_plugin/src/main/java/lesson/Example_18.java b/tutorials/plugins/gcm4_lesson_18_resources_plugin/src/main/java/lesson/Example_18.java index fdd29eb8b..dfb391ba8 100644 --- a/tutorials/plugins/gcm4_lesson_18_resources_plugin/src/main/java/lesson/Example_18.java +++ b/tutorials/plugins/gcm4_lesson_18_resources_plugin/src/main/java/lesson/Example_18.java @@ -35,6 +35,7 @@ import plugins.resources.ResourcesPlugin; import plugins.resources.ResourcesPluginData; import plugins.resources.reports.PersonResourceReport; +import plugins.resources.reports.PersonResourceReportPluginData; import plugins.resources.support.ResourceId; import plugins.stochastics.StochasticsPlugin; import plugins.stochastics.StochasticsPluginData; @@ -50,12 +51,17 @@ private Example_18() { private RandomGenerator randomGenerator = RandomGeneratorProvider.getRandomGenerator(9032703880551658180L); private Plugin getReportsPlugin() { + + + + ReportsPluginData reportsPluginData = // ReportsPluginData .builder()// - .addReport(() -> new PersonResourceReport(ModelReportLabel.PERSON_RESOURCE_REPORT, // - ReportPeriod.END_OF_SIMULATION, // - true, // - true)// + .addReport(() -> new PersonResourceReport( PersonResourceReportPluginData// + .builder()// + .setReportLabel(ModelReportLabel.PERSON_RESOURCE_REPORT)// + .setReportPeriod(ReportPeriod.END_OF_SIMULATION)// + .build())// ::init)// .addReport(() -> new TreatmentReport(ModelReportLabel.TREATMENT_REPORT)::init)//