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 "hello.txt.h"
15 #include "MockMain.class.h"
17 struct sjme_mock_configWorkData
19 /** The index type counts. */
20 sjme_jint indexTypeCount
[SJME_NUM_MOCK_DO_TYPES
];
22 /** The current run. */
23 sjme_mock_configWork current
;
25 /** The next thread ID. */
26 sjme_jint nextThreadId
;
30 * Mock function to do type.
36 sjme_mock_doFunc func
;
37 sjme_mock_doType type
;
38 } sjme_mockFuncToType
[SJME_NUM_MOCK_DO_TYPES
] =
40 {sjme_mock_doNvmFrame
,
41 SJME_MOCK_DO_TYPE_NVM_FRAME
},
42 {sjme_mock_doNvmObject
,
43 SJME_MOCK_DO_TYPE_NVM_OBJECT
},
44 {sjme_mock_doNvmState
,
45 SJME_MOCK_DO_TYPE_NVM_STATE
},
46 {sjme_mock_doNvmThread
,
47 SJME_MOCK_DO_TYPE_NVM_THREAD
},
48 {sjme_mock_doRomLibrary
,
49 SJME_MOCK_DO_TYPE_ROM_LIBRARY
},
50 {sjme_mock_doRomMockLibrary
,
51 SJME_MOCK_DO_TYPE_ROM_MOCK_LIBRARY
},
52 {sjme_mock_doRomSuite
,
53 SJME_MOCK_DO_TYPE_ROM_SUITE
},
56 {NULL
, SJME_MOCK_DO_TYPE_UNKNOWN
}
59 static sjme_errorCode
sjme_mock_defaultRomLibraryRawData(
60 sjme_attrInNotNull sjme_rom_library inLibrary
,
61 sjme_attrOutNotNullBuf(length
) sjme_pointer dest
,
62 sjme_attrInPositive sjme_jint srcPos
,
63 sjme_attrInPositive sjme_jint length
)
65 sjme_mock_configDataRomLibrary
* mock
;
67 if (inLibrary
== NULL
|| dest
== NULL
)
68 return SJME_ERROR_NULL_ARGUMENTS
;
70 if (srcPos
< 0 || length
< 0)
71 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
74 mock
= inLibrary
->cache
.common
.frontEnd
.data
;
76 /* Double check size. */
77 if (srcPos
+ length
< 0 || srcPos
+ length
> mock
->length
)
78 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
80 /* There is no actual data here? */
81 if (mock
->data
== NULL
)
82 return SJME_ERROR_ILLEGAL_STATE
;
84 /* Just do a normal copy over. */
85 memmove(dest
, (sjme_pointer
)(((uintptr_t)mock
->data
) + srcPos
), length
);
86 return SJME_ERROR_NONE
;
89 static sjme_errorCode
sjme_mock_defaultRomLibraryRawSize(
90 sjme_attrInNotNull sjme_rom_library inLibrary
,
91 sjme_attrOutNotNull sjme_jint
* outSize
)
93 sjme_mock_configDataRomLibrary
* mock
;
95 if (inLibrary
== NULL
|| outSize
== NULL
)
96 return SJME_ERROR_NULL_ARGUMENTS
;
99 mock
= inLibrary
->cache
.common
.frontEnd
.data
;
101 /* Is a simple set operation. */
102 *outSize
= mock
->length
;
103 return SJME_ERROR_NONE
;
106 static sjme_errorCode
sjme_mock_defaultRomMockLibraryResourceStream(
107 sjme_attrInNotNull sjme_rom_library inLibrary
,
108 sjme_attrOutNotNull sjme_stream_input
* outStream
,
109 sjme_attrInNotNull sjme_lpcstr resourceName
)
111 sjme_alloc_pool
* pool
;
115 if (inLibrary
== NULL
|| resourceName
== NULL
|| outStream
== NULL
)
116 return SJME_ERROR_NULL_ARGUMENTS
;
118 /* Which pool to allocate within? */
119 pool
= inLibrary
->cache
.common
.allocPool
;
122 sjme_message("Looking for resource %s...", resourceName
);
124 /* Depends on the resource name. */
125 if (0 == strcmp(resourceName
, "hello.txt"))
127 data
= hello_txt__bin
;
128 len
= hello_txt__len
;
130 else if (0 == strcmp(resourceName
, "MockMain.class"))
132 data
= mockmain_class__bin
;
133 len
= mockmain_class__len
;
138 return SJME_ERROR_RESOURCE_NOT_FOUND
;
140 /* Open the stream. */
141 return sjme_stream_inputOpenMemory(pool
, outStream
,
145 sjme_jboolean
sjme_mock_act(
146 sjme_attrInNotNull sjme_test
* inTest
,
147 sjme_attrInNotNull sjme_mock
* inState
,
148 sjme_attrInNotNull
const sjme_mock_configSet
* inSet
,
149 sjme_attrInValue sjme_jint special
)
152 sjme_mock_configWorkData data
;
153 sjme_mock_doType doType
;
156 if (inState
== NULL
|| inSet
== NULL
)
157 return sjme_die("Null arguments.");
159 /* Use the testing pool. */
160 inState
->allocPool
= inTest
->pool
;
162 /* Initialize base data. */
163 memset(&data
, 0, sizeof(data
));
165 /* Go through each entry, stop at NULl. */
166 for (dx
= 0; inSet
->order
[dx
] != NULL
; dx
++)
168 /* Always wipe the current data so it is fresh. */
169 memset(&data
.current
, 0, sizeof(data
.current
));
171 /* This index is just a straight through. */
172 data
.current
.indexAll
= dx
;
174 /* Find the type for this function. */
175 doType
= SJME_MOCK_DO_TYPE_UNKNOWN
;
176 for (i
= 0; i
< SJME_NUM_MOCK_DO_TYPES
; i
++)
177 if (inSet
->order
[dx
] == sjme_mockFuncToType
[i
].func
)
179 doType
= sjme_mockFuncToType
[i
].type
;
184 if (doType
== SJME_MOCK_DO_TYPE_UNKNOWN
)
185 return sjme_die("Could not find the type for do function.");
187 /* Increment up the index for this. */
188 data
.current
.type
= doType
;
189 data
.current
.indexType
= data
.indexTypeCount
[doType
]++;
190 data
.current
.special
= special
;
192 /* Run configuration function to initialize the data set. */
193 if (inSet
->config
!= NULL
)
194 if (!inSet
->config(inState
, &data
.current
))
195 return sjme_die("Configuration step failed at %d.", dx
);
197 /* Call do function to perform whatever test initialization. */
198 if (!inSet
->order
[dx
](inState
, &data
))
199 return sjme_die("Do failed at %d.", dx
);
203 return SJME_JNI_TRUE
;
206 sjme_pointer
sjme_mock_alloc(
207 sjme_attrInNotNull sjme_mock
* inState
,
208 sjme_attrInPositiveNonZero
size_t inLen
)
214 return sjme_dieP("No input state.");
217 if (sjme_error_is(sjme_alloc(inState
->allocPool
, inLen
,
219 return sjme_dieP("Could not allocate pointer in test pool.");
224 sjme_jboolean
sjme_mock_doNvmState(
225 sjme_attrInNotNull sjme_mock
* inState
,
226 sjme_attrInNotNull sjme_mock_configWorkData
* inData
)
230 if (inState
== NULL
|| inData
== NULL
)
231 return sjme_die("Null arguments.");
233 /* Allocate virtual machine state. */
234 newState
= sjme_mock_alloc(inState
,
235 sizeof(*inState
->nvmState
));
236 inState
->nvmState
= newState
;
238 /* Store test state, as required for some tests. */
239 newState
->common
.frontEnd
.data
= inState
;
241 /* Register any hooks? */
242 if (inData
->current
.data
.nvmState
.hooks
!= NULL
)
243 newState
->hooks
= inData
->current
.data
.nvmState
.hooks
;
246 return SJME_JNI_TRUE
;
249 sjme_jboolean
sjme_mock_doNvmFrame(
250 sjme_attrInNotNull sjme_mock
* inState
,
251 sjme_attrInNotNull sjme_mock_configWorkData
* inData
)
253 sjme_jint threadIndex
, treadMax
, tallyLocals
, stackBase
, desireMaxLocals
;
254 sjme_jint tallyStack
, desireMaxStack
, localIndex
;
255 sjme_nvm_thread thread
;
256 sjme_nvm_frame newFrame
;
257 sjme_basicTypeId typeId
;
258 sjme_nvm_frameTread
* tread
;
259 sjme_nvm_frameStack
* stack
;
260 sjme_nvm_frameLocalMap
* localMap
;
261 sjme_jbyte baseLocalAt
[SJME_NUM_JAVA_TYPE_IDS
];
263 if (inState
== NULL
|| inData
== NULL
)
264 return sjme_die("Null arguments.");
266 /* Make sure the requested thread index is valid. */
267 threadIndex
= inData
->current
.data
.nvmFrame
.threadIndex
;
268 if (threadIndex
< 0 || threadIndex
>= SJME_MOCK_MAX_THREADS
||
269 inState
->threads
[threadIndex
].nvmThread
== NULL
)
270 return sjme_die("Invalid thread index %d.", threadIndex
);
272 /* Get the actual thread. */
273 thread
= inState
->threads
[threadIndex
].nvmThread
;
275 /* Allocate new frame. */
276 newFrame
= sjme_mock_alloc(inState
, sizeof(*newFrame
));
277 if (newFrame
== NULL
)
278 return sjme_die("Could not allocate frame.");
280 /* Correlate the frame index to the thread. */
281 newFrame
->frameIndex
= thread
->numFrames
;
284 /* Link in frame to the thread. */
285 newFrame
->inThread
= thread
;
286 newFrame
->parent
= thread
->top
;
287 thread
->top
= newFrame
;
289 /* Track tally of locals and stack for consistency. */
293 /* Setup locals mapping. */
294 desireMaxLocals
= inData
->current
.data
.nvmFrame
.maxLocals
;
295 localMap
= sjme_mock_alloc(inState
,
296 SJME_SIZEOF_FRAME_LOCAL_MAP(desireMaxLocals
));
297 localMap
->max
= desireMaxLocals
;
299 /* Setup stack information. */
300 desireMaxStack
= inData
->current
.data
.nvmFrame
.maxStack
;
301 stack
= sjme_mock_alloc(inState
,
302 SJME_SIZEOF_FRAME_STACK(desireMaxStack
));
303 newFrame
->stack
= stack
;
304 stack
->limit
= desireMaxStack
;
306 /* Remember to set the local mapping in the frame. */
307 newFrame
->localMap
= localMap
;
309 /* Clear base local map set trackers. */
310 memset(baseLocalAt
, 0, sizeof(baseLocalAt
));
312 /* Need to initialize frame locals and stack? */
313 for (typeId
= 0; typeId
< SJME_NUM_JAVA_TYPE_IDS
; typeId
++)
315 /* Ignore if empty. */
316 treadMax
= inData
->current
.data
.nvmFrame
.treads
[typeId
].max
;
320 /* Allocate target tread. */
321 tread
= sjme_mock_alloc(inState
,
322 SJME_SIZEOF_FRAME_TREAD_VAR(typeId
, treadMax
));
323 newFrame
->treads
[typeId
] = tread
;
325 /* Setup stack base. */
326 stackBase
= inData
->current
.data
.nvmFrame
.treads
[typeId
]
328 if (stackBase
< 0 || stackBase
> treadMax
)
329 return sjme_die("Invalid test stack base %d, outside range %d.",
330 stackBase
, treadMax
);
332 /* Local tally goes up by the stack base. */
333 tallyLocals
+= stackBase
;
335 /* Tally number of stack items. */
336 tallyStack
+= treadMax
- stackBase
;
338 /* Setup other tread details. */
339 tread
->stackBaseIndex
= stackBase
;
340 tread
->count
= stackBase
;
341 tread
->max
= treadMax
;
343 /* Fill in local mappings for a given tread. */
344 for (localIndex
= 0; localIndex
< stackBase
; localIndex
++)
345 localMap
->maps
[localIndex
].to
[typeId
] = (sjme_jbyte
)localIndex
;
348 /* Store the type onto the stack. */
349 stack
->order
[stack
->count
] = typeId
;
354 /* Consistency check. */
355 if (tallyLocals
!= desireMaxLocals
)
356 return sjme_die("Calculated and desired locals invalid: %d != %d.",
357 tallyLocals
, desireMaxLocals
);
359 if (tallyStack
!= desireMaxStack
)
360 return sjme_die("Calculated and desired stack invalid: %d != %d.",
361 tallyStack
, desireMaxStack
);
364 return SJME_JNI_TRUE
;
367 sjme_jboolean
sjme_mock_doNvmObject(
368 sjme_attrInNotNull sjme_mock
* inState
,
369 sjme_attrInNotNull sjme_mock_configWorkData
* inData
)
371 sjme_jobject newObject
;
373 if (inState
== NULL
|| inData
== NULL
)
374 return sjme_die("Null arguments.");
376 /* Too many objects? */
377 if (inState
->numObjects
>= SJME_MOCK_MAX_OBJECTS
)
378 sjme_die("Too many mock objects.");
380 /* Allocate new object. */
381 newObject
= sjme_mock_alloc(inState
, sizeof(*newObject
));
382 inState
->objects
[inState
->numObjects
++] = newObject
;
384 /* Initialize object details. */
385 newObject
->refCount
= 1;
388 return SJME_JNI_TRUE
;
391 sjme_jboolean
sjme_mock_doNvmThread(
392 sjme_attrInNotNull sjme_mock
* inState
,
393 sjme_attrInNotNull sjme_mock_configWorkData
* inData
)
395 sjme_jint threadIndex
;
396 sjme_nvm_thread newThread
;
398 if (inState
== NULL
|| inData
== NULL
)
399 return sjme_die("Null arguments.");
401 /* Mock has a limited set of threads for testing purposes. */
402 threadIndex
= inState
->numThreads
;
403 if (threadIndex
>= SJME_MOCK_MAX_THREADS
)
404 return sjme_die("Too make mock threads.");
406 /* Allocate thread. */
407 newThread
= sjme_mock_alloc(inState
, sizeof(*newThread
));
408 if (newThread
== NULL
)
409 return sjme_die("Could not allocate thread.");
411 /* Store in thread and bump up. */
412 newThread
->threadId
= ++inData
->nextThreadId
;
413 newThread
->inState
= inState
->nvmState
;
414 inState
->threads
[threadIndex
].nvmThread
= newThread
;
417 return SJME_JNI_TRUE
;
420 sjme_jboolean
sjme_mock_doRomLibrary(
421 sjme_attrInNotNull sjme_mock
* inState
,
422 sjme_attrInNotNull sjme_mock_configWorkData
* inData
)
424 sjme_jint libraryIndex
;
425 sjme_rom_libraryBase
* library
;
426 sjme_mock_configDataRomLibrary
* data
;
427 sjme_rom_libraryFunctions
* functions
;
429 if (inState
== NULL
|| inData
== NULL
)
430 return sjme_die("Null arguments.");
432 /* Index of the resultant library. */
433 libraryIndex
= inState
->numRomLibraries
;
434 if (libraryIndex
>= SJME_MOCK_MAX_ROM_LIBRARIES
)
435 return sjme_die("Too many libraries.");
437 /* Allocate library. */
439 if (sjme_error_is(sjme_alloc(inState
->allocPool
,
440 sizeof(*library
), (void**)&library
)) ||
442 return sjme_die("Could not allocate library.");
444 /* Make a copy of the input data to be used as front end specific data. */
445 library
->cache
.common
.frontEnd
.data
= NULL
;
446 if (sjme_error_is(sjme_alloc_copy(inState
->allocPool
,
447 sizeof(inData
->current
.data
.romLibrary
),
448 &library
->cache
.common
.frontEnd
.data
,
449 &inData
->current
.data
.romLibrary
)) ||
450 library
->cache
.common
.frontEnd
.data
== NULL
)
451 return sjme_die("Could not copy data.");
453 /* Make sure the pool is set, otherwise other functions will not work. */
454 library
->cache
.common
.allocPool
= inState
->allocPool
;
456 /* Use the copied data instead. */
457 data
= library
->cache
.common
.frontEnd
.data
;
459 /* Setup baseline mock functions, if none are set for some. */
460 library
->functions
= &data
->functions
;
461 functions
= &data
->functions
;
463 /* Generic raw data access? */
464 if (functions
->rawData
== NULL
|| functions
->rawSize
== NULL
)
466 functions
->rawData
= sjme_mock_defaultRomLibraryRawData
;
467 functions
->rawSize
= sjme_mock_defaultRomLibraryRawSize
;
470 /* ID of the library. */
472 library
->id
= data
->id
;
474 library
->id
= inData
->current
.indexType
+ 1;
476 /* Name of the library. */
477 if (data
->name
!= NULL
)
478 library
->name
= data
->name
;
481 if (sjme_error_is(sjme_alloc_format(inState
->allocPool
,
482 (sjme_lpstr
*)&library
->name
,
483 "unnamed%d.jar", (int)(inData
->current
.indexType
+ 1))) ||
484 library
->name
== NULL
)
485 return sjme_die("Could not set default library name.");
488 /* Store in mock data. */
489 inState
->romLibraries
[inState
->numRomLibraries
++] = library
;
492 return SJME_JNI_TRUE
;
495 sjme_jboolean
sjme_mock_doRomMockLibrary(
496 sjme_attrInNotNull sjme_mock
* inState
,
497 sjme_attrInNotNull sjme_mock_configWorkData
* inData
)
499 sjme_errorCode error
;
500 sjme_jint libraryIndex
;
501 sjme_mock_configDataRomLibrary
* data
;
503 sjme_rom_library result
;
505 if (inState
== NULL
|| inData
== NULL
)
506 return sjme_die("Null arguments.");
508 /* Is this a JAR or not? */
509 isJar
= inData
->current
.data
.romMockLibrary
.isJar
;
511 /* Using an actual JAR file? Just open an actual library. */
514 /* Index of the resultant library. */
515 libraryIndex
= inState
->numRomLibraries
;
516 if (libraryIndex
>= SJME_MOCK_MAX_ROM_LIBRARIES
)
517 return sjme_die("Too many libraries.");
521 if (sjme_error_is(error
= sjme_rom_libraryFromZipMemory(
522 inState
->allocPool
, &result
, "mock.jar",
523 mock_jar__bin
, mock_jar__len
)) || result
== NULL
)
524 return sjme_die("Could not open library: %d", error
);
527 inState
->romLibraries
[inState
->numRomLibraries
++] = result
;
530 return SJME_JNI_TRUE
;
533 /* Synthetic resource access. */
536 /* Clear existing settings. */
537 data
= &inData
->current
.data
.romLibrary
;
538 memset(data
, 0, sizeof(*data
));
540 /* Setup aliased mock library. */
541 data
->name
= "mock.jar";
543 data
->functions
.resourceStream
=
544 sjme_mock_defaultRomMockLibraryResourceStream
;
546 /* This is just an alias so call the other accordingly. */
547 return sjme_mock_doRomLibrary(inState
, inData
);
551 sjme_jboolean
sjme_mock_doRomSuite(
552 sjme_attrInNotNull sjme_mock
* inState
,
553 sjme_attrInNotNull sjme_mock_configWorkData
* inData
)
555 sjme_jint suiteIndex
;
556 sjme_rom_suite suite
;
557 sjme_rom_suiteFunctions
* writeFunctions
;
558 sjme_mock_configDataRomSuite
* suiteData
;
560 if (inState
== NULL
|| inData
== NULL
)
561 return sjme_die("Null arguments.");
563 /* Too many suites declared already? */
564 suiteIndex
= inState
->numRomSuites
;
565 if (suiteIndex
>= SJME_MOCK_MAX_ROM_SUITES
)
566 return sjme_die("Too many ROM suites.");
568 /* Allocate suite. */
570 if (sjme_error_is(sjme_alloc(inState
->allocPool
,
571 sizeof(*suite
), (void**)&suite
)) || suite
== NULL
)
572 return sjme_die("Could not allocate suite.");
574 /* Quicker this way... */
575 suiteData
= &inData
->current
.data
.romSuite
;
577 /* Seed front end data. */
578 suite
->cache
.common
.frontEnd
.data
= inState
;
580 /* Copy suite functions. */
581 suite
->functions
= NULL
;
582 if (sjme_error_is(sjme_alloc_copy(inState
->allocPool
,
583 sizeof(*suite
->functions
),
584 (void**)&suite
->functions
,
585 &suiteData
->functions
)) ||
586 suite
->functions
== NULL
)
587 return sjme_die("Could not copy functions.");
589 /* Set front end to the test state. */
590 writeFunctions
= (sjme_rom_suiteFunctions
*)suite
->functions
;
592 /* If there is no cache init, just initialize it to something... */
593 if (writeFunctions
->init
== NULL
)
594 memset(&suite
->cache
, 0, sizeof(suite
->cache
));
596 /* Otherwise call the initializer. */
599 if (sjme_error_is(writeFunctions
->init(
601 return sjme_die("Could not initialize suite via cache init.");
604 /* Set the allocation pool to use if not set. */
605 if (suite
->cache
.common
.allocPool
== NULL
)
606 suite
->cache
.common
.allocPool
= inState
->allocPool
;
608 /* Is there a pre-cache used for libraries? */
609 if (suiteData
->cacheLibraries
!= NULL
)
610 suite
->cache
.libraries
= suiteData
->cacheLibraries
;
612 /* Place finalized suite down. */
613 inState
->romSuites
[inState
->numRomSuites
] = suite
;
616 return SJME_JNI_TRUE
;