test_class.declarator: ABYSSAL_DAGGER = new ItemStats(false, true, 0.453, 8,
  		ItemEquipmentStats.builder()
  			.slot(EquipmentInventorySlot.WEAPON.getSlotIdx())
  			.isTwoHanded(false)
  			.astab(75)
  			.aslash(40)
  			.acrush(-4)
  			.amagic(1)
  			.dmagic(1)
  			.str(75)
  			.aspeed(4)
  			.build())
test_class.modifier: private static final
test_class.original_string: private static final ItemStats ABYSSAL_DAGGER = new ItemStats(false, true, 0.453, 8,
  		ItemEquipmentStats.builder()
  			.slot(EquipmentInventorySlot.WEAPON.getSlotIdx())
  			.isTwoHanded(false)
  			.astab(75)
  			.aslash(40)
  			.acrush(-4)
  			.amagic(1)
  			.dmagic(1)
  			.str(75)
  			.aspeed(4)
  			.build());
test_class.type: ItemStats
test_class.var_name: ABYSSAL_DAGGER
test_class.declarator: KATANA = new ItemStats(false, true, 0, 8,
  		ItemEquipmentStats.builder()
  			.slot(EquipmentInventorySlot.WEAPON.getSlotIdx())
  			.isTwoHanded(true)
  			.astab(7)
  			.aslash(45)
  			.dstab(3)
  			.dslash(7)
  			.dcrush(7)
  			.drange(-3)
  			.str(40)
  			.aspeed(4)
  			.build())
test_class.modifier: private static final
test_class.original_string: private static final ItemStats KATANA = new ItemStats(false, true, 0, 8,
  		ItemEquipmentStats.builder()
  			.slot(EquipmentInventorySlot.WEAPON.getSlotIdx())
  			.isTwoHanded(true)
  			.astab(7)
  			.aslash(45)
  			.dstab(3)
  			.dslash(7)
  			.dcrush(7)
  			.drange(-3)
  			.str(40)
  			.aspeed(4)
  			.build());
test_class.type: ItemStats
test_class.var_name: KATANA
test_class.declarator: BLOWPIPE = new ItemStats(false, true, 0, 0,
  		ItemEquipmentStats.builder()
  			.slot(EquipmentInventorySlot.WEAPON.getSlotIdx())
  			.isTwoHanded(true)
  			.arange(60)
  			.rstr(40)
  			.aspeed(3)
  			.build())
test_class.modifier: private static final
test_class.original_string: private static final ItemStats BLOWPIPE = new ItemStats(false, true, 0, 0,
  		ItemEquipmentStats.builder()
  			.slot(EquipmentInventorySlot.WEAPON.getSlotIdx())
  			.isTwoHanded(true)
  			.arange(60)
  			.rstr(40)
  			.aspeed(3)
  			.build());
test_class.type: ItemStats
test_class.var_name: BLOWPIPE
test_class.declarator: HEAVY_BALLISTA = new ItemStats(false, true, 4, 8,
  		ItemEquipmentStats.builder()
  			.slot(EquipmentInventorySlot.WEAPON.getSlotIdx())
  			.isTwoHanded(true)
  			.arange(110)
  			.aspeed(7)
  			.build())
test_class.modifier: private static final
test_class.original_string: private static final ItemStats HEAVY_BALLISTA = new ItemStats(false, true, 4, 8,
  		ItemEquipmentStats.builder()
  			.slot(EquipmentInventorySlot.WEAPON.getSlotIdx())
  			.isTwoHanded(true)
  			.arange(110)
  			.aspeed(7)
  			.build());
test_class.type: ItemStats
test_class.var_name: HEAVY_BALLISTA
test_class.declarator: overlay
test_class.modifier: @Inject
test_class.original_string: @Inject
  	ItemStatOverlay overlay;
test_class.type: ItemStatOverlay
test_class.var_name: overlay
test_class.declarator: client
test_class.modifier: @Mock
  	@Bind
test_class.original_string: @Mock
  	@Bind
  	Client client;
