/* Copyright (c) 2012 LinkedIn Corp. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package com.linkedin.pegasus.generator.test; import com.linkedin.data.ByteString; import com.linkedin.data.Data; import com.linkedin.data.DataComplex; import com.linkedin.data.DataList; import com.linkedin.data.DataMap; import com.linkedin.data.TestUtil; import com.linkedin.data.schema.PathSpec; import com.linkedin.data.schema.RecordDataSchema; import com.linkedin.data.template.DataTemplate; import com.linkedin.data.template.DataTemplateUtil; import com.linkedin.data.template.IntegerArray; import com.linkedin.data.template.RecordTemplate; import com.linkedin.data.template.StringMap; import com.linkedin.data.template.TestDataTemplateUtil; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import org.testng.annotations.Test; import com.linkedin.data.template.GetMode; import com.linkedin.data.template.RequiredFieldNotPresentException; import com.linkedin.data.template.SetMode; import static org.testng.Assert.*; public class TestRecord { private void testField(RecordTemplate record, String fieldName, final Object value) { Class<?> valueClass = value.getClass(); TestDataTemplateUtil.FieldInfo fieldInfo = TestDataTemplateUtil.fieldInfo(record, fieldName); String getterPrefix = fieldInfo.getFieldClass() == Boolean.class ? "is" : "get"; String getMethodName = TestDataTemplateUtil.methodName(getterPrefix, fieldName); String setMethodName = TestDataTemplateUtil.methodName("set", fieldName); String hasMethodName = TestDataTemplateUtil.methodName("has", fieldName); String removeMethodName = TestDataTemplateUtil.methodName("remove", fieldName); Class<? extends RecordTemplate> recordClass = record.getClass(); DataMap dataMap = record.data(); boolean isOptional = fieldInfo.getField().getOptional(); try { Method getMethod = recordClass.getMethod(getMethodName); Method getModeMethod = recordClass.getMethod(getMethodName, GetMode.class); Method setMethod = recordClass.getMethod(setMethodName, valueClass); Method setModeMethod = recordClass.getMethod(setMethodName, valueClass, SetMode.class); Method hasMethod = recordClass.getMethod(hasMethodName); Method removeMethod = recordClass.getMethod(removeMethodName); Object prevValue; // fields TestDataTemplateUtil.assertPresentInFields(recordClass, fieldName); // has if (dataMap.containsKey(fieldName)) { assertTrue((Boolean) hasMethod.invoke(record)); prevValue = getMethod.invoke(record); } else { assertFalse((Boolean) hasMethod.invoke(record)); prevValue = null; } // set Object result = setMethod.invoke(record, value); assertSame(result, record); // has with field present assertTrue((Boolean) hasMethod.invoke(record)); // get with field present result = getMethod.invoke(record); if (value instanceof DataTemplate || value instanceof Enum) { assertSame(result, value); } else { assertEquals(result, value); } // GetMode.NULL, GetMode.DEFAULT, GetMode.STRICT with field present assertSame(getModeMethod.invoke(record, GetMode.NULL), result); assertSame(getModeMethod.invoke(record, GetMode.DEFAULT), result); assertSame(getModeMethod.invoke(record, GetMode.STRICT), result); // remove removeMethod.invoke(record); // has with field absent assertFalse((Boolean) hasMethod.invoke(record)); assertNull(getModeMethod.invoke(record, GetMode.NULL)); // GetMode.NULL with field absent result = getModeMethod.invoke(record, GetMode.NULL); assertNull(result); // GetMode.DEFAULT with field absent Object defaultValue = getModeMethod.invoke(record, GetMode.DEFAULT); Object defaultValueFromSchema = fieldInfo.getField().getDefault(); assertEquals(defaultValue == null, defaultValueFromSchema == null); if (defaultValue != null) { if (defaultValue instanceof DataTemplate) { assertEquals(((DataTemplate) defaultValue).data(), defaultValueFromSchema); } else if (defaultValue instanceof Enum) { assertEquals(defaultValue.toString(), defaultValueFromSchema); } else { assertSame(defaultValue, defaultValueFromSchema); } } // GetMode.STRICT with field absent boolean expectRequiredFieldNotFoundException = (! isOptional && defaultValue == null); try { result = getModeMethod.invoke(record, GetMode.STRICT); assertFalse(expectRequiredFieldNotFoundException); assertSame(result, defaultValue); } catch (InvocationTargetException exc) { assertTrue(expectRequiredFieldNotFoundException); assertTrue(exc.getTargetException() instanceof RequiredFieldNotPresentException); } // SetMode.IGNORE_NULL setModeMethod.invoke(record, value, SetMode.IGNORE_NULL); assertSame(getMethod.invoke(record), value); setModeMethod.invoke(record, null, SetMode.IGNORE_NULL); assertSame(getMethod.invoke(record), value); // SetMode.REMOVE_IF_NULL removeMethod.invoke(record); setModeMethod.invoke(record, value, SetMode.REMOVE_IF_NULL); assertSame(getMethod.invoke(record), value); setModeMethod.invoke(record, null, SetMode.REMOVE_IF_NULL); assertFalse((Boolean) hasMethod.invoke(record)); // SetMode.REMOVE_OPTIONAL_IF_NULL removeMethod.invoke(record); setModeMethod.invoke(record, value, SetMode.REMOVE_OPTIONAL_IF_NULL); assertSame(getMethod.invoke(record), value); try { setModeMethod.invoke(record, null, SetMode.REMOVE_OPTIONAL_IF_NULL); assertTrue(isOptional); assertFalse((Boolean) hasMethod.invoke(record)); } catch (InvocationTargetException exc) { assertFalse(isOptional); assertTrue(exc.getTargetException() instanceof IllegalArgumentException); } // SetMode.DISALLOW_NULL try { setModeMethod.invoke(record, null, SetMode.DISALLOW_NULL); } catch (InvocationTargetException exc) { assertTrue(exc.getTargetException() instanceof NullPointerException); } // restore original value if (prevValue != null) { result = setMethod.invoke(record, prevValue); assertSame(result, record); assertTrue((Boolean) hasMethod.invoke(record)); assertEquals(getMethod.invoke(record), prevValue); } } catch (IllegalAccessException exc) { fail("Unexpected exception", exc); } catch (InvocationTargetException exc) { fail("Unexpected exception", exc); } catch (NoSuchMethodException exc) { fail("Unexpected exception", exc); } } private <T extends RecordTemplate> void testRecord(Class<T> recordClass) { try { T record = recordClass.newInstance(); RecordDataSchema schema = (RecordDataSchema) DataTemplateUtil.getSchema(recordClass); RecordDataSchema schema2 = record.schema(); assertSame(schema, schema2); } catch (IllegalAccessException exc) { fail("Unexpected exception", exc); } catch (InstantiationException exc) { fail("Unexpected exception", exc); } } @Test public void testRecordTest() throws IOException { Object[][] inputs = { { "intField", 8 }, { "intOptionalField", 9 }, { "intDefaultField", 10 }, { "intDefaultOptionalField", 11 }, { "longField", 12L }, { "floatField", 13.0f }, { "doubleField", 14.0 }, { "booleanField", true }, { "stringField", "abc" }, { "bytesField", ByteString.copyAvroString("abcdef", true) }, { "enumField", EnumFruits.BANANA }, { "fixedField", new FixedMD5("0123456789abcdef") }, { "recordField", new RecordBar().setLocation("far") }, { "arrayField", new IntegerArray(new DataList(Arrays.asList(1, 2, 3, 4, 5))) }, { "mapField", new StringMap(new DataMap(TestUtil.asMap("k1", "v1", "k2", "v2", "k3", "v3"))) }, { "unionField", new RecordTest.UnionField(TestUtil.dataMapFromString("{ \"int\" : 3 }")) } }; RecordTest record = new RecordTest(); testRecord(record.getClass()); for (Object[] row : inputs) { String fieldName = (String) row[0]; Object value = row[1]; testField(record, fieldName, value); } } @Test public void testIntField() { RecordTest record = new RecordTest(); assertFalse(record.hasIntField()); assertEquals(record.getIntField(GetMode.NULL), null); assertEquals(record.getIntField(GetMode.DEFAULT), null); Exception exc; try { exc = null; record.getIntField(GetMode.STRICT); } catch (Exception e) { exc = e; } assertTrue(exc != null); assertTrue(exc instanceof RequiredFieldNotPresentException); try { exc = null; record.getIntField(); } catch (Exception e) { exc = e; } assertTrue(exc != null); assertTrue(exc instanceof RequiredFieldNotPresentException); Integer intValue = 13; record.setIntField(intValue); assertTrue(record.hasIntField()); assertEquals(record.getIntField(GetMode.NULL), intValue); assertEquals(record.getIntField(GetMode.DEFAULT), intValue); assertEquals(record.getIntField(GetMode.STRICT), intValue); assertEquals(record.getIntField(), intValue); } @Test public void testIntFieldAccessorMethodsExist() throws NoSuchMethodException, SecurityException { // test to make sure there is getter without mode assertSame(RecordTest.class.getMethod("getIntField").getReturnType(), Integer.class); // test to make sure there is getter with mode assertSame(RecordTest.class.getMethod("getIntField", GetMode.class).getReturnType(), Integer.class); // test to make sure that is a boxified setter with mode RecordTest.class.getMethod("setIntField", Integer.class, SetMode.class); // test to make sure there is unboxified setter without mode RecordTest.class.getMethod("setIntField", int.class); // test to make sure there is boxified setter without mode RecordTest.class.getMethod("setIntField", Integer.class); // test to make sure that is a boxified setter with mode RecordTest.class.getMethod("setIntField", Integer.class, SetMode.class); } @Test public void testIntOptionalField() { RecordTest record = new RecordTest(); assertFalse(record.hasIntOptionalField()); assertEquals(record.getIntOptionalField(GetMode.NULL), null); assertEquals(record.getIntOptionalField(GetMode.DEFAULT), null); assertEquals(record.getIntOptionalField(GetMode.STRICT), null); assertEquals(record.getIntOptionalField(), null); Integer intValue = 13; record.setIntOptionalField(intValue); assertTrue(record.hasIntOptionalField()); assertEquals(record.getIntOptionalField(GetMode.NULL), intValue); assertEquals(record.getIntOptionalField(GetMode.DEFAULT), intValue); assertEquals(record.getIntOptionalField(GetMode.STRICT), intValue); assertEquals(record.getIntOptionalField(), intValue); } @Test public void testIntDefaultField() { RecordTest record = new RecordTest(); assertFalse(record.hasIntDefaultField()); assertEquals(record.getIntDefaultField(GetMode.NULL), null); Integer defaultValue = 17; assertEquals(record.getIntDefaultField(GetMode.DEFAULT), defaultValue); assertEquals(record.getIntDefaultField(GetMode.STRICT), defaultValue); assertEquals(record.getIntDefaultField(), defaultValue); Integer intValue = 13; record.setIntDefaultField(intValue); assertTrue(record.hasIntDefaultField()); assertEquals(record.getIntDefaultField(GetMode.NULL), intValue); assertEquals(record.getIntDefaultField(GetMode.DEFAULT), intValue); assertEquals(record.getIntDefaultField(GetMode.STRICT), intValue); assertEquals(record.getIntDefaultField(), intValue); } @Test public void testIntDefaultOptionalField() { RecordTest record = new RecordTest(); assertFalse(record.hasIntDefaultOptionalField()); assertEquals(record.getIntDefaultOptionalField(GetMode.NULL), null); Integer defaultValue = 42; assertEquals(record.getIntDefaultOptionalField(GetMode.DEFAULT), defaultValue); assertEquals(record.getIntDefaultOptionalField(GetMode.STRICT), defaultValue); assertEquals(record.getIntDefaultOptionalField(), defaultValue); Integer intValue = 13; record.setIntDefaultOptionalField(intValue); assertTrue(record.hasIntDefaultOptionalField()); assertEquals(record.getIntDefaultOptionalField(GetMode.NULL), intValue); assertEquals(record.getIntDefaultOptionalField(GetMode.DEFAULT), intValue); assertEquals(record.getIntDefaultOptionalField(GetMode.STRICT), intValue); assertEquals(record.getIntDefaultOptionalField(), intValue); } @Test public void testCloneChangePrimitiveField() throws CloneNotSupportedException { RecordTest record = new RecordTest(); record.setIntField(52); RecordTest recordClone = record.clone(); assertEquals(recordClone, record); assertNotSame(recordClone.data(), record.data()); assertSame(recordClone.getIntField(), record.getIntField()); recordClone.setIntField(99); assertEquals(record.getIntField().intValue(), 52); assertEquals(recordClone.getIntField().intValue(), 99); } @Test public void testCloneChangeRecordField() throws CloneNotSupportedException { RecordTest record = new RecordTest(); record.setRecordField(new RecordBar()); record.getRecordField().setLocation("near"); RecordTest recordClone = record.clone(); assertEquals(recordClone, record); assertNotSame(recordClone.data(), record.data()); assertSame(recordClone.getRecordField(), record.getRecordField()); recordClone.getRecordField().setLocation("far"); assertEquals(record.getRecordField().getLocation(), "far"); assertEquals(recordClone.getRecordField().getLocation(), "far"); } @Test public void testCopyChangePrimitiveField() throws CloneNotSupportedException { RecordTest record = new RecordTest(); record.setIntField(52); RecordTest recordCopy = record.copy(); assertEquals(recordCopy, record); assertTrue(TestUtil.noCommonDataComplex(recordCopy, record)); assertNotSame(recordCopy.data(), record.data()); assertSame(recordCopy.getIntField(), record.getIntField()); recordCopy.setIntField(99); assertEquals(record.getIntField().intValue(), 52); assertEquals(recordCopy.getIntField().intValue(), 99); } @Test public void testCopyChangeRecordField() throws CloneNotSupportedException { RecordTest record = new RecordTest(); record.setRecordField(new RecordBar()); record.getRecordField().setLocation("near"); RecordTest recordCopy = record.copy(); assertEquals(recordCopy, record); assertTrue(TestUtil.noCommonDataComplex(recordCopy.data(), record.data())); assertNotSame(recordCopy.data(), record.data()); assertNotSame(recordCopy.getRecordField(), record.getRecordField()); assertNotSame(recordCopy.getRecordField().data(), record.getRecordField().data()); recordCopy.getRecordField().setLocation("far"); assertEquals(record.getRecordField().getLocation(), "near"); assertEquals(recordCopy.getRecordField().getLocation(), "far"); } }