Merge pull request #572 from jMonkeyEngine/define_list_fix

Fix DefineList regression
native-compilation-test
empirephoenix 8 years ago committed by GitHub
commit 63b0600b81
  1. 176
      jme3-core/src/main/java/com/jme3/shader/DefineList.java
  2. 122
      jme3-core/src/test/java/com/jme3/material/MaterialMatParamTest.java
  3. 255
      jme3-core/src/test/java/com/jme3/shader/DefineListTest.java

@ -36,144 +36,160 @@ import java.util.List;
/** /**
* The new define list. * The new define list.
* *
* @author Kirill Vainer * @author Kirill Vainer
*/ */
public final class DefineList { public final class DefineList {
public static final int MAX_DEFINES = 64; public static final int MAX_DEFINES = 64;
private long hash; private long isSet;
private final int[] vals; private final int[] values;
public DefineList(int numValues) { public DefineList(int numValues) {
if (numValues < 0 || numValues > MAX_DEFINES) { if (numValues < 0 || numValues > MAX_DEFINES) {
throw new IllegalArgumentException("numValues must be between 0 and 64"); throw new IllegalArgumentException("numValues must be between 0 and 64");
} }
vals = new int[numValues]; values = new int[numValues];
} }
private DefineList(DefineList original) { private DefineList(DefineList original) {
this.hash = original.hash; this.isSet = original.isSet;
this.vals = new int[original.vals.length]; this.values = new int[original.values.length];
System.arraycopy(original.vals, 0, vals, 0, vals.length); System.arraycopy(original.values, 0, values, 0, values.length);
}
private void rangeCheck(int id) {
assert 0 <= id && id < values.length;
}
public boolean isSet(int id) {
rangeCheck(id);
return (isSet & (1L << id)) != 0;
}
public void unset(int id) {
rangeCheck(id);
isSet &= ~(1L << id);
values[id] = 0;
} }
public void set(int id, int val) { public void set(int id, int val) {
assert 0 <= id && id < 64; rangeCheck(id);
if (val != 0) { isSet |= (1L << id);
hash |= (1L << id); values[id] = val;
} else {
hash &= ~(1L << id);
}
vals[id] = val;
} }
public void set(int id, float val) { public void set(int id, float val) {
set(id, Float.floatToIntBits(val)); set(id, Float.floatToIntBits(val));
} }
public void set(int id, boolean val) { public void set(int id, boolean val) {
set(id, val ? 1 : 0); if (val) {
set(id, 1);
} else {
// Because #ifdef usage is very common in shaders, unset the define
// instead of setting it to 0 for booleans.
unset(id);
}
} }
public void set(int id, VarType type, Object value) { public void set(int id, VarType type, Object value) {
if (value == null) { if (value != null) {
set(id, 0); switch (type) {
return; case Int:
} set(id, (Integer) value);
break;
switch (type) { case Float:
case Int: set(id, (Float) value);
set(id, (Integer) value); break;
break; case Boolean:
case Float: set(id, ((Boolean) value));
set(id, (Float) value); break;
break; default:
case Boolean: set(id, 1);
set(id, ((Boolean) value)); break;
break; }
default: } else {
set(id, 1); unset(id);
break;
} }
} }
public void setAll(DefineList other) { public void setAll(DefineList other) {
for (int i = 0; i < other.vals.length; i++) { for (int i = 0; i < other.values.length; i++) {
if (other.vals[i] != 0) { if (other.isSet(i)) {
vals[i] = other.vals[i]; set(i, other.getInt(i));
} }
} }
} }
public void clear() { public void clear() {
hash = 0; isSet = 0;
Arrays.fill(vals, 0); Arrays.fill(values, 0);
} }
public boolean getBoolean(int id) { public boolean getBoolean(int id) {
return vals[id] != 0; return values[id] != 0;
} }
public float getFloat(int id) { public float getFloat(int id) {
return Float.intBitsToFloat(vals[id]); return Float.intBitsToFloat(values[id]);
} }
public int getInt(int id) { public int getInt(int id) {
return vals[id]; return values[id];
} }
@Override @Override
public int hashCode() { public int hashCode() {
return (int)((hash >> 32) ^ hash); return (int) ((isSet >> 32) ^ isSet);
} }
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
DefineList o = (DefineList) other; DefineList o = (DefineList) other;
if (hash == o.hash) { if (isSet == o.isSet) {
for (int i = 0; i < vals.length; i++) { for (int i = 0; i < values.length; i++) {
if (vals[i] != o.vals[i]) return false; if (values[i] != o.values[i]) {
} return false;
return true; }
} }
return false; return true;
}
return false;
} }
public DefineList deepClone() { public DefineList deepClone() {
return new DefineList(this); return new DefineList(this);
} }
public void generateSource(StringBuilder sb, List<String> defineNames, List<VarType> defineTypes) { public void generateSource(StringBuilder sb, List<String> defineNames, List<VarType> defineTypes) {
for (int i = 0; i < vals.length; i++) { for (int i = 0; i < values.length; i++) {
if (vals[i] != 0) { if (!isSet(i)) {
String defineName = defineNames.get(i); continue;
}
sb.append("#define ");
sb.append(defineName); sb.append("#define ").append(defineNames.get(i)).append(' ');
sb.append(" ");
if (defineTypes != null && defineTypes.get(i) == VarType.Float) {
if (defineTypes != null && defineTypes.get(i) == VarType.Float) { float val = Float.intBitsToFloat(values[i]);
float val = Float.intBitsToFloat(vals[i]); if (Float.isInfinite(val) || Float.isNaN(val)) {
if (Float.isInfinite(val) || Float.isNaN(val)) { throw new IllegalArgumentException(
throw new IllegalArgumentException( "GLSL does not support NaN "
"GLSL does not support NaN " + "or Infinite float literals");
+ "or Infinite float literals");
}
sb.append(val);
} else {
sb.append(vals[i]);
} }
sb.append(val);
sb.append("\n"); } else {
sb.append(values[i]);
} }
sb.append('\n');
} }
} }
public String generateSource(List<String> defineNames, List<VarType> defineTypes) { public String generateSource(List<String> defineNames, List<VarType> defineTypes) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
generateSource(sb, defineNames, defineTypes); generateSource(sb, defineNames, defineTypes);
return sb.toString(); return sb.toString();
} }
} }