test_class.type: Client
test_class.var_name: client
test_class.declarator: config
test_class.modifier: @Mock
  	@Bind
test_class.original_string: @Mock
  	@Bind
  	ItemStatConfig config;
test_class.type: ItemStatConfig
test_class.var_name: config
test_class.declarator: itemManager
test_class.modifier: @Mock
  	@Bind
test_class.original_string: @Mock
  	@Bind
  	ItemManager itemManager;
test_class.type: ItemManager
test_class.var_name: itemManager
test_class.file: runelite-client/src/test/java/net/runelite/client/plugins/itemstats/ItemStatOverlayTest.java
test_class.identifier: ItemStatOverlayTest
test_case.body: @Test
  	public void testBuildStatBonusString()
  	{
  		// Empty equipment (fully unarmed)
  		final ItemContainer equipment = mock(ItemContainer.class);
  		when(client.getItemContainer(InventoryID.EQUIPMENT)).thenReturn(equipment);
  
  		String tooltip;
  		String sanitizedTooltip;
  
  		tooltip = overlay.buildStatBonusString(ABYSSAL_DAGGER);
  		sanitizedTooltip = Text.sanitizeMultilineText(tooltip);
  		assertTrue(sanitizedTooltip.contains("Stab: +75"));
  		assertTrue(sanitizedTooltip.contains("Slash: +40"));
  		assertTrue(sanitizedTooltip.contains("Crush: -4"));
  		assertEquals(2, StringUtils.countMatches(sanitizedTooltip, "Magic: +1")); // Attack and defense
  		assertTrue(sanitizedTooltip.contains("Melee Str: +75"));
  		assertFalse(sanitizedTooltip.contains("Speed:"));
  
  		tooltip = overlay.buildStatBonusString(KATANA);
  		sanitizedTooltip = Text.sanitizeMultilineText(tooltip);
  		assertTrue(sanitizedTooltip.contains("Stab: +7"));
  		assertTrue(sanitizedTooltip.contains("Slash: +45"));
  		assertTrue(sanitizedTooltip.contains("Stab: +3")); // Defense
  		assertTrue(sanitizedTooltip.contains("Slash: +7")); // Defense
  		assertTrue(sanitizedTooltip.contains("Crush: +7")); // Defense
  		assertTrue(sanitizedTooltip.contains("Range: -3")); // Defense
  		assertTrue(sanitizedTooltip.contains("Melee Str: +40"));
  		assertFalse(sanitizedTooltip.contains("Speed:"));
  
  		tooltip = overlay.buildStatBonusString(BLOWPIPE);
  		sanitizedTooltip = Text.sanitizeMultilineText(tooltip);
  		assertTrue(sanitizedTooltip.contains("Range: +60"));
  		assertTrue(sanitizedTooltip.contains("Range Str: +40"));
  		assertTrue(sanitizedTooltip.contains("Speed: -1"));
  		assertFalse(sanitizedTooltip.contains("Stab:"));
  
  		tooltip = overlay.buildStatBonusString(HEAVY_BALLISTA);
  		sanitizedTooltip = Text.sanitizeMultilineText(tooltip);
  		assertTrue(sanitizedTooltip.contains("Range: +110"));
  		assertTrue(sanitizedTooltip.contains("Speed: +3"));
  		assertFalse(sanitizedTooltip.contains("Stab:"));
  	}
test_case.class_method_signature: ItemStatOverlayTest.testBuildStatBonusString()
test_case.full_signature: @Test public void testBuildStatBonusString()
test_case.identifier: testBuildStatBonusString
test_case.invocations: mock thenReturn when getItemContainer buildStatBonusString sanitizeMultilineText assertTrue contains assertTrue contains assertTrue contains assertEquals countMatches assertTrue contains assertFalse contains buildStatBonusString sanitizeMultilineText assertTrue contains assertTrue contains assertTrue contains assertTrue contains assertTrue contains assertTrue contains assertTrue contains assertFalse contains buildStatBonusString sanitizeMultilineText assertTrue contains assertTrue contains assertTrue contains assertFalse contains buildStatBonusString sanitizeMultilineText assertTrue contains assertTrue contains assertFalse contains
test_case.modifiers: @Test public
test_case.parameters: ()
test_case.return: void
test_case.signature: void testBuildStatBonusString()
focal_class.declarator: UNARMED = new ItemStats(false, true, 0, 0,
  		ItemEquipmentStats.builder()
  			.aspeed(4)
  			.build())
