1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // -------------------------------------------------------------------------*/
14 #include "sjme/debug.h"
15 #include "sjme/nvm/nvmFunc.h"
19 #define TEST_NUM_OBJECT_IDS 3
21 typedef struct testHookResult
23 /** The number of GCed objects. */
26 /** The GCed objects. */
27 sjme_jobject gc
[SJME_MOCK_MAX_OBJECTS
];
30 static sjme_jboolean
hookGcNvmLocalPopReference(sjme_nvm_frame frame
,
31 sjme_jobject instance
)
34 testHookResult
* hookResult
;
37 sjme_message("GC of %p...", instance
);
39 /* Mock must be set. */
40 mock
= frame
->inThread
->inState
->common
.frontEnd
.data
;
42 return SJME_JNI_FALSE
;
44 /* There must be a hook result. */
45 hookResult
= mock
->special
;
46 if (hookResult
== NULL
)
47 return SJME_JNI_FALSE
;
49 /* Track it, within reason. */
50 if (hookResult
->count
< SJME_MOCK_MAX_OBJECTS
)
51 hookResult
->gc
[hookResult
->count
++] = instance
;
57 const sjme_nvm_stateHooks hooksNvmLocalPopReference
=
59 .gc
= hookGcNvmLocalPopReference
,
62 sjme_jboolean
configNvmLocalPopReference(
63 sjme_attrInNotNull sjme_mock
* inState
,
64 sjme_attrInNotNull sjme_mock_configWork
* inCurrent
)
66 sjme_mock_configDataNvmState
* state
;
67 sjme_mock_configDataNvmFrame
* frame
;
70 if (inState
== NULL
|| inCurrent
== NULL
)
71 return SJME_JNI_FALSE
;
74 state
= &inCurrent
->data
.nvmState
;
75 frame
= &inCurrent
->data
.nvmFrame
;
78 switch (inCurrent
->type
)
80 case SJME_MOCK_DO_TYPE_NVM_STATE
:
81 state
->hooks
= &hooksNvmLocalPopReference
;
84 case SJME_MOCK_DO_TYPE_NVM_FRAME
:
87 frame
->treads
[SJME_JAVA_TYPE_ID_OBJECT
].max
= 2;
88 frame
->treads
[SJME_JAVA_TYPE_ID_OBJECT
].stackBaseIndex
= 1;
95 /** Mock set for test. */
96 static const sjme_mock_configSet mockNvmLocalPopReference
=
98 configNvmLocalPopReference
,
103 sjme_mock_doNvmState
,
104 sjme_mock_doNvmThread
,
105 sjme_mock_doNvmFrame
,
106 sjme_mock_doNvmObject
,
107 sjme_mock_doNvmObject
,
112 SJME_TEST_DECLARE(testNvmLocalPopReference
)
114 sjme_jbyte firstId
, secondId
;
116 sjme_nvm_frame frame
;
117 sjme_jint oldNumStack
;
118 sjme_nvm_frameTread
* objectsTread
;
119 sjme_nvm_frameStack
* stack
;
120 testHookResult hookResult
;
122 /* Test all possible combination of objects: [a, b, NULl]. */
123 /* This is for testing that reference counting works in this case. */
124 for (firstId
= 0; firstId
< TEST_NUM_OBJECT_IDS
; firstId
++)
125 for (secondId
= 0; secondId
< TEST_NUM_OBJECT_IDS
; secondId
++)
127 /* Perform the mock. */
128 memset(&state
, 0, sizeof(state
));
129 if (!sjme_mock_act(test
, &state
,
130 &mockNvmLocalPopReference
,
131 firstId
+ (secondId
* TEST_NUM_OBJECT_IDS
)))
132 sjme_die("Invalid mock");
134 /* Set special data for testing. */
135 memset(&hookResult
, 0, sizeof(hookResult
));
136 state
.special
= &hookResult
;
138 /* Get initialize frame size. */
139 frame
= state
.threads
[0].nvmThread
->top
;
141 /* Setup integer values. */
142 objectsTread
= frame
->treads
[SJME_JAVA_TYPE_ID_OBJECT
];
143 stack
= frame
->stack
;
144 objectsTread
->values
.jobjects
[0] = state
.objects
[secondId
];
145 objectsTread
->values
.jobjects
[1] = state
.objects
[firstId
];
146 objectsTread
->count
= objectsTread
->stackBaseIndex
+ 1;
148 stack
->order
[0] = SJME_JAVA_TYPE_ID_OBJECT
;
150 /* Pop integer from the stack to the first local. */
151 oldNumStack
= stack
->count
;
152 if (!sjme_nvm_localPopReference(frame
, 0))
153 return sjme_unit_fail(test
, "Failed to pop local reference.");
155 /* Only a specific object should be GCed and only in a certain */
157 if (state
.objects
[secondId
] != NULL
&&
158 state
.objects
[secondId
] != state
.objects
[firstId
])
160 sjme_unit_equalL(test
,
161 hookResult
.gc
[0], state
.objects
[secondId
],
162 "Old local was not what should have been GCed?");
163 sjme_unit_equalI(test
,
165 "Different old local not GCed?");
168 /* New stack should be lower. */
169 sjme_unit_equalI(test
, stack
->count
, oldNumStack
- 1,
170 "Items in stack not lower?");
172 /* Check that the value was moved over. */
173 sjme_unit_equalL(test
, state
.objects
[firstId
],
174 objectsTread
->values
.jobjects
[0],
175 "Popped stack into local was not the correct value.");
177 /* And the stack value was cleared. */
178 sjme_unit_equalL(test
, NULL
, objectsTread
->values
.jobjects
[1],
179 "Stack value did not get cleared.");
183 return SJME_TEST_RESULT_PASS
;