Coverage Report

Created: 2025-12-14 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/tools/xst262.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2025  Moddable Tech, Inc.
3
 *
4
 *   This file is part of the Moddable SDK Tools.
5
 * 
6
 *   The Moddable SDK Tools is free software: you can redistribute it and/or modify
7
 *   it under the terms of the GNU General Public License as published by
8
 *   the Free Software Foundation, either version 3 of the License, or
9
 *   (at your option) any later version.
10
 * 
11
 *   The Moddable SDK Tools is distributed in the hope that it will be useful,
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *   GNU General Public License for more details.
15
 * 
16
 *   You should have received a copy of the GNU General Public License
17
 *   along with the Moddable SDK Tools.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 */
20
21
#include "xsAll.h"
22
#include "xsScript.h"
23
#include "xs.h"
24
#include "yaml.h"
25
26
extern void fxBuildAgent(xsMachine* the);
27
extern txScript* fxLoadScript(txMachine* the, txString path, txUnsigned flags);
28
extern void fxFulfillModuleFile(txMachine* the);
29
extern void fxRejectModuleFile(txMachine* the);
30
extern void fxRunLoop(txMachine* the);
31
extern void fxRunModuleFile(txMachine* the, txString path);
32
extern void fxRunProgramFile(txMachine* the, txString path, txUnsigned flags);
33
extern int main262(int argc, char* argv[]);
34
35
#ifdef mxMultipleThreads
36
  #define mxPoolSize 3
37
#else
38
0
  #define mxPoolSize 1