focal_class.modifier: @VisibleForTesting
  	static final
focal_class.original_string: @VisibleForTesting
  	static final ItemStats UNARMED = new ItemStats(false, true, 0, 0,
  		ItemEquipmentStats.builder()
  			.aspeed(4)
  			.build());
focal_class.type: ItemStats
focal_class.var_name: UNARMED
focal_class.declarator: client
focal_class.modifier: @Inject
  	private
focal_class.original_string: @Inject
  	private Client client;
focal_class.type: Client
focal_class.var_name: client
focal_class.declarator: itemManager
focal_class.modifier: @Inject
  	private
focal_class.original_string: @Inject
  	private ItemManager itemManager;
focal_class.type: ItemManager
focal_class.var_name: itemManager
focal_class.declarator: tooltipManager
focal_class.modifier: @Inject
  	private
focal_class.original_string: @Inject
  	private TooltipManager tooltipManager;
focal_class.type: TooltipManager
focal_class.var_name: tooltipManager
focal_class.declarator: statChanges
focal_class.modifier: @Inject
  	private
focal_class.original_string: @Inject
  	private ItemStatChanges statChanges;
focal_class.type: ItemStatChanges
focal_class.var_name: statChanges
focal_class.declarator: config
focal_class.modifier: @Inject
  	private
focal_class.original_string: @Inject
  	private ItemStatConfig config;
focal_class.type: ItemStatConfig
focal_class.var_name: config
focal_class.file: runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java
focal_class.identifier: ItemStatOverlay
focal_class.class_method_signature: ItemStatOverlay.render(Graphics2D graphics)
focal_class.full_signature: @Override public Dimension render(Graphics2D graphics)
focal_class.identifier: render
focal_class.modifiers: @Override public
focal_class.parameters: (Graphics2D graphics)
focal_class.return: Dimension
focal_class.signature: Dimension render(Graphics2D graphics)
focal_class.class_method_signature: ItemStatOverlay.getChangeString(
  		final double value,
  		final boolean inverse,
  		final boolean showPercent)
focal_class.full_signature: private String getChangeString(
  		final double value,
  		final boolean inverse,
  		final boolean showPercent)
focal_class.identifier: getChangeString
focal_class.modifiers: private
focal_class.parameters: (
  		final double value,
  		final boolean inverse,
  		final boolean showPercent)
focal_class.return: String
focal_class.signature: String getChangeString(
  		final double value,
  		final boolean inverse,
  		final boolean showPercent)
focal_class.class_method_signature: ItemStatOverlay.buildStatRow(
  		final String label,
  		final double value,
  		final double diffValue,
  		final boolean inverse,
  		final boolean showPercent)
focal_class.full_signature: private String buildStatRow(
  		final String label,
  		final double value,
  		final double diffValue,
  		final boolean inverse,
  		final boolean showPercent)
focal_class.identifier: buildStatRow
focal_class.modifiers: private
focal_class.parameters: (
  		final String label,
  		final double value,
  		final double diffValue,
  		final boolean inverse,
  		final boolean showPercent)
focal_class.return: String
focal_class.signature: String buildStatRow(
  		final String label,
  		final double value,
  		final double diffValue,
  		final boolean inverse,
  		final boolean showPercent)
focal_class.class_method_signature: ItemStatOverlay.buildStatRow(
  		final String label,
  		final double value,
  		final double diffValue,
  		final boolean inverse,
  		final boolean showPercent,
  		final boolean showBase)