@ -54,16 +54,15 @@ import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture; import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D; import com.jme3.texture.Texture2D;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import static org.junit.Assert.assertEquals;
import java.util.Map;
import org.junit.Before; import org.junit.Before;
/** /**
* Validates how {@link MatParamOverride MPOs} work on the material level. * Validates {@link MatParam}s.
* *
* @author Kirill Vainer * @author Kirill Vainer
*/ */
public class MaterialMatParamOverrideTest { public class MaterialMatParamTest {
private static final HashSet<String> IGNORED_UNIFORMS = new HashSet<String>( private static final HashSet<String> IGNORED_UNIFORMS = new HashSet<String>(
Arrays.asList(new String[]{"m_ParallaxHeight", "m_Shininess", "m_BackfaceShadows"})); Arrays.asList(new String[]{"m_ParallaxHeight", "m_Shininess", "m_BackfaceShadows"}));
@ -84,6 +83,14 @@ public class MaterialMatParamOverrideTest {
outUniforms(uniform("UseMaterialColors", VarType.Boolean, true)); outUniforms(uniform("UseMaterialColors", VarType.Boolean, true));
} }
@Test
public void testBoolMpFalse() {
material("Common/MatDefs/Light/Lighting.j3md");
inputMp(mpoBool("UseMaterialColors", false));
outDefines(def("MATERIAL_COLORS", VarType.Boolean, false));
outUniforms(uniform("UseMaterialColors", VarType.Boolean, false));
}
@Test @Test
public void testBoolOverrideFalse() { public void testBoolOverrideFalse() {
material("Common/MatDefs/Light/Lighting.j3md"); material("Common/MatDefs/Light/Lighting.j3md");
@ -118,6 +125,14 @@ public class MaterialMatParamOverrideTest {
outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 3.12f)); outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 3.12f));
} }
@Test
public void testFloatMpZero() {
material("Common/MatDefs/Light/Lighting.j3md");
inputMp(mpoFloat("AlphaDiscardThreshold", 0.0f));
outDefines(def("DISCARD_ALPHA", VarType.Float, 0.0f));
outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 0.0f));
}
@Test @Test
public void testFloatOverride() { public void testFloatOverride() {
material("Common/MatDefs/Light/Lighting.j3md"); material("Common/MatDefs/Light/Lighting.j3md");
@ -190,6 +205,14 @@ public class MaterialMatParamOverrideTest {
outDefines(def("NUM_BONES", VarType.Int, 1234)); outDefines(def("NUM_BONES", VarType.Int, 1234));
outUniforms(uniform("NumberOfBones", VarType.Int, 1234)); outUniforms(uniform("NumberOfBones", VarType.Int, 1234));
} }
@Test
public void testIntMpZero() {
material("Common/MatDefs/Light/Lighting.j3md");
inputMp(mpoInt("NumberOfBones", 0));
outDefines(def("NUM_BONES", VarType.Int, 0));
outUniforms(uniform("NumberOfBones", VarType.Int, 0));
}
@Test @Test
public void testIntOverride() { public void testIntOverride() {
@ -377,25 +400,31 @@ public class MaterialMatParamOverrideTest {
outTextures(tex1); outTextures(tex1);
} }
private static final class Define { private static class Define {
public String name; public String name;
public VarType type; public VarType type;
public Object value; public Object value;
@Override @Override
public int hashCode() { public String toString() {
int hash = 3; switch (type) {
hash = 89 * hash + this.name.hashCode(); case Boolean:
hash = 89 * hash + this.type.hashCode(); if ((Boolean)value) {
hash = 89 * hash + this.value.hashCode(); return "#define " + name + " 1\n";
return hash; } else {
} return "";
}
@Override case Int:
public boolean equals(Object obj) { case Float:
final Define other = (Define) obj; return "#define " + name + " " + value + "\n";
return this.name.equals(other.name) && this.type.equals(other.type) && this.value.equals(other.value); default:
if (value != null) {
return "#define " + name + " 1\n";
} else {
return "";
}
}
} }
} }
@ -411,13 +440,13 @@ public class MaterialMatParamOverrideTest {
private final NullRenderer renderer = new NullRenderer() { private final NullRenderer renderer = new NullRenderer() {
@Override @Override
public void setShader(Shader shader) { public void setShader(Shader shader) {
MaterialMatParamOverrideTest.this.usedShader = shader; MaterialMatParamTest.this.usedShader = shader;
evaluated = true; evaluated = true;
} }
@Override @Override
public void setTexture(int unit, Texture texture) { public void setTexture(int unit, Texture texture) {
MaterialMatParamOverrideTest.this.usedTextures[unit] = texture; MaterialMatParamTest.this.usedTextures[unit] = texture;
} }
}; };
private final RenderManager renderManager = new RenderManager(renderer); private final RenderManager renderManager = new RenderManager(renderer);
@ -512,11 +541,11 @@ public class MaterialMatParamOverrideTest {
} }
private void outDefines(Define... expectedDefinesArray) { private void outDefines(Define... expectedDefinesArray) {
Map<String, Define> nameToDefineMap = new HashMap<String, Define>(); StringBuilder expectedDefineSource = new StringBuilder();
for (Define define : expectedDefinesArray) { for (Define define : expectedDefinesArray) {
nameToDefineMap.put(define.name, define); expectedDefineSource.append(define.toString());
} }
if (!evaluated) { if (!evaluated) {
evaluateTechniqueDef(); evaluateTechniqueDef();
} }
@ -525,56 +554,11 @@ public class MaterialMatParamOverrideTest {
Technique tech = mat.getActiveTechnique(); Technique tech = mat.getActiveTechnique();
TechniqueDef def = tech.getDef(); TechniqueDef def = tech.getDef();
DefineList actualDefines = tech.getDynamicDefines(); DefineList actualDefines = tech.getDynamicDefines();
String[] defineNames = def.getDefineNames(); String[] defineNames = def.getDefineNames();
VarType[] defineTypes = def.getDefineTypes(); VarType[] defineTypes = def.getDefineTypes();
String actualDefineSource = actualDefines.generateSource(Arrays.asList(defineNames), Arrays.asList(defineTypes));
Assert.assertEquals(defineNames.length, defineTypes.length); assertEquals(expectedDefineSource.toString(), actualDefineSource);
for (int index = 0; index < defineNames.length; index++) {
String name = defineNames[index];
VarType type = defineTypes[index];
Define expectedDefine = nameToDefineMap.remove(name);
Object expectedValue = null;
if (expectedDefine != null) {
Assert.assertEquals(expectedDefine.type, type);
expectedValue = expectedDefine.value;
}
switch (type) {
case Boolean:
if (expectedValue != null) {
Assert.assertEquals((boolean) (Boolean) expectedValue, actualDefines.getBoolean(index));
} else {
Assert.assertEquals(false, actualDefines.getBoolean(index));
}
break;
case Int:
if (expectedValue != null) {
Assert.assertEquals((int) (Integer) expectedValue, actualDefines.getInt(index));
} else {
Assert.assertEquals(0, actualDefines.getInt(index));
}
break;
case Float:
if (expectedValue != null) {
Assert.assertEquals((float) (Float) expectedValue, actualDefines.getFloat(index), 0f);
} else {
Assert.assertEquals(0f, actualDefines.getFloat(index), 0f);
}
break;
default:
if (expectedValue != null) {
Assert.assertEquals(1, actualDefines.getInt(index));
} else {
Assert.assertEquals(0, actualDefines.getInt(index));
}
break;
}
}
Assert.assertTrue(nameToDefineMap.isEmpty());
} }
private void outUniforms(Uniform... uniforms) { private void outUniforms(Uniform... uniforms) {

@ -40,7 +40,7 @@ import org.junit.Test;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class DefineListTest { public class DefineListTest {
private static final List<String> DEFINE_NAMES = Arrays.asList("BOOL_VAR", "INT_VAR", "FLOAT_VAR"); private static final List<String> DEFINE_NAMES = Arrays.asList("BOOL_VAR", "INT_VAR", "FLOAT_VAR");
private static final List<VarType> DEFINE_TYPES = Arrays.asList(VarType.Boolean, VarType.Int, VarType.Float); private static final List<VarType> DEFINE_TYPES = Arrays.asList(VarType.Boolean, VarType.Int, VarType.Float);
private static final int NUM_DEFINES = DEFINE_NAMES.size(); private static final int NUM_DEFINES = DEFINE_NAMES.size();
@ -53,49 +53,49 @@ public class DefineListTest {
public void testHashCollision() { public void testHashCollision() {
DefineList dl1 = new DefineList(64); DefineList dl1 = new DefineList(64);
DefineList dl2 = new DefineList(64); DefineList dl2 = new DefineList(64);
// Try to cause a hash collision // Try to cause a hash collision
// (since bit #32 is aliased to bit #1 in 32-bit ints) // (since bit #32 is aliased to bit #1 in 32-bit ints)
dl1.set(0, 123); dl1.set(0, 123);
dl1.set(32, 0); dl1.set(32, 0);
dl2.set(32, 0); dl2.set(32, 0);
dl2.set(0, 123); dl2.set(0, 123);
assert dl1.hashCode() == dl2.hashCode(); assert dl1.hashCode() == dl2.hashCode();
assert dl1.equals(dl2); assert dl1.equals(dl2);
} }
@Test @Test
public void testGetSet() { public void testGetSet() {
DefineList dl = new DefineList(NUM_DEFINES); DefineList dl = new DefineList(NUM_DEFINES);
assertFalse(dl.getBoolean(BOOL_VAR)); assertFalse(dl.getBoolean(BOOL_VAR));
assertEquals(dl.getInt(INT_VAR), 0); assertEquals(dl.getInt(INT_VAR), 0);
assertEquals(dl.getFloat(FLOAT_VAR), 0f, 0f); assertEquals(dl.getFloat(FLOAT_VAR), 0f, 0f);
dl.set(BOOL_VAR, true); dl.set(BOOL_VAR, true);
dl.set(INT_VAR, -1); dl.set(INT_VAR, -1);
dl.set(FLOAT_VAR, Float.NaN); dl.set(FLOAT_VAR, Float.NaN);
assertTrue(dl.getBoolean(BOOL_VAR)); assertTrue(dl.getBoolean(BOOL_VAR));
assertEquals(dl.getInt(INT_VAR), -1); assertEquals(dl.getInt(INT_VAR), -1);
assertTrue(Float.isNaN(dl.getFloat(FLOAT_VAR))); assertTrue(Float.isNaN(dl.getFloat(FLOAT_VAR)));
} }
private String generateSource(DefineList dl) { private String generateSource(DefineList dl) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
dl.generateSource(sb, DEFINE_NAMES, DEFINE_TYPES); dl.generateSource(sb, DEFINE_NAMES, DEFINE_TYPES);
return sb.toString(); return sb.toString();
} }
@Test @Test
public void testSourceInitial() { public void testSourceInitial() {
DefineList dl = new DefineList(NUM_DEFINES); DefineList dl = new DefineList(NUM_DEFINES);
assert dl.hashCode() == 0; assert dl.hashCode() == 0;
assert generateSource(dl).equals(""); assert generateSource(dl).equals("");
} }
@Test @Test
public void testSourceBooleanDefine() { public void testSourceBooleanDefine() {
DefineList dl = new DefineList(NUM_DEFINES); DefineList dl = new DefineList(NUM_DEFINES);
@ -103,35 +103,47 @@ public class DefineListTest {
dl.set(BOOL_VAR, true); dl.set(BOOL_VAR, true);
assert dl.hashCode() == 1; assert dl.hashCode() == 1;
assert generateSource(dl).equals("#define BOOL_VAR 1\n"); assert generateSource(dl).equals("#define BOOL_VAR 1\n");
dl.set(BOOL_VAR, false); dl.set(BOOL_VAR, false);
assert dl.hashCode() == 0; assert dl.hashCode() == 0;
assert generateSource(dl).equals(""); assert generateSource(dl).equals("");
dl.set(BOOL_VAR, true);
assert dl.hashCode() == 1;
assert generateSource(dl).equals("#define BOOL_VAR 1\n");
dl.unset(BOOL_VAR);
assert dl.hashCode() == 0;
assert generateSource(dl).equals("");
} }
@Test @Test
public void testSourceIntDefine() { public void testSourceIntDefine() {
DefineList dl = new DefineList(NUM_DEFINES); DefineList dl = new DefineList(NUM_DEFINES);
int hashCodeWithInt = 1 << INT_VAR; int hashCodeWithInt = 1 << INT_VAR;
dl.set(INT_VAR, 123); dl.set(INT_VAR, 123);
assert dl.hashCode() == hashCodeWithInt; assert dl.hashCode() == hashCodeWithInt;
assert generateSource(dl).equals("#define INT_VAR 123\n"); assert generateSource(dl).equals("#define INT_VAR 123\n");
dl.set(INT_VAR, 0); dl.set(INT_VAR, 0);
assert dl.hashCode() == 0; assert dl.hashCode() == hashCodeWithInt;
assert generateSource(dl).equals(""); assert generateSource(dl).equals("#define INT_VAR 0\n");
dl.set(INT_VAR, -99); dl.set(INT_VAR, -99);
assert dl.hashCode() == hashCodeWithInt; assert dl.hashCode() == hashCodeWithInt;
assert generateSource(dl).equals("#define INT_VAR -99\n"); assert generateSource(dl).equals("#define INT_VAR -99\n");
dl.set(INT_VAR, Integer.MAX_VALUE); dl.set(INT_VAR, Integer.MAX_VALUE);
assert dl.hashCode() == hashCodeWithInt; assert dl.hashCode() == hashCodeWithInt;
assert generateSource(dl).equals("#define INT_VAR 2147483647\n"); assert generateSource(dl).equals("#define INT_VAR 2147483647\n");
dl.unset(INT_VAR);
assert dl.hashCode() == 0;
assert generateSource(dl).equals("");
} }
@Test @Test
public void testSourceFloatDefine() { public void testSourceFloatDefine() {
DefineList dl = new DefineList(NUM_DEFINES); DefineList dl = new DefineList(NUM_DEFINES);
@ -139,162 +151,193 @@ public class DefineListTest {
dl.set(FLOAT_VAR, 1f); dl.set(FLOAT_VAR, 1f);
assert dl.hashCode() == (1 << FLOAT_VAR); assert dl.hashCode() == (1 << FLOAT_VAR);
assert generateSource(dl).equals("#define FLOAT_VAR 1.0\n"); assert generateSource(dl).equals("#define FLOAT_VAR 1.0\n");
dl.set(FLOAT_VAR, 0f); dl.set(FLOAT_VAR, 0f);
assert dl.hashCode() == 0; assert dl.hashCode() == (1 << FLOAT_VAR);
assert generateSource(dl).equals(""); assert generateSource(dl).equals("#define FLOAT_VAR 0.0\n");
dl.set(FLOAT_VAR, -1f); dl.set(FLOAT_VAR, -1f);
assert generateSource(dl).equals("#define FLOAT_VAR -1.0\n"); assert generateSource(dl).equals("#define FLOAT_VAR -1.0\n");
dl.set(FLOAT_VAR, FastMath.FLT_EPSILON); dl.set(FLOAT_VAR, FastMath.FLT_EPSILON);
assert generateSource(dl).equals("#define FLOAT_VAR 1.1920929E-7\n"); assert generateSource(dl).equals("#define FLOAT_VAR 1.1920929E-7\n");
dl.set(FLOAT_VAR, FastMath.PI); dl.set(FLOAT_VAR, FastMath.PI);
assert generateSource(dl).equals("#define FLOAT_VAR 3.1415927\n"); assert generateSource(dl).equals("#define FLOAT_VAR 3.1415927\n");
try { try {
dl.set(FLOAT_VAR, Float.NaN); dl.set(FLOAT_VAR, Float.NaN);
generateSource(dl); generateSource(dl);
assert false; assert false;
} catch (IllegalArgumentException ex) { } } catch (IllegalArgumentException ex) {
}
try { try {
dl.set(FLOAT_VAR, Float.POSITIVE_INFINITY); dl.set(FLOAT_VAR, Float.POSITIVE_INFINITY);
generateSource(dl); generateSource(dl);
assert false; assert false;
} catch (IllegalArgumentException ex) { } } catch (IllegalArgumentException ex) {
}
try { try {
dl.set(FLOAT_VAR, Float.NEGATIVE_INFINITY); dl.set(FLOAT_VAR, Float.NEGATIVE_INFINITY);
generateSource(dl); generateSource(dl);
assert false; assert false;
} catch (IllegalArgumentException ex) { } } catch (IllegalArgumentException ex) {
}
} }
@Test @Test
public void testEqualsAndHashCode() { public void testEqualsAndHashCode() {
DefineList dl1 = new DefineList(NUM_DEFINES); DefineList dl1 = new DefineList(NUM_DEFINES);
DefineList dl2 = new DefineList(NUM_DEFINES); DefineList dl2 = new DefineList(NUM_DEFINES);
assertTrue(dl1.hashCode() == 0); assertEquals(0, dl1.hashCode());
assertEquals(0, dl2.hashCode());
assertEquals(dl1, dl2); assertEquals(dl1, dl2);
dl1.set(BOOL_VAR, true); dl1.set(BOOL_VAR, true);
assertTrue(dl1.hashCode() == 1); assertEquals(1, dl1.hashCode());
assertNotSame(dl1, dl2); assertEquals(0, dl2.hashCode());
assertNotEquals(dl1, dl2);
dl2.set(BOOL_VAR, true); dl2.set(BOOL_VAR, true);
assertEquals(1, dl1.hashCode());
assertEquals(1, dl2.hashCode());
assertEquals(dl1, dl2); assertEquals(dl1, dl2);
dl1.set(INT_VAR, 2); dl1.set(INT_VAR, 2);
assertTrue(dl1.hashCode() == (1|2)); assertEquals(1 | 2, dl1.hashCode());
assertNotSame(dl1, dl2); assertEquals(1, dl2.hashCode());
assertNotEquals(dl1, dl2);
dl2.set(INT_VAR, 2); dl2.set(INT_VAR, 2);
assertEquals(1 | 2, dl1.hashCode());
assertEquals(1 | 2, dl2.hashCode());
assertEquals(dl1, dl2); assertEquals(dl1, dl2);
dl1.set(BOOL_VAR, false); dl1.set(BOOL_VAR, false);
assertTrue(dl1.hashCode() == 2); assertEquals(2, dl1.hashCode());
assertNotSame(dl1, dl2); assertEquals(1 | 2, dl2.hashCode());
assertNotEquals(dl1, dl2);
dl2.unset(BOOL_VAR);
assertEquals(2, dl1.hashCode());
assertEquals(2, dl2.hashCode());
assertEquals(dl1, dl2); // unset is the same as false
dl1.unset(BOOL_VAR);
assertEquals(2, dl1.hashCode());
assertEquals(2, dl2.hashCode());
assertEquals(dl1, dl2);
} }
@Test @Test
public void testDeepClone() { public void testDeepClone() {
DefineList dl1 = new DefineList(NUM_DEFINES); DefineList dl1 = new DefineList(NUM_DEFINES);
DefineList dl2 = dl1.deepClone(); DefineList dl2 = dl1.deepClone();
assertFalse(dl1 == dl2); assertNotSame(dl1, dl2);
assertTrue(dl1.equals(dl2)); assertEquals(dl1, dl2);
assertTrue(dl1.hashCode() == dl2.hashCode()); assertEquals(dl1.hashCode(), dl2.hashCode());
dl1.set(BOOL_VAR, true); dl1.set(BOOL_VAR, true);
dl2 = dl1.deepClone(); dl2 = dl1.deepClone();
assertTrue(dl1.equals(dl2)); assertEquals(dl1, dl2);
assertTrue(dl1.hashCode() == dl2.hashCode()); assertEquals(dl1.hashCode(), dl2.hashCode());
dl1.set(BOOL_VAR, false);
dl2 = dl1.deepClone();
assertEquals(dl1, dl2);
assertEquals(dl1.hashCode(), dl2.hashCode());
dl1.set(INT_VAR, 123); dl1.set(INT_VAR, 123);
assertFalse(dl1.equals(dl2)); assertNotEquals(dl1, dl2);
assertFalse(dl1.hashCode() == dl2.hashCode()); assertNotEquals(dl1.hashCode(), dl2.hashCode());
dl2 = dl1.deepClone(); dl2 = dl1.deepClone();
assertTrue(dl1.equals(dl2)); assertEquals(dl1, dl2);
assertTrue(dl1.hashCode() == dl2.hashCode()); assertEquals(dl1.hashCode(), dl2.hashCode());
} }
@Test @Test
public void testGenerateSource() { public void testGenerateSource() {
DefineList dl = new DefineList(NUM_DEFINES); DefineList dl = new DefineList(NUM_DEFINES);
assertEquals("", generateSource(dl)); assertEquals("", generateSource(dl));
dl.set(BOOL_VAR, true); dl.set(BOOL_VAR, true);
assertEquals("#define BOOL_VAR 1\n", generateSource(dl)); assertEquals("#define BOOL_VAR 1\n", generateSource(dl));
dl.set(INT_VAR, 123); dl.set(INT_VAR, 123);
assertEquals("#define BOOL_VAR 1\n" + assertEquals("#define BOOL_VAR 1\n"
"#define INT_VAR 123\n", generateSource(dl)); + "#define INT_VAR 123\n", generateSource(dl));
dl.set(BOOL_VAR, false); dl.set(BOOL_VAR, false);
assertEquals("#define INT_VAR 123\n", generateSource(dl)); assertEquals("#define INT_VAR 123\n", generateSource(dl));
dl.set(BOOL_VAR, true); dl.set(BOOL_VAR, true);
// should have predictable ordering based on defineId // should have predictable ordering based on defineId
assertEquals("#define BOOL_VAR 1\n" + assertEquals("#define BOOL_VAR 1\n"
"#define INT_VAR 123\n", generateSource(dl)); + "#define INT_VAR 123\n", generateSource(dl));
dl.unset(BOOL_VAR);
assertEquals("#define INT_VAR 123\n", generateSource(dl));
} }
private static String doLookup(HashMap<DefineList, String> map, boolean boolVal, int intVal, float floatVal) { private static String doLookup(HashMap<DefineList, String> map, Boolean boolVal, Integer intVal, Float floatVal) {
DefineList dl = new DefineList(NUM_DEFINES); DefineList dl = new DefineList(NUM_DEFINES);
dl.set(BOOL_VAR, boolVal); dl.set(BOOL_VAR, VarType.Boolean, boolVal);
dl.set(INT_VAR, intVal); dl.set(INT_VAR, VarType.Int, intVal);
dl.set(FLOAT_VAR, floatVal); dl.set(FLOAT_VAR, VarType.Float, floatVal);
return map.get(dl); return map.get(dl);
} }
@Test @Test
public void testHashLookup() { public void testHashLookup() {
String STR_EMPTY = "This is an empty define list"; String STR_EMPTY = "This is an empty define list";
String STR_INT = "This define list has an int value"; String STR_INT = "This define list has an int value";
String STR_BOOL = "This define list just has boolean value set"; String STR_BOOL = "This define list just has boolean value set";
String STR_BOOL_INT = "This define list has both a boolean and int value"; String STR_BOOL_INT = "This define list has both a boolean and int value";
String STR_BOOL_INT_FLOAT = "This define list has a boolean, int, and float value"; String STR_BOOL_INT_FLOAT = "This define list has a boolean, int, and float value";
HashMap<DefineList, String> map = new HashMap<DefineList, String>(); HashMap<DefineList, String> map = new HashMap<>();
DefineList lookup = new DefineList(NUM_DEFINES); DefineList lookup = new DefineList(NUM_DEFINES);
map.put(lookup.deepClone(), STR_EMPTY); map.put(lookup.deepClone(), STR_EMPTY);
lookup.set(BOOL_VAR, true); lookup.set(BOOL_VAR, true);
map.put(lookup.deepClone(), STR_BOOL); map.put(lookup.deepClone(), STR_BOOL);
lookup.set(BOOL_VAR, false); lookup.set(BOOL_VAR, false);
lookup.set(INT_VAR, 123); lookup.set(INT_VAR, 123);
map.put(lookup.deepClone(), STR_INT); map.put(lookup.deepClone(), STR_INT);
lookup.set(BOOL_VAR, true); lookup.set(BOOL_VAR, true);
map.put(lookup.deepClone(), STR_BOOL_INT); map.put(lookup.deepClone(), STR_BOOL_INT);
lookup.set(FLOAT_VAR, FastMath.PI); lookup.set(FLOAT_VAR, FastMath.PI);
map.put(lookup.deepClone(), STR_BOOL_INT_FLOAT); map.put(lookup.deepClone(), STR_BOOL_INT_FLOAT);
assertEquals(doLookup(map, false, 0, 0f), STR_EMPTY); assertEquals(STR_EMPTY, doLookup(map, null, null, null));
assertEquals(doLookup(map, false, 123, 0f), STR_INT); assertEquals(STR_INT, doLookup(map, false, 123, null));
assertEquals(doLookup(map, true, 0, 0f), STR_BOOL); assertEquals(STR_BOOL, doLookup(map, true, null, null));
assertEquals(doLookup(map, true, 123, 0f), STR_BOOL_INT); assertEquals(STR_BOOL_INT, doLookup(map, true, 123, null));
assertEquals(doLookup(map, true, 123, FastMath.PI), STR_BOOL_INT_FLOAT); assertEquals(STR_BOOL_INT_FLOAT, doLookup(map, true, 123, FastMath.PI));
} }
} }

Loading…
Cancel
Save