39
#endif
40
41
typedef struct sxContext txContext;
42
typedef struct sxFeature txFeature;
43
typedef struct sxPool txPool;
44
typedef struct sxResult txResult;
45
46
struct sxContext {
47
  txContext* next;
48
  txResult* result;
49
  yaml_document_t* document;
50
  yaml_node_t* includes;
51
  yaml_node_t* negative;
52
  char path[1];
53
};
54
55
struct sxFeature {
56
  txFeature* next;
57
  int count;
58
  char name[1];
59
};
60
61
enum {
62
  XST_NO_FLAG = 0,
63
  XST_LOCKDOWN_FLAG = 1,
64
  XST_COMPARTMENT_FLAG = 2,
65
  XST_REPORT_FLAG = 4,
66
  XST_TRACE_FLAG = 8,
67
};
68
69
struct sxPool {
70
  txContext* firstContext;
71
  txFeature* firstFeature;
72
  txUnsigned flags;
73
  txInteger count;
74
  txCondition countCondition;
75
  txMutex countMutex;
76
  txResult* current;
77
  txMutex resultMutex;
78
#if mxWindows
79
  HANDLE threads[mxPoolSize];
80
#else
81
  pthread_t threads[mxPoolSize];
82
#endif
83
  char harnessPath[C_PATH_MAX];
84
  int testPathLength;
85
};
86
87
struct sxResult {
88
  txResult* next;
89
  txResult* parent;
90
  txResult* first;
91
  union {
92
    struct {
93
      int flag;
94
      int count;
95
      int offset;
96
    } file;
97
    struct {
98
      int testCount;
99
      int successCount;
100
      int pendingCount;
101
    } folder;
102
  };
103
  char path[1];
104
};
105
106
static void fx_agent_stop(xsMachine* the);
107
static void fx_done(xsMachine* the);
108
109
static void fxCheckEvent(yaml_event_t* event, yaml_event_type_t type, char* value);
110
static void fxCompareResults(txResult* input, txResult* output);
111
static void fxCountResult(txPool* pool, txContext* context, int success, int pending, char* message);
112
static void fxDefaultFeatures(txPool* pool);
113
static int fxFilterResult(txResult* result);
114
static void fxFreeFeatures(txPool* pool);
115
static void fxFreeResult(txResult* result);
116
static void fxFreeResults(txPool* pool);
117
static yaml_node_t *fxGetMappingValue(yaml_document_t* document, yaml_node_t* mapping, char* name);
118
static txFeature* fxNewFeature(char* name);
119
static txResult* fxNewResult(char* path, char* message);
120
static void fxPopResult(txPool* pool);
121
static void fxPrintBusy(txPool* pool);
122
static void fxPrintClear(txPool* pool);
123
static void fxPrintFailure(txResult* output);
124
static void fxPrintFeatures(txPool* pool);
125
static void fxPrintPath(txResult* result);
126
static void fxPrintResult(txPool* pool, txResult* result, int c);
127
static void fxPrintSuccess(txResult* input);
128
static void fxPushResult(txPool* pool, char* path);
129
static txResult* fxReadConfiguration(txPool* pool, char* path);
130
static txResult* fxReadResult(yaml_parser_t* parser, char* path);
131
static void fxRunDirectory(txPool* pool, char* path);
132
static void fxRunFile(txPool* pool, char* path);
133
#if mxWindows
134
static unsigned int __stdcall fxRunFileThread(void* it);
135
#else
136
static void* fxRunFileThread(void* it);
137
#endif
138
static void fxRunContext(txPool* pool, txContext* context);
139
static int fxRunTestCase(txPool* pool, txContext* context, char* path, txUnsigned flags, int async, char* message);
140
static int fxStringEndsWith(const char *string, const char *suffix);
141
static void fxWriteConfiguration(txPool* pool, char* path);
142
static void fxWriteResult(FILE* file, txResult* result, int c);
143
144
static void fxBuildCompartmentGlobals(txMachine* the);
145
static void fxLoadHook(txMachine* the);
146
static void fxRunProgramFileInCompartment(txMachine* the, txString path, txUnsigned flags);
147
static void fxRunModuleFileInCompartment(txMachine* the, txString path);
148
149
0
#define mxFeaturesCount 13
150
static char* gxFeatures[mxFeaturesCount] = { 
151
  "Array.fromAsync",
152
  "Atomics.pause",
153
  "FinalizationRegistry.prototype.cleanupSome",
154
  "Math.sumPrecise",
155
  "ShadowRealm",
156
  "Temporal",
157
  "arbitrary-module-namespace-names",
158
  "decorators",
159
  "import-assertions",
160
  "iterator-sequencing",
161
  "json-parse-with-source",
162
  "source-phase-imports",
163
  "source-phase-imports-module-source"
164
};
165
166
int main262(int argc, char* argv[]) 
167
0
{
168
0
  txPool _pool;
169
0
  txPool* pool = &_pool;
170
0
  char separator[2];
171
0
  char path[C_PATH_MAX];
172
0
  char inputPath[C_PATH_MAX] = "";
173
0
  char outputPath[C_PATH_MAX] = "";
174
0
  int error = 0;
175
0
  int argi = 1;
176
0
  int argj = 0;
177
0
  c_timeval from;
178
0
  c_timeval to;
179
0
  txResult* input = NULL;
180
181
0
  c_memset(pool, 0, sizeof(txPool));
182
0
  fxCreateCondition(&(pool->countCondition));
183
0
  fxCreateMutex(&(pool->countMutex));
184
0
  fxCreateMutex(&(pool->resultMutex));
185
0
  {
186
  #if mxWindows
187
  #elif mxMacOSX
188
    pthread_attr_t attr; 
189
    pthread_t self = pthread_self();
190
      size_t size = pthread_get_stacksize_np(self);
191
      pthread_attr_init(&attr);
192
      pthread_attr_setstacksize(&attr, size);
193
  #elif mxLinux
194
  #endif  
195
0
    for (argi = 0; argi < mxPoolSize; argi++) {
196
    #if mxWindows
197
      pool->threads[argi] = (HANDLE)_beginthreadex(NULL, 0, fxRunFileThread, pool, 0, NULL);
198
    #elif mxMacOSX
199
      pthread_create(&(pool->threads[argi]), &attr, &fxRunFileThread, pool);
200
    #else
201
0
      pthread_create(&(pool->threads[argi]), NULL, &fxRunFileThread, pool);
202
0
    #endif
203
0
    }
204
0
  }
205
0
  fxDefaultFeatures(pool);
206
  
207
0
  fxInitializeSharedCluster(C_NULL);
208
209
0
  separator[0] = mxSeparator;
210
0
  separator[1] = 0;
211
0
  c_strcpy(path, "..");
212
0
  c_strcat(path, separator);
213
0
  c_strcat(path, "harness");
214
0
  if (!c_realpath(path, pool->harnessPath)) {
215
0
    fprintf(stderr, "### directory not found: %s\n", path);
216
0
    return 1;
217
0
  }
218
0
  c_strcat(pool->harnessPath, separator);
219
0
  if (!c_realpath(".", path)) {
220
0
    fprintf(stderr, "### directory not found: .\n");
221
0
    return 1;
222
0
  }
223
0
  c_strcat(path, separator);
224
0
  pool->testPathLength = mxStringLength(path);
225
0
  pool->current = NULL;
226
0
  fxPushResult(pool, "");
227
  
228
0
  c_gettimeofday(&from, NULL);
229
0
  for (argi = 1; argi < argc; argi++) {
230
0
    if (!strcmp(argv[argi], "-c")) {
231
      // reserved
232
0
    }
233
0
    else if (!strcmp(argv[argi], "-i")) {
234
0
      argi++;
235
0
      if (argi < argc) {
236
0
        if (!c_realpath(argv[argi], inputPath)) {
237
0
          fprintf(stderr, "### input not found: %s\n", argv[argi]);
238
0
          return 1;
239
0
        }
240
0
        input = fxReadConfiguration(pool, inputPath);
241
0
      }
242
0
      else {
243
0
        fprintf(stderr, "### no input path\n");
244
0
        return 1;
245
0
      }
246
0
    }
247
0
    else if (!strcmp(argv[argi], "-o")) {
248
0
      argi++;
249
0
      if (argi < argc) {
250
0
        char* slash;
251
0
        c_strcpy(path, argv[argi]);
252
0
        slash = c_strrchr(path, mxSeparator);
253
0
        if (slash) {
254
0
          *slash = 0;
255
0
          if (!c_realpath(path, outputPath)) {
256
0
            fprintf(stderr, "### output not found: %s\n", path);
257
0
            return 1;
258
0
          }
259
0
          *slash = mxSeparator;
260
0
          c_strcat(outputPath, slash);
261
0
        }
262
0
        else
263
0
          c_strcpy(outputPath, path);
264
0
      }
265
0
      else {
266
0
        fprintf(stderr, "### no output path\n");
267
0
        return 1;
268
0
      }
269
0
    }
270
0
    else if (!strcmp(argv[argi], "-l"))
271
0
      pool->flags |= XST_LOCKDOWN_FLAG;
272
0
    else if (!strcmp(argv[argi], "-lc"))
273
0
      pool->flags |= XST_LOCKDOWN_FLAG | XST_COMPARTMENT_FLAG;
274
0
    else if (!strcmp(argv[argi], "-t")) {
275
      #ifdef mxMultipleThreads
276
        pool->flags |= XST_REPORT_FLAG;
277
      #else
278
0
        pool->flags |= XST_TRACE_FLAG;
279
0
      #endif
280
0
    }
281
0
  }
282
0
  if (input) {
283
0
    txResult* result = input->first;
284
0
    while (result) {
285
0
      if (c_realpath(result->path, path)) {
286
0
        argj++;
287
0
        fxPushResult(pool, path + pool->testPathLength);
288
0
        fxRunDirectory(pool, path);
289
0
        fxPopResult(pool);
290
0
      }
291
0
      result = result->next;
292
0
    }
293
0
  }
294
0
  else {
295
0
    for (argi = 1; argi < argc; argi++) {
296
0
      if (!strcmp(argv[argi], "-i")) {
297
0
        argi++;
298
0
        continue;
299
0
      }
300
0
      if (!strcmp(argv[argi], "-o")) {
301
0
        argi++;
302
0
        continue;
303
0
      }
304
0
      if (argv[argi][0] == '-')
305
0
        continue;
306
0
      if (c_realpath(argv[argi], path)) {
307
0
        argj++;
308
#if mxWindows
309
        DWORD attributes = GetFileAttributes(path);
310
        if (attributes != 0xFFFFFFFF) {
311
          if (attributes & FILE_ATTRIBUTE_DIRECTORY) {
312
#else   
313
0
        struct stat a_stat;
314
0
        if (stat(path, &a_stat) == 0) {
315
0
          if (S_ISDIR(a_stat.st_mode)) {
316
0
#endif
317
0
            fxPushResult(pool, path + pool->testPathLength);
318
0
            fxRunDirectory(pool, path);
319
0
            fxPopResult(pool);
320
0
          }
321
0
          else if (fxStringEndsWith(path, ".js") && !fxStringEndsWith(path, "_FIXTURE.js"))
322
0
            fxRunFile(pool, path);
323
0
        }
324
0
      }
325
0
      else {
326
0
        fprintf(stderr, "### test not found: %s\n", argv[argi]);
327
0
        error = 1;
328
0
      }
329
0
    }
330
0
  }
331
  
332
0
    fxLockMutex(&(pool->countMutex));
333
0
    while (pool->count > 0)
334
0
    fxSleepCondition(&(pool->countCondition), &(pool->countMutex));
335
0
  pool->count = -1;
336
0
  fxWakeAllCondition(&(pool->countCondition));
337
0
    fxUnlockMutex(&(pool->countMutex));
338
0
  for (argi = 0; argi < mxPoolSize; argi++) {
339
  #if mxWindows
340
    WaitForSingleObject(pool->threads[argi], INFINITE);
341
    CloseHandle(pool->threads[argi]);
342
  #else
343
0
    pthread_join(pool->threads[argi], NULL);
344
0
  #endif
345
0
  }
346
  
347
0
  c_gettimeofday(&to, NULL);
348
0
  fxTerminateSharedCluster(C_NULL);
349
  
350
0
  int seconds = to.tv_sec - from.tv_sec;
351
0
  int minutes = seconds / 60;
352
0
  int hours = minutes / 60;
353
0
  if (!(pool->flags & XST_TRACE_FLAG))
354
0
    fxPrintClear(pool);
355
0
  fprintf(stderr, "# %d:%.2d:%.2d\n", hours, minutes % 60, seconds % 60);
356
  
357
0
  if (input) {
358
0
    fxFilterResult(pool->current);
359
0
    fxCompareResults(input, pool->current);
360
0
  }
361
0
  else if (argj) {
362
0
    txResult* result = pool->current;
363
0
    if (pool->flags & (XST_REPORT_FLAG | XST_TRACE_FLAG)) {
364
0
      if (result->folder.testCount) {
365
0
        int value = (10000 * result->folder.successCount) / result->folder.testCount;
366
0
        fprintf(stderr, "# %d.%.2d%%", value / 100, value % 100);
367
0
        if (result->folder.pendingCount) {
368
0
          if (result->folder.successCount + result->folder.pendingCount == result->folder.testCount)
369
0
            value = 10000 - value;
370
0
          else
371
0
            value = (10000 * result->folder.pendingCount) / result->folder.testCount;
372
0
          fprintf(stderr, " (%d.%.2d%%)", value / 100, value % 100);
373
          
374
0
          value = (10000 * result->folder.successCount) / (result->folder.testCount - result->folder.pendingCount);
375
0
          fprintf(stderr, " [%d.%.2d%%]", value / 100, value % 100);
376
0
        }
377
0
      }
378
0
      else
379
0
        fprintf(stderr, "# 0.00%%");
380
0
      fxPrintResult(pool, result, 0);
381
0
      fxPrintFeatures(pool);
382
0
    }
383
0
    if (!(pool->flags & XST_TRACE_FLAG))
384
0
      fxPrintFailure(pool->current);
385
0
    if (*outputPath)
386
0
      fxWriteConfiguration(pool, outputPath);
387
0
  }
388
0
  fxFreeResults(pool);
389
0
  fxFreeFeatures(pool);
390
0
  return error;
391
0
}
392
393
void fx_agent_stop(xsMachine* the)
394
0
{
395
0
  txAgentCluster* agentCluster = &gxAgentCluster;
396
0
  txAgent* agent = agentCluster->firstAgent;
397
0
  if (agent) {
398
0
    while (agent) {
399
0
      txAgent* next = agent->next;
400
0
      if (agent->thread) {
401
        #if mxWindows
402
          WaitForSingleObject(agent->thread, INFINITE);
403
          CloseHandle(agent->thread);
404
        #else
405
0
          pthread_join(agent->thread, NULL);
406
0
        #endif
407
0
      }
408
0
      c_free(agent);
409
0
      agent = next;
410
0
    }
411
0
    if (agentCluster->dataBuffer)
412
0
      c_free(agentCluster->dataBuffer);
413
0
    agentCluster->firstAgent = C_NULL;
414
0
    agentCluster->lastAgent = C_NULL;
415
0
    agentCluster->count = 0;
416
0
    agentCluster->dataBuffer = C_NULL;
417
0
    agentCluster->dataValue = 0;
418
0
    agentCluster->firstReport = C_NULL;
419
0
    agentCluster->lastReport = C_NULL;
420
0
  }
421
0
}
422
423
void fx_done(xsMachine* the)
424
0
{
425
0
  if ((xsToInteger(xsArgc) > 0) && (xsTest(xsArg(0))))
426
0
    *((txSlot*)the->rejection) = xsArg(0);
427
0
  else
428
0
    *((txSlot*)the->rejection) = xsUndefined;
429
0
}
430
431
void fxCheckEvent(yaml_event_t* event, yaml_event_type_t type, char* value)
432
0
{
433
0
  if (event->type != type) {
434
0
    fprintf(stderr, "### invalid yaml type\n");
435
0
    c_exit(1);
436
0
  }
437
0
  if (value) {
438
0
    if (c_strcmp((char*)event->data.scalar.value, value) ){
439
0
      fprintf(stderr, "### invalid yaml: %s instead of %s\n", (char*)event->data.scalar.value, value);
440
0
      c_exit(1);
441
0
    }
442
0
  }
443
0
}
444
445
void fxCompareResults(txResult* input, txResult* output)
446
0
{
447
0
  if (input->file.flag < 0) {
448
0
    return;
449
0
  }
450
0
  input = input->first;
451
0
  output = output->first;
452
0
  while (input && output) {
453
0
    int comparison = c_strcmp(input->path, output->path);
454
0
    if (comparison < 0) {
455
0
      fxPrintSuccess(input);
456
0
      input = input->next;
457
0
    }
458
0
    else if (comparison > 0) {
459
0
      fxPrintFailure(output);
460
0
      output = output->next;
461
0
    }
462
0
    else {
463
0
      fxCompareResults(input, output);
464
0
      input = input->next;
465
0
      output = output->next;
466
0
    }
467
0
  }
468
0
  while (input) {
469
0
    fxPrintSuccess(input);
470
0
    input = input->next;
471
0
  }
472
0
  while (output) {
473
0
    fxPrintFailure(output);
474
0
    output = output->next;
475
0
  }
476
0
}
477
478
void fxCountResult(txPool* pool, txContext* context, int success, int pending, char* message) 
479
0
{
480
0
  txResult* result = context->result;
481
0
  fxLockMutex(&(pool->resultMutex));
482
0
  if (!success && !pending) {
483
0
    char* name = c_strrchr(context->path, mxSeparator) + 1;
484
0
    txResult* former = C_NULL;
485
0
    txResult* current = result->first;
486
0
    int comparison = 1;
487
0
    while (current) {
488
0
      comparison = c_strcmp(current->path, name);
489
0
      if (comparison >= 0)
490
0
        break;
491
0
      comparison = 1;
492
0
      former = current;
493
0
      current = current->next;
494
0
    }
495
0
    if (comparison > 0) {
496
0
      txResult* failure = fxNewResult(name, message + 2);
497
0
      failure->next = current;
498
0
      failure->parent = result;
499
0
      failure->file.count = 1;
500
0
      if (former)
501
0
        former->next = failure;
502
0
      else
503
0
        result->first = failure;
504
0
    }
505
0
    else if (comparison == 0)
506
0
      current->file.count++;
507
0
  }
508
0
  while (result) {
509
0
    result->folder.testCount++;
510
0
    result->folder.successCount += success;
511
0
    result->folder.pendingCount += pending;
512
0
    result = result->parent;
513
0
  }
514
0
  fxUnlockMutex(&(pool->resultMutex));
515
0
}
516
517
void fxDefaultFeatures(txPool* pool)
518
0
{
519
0
  txFeature** address = &(pool->firstFeature);
520
0
  int i;
521
0
  for (i = 0; i < mxFeaturesCount; i++) {
522
0
    txFeature* feature = fxNewFeature(gxFeatures[i]);
523
0
    *address = feature;
524
0
    address = &(feature->next);
525
0
  }
526
0
}
527
528
int fxFilterResult(txResult* result)
529
0
{
530
0
  txResult** address = &(result->first);
531
0
  int flag = 0;
532
0
  if (result->file.flag < 0) 
533
0
    return 1;
534
0
  while ((result = *address)) {
535
0
    if (fxFilterResult(result)) {
536
0
      address = &(result->next);
537
0
      flag = 1;
538
0
    }
539
0
    else {
540
0
      *address = result->next;
541
0
      c_free(result);
542
0
    }
543
0
  }
544
0
  return flag;
545
0
}
546
547
void fxFreeFeatures(txPool* pool)
548
0
{
549
0
  txFeature** address = &(pool->firstFeature);
550
0
  txFeature* feature;
551
0
  while ((feature = *address)) {
552
0
    *address = feature->next;
553
0
    c_free(feature);
554
0
  }
555
0
}
556
557
void fxFreeResult(txResult* result)
558
0
{
559
0
  txResult** address = &(result->first);
560
0
  while ((result = *address)) {
561
0
    fxFreeResult(result);
562
0
    *address = result->next;
563
0
    c_free(result);
564
0
  }
565
0
}
566
567
void fxFreeResults(txPool* pool)
568
0
{
569
0
  txResult** address = &(pool->current);
570
0
  txResult* result;
571
0
  while ((result = *address)) {
572
0
    fxFreeResult(result);
573
0
    *address = result->next;
574
0
    c_free(result);
575
0
  }
576
0
}
577
578
static void fxFreeResult(txResult* result);
579
static void fxFreeResults(txPool* pool);
580
581
yaml_node_t *fxGetMappingValue(yaml_document_t* document, yaml_node_t* mapping, char* name)
582
0
{
583
0
  yaml_node_pair_t* pair = mapping->data.mapping.pairs.start;
584
0
  while (pair < mapping->data.mapping.pairs.top) {
585
0
    yaml_node_t* key = yaml_document_get_node(document, pair->key);
586
0
    if (!strcmp((char*)key->data.scalar.value, name)) {
587
0
      return yaml_document_get_node(document, pair->value);
588
0
    }
589
0
    pair++;
590
0
  }
591
0
  return NULL;
592
0
}
593
594
txFeature* fxNewFeature(char* name)
595
0
{
596
0
  int nameLength = mxStringLength(name);
597
0
  txFeature* feature = c_malloc(sizeof(txFeature) + nameLength);
598
0
  if (!feature) {
599
0
    c_exit(1);
600
0
  }
601
0
  feature->next = NULL;
602
0
  feature->count = 0;
603
0
  c_memcpy(feature->name, name, nameLength + 1);
604
0
  return feature;
605
0
}
606
607
txResult* fxNewResult(char* path, char* message)
608
0
{
609
0
  int pathLength = mxStringLength(path);
610
0
  txResult* result = NULL;
611
0
  if (message) {
612
0
      int messageLength = mxStringLength(message);
613
0
    result = c_malloc(sizeof(txResult) + pathLength + 1 + messageLength);
614
0
    if (!result) {
615
0
      c_exit(1);
616
0
    }
617
0
    result->next = NULL;
618
0
    result->parent = NULL;
619
0
    result->first = NULL;
620
0
    result->file.flag = -1;
621
0
    result->file.count = 0;
622
0
    result->file.offset = pathLength + 1;
623
0
      c_memcpy(result->path, path, pathLength + 1);
624
0
      c_memcpy(result->path + pathLength + 1, message, messageLength + 1);
625
0
  }
626
0
  else {
627
0
    result = c_malloc(sizeof(txResult) + pathLength);
628
0
    if (!result) {
629
0
      c_exit(1);
630
0
    }
631
0
    result->next = NULL;
632
0
    result->parent = NULL;
633
0
    result->first = NULL;
634
0
    result->folder.testCount = 0;
635
0
    result->folder.successCount = 0;
636
0
    result->folder.pendingCount = 0;
637
0
      c_memcpy(result->path, path, pathLength + 1);
638
0
  }
639
0
  return result;
640
0
}
641
642
void fxPopResult(txPool* pool) 
643
0
{
644
0
  pool->current = pool->current->parent;
645
0
}
646
647
void fxPushResult(txPool* pool, char* path) 
648
0
{
649
0
  txResult* parent = pool->current;
650
0
  txResult* result = fxNewResult(path, NULL);
651
0
  result->parent = parent;
652
0
  if (parent) {
653
0
    fxLockMutex(&(pool->resultMutex));
654
0
    txResult* former = C_NULL;
655
0
    txResult* current = parent->first;
656
0
    while (current) {
657
0
      if (c_strcmp(current->path, path) >= 0)
658
0
        break;
659
0
      former = current;
660
0
      current = current->next;
661
0
    }
662
0
    if (former)
663
0
      former->next = result;
664
0
    else
665
0
      parent->first = result;
666
0
    result->next = current;
667
0
    fxUnlockMutex(&(pool->resultMutex));
668
0
  }
669
0
  pool->current = result;
670
0
}
671
672
static int c = 0;
673
674
void fxPrintBusy(txPool* pool)
675
0
{
676
0
  fprintf(stderr, "\b\b\b\b\b\b\b\b# %6.6d", c++);  
677
0
}
678
679
void fxPrintClear(txPool* pool)
680
0
{
681
0
  fprintf(stderr, "\b\b\b\b\b\b\b\b");
682
0
  c++;
683
0
}
684
685
void fxPrintFailure(txResult* output)
686
0
{
687
0
  if (output->file.flag < 0) {
688
0
    fxPrintPath(output);
689
0
    fprintf(stderr, ": %s\n", output->path + output->file.offset);
690
0
  }
691
0
  else {
692
0
    output = output->first;
693
0
    while (output) {
694
0
      fxPrintFailure(output);
695
0
      output = output->next;
696
0
    }
697
0
  }
698
0
}
699
700
void fxPrintFeatures(txPool* pool)
701
0
{
702
0
  txFeature* feature = pool->firstFeature;
703
0
  while (feature) {
704
0
    if (feature->count)
705
0
      fprintf(stderr, "- %s (%d)\n", feature->name, feature->count);
706
0
    feature = feature->next;
707
0
  }
708
0
}
709
710
void fxPrintPath(txResult* result)
711
0
{
712
0
  if (result->parent && (result->parent->path[0])) {
713
0
    fxPrintPath(result->parent);
714
0
    fprintf(stderr, "/");
715
0
  }
716
0
  else
717
0
    fprintf(stderr, "### ");
718
0
  fprintf(stderr, "%s", result->path);
719
0
}
720
721
void fxPrintResult(txPool* pool, txResult* result, int c)
722
0
{
723
0
  if (result->file.flag >= 0) {
724
0
    int i = 0;
725
0
    while (i < c) {
726
0
      fprintf(stderr, "    ");
727
0
      i++;
728
0
    }
729
0
    fprintf(stderr, " %d/%d", result->folder.successCount, result->folder.testCount);
730
0
    if (result->folder.pendingCount)
731
0
      fprintf(stderr, " (%d)", result->folder.pendingCount);
732
0
    fprintf(stderr, " %s\n", result->path);
733
0
    c++;
734
0
    result = result->first;
735
0
    while (result) {
736
0
      fxPrintResult(pool, result, c);
737
0
      result = result->next;
738
0
    }
739
0
  }
740
0
}
741
742
void fxPrintSuccess(txResult* input)
743
0
{
744
0
  if (input->file.flag < 0) {
745
0
    fxPrintPath(input);
746
0
    fprintf(stderr, ": OK\n");
747
0
  }
748
0
  else {
749
0
    input = input->first;
750
0
    while (input) {
751
0
      fxPrintSuccess(input);
752
0
      input = input->next;
753
0
    }
754
0
  }
755
0
}
756
757
txResult* fxReadConfiguration(txPool* pool, char* path)
758
0
{
759
0
  txFeature** address = &(pool->firstFeature);
760
0
  txFeature* feature = NULL;
761
0
  txResult* result = NULL;
762
  
763
0
  FILE* input = fopen(path, "r");
764
0
  if (!input) {
765
0
    fprintf(stderr, "### cannot open: %s\n", path);
766
0
    c_exit(1);
767
0
  }
768
0
  yaml_parser_t _parser;
769
0
  yaml_parser_t* parser = NULL;
770
0
  yaml_event_t _event;
771
0
  yaml_event_t* event = &_event;
772
0
  if (!yaml_parser_initialize(&_parser)) goto bail;
773
0
  parser = &_parser;
774
0
  yaml_parser_set_input_file(parser, input);
775
0
  yaml_parser_parse(parser, event);
776
0
  yaml_event_delete(event);
777
0
  yaml_parser_parse(parser, event);
778
0
  yaml_event_delete(event);
779
  
780
0
  yaml_parser_parse(parser, event); 
781
0
  fxCheckEvent(event, YAML_MAPPING_START_EVENT, NULL);
782
0
  yaml_event_delete(event);
783
  
784
0
  yaml_parser_parse(parser, event);
785
0
  fxCheckEvent(event, YAML_SCALAR_EVENT, "mode");
786
0
  yaml_event_delete(event);
787
0
  yaml_parser_parse(parser, event);
788
0
  fxCheckEvent(event, YAML_SCALAR_EVENT, NULL);
789
0
  if (!c_strcmp((char*)event->data.scalar.value, "lockdown"))
790
0
    pool->flags |= XST_LOCKDOWN_FLAG;
791
0
  else if (!c_strcmp((char*)event->data.scalar.value, "lockdown compartment"))
792
0
    pool->flags |= XST_LOCKDOWN_FLAG | XST_COMPARTMENT_FLAG;
793
0
  else if (c_strcmp((char*)event->data.scalar.value, "default"))
794
0
    fprintf(stderr, "### invalid kind: %s\n", (char*)event->data.scalar.value);
795
0
  yaml_event_delete(event);
796
797
0
  yaml_parser_parse(parser, event);
798
0
  fxCheckEvent(event, YAML_SCALAR_EVENT, "skip");
799
0
  yaml_event_delete(event);
800
0
  yaml_parser_parse(parser, event); 
801
0
  fxCheckEvent(event, YAML_SEQUENCE_START_EVENT, NULL);
802
0
  yaml_event_delete(event);
803
0
  yaml_parser_parse(parser, event);
804
0
  while (event->type != YAML_SEQUENCE_END_EVENT) {
805
0
    fxCheckEvent(event, YAML_SCALAR_EVENT, NULL);
806
0
    *address = feature = fxNewFeature((char*)event->data.scalar.value);
807
0
    address = &(feature->next);
808
0
    yaml_event_delete(event);
809
0
    yaml_parser_parse(parser, event);
810
0
  }
811
0
  yaml_event_delete(event);
812
  
813
0
  yaml_parser_parse(parser, event);
814
0
  fxCheckEvent(event, YAML_SCALAR_EVENT, "fail");
815
0
  yaml_event_delete(event);
816
  
817
0
  result = fxReadResult(parser, "");
818
  
819
0
  yaml_parser_parse(parser, event);
820
0
  fxCheckEvent(event, YAML_MAPPING_END_EVENT, NULL);
821
0
  yaml_event_delete(event);
822
  
823
0
bail:
824
0
  if (parser)
825
0
    yaml_parser_delete(parser);
826
0
  fclose(input);
827
0
  return result;
828
0
}
829
830
txResult* fxReadResult(yaml_parser_t* parser, char* path)
831
0
{
832
0
  txResult* result = NULL;
833
0
  txResult** address;
834
0
  yaml_event_t _event;
835
0
  yaml_event_t* event = &_event;
836
0
  yaml_parser_parse(parser, event); 
837
0
  if (event->type == YAML_SEQUENCE_START_EVENT) {
838
0
    result = fxNewResult(path, NULL);
839
0
    address = &(result->first);
840
0
    yaml_event_delete(event);
841
0
    yaml_parser_parse(parser, event);
842
0
    while (event->type != YAML_SEQUENCE_END_EVENT) {
843
0
      txResult* child;
844
0
      fxCheckEvent(event, YAML_MAPPING_START_EVENT, NULL);
845
0
      yaml_event_delete(event);
846
0
      yaml_parser_parse(parser, event);
847
0
      fxCheckEvent(event, YAML_SCALAR_EVENT, NULL);
848
0
      *address = child = fxReadResult(parser, (char*)event->data.scalar.value);
849
0
      child->parent = result;
850
0
      address = &(child->next);
851
0
      yaml_event_delete(event);
852
0
      yaml_parser_parse(parser, event);
853
0
      fxCheckEvent(event, YAML_MAPPING_END_EVENT, NULL);
854
0
      yaml_event_delete(event);
855
0
      yaml_parser_parse(parser, event);
856
0
    }
857
0
  }
858
0
  else {
859
0
    fxCheckEvent(event, YAML_SCALAR_EVENT, NULL);
860
0
    if (event->data.scalar.length > 0)
861
0
      result = fxNewResult(path, (char*)event->data.scalar.value);
862
0
    else
863
0
      result = fxNewResult(path, NULL);
864
0
  } 
865
0
  yaml_event_delete(event);
866
0
  return result;
867
0
}
868
869
void fxRunDirectory(txPool* pool, char* path)
870
0
{
871
0
  typedef struct sxEntry txEntry;
872
0
  struct sxEntry {
873
0
    txEntry* nextEntry;
874
0
    char name[1];
875
0
  };
876
877
#if mxWindows
878
  size_t length;
879
  HANDLE findHandle = INVALID_HANDLE_VALUE;
880
  WIN32_FIND_DATA findData;
881
  length = strlen(path);
882
  path[length] = '\\';
883
  length++;
884
  path[length] = '*';
885
  path[length + 1] = 0;
886
  findHandle = FindFirstFile(path, &findData);
887
  if (findHandle != INVALID_HANDLE_VALUE) {
888
    txEntry* entry;
889
    txEntry* firstEntry = NULL;
890
    txEntry* nextEntry;
891
    txEntry** address;
892
    do {
893
      if ((findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ||
894
        !strcmp(findData.cFileName, ".") ||
895
        !strcmp(findData.cFileName, ".."))
896
        continue;
897
      entry = malloc(sizeof(txEntry) + strlen(findData.cFileName));
898
      if (!entry)
899
        break;
900
      strcpy(entry->name, findData.cFileName);
901
      address = &firstEntry;
902
      while ((nextEntry = *address)) {
903
        if (strcmp(entry->name, nextEntry->name) < 0)
904
          break;
905
        address = &nextEntry->nextEntry;
906
      }
907
      entry->nextEntry = nextEntry;
908
      *address = entry;
909
    } while (FindNextFile(findHandle, &findData));
910
    FindClose(findHandle);
911
    while (firstEntry) {
912
      DWORD attributes;
913
      strcpy(path + length, firstEntry->name);
914
      attributes = GetFileAttributes(path);
915
      if (attributes != 0xFFFFFFFF) {
916
        if (attributes & FILE_ATTRIBUTE_DIRECTORY) {
917
          fxPushResult(pool, firstEntry->name);
918
          fxRunDirectory(pool, path);
919
          fxPopResult(pool);
920
        }
921
        else if (fxStringEndsWith(path, ".js") && !fxStringEndsWith(path, "_FIXTURE.js"))
922
          fxRunFile(pool, path);
923
      }
924
      nextEntry = firstEntry->nextEntry;
925
      free(firstEntry);
926
      firstEntry = nextEntry;
927
    }
928
  }
929
#else
930
0
    DIR* dir;
931
0
  int length;
932
0
  dir = opendir(path);
933
0
  length = strlen(path);
934
0
  path[length] = '/';
935
0
  length++;
936
0
  if (dir) {
937
0
    struct dirent *ent;
938
0
    txEntry* entry;
939
0
    txEntry* firstEntry = NULL;
940
0
    txEntry* nextEntry;
941
0
    txEntry** address;
942
0
    while ((ent = readdir(dir))) {
943
0
      if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
944
0
        continue;
945
0
      entry = malloc(sizeof(txEntry) + strlen(ent->d_name));
946
0
      if (!entry)
947
0
        break;
948
0
      strcpy(entry->name, ent->d_name);
949
0
      address = &firstEntry;
950
0
      while ((nextEntry = *address)) {
951
0
        if (strcmp(entry->name, nextEntry->name) < 0)
952
0
          break;
953
0
        address = &nextEntry->nextEntry;
954
0
      }
955
0
      entry->nextEntry = nextEntry;
956
0
      *address = entry;
957
0
    }
958
0
    closedir(dir);
959
0
    while (firstEntry) {
960
0
      struct stat a_stat;
961
0
      strcpy(path + length, firstEntry->name);
962
0
      if (stat(path, &a_stat) == 0) {
963
0
        if (S_ISDIR(a_stat.st_mode)) {
964
0
          fxPushResult(pool, firstEntry->name);
965
0
          fxRunDirectory(pool, path);
966
0
          fxPopResult(pool);
967
0
        }
968
0
        else if (fxStringEndsWith(path, ".js") && !fxStringEndsWith(path, "_FIXTURE.js"))
969
0
          fxRunFile(pool, path);
970
0
      }
971
0
      nextEntry = firstEntry->nextEntry;
972
0
      free(firstEntry);
973
0
      firstEntry = nextEntry;
974
0
    }
975
0
  }
976
0
#endif
977
0
}
978
979
void fxRunFile(txPool* pool, char* path)
980
0
{
981
0
  txContext* context = c_malloc(sizeof(txContext) + c_strlen(path));
982
0
  txContext** address;
983
0
  txContext* former;
984
0
  if (!context) return;
985
0
  c_memset(context, 0, sizeof(txContext));
986
0
  context->result = pool->current;
987
0
  c_strcpy(context->path, path);
988
0
    fxLockMutex(&(pool->countMutex));
989
0
    while (pool->count == mxPoolSize)
990
0
    fxSleepCondition(&(pool->countCondition), &(pool->countMutex));
991
0
  address = &(pool->firstContext);  
992
0
  while ((former = *address))
993
0
    address = &(former->next);
994
0
  *address = context;
995
0
  pool->count++;
996
0
  fxWakeAllCondition(&(pool->countCondition));
997
0
    fxUnlockMutex(&(pool->countMutex));
998
0
}
999
1000
#if mxWindows
1001
unsigned int __stdcall fxRunFileThread(void* it)
1002
#else
1003
void* fxRunFileThread(void* it)
1004
#endif
1005
0
{
1006
0
  txPool* pool = it;
1007
0
  txContext* context;
1008
0
  for (;;) {
1009
0
      fxLockMutex(&(pool->countMutex));
1010
0
      while (pool->count == 0)
1011
0
      fxSleepCondition(&(pool->countCondition), &(pool->countMutex));
1012
0
    if (pool->count > 0) {
1013
0
      context = pool->firstContext;
1014
0
      pool->firstContext = context->next;
1015
0
      pool->count--;
1016
0
      fxWakeAllCondition(&(pool->countCondition));
1017
0
      fxUnlockMutex(&(pool->countMutex));
1018
      
1019
0
      fxRunContext(pool, context);
1020
0
      c_free(context);
1021
0
    }
1022
0
    else if (pool->count < 0) {
1023
0
      fxUnlockMutex(&(pool->countMutex));
1024
0
      break;
1025
0
    }
1026
0
  }
1027
#if mxWindows
1028
  return 0;
1029
#else
1030
0
  return NULL;
1031
0
#endif
1032
0
}
1033
1034
void fxRunContext(txPool* pool, txContext* context)
1035
0
{
1036
0
  txAgentCluster* agentCluster = &gxAgentCluster;
1037
0
  char* path = context->path;
1038
0
  FILE* file = NULL;
1039
0
  size_t size;
1040
0
  char* buffer = NULL;
1041
0
  char* begin;
1042
0
  char* end;
1043
0
  yaml_parser_t _parser;
1044
0
  yaml_parser_t* parser = NULL;
1045
0
  yaml_document_t _document;
1046
0
  yaml_document_t* document = NULL;
1047
0
  yaml_node_t* root;
1048
0
  yaml_node_t* value;
1049
0
  int async = 0;
1050
0
  int atomics = 0;
1051
0
  int sloppy = 1;
1052
0
  int strict = 1;
1053
0
  int module = 0;
1054
0
  int pending = 0;
1055
0
  char message[1024];
1056
  
1057
0
  file = fopen(path, "rb");
1058
0
  if (!file) goto bail;
1059
0
  fseek(file, 0, SEEK_END);
1060
0
  size = ftell(file);
1061
0
  if (!size) goto bail;
1062
0
  fseek(file, 0, SEEK_SET);
1063
0
  buffer = malloc(size + 1);
1064
0
  if (!buffer) goto bail;
1065
0
  if (fread(buffer, 1, size, file) != size) goto bail; 
1066
0
  buffer[size] = 0;
1067
0
  fclose(file);
1068
0
  file = NULL;
1069
  
1070
0
  begin = strstr(buffer, "/*---");
1071
0
  if (!begin) goto bail;
1072
0
  begin += 5;
1073
0
  end = strstr(begin, "---*/");
1074
0
  if (!end) goto bail;
1075
1076
0
  if (!yaml_parser_initialize(&_parser)) goto bail;
1077
0
  parser = &_parser;
1078
0
  yaml_parser_set_input_string(parser, (unsigned char *)begin, end - begin);
1079
0
  if (!yaml_parser_load(parser, &_document)) goto bail;
1080
0
  document = &_document;
1081
0
  root = yaml_document_get_root_node(document);
1082
0
  if (!root) goto bail;
1083
    
1084
0
  context->document = document;
1085
0
  context->includes = fxGetMappingValue(document, root, "includes");
1086
0
  value = fxGetMappingValue(document, root, "negative");
1087
0
  if (value)
1088
0
    context->negative = fxGetMappingValue(document, value, "type");
1089
0
  else
1090
0
    context->negative = NULL;
1091
  
1092
0
  value = fxGetMappingValue(document, root, "flags");
1093
0
  if (value) {
1094
0
    yaml_node_item_t* item = value->data.sequence.items.start;
1095
0
    while (item < value->data.sequence.items.top) {
1096
0
      yaml_node_t* node = yaml_document_get_node(document, *item);
1097
0
      if (!strcmp((char*)node->data.scalar.value, "async")) {
1098
0
        async = 1;
1099
0
      }
1100
0
      else if (!strcmp((char*)node->data.scalar.value, "onlyStrict")) {
1101
0
        sloppy = 0;
1102
0
        strict = 1;
1103
0
        module = 0;
1104
0
      }
1105
0
      else if (!strcmp((char*)node->data.scalar.value, "noStrict")) {
1106
0
        sloppy = 1;
1107
0
        strict = 0;
1108
0
        module = 0;
1109
0
      }
1110
0
      else if (!strcmp((char*)node->data.scalar.value, "module")) {
1111
0
        sloppy = 0;
1112
0
        strict = 0;
1113
0
        module = 1;
1114
0
      }
1115
0
      else if (!strcmp((char*)node->data.scalar.value, "raw")) {
1116
0
        sloppy = 1;
1117
0
        strict = 0;
1118
0
        module = 0;
1119
0
      }
1120
0
      else if (!strcmp((char*)node->data.scalar.value, "CanBlockIsFalse")) {
1121
0
        sloppy = 0;
1122
0
        strict = 0;
1123
0
        module = 0;
1124
0
        pending = 1;
1125
0
        snprintf(message, sizeof(message), "flag: CanBlockIsFalse");
1126
0
      }
1127
0
      item++;
1128
0
    }
1129
0
  }
1130
1131
0
  value = fxGetMappingValue(document, root, "features");
1132
0
  if (value) {
1133
0
    yaml_node_item_t* item = value->data.sequence.items.start;
1134
0
    while (item < value->data.sequence.items.top) {
1135
0
      yaml_node_t* node = yaml_document_get_node(document, *item);
1136
0
      txFeature* feature = pool->firstFeature;
1137
0
      while (feature) {
1138
0
        if (!c_strcmp((char*)node->data.scalar.value, feature->name)) {
1139
0
          sloppy = 0;
1140
0
          strict = 0;
1141
0
          module = 0;
1142
0
          pending = 1;
1143
0
          snprintf(message, sizeof(message), "feature: %s", (char*)node->data.scalar.value);
1144
0
          feature->count++;
1145
0
          break;
1146
0
        }
1147
0
        feature = feature->next;
1148
0
      }
1149
0
      if (!strcmp((char*)node->data.scalar.value, "Atomics")) {
1150
0
        atomics = 1;
1151
0
      }
1152
0
      item++;
1153
0
    }
1154
0
  }
1155
0
  if (atomics) {
1156
0
    fxLockMutex(&(agentCluster->mainMutex));
1157
0
  }
1158
1159
0
  if (pool->flags & XST_LOCKDOWN_FLAG) {
1160
0
    if (sloppy) {
1161
0
      sloppy = 0;
1162
0
      pending = 1;
1163
0
      snprintf(message, sizeof(message), "flag: noStrict");
1164
0
    }
1165
0
  }
1166
  
1167
0
  if (sloppy) {
1168
0
    if (pool->flags & XST_TRACE_FLAG)
1169
0
      fprintf(stderr, "### %s (sloppy): ", path + pool->testPathLength);
1170
0
    fxRunTestCase(pool, context, path, mxProgramFlag | mxDebugFlag, async, message);
1171
0
    if (pool->flags & XST_TRACE_FLAG)
1172
0
      fprintf(stderr, "%s\n", message);
1173
0
    else
1174
0
      fxPrintBusy(pool);
1175
0
  }
1176
0
  if (strict) {
1177
0
    if (pool->flags & XST_TRACE_FLAG)
1178
0
      fprintf(stderr, "### %s (strict): ", path + pool->testPathLength);
1179
0
    fxRunTestCase(pool, context, path, mxProgramFlag | mxDebugFlag | mxStrictFlag, async, message);
1180
0
    if (pool->flags & XST_TRACE_FLAG)
1181
0
      fprintf(stderr, "%s\n", message);
1182
0
    else
1183
0
      fxPrintBusy(pool);
1184
0
  }
1185
0
  if (module) {
1186
0
    if (pool->flags & XST_TRACE_FLAG)
1187
0
      fprintf(stderr, "### %s (module): ", path + pool->testPathLength);
1188
0
    fxRunTestCase(pool, context, path, 0, async, message);
1189
0
    if (pool->flags & XST_TRACE_FLAG)
1190
0
      fprintf(stderr, "%s\n", message);
1191
0
    else
1192
0
      fxPrintBusy(pool);
1193
0
  }
1194
0
  if (atomics) {
1195
0
    fxUnlockMutex(&(agentCluster->mainMutex));
1196
0
  }
1197
1198
0
  if (pending) {
1199
0
    fxCountResult(pool, context, 0, 1, message);
1200
0
    if (pool->flags & XST_TRACE_FLAG)
1201
0
      fprintf(stderr, "### %s (skip): %s\n", path + pool->testPathLength, message);
1202
0
    else
1203
0
      fxPrintBusy(pool);
1204
0
  }
1205
0
bail: 
1206
0
  context->negative = NULL;
1207
0
  context->includes = NULL;
1208
0
  context->document = NULL;
1209
0
  if (document)
1210
0
    yaml_document_delete(document);
1211
0
  if (parser)
1212
0
    yaml_parser_delete(parser);
1213
0
  if (buffer)
1214
0
    free(buffer);
1215
0
  if (file)
1216
0
    fclose(file);
1217
0
}
1218
1219
int fxRunTestCase(txPool* pool, txContext* context, char* path, txUnsigned flags, int async, char* message)
1220
0
{
1221
0
  xsCreation _creation = {
1222
0
    16 * 1024 * 1024,   /* initialChunkSize */
1223
0
    16 * 1024 * 1024,   /* incrementalChunkSize */
1224
0
    1 * 1024 * 1024,  /* initialHeapCount */
1225
0
    1 * 1024 * 1024,  /* incrementalHeapCount */
1226
0
    256 * 1024,     /* stackCount */
1227
0
    1024,         /* initialKeyCount */
1228
0
    1024,       /* incrementalKeyCount */
1229
0
    1993,         /* nameModulo */
1230
0
    127,        /* symbolModulo */
1231
0
    64 * 1024,      /* parserBufferSize */
1232
0
    1993,       /* parserTableModulo */
1233
0
  };
1234
0
  xsCreation* creation = &_creation;
1235
0
  xsMachine* machine;
1236
0
  char buffer[C_PATH_MAX];
1237
0
  int success = 0;  
1238
0
  machine = xsCreateMachine(creation, "xst262", NULL);
1239
0
  xsBeginHost(machine);
1240
0
  {
1241
0
    xsVars(5);
1242
0
    xsTry {
1243
0
      fxBuildAgent(the);
1244
0
      c_strcpy(buffer, pool->harnessPath);
1245
0
      c_strcat(buffer, "sta.js");
1246
0
      fxRunProgramFile(the, buffer, mxProgramFlag | mxDebugFlag);
1247
0
      c_strcpy(buffer, pool->harnessPath);
1248
0
      c_strcat(buffer, "assert.js");
1249
0
      fxRunProgramFile(the, buffer, mxProgramFlag | mxDebugFlag);
1250
0
      if (async) {
1251
0
        xsResult = xsNewHostFunction(fx_done, 1);
1252
0
        xsSet(xsGlobal, xsID("$DONE"), xsResult);
1253
0
        xsVar(0) = xsString("Test did not run to completion");
1254
0
      }
1255
0
      else
1256
0
        xsVar(0) = xsUndefined;
1257
0
      if (context->includes) {
1258
0
        yaml_node_item_t* item = context->includes->data.sequence.items.start;
1259
0
        while (item < context->includes->data.sequence.items.top) {
1260
0
          yaml_node_t* node = yaml_document_get_node(context->document, *item);
1261
0
          c_strcpy(buffer, pool->harnessPath);
1262
0
          c_strcat(buffer, (char*)node->data.scalar.value);
1263
0
          fxRunProgramFile(the, buffer, mxProgramFlag | mxDebugFlag);
1264
0
          item++;
1265
0
        }
1266
0
      }
1267
0
      mxPop();
1268
0
      if (pool->flags & XST_LOCKDOWN_FLAG)
1269
0
        xsCall0(xsGlobal, xsID("lockdown"));
1270
0
      the->rejection = &xsVar(0);
1271
0
      if (flags) {
1272
0
        if (pool->flags & XST_COMPARTMENT_FLAG)
1273
0
          fxRunProgramFileInCompartment(the, path, flags);
1274
0
        else
1275
0
          fxRunProgramFile(the, path, flags);
1276
0
      }
1277
0
      else {
1278
0
        if (pool->flags & XST_COMPARTMENT_FLAG)
1279
0
          fxRunModuleFileInCompartment(the, path);
1280
0
        else
1281
0
          fxRunModuleFile(the, path);
1282
0
      }
1283
0
      fxRunLoop(the);
1284
0
      if (xsTest(xsVar(0))) 
1285
0
        xsThrow(xsVar(0));
1286
0
      if (context->negative) {
1287
0
        snprintf(message, 1024, "# Expected a %s but got no errors", context->negative->data.scalar.value);
1288
0
      }
1289
0
      else {
1290
0
        snprintf(message, 1024, "OK");
1291
0
        success = 1;
1292
0
      }
1293
0
    }
1294
0
    xsCatch {
1295
0
      if (context->negative) {
1296
0
        txString name;
1297
0
        xsResult = xsGet(xsException, xsID("constructor"));
1298
0
        name = xsToString(xsGet(xsResult, xsID("name")));
1299
0
        if (strcmp(name, (char*)context->negative->data.scalar.value))
1300
0
          snprintf(message, 1024, "# Expected a %s but got a %s", context->negative->data.scalar.value, name);
1301
0
        else {
1302
0
          snprintf(message, 1024, "OK");
1303
0
          success = 1;
1304
0
        }
1305
0
      }
1306
0
      else {
1307
0
        snprintf(message, 1024, "# %s", xsToString(xsException));
1308
0
      }
1309
0
    }
1310
0
  }
1311
0
  xsEndHost(machine);
1312
0
  if (machine->exitStatus) {
1313
0
    success = 0;
1314
0
    if ((machine->exitStatus == XS_NOT_ENOUGH_MEMORY_EXIT) || (machine->exitStatus == XS_JAVASCRIPT_STACK_OVERFLOW_EXIT) || (machine->exitStatus == XS_NATIVE_STACK_OVERFLOW_EXIT)) {
1315
0
      if (context->negative) {
1316
0
        if (!strcmp("RangeError", (char*)context->negative->data.scalar.value)) {
1317
0
          snprintf(message, 1024, "OK");
1318
0
          success = 1;
1319
0
        }
1320
0
      }
1321
0
    }
1322
0
    if (!success) {
1323
0
      snprintf(message, 1024, "# %s", fxAbortString(machine->exitStatus));
1324
0
      success = 0;
1325
0
    }
1326
0
  }
1327
0
  fx_agent_stop(machine);
1328
0
  xsDeleteMachine(machine);
1329
1330
0
  fxCountResult(pool, context, success, 0, message);
1331
0
  return success;
1332
0
}
1333
1334
int fxStringEndsWith(const char *string, const char *suffix)
1335
0
{
1336
0
  size_t stringLength = strlen(string);
1337
0
  size_t suffixLength = strlen(suffix);
1338
0
  return (stringLength >= suffixLength) && (0 == strcmp(string + (stringLength - suffixLength), suffix));
1339
0
}
1340
1341
void fxWriteConfiguration(txPool* pool, char* path)
1342
0
{
1343
0
  FILE* file = fopen(path, "w");
1344
0
  txResult* result;
1345
0
  if (!file)
1346
0
    fprintf(stderr, "### cannot create: %s\n", path);
1347
0
  if (pool->flags & XST_LOCKDOWN_FLAG) {
1348
0
    if (pool->flags & XST_COMPARTMENT_FLAG)
1349
0
      fprintf(file, "mode: lockdown compartment\n");
1350
0
    else
1351
0
      fprintf(file, "mode: lockdown\n");
1352
0
  }
1353
0
  else
1354
0
    fprintf(file, "mode: default\n");
1355
0
  fprintf(file, "skip:\n");
1356
0
  txFeature* feature = pool->firstFeature;
1357
0
  while (feature) {
1358
0
    fprintf(file, "    - %s\n", feature->name);
1359
0
    feature = feature->next;
1360
0
  }
1361
0
  fprintf(file, "fail:\n");
1362
0
  result = pool->current->first;
1363
0
  while (result) {
1364
0
    fxFilterResult(result);
1365
0
    fxWriteResult(file, result, 1);
1366
0
    result = result->next;
1367
0
  }
1368
0
  fclose(file);
1369
0
}
1370
1371
void fxWriteResult(FILE* file, txResult* result, int c)
1372
0
{
1373
0
  int i = 0;
1374
0
  while (i < c) {
1375
0
    fprintf(file, "    ");
1376
0
    i++;
1377
0
  }
1378
0
  if (result->file.flag < 0) {
1379
0
    char buffer[16];
1380
0
    char *p = result->path + result->file.offset, *q;
1381
0
    fprintf(file, "- %s: \"", result->path);
1382
0
    while (((p = mxStringByteDecode(p, &c))) && (c != C_EOF)) {
1383
0
      q = buffer;
1384
0
      if ((c == '\\') || (c == '"')) {
1385
0
        q = fxUTF8Encode(q, '\\');
1386
0
        q = fxUTF8Encode(q, c);
1387
0
      }
1388
0
      else if ((0xD800 <= c) && (c <= 0xDFFF))
1389
0
        q = fxUTF8Encode(q, 0xFFFD);
1390
0
      else
1391
0
        q = fxUTF8Encode(q, c);
1392
0
      *q = 0;
1393
0
      fprintf(file, "%s", buffer);
1394
0
    }
1395
0
    fprintf(file, "\"\n");
1396
0
  }
1397
0
  else {
1398
0
    fprintf(file, "- %s:\n", result->path);
1399
0
    c++;
1400
0
    result = result->first;
1401
0
    while (result) {
1402
0
      fxWriteResult(file, result, c + 1);
1403
0
      result = result->next;
1404
0
    }
1405
0
  }
1406
0
}
1407
1408
void fxBuildCompartmentGlobals(txMachine* the)
1409
0
{
1410
0
  txSlot* realm = mxProgram.value.reference->next->value.module.realm;
1411
0
  txSlot* global = mxRealmGlobal(realm)->value.reference;
1412
0
  txSlot* environment = mxRealmClosures(realm)->value.reference;
1413
0
  txSlot* slot;
1414
0
  txSlot* property;
1415
  
1416
0
  mxPush(mxObjectPrototype);
1417
0
  property = fxLastProperty(the, fxNewHostObject(the, NULL));
1418
0
  slot = global->next->next;
1419
0
  while (slot) {
1420
0
    if (slot->ID > mxID(_globalThis)) {
1421
//      fprintf(stderr, "%s\n", fxGetKeyName(the, slot->ID));
1422
0
      property = fxNextSlotProperty(the, property, slot, slot->ID, XS_NO_FLAG);
1423
0
    }
1424
0
    slot = slot->next;
1425
0
  }
1426
0
  slot = environment->next->next;
1427
0
  while (slot) {
1428
0
    if (slot->kind == XS_CLOSURE_KIND) {
1429
//      fprintf(stderr, "%s\n", fxGetKeyName(the, slot->ID));
1430
0
      property = fxNextSlotProperty(the, property, slot->value.closure, slot->ID, XS_NO_FLAG);
1431
0
    }
1432
0
    slot = slot->next;
1433
0
  }
1434
0
  mxPullSlot(mxResult);
1435
0
}
1436
1437
void fxLoadHook(txMachine* the)
1438
0
{
1439
0
  xsVars(2);
1440
0
  xsVar(0) = xsNewObject();
1441
0
  xsSet(xsVar(0), xsID("namespace"), xsArg(0));
1442
0
  xsVar(1) = xsGet(xsGlobal, xsID("Promise"));
1443
0
  xsResult = xsCall1(xsVar(1), xsID("resolve"), xsVar(0));
1444
0
}
1445
1446
void fxRunModuleFileInCompartment(txMachine* the, txString path)
1447
0
{
1448
0
  xsVar(1) = xsNewObject();
1449
0
  fxBuildCompartmentGlobals(the);
1450
0
  xsSet(xsVar(1), xsID("globals"), xsResult);
1451
0
  xsVar(2) = xsNewHostFunction(fxLoadHook, 1);
1452
0
  xsSet(xsVar(1), xsID("loadHook"), xsVar(2));
1453
0
  xsVar(2) = xsNew1(xsGlobal, xsID("Compartment"), xsVar(1));
1454
0
  xsResult = xsCall1(xsVar(2), xsID("import"), xsString(path));
1455
0
  xsVar(3) = xsNewHostFunction(fxFulfillModuleFile, 1);
1456
0
  xsVar(4) = xsNewHostFunction(fxRejectModuleFile, 1);
1457
0
  xsCall2(xsResult, xsID("then"), xsVar(3), xsVar(4));
1458
0
}
1459
1460
void fxRunProgramFileInCompartment(txMachine* the, txString path, txUnsigned flags)
1461
0
{
1462
0
  xsVar(1) = xsNewObject();
1463
0
  fxBuildCompartmentGlobals(the);
1464
0
  xsSet(xsVar(1), xsID("globals"), xsResult);
1465
1466
0
  xsVar(2) = xsNewHostFunction(fxLoadHook, 1);
1467
0
  xsSet(xsVar(1), xsID("loadHook"), xsVar(2));
1468
0
  xsVar(2) = xsNew1(xsGlobal, xsID("Compartment"), xsVar(1));
1469
0
  {
1470
0
    txSlot* module = mxVarv(2)->value.reference;
1471
0
    txSlot* realm = mxModuleInstanceInternal(module)->value.module.realm;
1472
0
    txScript* script = fxLoadScript(the, path, flags);
1473
1474
0
    xsVar(1) = xsGet(xsGlobal, xsID("$262"));
1475
0
    xsVar(1) = xsGet(xsVar(1), xsID("evalScript"));
1476
0
    mxFunctionInstanceHome(mxVarv(1)->value.reference)->value.home.module = module;
1477
      
1478
0
    mxModuleInstanceInternal(module)->value.module.id = fxID(the, path);
1479
0
    fxRunScript(the, script, mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, module);
1480
0
  }
1481
0
}
1482
1483
1484
1485
1486
1487
1488
1489