focal_class.full_signature: private String buildStatRow(
  		final String label,
  		final double value,
  		final double diffValue,
  		final boolean inverse,
  		final boolean showPercent,
  		final boolean showBase)
focal_class.identifier: buildStatRow
focal_class.modifiers: private
focal_class.parameters: (
  		final String label,
  		final double value,
  		final double diffValue,
  		final boolean inverse,
  		final boolean showPercent,
  		final boolean showBase)
focal_class.return: String
focal_class.signature: String buildStatRow(
  		final String label,
  		final double value,
  		final double diffValue,
  		final boolean inverse,
  		final boolean showPercent,
  		final boolean showBase)
focal_class.class_method_signature: ItemStatOverlay.getItemStatsFromContainer(ItemContainer container, int slotID)
focal_class.full_signature: private ItemStats getItemStatsFromContainer(ItemContainer container, int slotID)
focal_class.identifier: getItemStatsFromContainer
focal_class.modifiers: private
focal_class.parameters: (ItemContainer container, int slotID)
focal_class.return: ItemStats
focal_class.signature: ItemStats getItemStatsFromContainer(ItemContainer container, int slotID)
focal_class.class_method_signature: ItemStatOverlay.buildStatBonusString(ItemStats s)
focal_class.full_signature: @VisibleForTesting String buildStatBonusString(ItemStats s)
focal_class.identifier: buildStatBonusString
focal_class.modifiers: @VisibleForTesting
focal_class.parameters: (ItemStats s)
focal_class.return: String
focal_class.signature: String buildStatBonusString(ItemStats s)
focal_class.class_method_signature: ItemStatOverlay.buildStatChangeString(StatChange c)
focal_class.full_signature: private String buildStatChangeString(StatChange c)
focal_class.identifier: buildStatChangeString
focal_class.modifiers: private
focal_class.parameters: (StatChange c)
focal_class.return: String
focal_class.signature: String buildStatChangeString(StatChange c)
focal_class.superclass: extends Overlay
focal_method.body: @VisibleForTesting
  	String buildStatBonusString(ItemStats s)
  	{
  		ItemStats other = null;
  		// Used if switching into a 2 handed weapon to store off-hand stats
  		ItemStats offHand = null;
  		final ItemEquipmentStats currentEquipment = s.getEquipment();
  
  		ItemContainer c = client.getItemContainer(InventoryID.EQUIPMENT);
  		if (s.isEquipable() && currentEquipment != null && c != null)
  		{
  			final int slot = currentEquipment.getSlot();
  
  			other = getItemStatsFromContainer(c, slot);
  			// Check if this is a shield and there's a two-handed weapon equipped
  			if (other == null && slot == EquipmentInventorySlot.SHIELD.getSlotIdx())
  			{
  				other = getItemStatsFromContainer(c, EquipmentInventorySlot.WEAPON.getSlotIdx());
  				if (other != null)
  				{
  					final ItemEquipmentStats otherEquip = other.getEquipment();
  					if (otherEquip != null)
  					{
  						// Account for speed change when two handed weapon gets removed
  						// shield - (2h - unarmed) == shield - 2h + unarmed
  						other = otherEquip.isTwoHanded() ? other.subtract(UNARMED) : null;
  					}
  				}
  			}
  
  			if (slot == EquipmentInventorySlot.WEAPON.getSlotIdx())
  			{
  				if (other == null)
  				{
  					other = UNARMED;
  				}
  
  				// Get offhand's stats to be removed from equipping a 2h weapon
  				if (currentEquipment.isTwoHanded())
  				{
  					offHand = getItemStatsFromContainer(c, EquipmentInventorySlot.SHIELD.getSlotIdx());
  				}
  			}
  		}
  
  		final ItemStats subtracted = s.subtract(other).subtract(offHand);
  		final ItemEquipmentStats e = subtracted.getEquipment();
  
  		final StringBuilder b = new StringBuilder();
  
  		if (config.showWeight())
  		{
  			double sw = config.alwaysShowBaseStats() ? subtracted.getWeight() : s.getWeight();
  			b.append(buildStatRow("Weight", s.getWeight(), sw, true, false, s.isEquipable()));
  		}
  
  		if (subtracted.isEquipable() && e != null)
  		{
  			b.append(buildStatRow("Prayer", currentEquipment.getPrayer(), e.getPrayer(), false, false));
  			b.append(buildStatRow("Speed", currentEquipment.getAspeed(), e.getAspeed(), true, false));
  			b.append(buildStatRow("Melee Str", currentEquipment.getStr(), e.getStr(), false, false));
  			b.append(buildStatRow("Range Str", currentEquipment.getRstr(), e.getRstr(), false, false));
  			b.append(buildStatRow("Magic Dmg", currentEquipment.getMdmg(), e.getMdmg(), false, true));
  
  			final StringBuilder abb = new StringBuilder();
  			abb.append(buildStatRow("Stab", currentEquipment.getAstab(), e.getAstab(), false, false));
  			abb.append(buildStatRow("Slash", currentEquipment.getAslash(), e.getAslash(), false, false));
  			abb.append(buildStatRow("Crush", currentEquipment.getAcrush(), e.getAcrush(), false, false));
  			abb.append(buildStatRow("Magic", currentEquipment.getAmagic(), e.getAmagic(), false, false));
  			abb.append(buildStatRow("Range", currentEquipment.getArange(), e.getArange(), false, false));
  
  			if (abb.length() > 0)
  			{
  				b.append(ColorUtil.wrapWithColorTag("Attack Bonus</br>", JagexColors.MENU_TARGET)).append(abb);
  			}
  
  			final StringBuilder dbb = new StringBuilder();
  			dbb.append(buildStatRow("Stab", currentEquipment.getDstab(), e.getDstab(), false, false));
  			dbb.append(buildStatRow("Slash", currentEquipment.getDslash(), e.getDslash(), false, false));
  			dbb.append(buildStatRow("Crush", currentEquipment.getDcrush(), e.getDcrush(), false, false));
  			dbb.append(buildStatRow("Magic", currentEquipment.getDmagic(), e.getDmagic(), false, false));
  			dbb.append(buildStatRow("Range", currentEquipment.getDrange(), e.getDrange(), false, false));
  
  			if (dbb.length() > 0)
  			{
  				b.append(ColorUtil.wrapWithColorTag("Defence Bonus</br>", JagexColors.MENU_TARGET)).append(dbb);
  			}
  		}
  
  		return b.toString();
  	}
