importProject turns a PC's or notebook's Java file tree into Swift's virtual file system, as Swift's registerVirtualFileSystem does: images by type or extension from Base64, text by type, unknown types as binary data or text, unsafe names and collisions left out with a warning, and the whole import rejected over the project quota. NSString.pathExtension is measured in the oracle, which now writes every imported file system. On the 13 files Swift reads completely every file matches, images compared by hash. Intended: a host whose file has no file system stays empty, as in Java, where Swift adds the demo files of a new device. Pending the applications step, the comparison reads our /webserver as Swift's /www and leaves out the e-mail and Gnutella state files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
104 lines
3.7 KiB
TypeScript
104 lines
3.7 KiB
TypeScript
// Swift String behaviour, measured in the Swift core (strings.swift.json,
|
|
// tools/swift-oracle --strings): every case must come out the same here.
|
|
|
|
import { readFileSync } from 'node:fs';
|
|
import { dirname, join } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { describe, expect, it } from 'vitest';
|
|
import {
|
|
base64Encode,
|
|
containsSwiftControlCharacter,
|
|
swiftBase64Decode,
|
|
swiftCompare,
|
|
swiftEqual,
|
|
swiftLowercased,
|
|
swiftPathExtension,
|
|
swiftTrim,
|
|
} from '../src/index.js';
|
|
|
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
const cases = JSON.parse(readFileSync(join(here, 'strings.cases.json'), 'utf8')) as {
|
|
trim: string[];
|
|
lowercased: string[];
|
|
equal: [string, string][];
|
|
sort: string[][];
|
|
base64: string[];
|
|
controlCharacters: string[];
|
|
pathExtension: string[];
|
|
};
|
|
const swift = JSON.parse(readFileSync(join(here, 'strings.swift.json'), 'utf8')) as {
|
|
trim: string[];
|
|
lowercased: string[];
|
|
equal: boolean[];
|
|
sort: string[][];
|
|
base64: (number[] | null)[];
|
|
controlCharacters: boolean[];
|
|
pathExtension: string[];
|
|
whitespacesAndNewlinesSet: [number, number][];
|
|
controlCharactersSet: [number, number][];
|
|
};
|
|
|
|
/** The scalars for which `test` holds, as ranges [first, last] — the oracle's shape. */
|
|
function scalarRanges(test: (scalar: string) => boolean): [number, number][] {
|
|
const ranges: [number, number][] = [];
|
|
for (let value = 0; value <= 0x10ffff; value++) {
|
|
if (value >= 0xd800 && value <= 0xdfff) continue;
|
|
if (!test(String.fromCodePoint(value))) continue;
|
|
const last = ranges.at(-1);
|
|
if (last !== undefined && last[1] === value - 1) last[1] = value;
|
|
else ranges.push([value, value]);
|
|
}
|
|
return ranges;
|
|
}
|
|
|
|
describe('Swift string semantics', () => {
|
|
it('trims like trimmingCharacters(in: .whitespacesAndNewlines)', () => {
|
|
expect(cases.trim.map(swiftTrim)).toEqual(swift.trim);
|
|
});
|
|
|
|
it('lower-cases like lowercased()', () => {
|
|
expect(cases.lowercased.map(swiftLowercased)).toEqual(swift.lowercased);
|
|
});
|
|
|
|
it('compares like ==', () => {
|
|
expect(cases.equal.map(([lhs, rhs]) => swiftEqual(lhs, rhs))).toEqual(swift.equal);
|
|
});
|
|
|
|
it('sorts like sorted()', () => {
|
|
expect(cases.sort.map((list) => [...list].sort(swiftCompare))).toEqual(swift.sort);
|
|
});
|
|
|
|
it('decodes Base64 like Data(base64Encoded:options: .ignoreUnknownCharacters)', () => {
|
|
expect(cases.base64.map((text) => {
|
|
const bytes = swiftBase64Decode(text);
|
|
return bytes === undefined ? null : [...bytes];
|
|
})).toEqual(swift.base64);
|
|
});
|
|
|
|
it('finds control characters like CharacterSet.controlCharacters', () => {
|
|
expect(cases.controlCharacters.map(containsSwiftControlCharacter)).toEqual(swift.controlCharacters);
|
|
});
|
|
|
|
it('finds the extension like NSString.pathExtension', () => {
|
|
expect(cases.pathExtension.map(swiftPathExtension)).toEqual(swift.pathExtension);
|
|
});
|
|
|
|
it('trims exactly the scalars Swift trims, all of Unicode', () => {
|
|
expect(scalarRanges((scalar) => swiftTrim(`${scalar}a`) === 'a')).toEqual(swift.whitespacesAndNewlinesSet);
|
|
});
|
|
|
|
it('counts the same scalars as control characters, except Foundation\'s plane-14 artefact', () => {
|
|
const below = (ranges: [number, number][]) => ranges.filter(([first]) => first < 0xe0100);
|
|
expect(scalarRanges(containsSwiftControlCharacter).filter(([first]) => first < 0xe0100)).toEqual(
|
|
below(swift.controlCharactersSet).map(([first, last]) => [first, Math.min(last, 0xe00ff)]),
|
|
);
|
|
});
|
|
|
|
it('encodes Base64 so that it decodes again', () => {
|
|
for (const length of [0, 1, 2, 3, 4, 5, 255]) {
|
|
const bytes = Uint8Array.from({ length }, (_, index) => (index * 37) & 0xff);
|
|
expect(swiftBase64Decode(base64Encode(bytes))).toEqual(bytes);
|
|
}
|
|
});
|
|
});
|