xref: /AOO41X/main/qadevOOo/tests/java/mod/_forms/GenericModelTest.java (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 package mod._forms;
28 import com.sun.star.beans.NamedValue;
29 import com.sun.star.beans.PropertyValue;
30 import com.sun.star.container.XIndexAccess;
31 import java.io.PrintWriter;
32 
33 import lib.StatusException;
34 import lib.TestCase;
35 import lib.TestEnvironment;
36 import lib.TestParameters;
37 import util.DBTools;
38 import util.FormTools;
39 import util.WriterTools;
40 
41 import com.sun.star.beans.XPropertySet;
42 import com.sun.star.drawing.XControlShape;
43 import com.sun.star.drawing.XShape;
44 import com.sun.star.form.XBoundComponent;
45 import com.sun.star.form.XForm;
46 import com.sun.star.form.XLoadable;
47 import com.sun.star.lang.XMultiServiceFactory;
48 import com.sun.star.lang.XComponent;
49 import com.sun.star.sdbc.XConnection;
50 import com.sun.star.sdbc.XResultSetUpdate;
51 import com.sun.star.sdb.XDocumentDataSource;
52 import com.sun.star.text.XTextDocument;
53 import com.sun.star.uno.AnyConverter;
54 import com.sun.star.uno.Type;
55 import com.sun.star.uno.UnoRuntime;
56 import com.sun.star.uno.XInterface;
57 import com.sun.star.util.XCloseable;
58 import java.util.ArrayList;
59 import lib.Status;
60 import util.utils;
61 
62 
63 /**
64 * Test for object which is represented by service
65 * <code>com.sun.star.form.component.DateField</code>. <p>
66 * Object implements the following interfaces :
67 * <ul>
68 *  <li> <code>com::sun::star::io::XPersistObject</code></li>
69 *  <li> <code>com::sun::star::awt::UnoControlDateFieldModel</code></li>
70 *  <li> <code>com::sun::star::form::XReset</code></li>
71 *  <li> <code>com::sun::star::form::XBoundComponent</code></li>
72 *  <li> <code>com::sun::star::form::FormComponent</code></li>
73 *  <li> <code>com::sun::star::form::component::DateField</code></li>
74 *  <li> <code>com::sun::star::beans::XFastPropertySet</code></li>
75 *  <li> <code>com::sun::star::beans::XMultiPropertySet</code></li>
76 *  <li> <code>com::sun::star::form::XUpdateBroadcaster</code></li>
77 *  <li> <code>com::sun::star::form::DataAwareControlModel</code></li>
78 *  <li> <code>com::sun::star::beans::XPropertyState</code></li>
79 *  <li> <code>com::sun::star::form::FormControlModel</code></li>
80 *  <li> <code>com::sun::star::container::XNamed</code></li>
81 *  <li> <code>com::sun::star::lang::XComponent</code></li>
82 *  <li> <code>com::sun::star::lang::XEventListener</code></li>
83 *  <li> <code>com::sun::star::beans::XPropertyAccess</code></li>
84 *  <li> <code>com::sun::star::beans::XPropertyContainer</code></li>
85 *  <li> <code>com::sun::star::beans::XPropertySet</code></li>
86 *  <li> <code>com::sun::star::form::XLoadListener</code></li>
87 *  <li> <code>com::sun::star::container::XChild</code></li>
88 * </ul>
89 * The following files used by this test :
90 * <ul>
91 *  <li><b> TestDB </b> (directory) : directory with test database </li>
92 *  <li><b> TestDB/TestDB.dbf </b> : table file. See
93 *    {@link util.DBTools DBTools} class for more information.</li>
94 * </ul> <p>
95 * This object test <b> is NOT </b> designed to be run in several
96 * threads concurently.
97 * @see com.sun.star.io.XPersistObject
98 * @see com.sun.star.awt.UnoControlDateFieldModel
99 * @see com.sun.star.form.XReset
100 * @see com.sun.star.form.XBoundComponent
101 * @see com.sun.star.form.FormComponent
102 * @see com.sun.star.form.component.DateField
103 * @see com.sun.star.beans.XFastPropertySet
104 * @see com.sun.star.beans.XMultiPropertySet
105 * @see com.sun.star.form.XUpdateBroadcaster
106 * @see com.sun.star.form.DataAwareControlModel
107 * @see com.sun.star.beans.XPropertyState
108 * @see com.sun.star.form.FormControlModel
109 * @see com.sun.star.container.XNamed
110 * @see com.sun.star.lang.XComponent
111 * @see com.sun.star.lang.XEventListener
112 * @see com.sun.star.beans.XPropertyAccess
113 * @see com.sun.star.beans.XPropertyContainer
114 * @see com.sun.star.beans.XPropertySet
115 * @see com.sun.star.form.XLoadListener
116 * @see com.sun.star.container.XChild
117 * @see ifc.io._XPersistObject
118 * @see ifc.awt._UnoControlDateFieldModel
119 * @see ifc.form._XReset
120 * @see ifc.form._XBoundComponent
121 * @see ifc.form._FormComponent
122 * @see ifc.form.component._DateField
123 * @see ifc.beans._XFastPropertySet
124 * @see ifc.beans._XMultiPropertySet
125 * @see ifc.form._XUpdateBroadcaster
126 * @see ifc.form._DataAwareControlModel
127 * @see ifc.beans._XPropertyState
128 * @see ifc.form._FormControlModel
129 * @see ifc.container._XNamed
130 * @see ifc.lang._XComponent
131 * @see ifc.lang._XEventListener
132 * @see ifc.beans._XPropertySet
133 * @see ifc.form._XLoadListener
134 * @see ifc.container._XChild
135 */
136 public class GenericModelTest extends TestCase {
137     private static XTextDocument m_xTextDoc;
138     private static Object m_dbSrc = null;
139     private static DBTools.DataSourceInfo m_srcInf = null;
140     /**
141      * This is the name of the Data Base which the test uses: "APITestDatabase"
142      */
143     protected final static String m_dbSourceName = "APITestDatabase";
144     protected final static String m_TestDB = "TestDB";
145     private DBTools m_dbTools = null;
146 
147     private static boolean m_ConnectionColsed = false;
148 
149     /**
150      * descibes the kind of the shape which should be created.
151      * Example: m_kindOfshape=DateFiled
152      */
153     public static String m_kindOfControl = null;
154 
155     /**
156      * If your object needs some special propery values you can specify them with this
157      * <CODE>ArrayList</CODE>. You have to add a <CODE>NamedValue</CODE> to this list.
158      * Example:
159      * NamedValue myProp = new NamedValue();
160      * myProp.Name = "Test";
161      * myProp.Value = "My special Value";
162      * m_propertiesToSet.add(myProp);
163      */
164     public static ArrayList m_propertiesToSet = new ArrayList();
165 
166     /**
167      * This variable contains the name of the property which should be changed while
168      * interface <CODE>com::sun::star::form::XUpdateBroadcaster</CODE> is tested. The
169      * interface test needs the <CODE>ObjectRelation</CODE>
170      * "XUpdateBroadcaster.Checker" which is a <CODE>ifc.form._XUpdateBroadcaster.UpdateChecker</CODE>.
171      * @see ifc.form._XUpdateBroadcaster.UpdateChecker
172      * @see ifc.form._XUpdateBroadcaster
173      */
174     public static String m_ChangePropertyName = null;
175     /**
176      * This variable contains the value the property should be set while
177      * interface <CODE>com::sun::star::form::XUpdateBroadcaster</CODE> is tested.
178      * The interface test needs the <CODE>ObjectRelation</CODE>
179      * "XUpdateBroadcaster.Checker" which is a <CODE>ifc.form._XUpdateBroadcaster.UpdateChecker</CODE>.
180      * Normaly the <CODE>Checker</CODE> uses <CODE>util.ValueChanger</CODE> to change
181      * the value of the property. If the current of this property is NULL the
182      * <CODE>ValueChanger</CODE> is unable to change the value. In this case the value
183      * of this variable was used.
184      */
185     public static Object m_ChangePropertyValue = null;
186 
187     /**
188      * This variable contains the implelemtation name of the object.
189      */
190     public static String m_ObjectName = null;
191 
192     /**
193      * For local implementaions of <CODE>Checker</CODE> this variable contains the
194      * <CODE>FormLoader</CODE>
195      */
196     protected static XLoadable m_XFormLoader = null;
197     /**
198      * For local implementaions of <CODE>Checker</CODE> this variable contains the
199      * <CODE>XPropertySet</CODE>
200      */
201     protected static XPropertySet m_XPS = null;
202     /**
203      * For local implementaions of <CODE>Checker</CODE> this variable contains the
204      * <CODE>Control</CODE>
205      */
206     protected static XInterface m_XCtrl = null;
207     /**
208      * The insterface test of <CODE>ifc.form._DataWareControlModel</CODE> expects an
209      * object relation <CODE>'LC'</CODE>. This is a <CODE>XControlModel</CODE> of a shape.
210      * This variable contains the kind of shape to create for the interface test,
211      * f.e. "FixedText"
212      * @see ifc.form._DataAwareControlModel
213      */
214     protected static String m_LCShape_Type = null;
215 
216     protected static String m_XPropertyAccess_propertyToChange = "HelpText";
217 
218     protected static String m_XPropertyContainer_propertyNotRemovable = "HelpText";
219     /**
220      * If this variable is true some more debug info was logged. It was setted by the parameter variable
221      * <code>debug_is_active</code>
222      */
223     protected static boolean debug = false;
224 
225     /**
226      * Creates Writer document where controls are placed.
227      * @param tParam the test paremter
228      * @param log the log writer
229      */
230     protected void initialize(TestParameters tParam, PrintWriter log) {
231         log.println("creating a textdocument");
232         m_xTextDoc = WriterTools.createTextDoc(((XMultiServiceFactory) tParam.getMSF()));
233         m_ConnectionColsed = false;
234         debug = tParam.getBool(util.PropertyName.DEBUG_IS_ACTIVE);
235         m_propertiesToSet.clear();
236     }
237 
238     /**
239      * close the connection
240      * close the data source
241      * close the document
242      * revoke the data source
243      * @param tParam the test parameter
244      * @param log the log writer
245      */
246     protected void cleanup(TestParameters tParam, PrintWriter log) {
247         log.println("closing connection...");
248 
249         // some interface tests call cleanup to reset the environment. If such
250         // a test is the last one cleanup was called twice. The second call
251         // causes then nasty exceptions...
252         if (m_ConnectionColsed) return;
253 
254         try {
255             XIndexAccess forms = UnoRuntime.queryInterface( XIndexAccess.class,
256                 FormTools.getForms( WriterTools.getDrawPage( m_xTextDoc ) ) );
257             XForm myForm = (XForm) AnyConverter.toObject(new Type(XForm.class),
258                                                  forms.getByIndex(0));
259 
260             if (debug){
261                 if (myForm == null){
262                     log.println("ERROR: could not get 'Standard' from drawpage!");
263                 }
264                 log.println("the draw page contains folowing elemtens:");
265                 String[] elements = FormTools.getForms(WriterTools.getDrawPage(m_xTextDoc)).getElementNames();
266                 for (int i = 0; i< elements.length; i++){
267                     log.println("Element[" + i + "] :" + elements[i]);
268                 }
269 
270             }
271 
272             XPropertySet xSetProp = UnoRuntime.queryInterface( XPropertySet.class, myForm );
273             XConnection connection = UnoRuntime.queryInterface( XConnection.class, xSetProp.getPropertyValue( "ActiveConnection" ) );
274             if ( connection == null )
275             {
276                 if ( debug )
277                     log.println("ERROR: could not get property 'ActiveConnection' from the XForm");
278             }
279             else
280             {
281                 connection.close();
282             }
283         } catch (Exception e) {
284             log.println("ERROR: Can't close the connection: " + e.toString());
285             e.printStackTrace( log );
286         }
287 
288         log.println("closing data source...");
289         try {
290             XCloseable closer = (XCloseable) UnoRuntime.queryInterface(
291                                         XCloseable.class, m_dbSrc);
292             if ( closer == null )
293             {
294                 XDocumentDataSource dataSource = (XDocumentDataSource)UnoRuntime.queryInterface(
295                     XDocumentDataSource.class, m_dbSrc);
296                 if ( dataSource != null )
297                     closer = (XCloseable) UnoRuntime.queryInterface(
298                         XCloseable.class, dataSource.getDatabaseDocument() );
299             }
300             if (debug && closer==null){
301                 log.println("ERROR: couldn't get 'XCloseable' from DataSource");
302             }
303             closer.close(true);
304         } catch (com.sun.star.util.CloseVetoException e) {
305             log.println("ERROR: couldn't close data source: " + e.toString());
306         } catch (com.sun.star.lang.DisposedException e) {
307             log.println("ERROR: couldn't close data source: " + e.toString());
308         } catch (Exception e) {
309             log.println("ERROR: couldn't close data source: " + e.toString());
310         }
311 
312         log.println("disposing data source...");
313         try {
314             XComponent dataSourceComp = (XComponent)UnoRuntime.queryInterface(
315                 XComponent.class, m_dbSrc);
316             dataSourceComp.dispose();
317         }
318         catch (Exception e) {
319             log.println("couldn't dispose the data source");
320         }
321 
322         log.println("closing document...");
323 
324         try {
325             XCloseable closer = (XCloseable) UnoRuntime.queryInterface(
326                                         XCloseable.class, m_xTextDoc);
327             closer.close(true);
328         } catch (com.sun.star.util.CloseVetoException e) {
329             log.println("ERROR: couldn't close document: " + e.toString());
330         } catch (com.sun.star.lang.DisposedException e) {
331             log.println("ERROR: couldn't close document: " + e.toString());
332         } catch (Exception e) {
333             log.println("ERROR: couldn't close document: " + e.toString());
334         }
335 
336         log.println("revoking data source...");
337         try {
338             m_dbTools.revokeDB(m_dbSourceName);
339         } catch (com.sun.star.container.NoSuchElementException e){
340         } catch (com.sun.star.uno.Exception e) {
341             log.println("ERROR: Error while object test cleaning up: " + e.toString());
342         }
343 
344         m_ConnectionColsed = true;
345     }
346 
347     /**
348      * Creating a Testenvironment for the interfaces to be tested.
349      * First <code>TestDB</code> database is registered.
350      * Creates DateField in the Form, then binds it to TestDB
351      * database and returns Field's control. <p>
352      *     Object relations created :
353      * <ul>
354      *  <li> <code>'OBJNAME'</code> for
355      *      {@link ifc.io._XPersistObject} : name of service which is
356      *    represented by this object. </li>
357      *  <li> <code>'LC'</code> for {@link ifc.form._DataAwareControlModel}.
358      *    Specifies the value for LabelControl property. It is
359      *    <code>FixedText</code> component added to the document.</li>
360      *  <li> <code>'FL'</code> for
361      *      {@link ifc.form._DataAwareControlModel} interface.
362      *    Specifies XLoadable implementation which connects form to
363      *    the data source.</li>
364      *  <li> <code>'XUpdateBroadcaster.Checker'</code> : <code>
365      *    _XUpdateBroadcaster.UpdateChecker</code> interface implementation
366      *    which can update, commit data and check if the data was successfully
367      *    commited.</li>
368      *  <li> <code>'DataAwareControlModel.NewFieldName'</code> : for
369      *    <code>com.sun.star.form.DataAwareControlModel</code> service
370      *    which contains new name of the field ('_DATE') to bind control to.
371      *  </li>
372      *  <li> <code>'XFastPropertySet.ExcludeProps'</code> : for
373      *    <code>com.sun.star.beans.XFastPropertySet</code> interface
374      *    the property FormatKey can have only restricted set of values.
375      *  </li>
376      * </ul>
377      * @see ifc.form._XUpdateBroadcaster
378      * @param Param the test parameter
379      * @param log the log writer
380      * @return a test environment
381      */
382     protected synchronized TestEnvironment createTestEnvironment(TestParameters Param,
383                                                                  PrintWriter log) {
384         XInterface oObj = null;
385         XControlShape aShape = null;
386         XMultiServiceFactory xMSF = (XMultiServiceFactory) Param.getMSF();
387 
388         try{
389             log.println("adding contol shape '" + m_kindOfControl + "'");
390             aShape = FormTools.createControlShape(m_xTextDoc, 3000,
391                                                             4500, 15000, 10000,
392                                                             m_kindOfControl);
393         } catch (Exception e){
394             e.printStackTrace(log);
395             throw new StatusException("Couldn't create following control shape (m_kindOfControl): '" +
396                                         m_kindOfControl + "': ", e);
397 
398         }
399 
400         WriterTools.getDrawPage(m_xTextDoc).add((XShape) aShape);
401         oObj = aShape.getControl();
402 
403         log.println("Implementation name: " + util.utils.getImplName(oObj));
404 
405         try {
406             String sourceTestDB = utils.getFullURL(utils.getFullTestDocName("TestDB/testDB.dbf"));
407             String destTestDB = utils.getOfficeTemp(xMSF);
408             destTestDB = utils.getFullURL(destTestDB + "testDB.dbf");
409 
410             log.println("copy '"+sourceTestDB + "' -> '" + destTestDB + "'");
411             utils.copyFile(xMSF, sourceTestDB, destTestDB);
412 
413             m_dbTools = new DBTools( xMSF, log );
414             String tmpDir = utils.getOfficeTemp((xMSF));
415 
416             m_srcInf = m_dbTools.newDataSourceInfo();
417             m_srcInf.URL = "sdbc:dbase:" + DBTools.dirToUrl(tmpDir);
418             log.println("data source: " + m_srcInf.URL);
419 
420             m_dbSrc = m_srcInf.getDataSourceService();
421             m_dbTools.reRegisterDB(m_dbSourceName, m_dbSrc);
422 
423             m_XFormLoader = FormTools.bindForm(m_xTextDoc, m_dbSourceName,
424                                             m_TestDB);
425         } catch (com.sun.star.uno.Exception e) {
426             log.println("!!! Can't access TestDB !!!");
427             e.printStackTrace(log);
428             throw new StatusException("Can't access TestDB", e);
429         }
430 
431         log.println("creating a new environment for object");
432 
433         TestEnvironment tEnv = new TestEnvironment(oObj);
434 
435         tEnv.addObjRelation("OBJNAME", m_ObjectName);
436 
437         log.println("adding shape '" + m_LCShape_Type +"' for DataAwareControlModel test");
438         aShape = FormTools.createControlShape(m_xTextDoc, 6000, 4500, 15000,
439                                               10000, m_LCShape_Type);
440         WriterTools.getDrawPage(m_xTextDoc).add((XShape) aShape);
441 
442         m_XPS = (XPropertySet) UnoRuntime.queryInterface(
443                                         XPropertySet.class, oObj);
444 
445         int i = 0;
446         NamedValue prop = null;
447         try {
448             for (i = 0; i < m_propertiesToSet.size(); i++){
449                 prop = (NamedValue) m_propertiesToSet.get(i);
450 
451                 log.println("setting property: '"+prop.Name+"' to value '"+prop.Value.toString()+"'");
452 
453                 m_XPS.setPropertyValue(prop.Name, prop.Value);
454             }
455         } catch (com.sun.star.lang.WrappedTargetException e) {
456             e.printStackTrace(log);
457             throw new StatusException("Couldn't set property '" + prop.Name + "': ", e);
458         } catch (com.sun.star.lang.IllegalArgumentException e) {
459             e.printStackTrace(log);
460             throw new StatusException("Couldn't set property '" + prop.Name + "': ", e);
461         } catch (com.sun.star.beans.PropertyVetoException e) {
462             e.printStackTrace(log);
463             throw new StatusException("Couldn't set property '" + prop.Name + "': ", e);
464         } catch (com.sun.star.beans.UnknownPropertyException e) {
465             e.printStackTrace(log);
466             throw new StatusException("Couldn't set property '" + prop.Name + "': ", e);
467         } catch (java.lang.ClassCastException e) {
468             e.printStackTrace(log);
469             throw new StatusException("Couldn't get property on index '" + i + "': ", e);
470         }
471 
472         // added LabelControl for 'DataAwareControlModel'
473         tEnv.addObjRelation("LC", aShape.getControl());
474 
475         // added FormLoader for 'DataAwareControlModel'
476         tEnv.addObjRelation("FL", m_XFormLoader);
477 
478         // adding relation for XUpdateBroadcaster
479         m_XCtrl = oObj;
480 
481     tEnv.addObjRelation("XUpdateBroadcaster.Checker",
482                             new Checker(m_XFormLoader, m_XPS, m_XCtrl, m_ChangePropertyName, m_ChangePropertyValue));
483 
484         // adding relation for DataAwareControlModel service
485         tEnv.addObjRelation("DataAwareControlModel.NewFieldName",
486                             DBTools.TST_DATE_F);
487 
488         //adding ObjRelation for XPersistObject
489         tEnv.addObjRelation("PSEUDOPERSISTENT", new Boolean(true));
490 
491         // adding relation for XFastPropertySet
492         java.util.HashSet exclude = new java.util.HashSet();
493         exclude.add("FormatKey");
494         tEnv.addObjRelation("XFastPropertySet.ExcludeProps", exclude);
495 
496         PropertyValue propVal = new PropertyValue();
497         propVal.Name = m_XPropertyAccess_propertyToChange;
498         propVal.Value = "Text since XPropertyAccess";
499         tEnv.addObjRelation("XPropertyAccess.propertyToChange", propVal);
500         tEnv.addObjRelation("XPropertyContainer.propertyNotRemovable", m_XPropertyContainer_propertyNotRemovable);
501 
502 
503         return tEnv;
504     } // finish method getTestEnvironment
505 
506 
507     static class Checker implements ifc.form._XUpdateBroadcaster.UpdateChecker {
508             private Object lastValue = null;
509             XLoadable formLoaderF = null;
510             XPropertySet ps = null;
511             XInterface ctrl = null;
512             String ChangePropertyName = null;
513             Object ChangePropertyValue = null;
514 
515             public Checker(XLoadable xl, XPropertySet ps, XInterface ctrl, String ChangePropertyName, Object ChangePropertyValue) {
516                 formLoaderF = xl;
517                 this.ps = ps;
518                 this.ctrl = ctrl;
519                 this.ChangePropertyName=ChangePropertyName;
520                 this.ChangePropertyValue=ChangePropertyValue;
521             }
522 
523             public void update() throws com.sun.star.uno.Exception {
524                 if (!formLoaderF.isLoaded()) {
525                     formLoaderF.load();
526                 }
527 
528                 lastValue = util.ValueChanger.changePValue(ps.getPropertyValue(ChangePropertyName));
529 
530                 if (lastValue == null){
531 
532                     if (ChangePropertyValue != null){
533 
534                         lastValue = ChangePropertyValue;
535 
536                     } else {
537 
538                         String msg = "The initial value of the property '" + ChangePropertyName + "' is NULL\n";
539                         msg += "The member variable 'm_ChangePropertyValue' is NULL\n";
540                         msg += "Could not change Property.";
541 
542                         throw new StatusException(Status.failed(msg));
543                     }
544                 }
545                 ps.setPropertyValue(ChangePropertyName, lastValue);
546             }
547 
548             public void commit() throws com.sun.star.sdbc.SQLException {
549                 XBoundComponent bound = (XBoundComponent) UnoRuntime.queryInterface(
550                                                 XBoundComponent.class, ctrl);
551                 XResultSetUpdate update = (XResultSetUpdate) UnoRuntime.queryInterface(
552                                                   XResultSetUpdate.class,
553                                                   formLoaderF);
554 
555                 bound.commit();
556                 update.updateRow();
557             }
558 
559             public boolean wasCommited() throws com.sun.star.uno.Exception {
560                 formLoaderF.reload();
561 
562                 Object newValue = ps.getPropertyValue(ChangePropertyName);
563 
564                 return (newValue != null) && (util.ValueComparer.equalValue(lastValue, newValue));
565             }
566         }
567 } // finish class GenericModelTest
568