focal_method.class_method_signature: ItemStatOverlay.buildStatBonusString(ItemStats s)
focal_method.full_signature: @VisibleForTesting String buildStatBonusString(ItemStats s)
focal_method.identifier: buildStatBonusString
focal_method.invocations: getEquipment getItemContainer isEquipable getSlot getItemStatsFromContainer getSlotIdx getItemStatsFromContainer getSlotIdx getEquipment isTwoHanded subtract getSlotIdx isTwoHanded getItemStatsFromContainer getSlotIdx subtract subtract getEquipment showWeight alwaysShowBaseStats getWeight getWeight append buildStatRow getWeight isEquipable isEquipable append buildStatRow getPrayer getPrayer append buildStatRow getAspeed getAspeed append buildStatRow getStr getStr append buildStatRow getRstr getRstr append buildStatRow getMdmg getMdmg append buildStatRow getAstab getAstab append buildStatRow getAslash getAslash append buildStatRow getAcrush getAcrush append buildStatRow getAmagic getAmagic append buildStatRow getArange getArange length append append wrapWithColorTag append buildStatRow getDstab getDstab append buildStatRow getDslash getDslash append buildStatRow getDcrush getDcrush append buildStatRow getDmagic getDmagic append buildStatRow getDrange getDrange length append append wrapWithColorTag toString
focal_method.modifiers: @VisibleForTesting
focal_method.parameters: (ItemStats s)
focal_method.return: String
focal_method.signature: String buildStatBonusString(ItemStats s)