Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/workflows/format-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: JSON Format Check

on:
push:
branches: [main, master]
pull_request:
branches: [main, master]

jobs:
format-check:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Check JSON formatting
run: npm run format:check
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
package-lock.json
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ FlintBenchmark is freely available for other FOSS projects to use for testing an

Feel free to integrate these tests into your development workflow, CI/CD pipeline, or use them as a reference for expected vanilla behavior.

## JSON Formatting
All test JSON files are formatted using [FracturedJson](https://github.com/j-brooke/FracturedJson), which produces human-readable yet compact output. Small arrays and objects are inlined, while larger ones are expanded for readability.

To format all JSON files:
```bash
npm install
npm run format
```

To check formatting (used in CI):
```bash
npm run format:check
```

## License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. This means you are free to use, modify, and distribute the tests in this repository for any purpose, including developing and testing your own server implementations.

Expand Down
13 changes: 13 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "flintbenchmark",
"version": "1.0.0",
"description": "Benchmark repository for testing Minecraft server implementations",
"scripts": {
"format": "node scripts/format-json.js",
"format:check": "node scripts/format-json.js --check"
},
"devDependencies": {
"fracturedjsonjs": "^4.0.0"
},
"license": "MIT"
}
130 changes: 130 additions & 0 deletions scripts/format-json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#!/usr/bin/env node

/**
* JSON Formatter for FlintBenchmark
* Uses FracturedJson to produce human-readable, compact JSON output.
* Small arrays/objects are inlined, larger ones are expanded.
*
* Usage:
* node scripts/format-json.js # Format all JSON files in tests/
* node scripts/format-json.js --check # Check if files are formatted (for CI)
*/

const fs = require('fs');
const path = require('path');
const { Formatter } = require('fracturedjsonjs');

const TESTS_DIR = path.join(__dirname, '..', 'tests');

// FracturedJson configuration for optimal readability
const formatter = new Formatter();
formatter.MaxTotalLineLength = 100; // Max line length before wrapping
formatter.MaxInlineLength = 60; // Max length for inline arrays/objects
formatter.MaxInlineComplexity = 2; // Max nesting for inline elements
formatter.MaxCompactArrayComplexity = 1; // Compact simple arrays
formatter.NestedBracketPadding = false; // No extra spaces in nested brackets
formatter.SimpleBracketPadding = true; // Spaces in simple brackets like [1, 2, 3]
formatter.ColonPadding = true; // Space after colons
formatter.CommaPadding = true; // Space after commas
formatter.IndentSpaces = 2; // 2-space indentation
formatter.PreferMultipleItemsPerLine = true; // Multiple items per line when possible
formatter.TableObjectMinimumSimilarity = 0.5; // Align similar objects in tables
formatter.TableArrayMinimumSimilarity = 0.5; // Align similar arrays in tables

/**
* Find all JSON files recursively in a directory
*/
function findJsonFiles(dir) {
const files = [];
const entries = fs.readdirSync(dir, { withFileTypes: true });

for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
files.push(...findJsonFiles(fullPath));
} else if (entry.isFile() && entry.name.endsWith('.json')) {
files.push(fullPath);
}
}

return files;
}

/**
* Format a single JSON file
* Returns true if file was modified (or would be modified in check mode)
*/
function formatFile(filePath, checkOnly = false) {
const content = fs.readFileSync(filePath, 'utf8');

let parsed;
try {
parsed = JSON.parse(content);
} catch (e) {
console.error(`❌ Invalid JSON: ${filePath}`);
console.error(` ${e.message}`);
return { error: true, changed: false };
}

const formatted = formatter.Serialize(parsed) + '\n';

if (content === formatted) {
return { error: false, changed: false };
}

if (checkOnly) {
return { error: false, changed: true };
}

fs.writeFileSync(filePath, formatted, 'utf8');
return { error: false, changed: true };
}

// Main execution
const args = process.argv.slice(2);
const checkOnly = args.includes('--check');

console.log(checkOnly ? '🔍 Checking JSON formatting...' : '✨ Formatting JSON files...');
console.log();

const jsonFiles = findJsonFiles(TESTS_DIR);
let hasErrors = false;
let changedCount = 0;

for (const file of jsonFiles) {
const relativePath = path.relative(path.join(__dirname, '..'), file);
const result = formatFile(file, checkOnly);

if (result.error) {
hasErrors = true;
} else if (result.changed) {
changedCount++;
if (checkOnly) {
console.log(`❌ ${relativePath} (needs formatting)`);
} else {
console.log(`✅ ${relativePath}`);
}
}
}

console.log();

if (hasErrors) {
console.log('❌ Some files contain invalid JSON');
process.exit(1);
}

if (checkOnly) {
if (changedCount > 0) {
console.log(`❌ ${changedCount} file(s) need formatting. Run 'npm run format' to fix.`);
process.exit(1);
} else {
console.log(`✅ All ${jsonFiles.length} JSON files are properly formatted.`);
}
} else {
if (changedCount > 0) {
console.log(`✅ Formatted ${changedCount} file(s).`);
} else {
console.log(`✅ All ${jsonFiles.length} JSON files were already formatted.`);
}
}
90 changes: 40 additions & 50 deletions tests/fluids/mixing.json
Original file line number Diff line number Diff line change
@@ -1,66 +1,56 @@
{
"name": "water_mixing_with_lava",
"description": "Water converts lava source to obsidian",
"tags": ["interaction", "lava"],
"name": "water_mixing_with_lava",
"description": "Water converts lava source to obsidian",
"tags": ["interaction", "lava"],
"setup": {
"cleanup": {
"region": [[0, 0, 0], [6, 5, 4]]
"region": [ [0, 0, 0], [6, 5, 4] ]
}
},
},
"timeline": [
{
"at": 0,
"do": "fill",
"region": [[0, 0, 0], [6, 0, 4]],
"at": 0,
"do": "fill",
"region": [ [0, 0, 0], [6, 0, 4] ],
"with": {"id": "minecraft:stone"}
},
},
{
"at": 1,
"do": "place_each",
"at": 1,
"do": "place_each",
"blocks": [
{"pos": [0, 1, 0], "block": {"id": "minecraft:stone"}},
{"pos": [1, 1, 0], "block": {"id": "minecraft:stone"}},
{"pos": [2, 1, 0], "block": {"id": "minecraft:stone"}},
{"pos": [3, 1, 0], "block": {"id": "minecraft:stone"}},
{"pos": [4, 1, 0], "block": {"id": "minecraft:stone"}},
{"pos": [5, 1, 0], "block": {"id": "minecraft:stone"}},
{"pos": [6, 1, 0], "block": {"id": "minecraft:stone"}},
{"pos": [0, 1, 4], "block": {"id": "minecraft:stone"}},
{"pos": [1, 1, 4], "block": {"id": "minecraft:stone"}},
{"pos": [2, 1, 4], "block": {"id": "minecraft:stone"}},
{"pos": [3, 1, 4], "block": {"id": "minecraft:stone"}},
{"pos": [4, 1, 4], "block": {"id": "minecraft:stone"}},
{"pos": [5, 1, 4], "block": {"id": "minecraft:stone"}},
{"pos": [6, 1, 4], "block": {"id": "minecraft:stone"}},
{"pos": [0, 1, 1], "block": {"id": "minecraft:stone"}},
{"pos": [0, 1, 2], "block": {"id": "minecraft:stone"}},
{"pos": [0, 1, 3], "block": {"id": "minecraft:stone"}},
{"pos": [6, 1, 1], "block": {"id": "minecraft:stone"}},
{"pos": [6, 1, 2], "block": {"id": "minecraft:stone"}},
{"pos": [6, 1, 3], "block": {"id": "minecraft:stone"}}
{ "pos": [0, 1, 0], "block": {"id": "minecraft:stone"} },
{ "pos": [1, 1, 0], "block": {"id": "minecraft:stone"} },
{ "pos": [2, 1, 0], "block": {"id": "minecraft:stone"} },
{ "pos": [3, 1, 0], "block": {"id": "minecraft:stone"} },
{ "pos": [4, 1, 0], "block": {"id": "minecraft:stone"} },
{ "pos": [5, 1, 0], "block": {"id": "minecraft:stone"} },
{ "pos": [6, 1, 0], "block": {"id": "minecraft:stone"} },
{ "pos": [0, 1, 4], "block": {"id": "minecraft:stone"} },
{ "pos": [1, 1, 4], "block": {"id": "minecraft:stone"} },
{ "pos": [2, 1, 4], "block": {"id": "minecraft:stone"} },
{ "pos": [3, 1, 4], "block": {"id": "minecraft:stone"} },
{ "pos": [4, 1, 4], "block": {"id": "minecraft:stone"} },
{ "pos": [5, 1, 4], "block": {"id": "minecraft:stone"} },
{ "pos": [6, 1, 4], "block": {"id": "minecraft:stone"} },
{ "pos": [0, 1, 1], "block": {"id": "minecraft:stone"} },
{ "pos": [0, 1, 2], "block": {"id": "minecraft:stone"} },
{ "pos": [0, 1, 3], "block": {"id": "minecraft:stone"} },
{ "pos": [6, 1, 1], "block": {"id": "minecraft:stone"} },
{ "pos": [6, 1, 2], "block": {"id": "minecraft:stone"} },
{ "pos": [6, 1, 3], "block": {"id": "minecraft:stone"} }
]
},
},
{ "at": 2, "do": "place", "pos": [4, 1, 2], "block": {"id": "minecraft:lava", "level": 0} },
{ "at": 3, "do": "place", "pos": [2, 1, 2], "block": {"id": "minecraft:water", "level": 0} },
{ "at": 2, "do": "place", "pos": [4, 1, 2], "block": {"id": "minecraft:lava", "level": 0} },
{ "at": 3, "do": "place", "pos": [2, 1, 2], "block": {"id": "minecraft:water", "level": 0} },
{
"at": 2,
"do": "place",
"pos": [4, 1, 2],
"block": {"id": "minecraft:lava", "level": 0}
},
{
"at": 3,
"do": "place",
"pos": [2, 1, 2],
"block": {"id": "minecraft:water", "level": 0}
},
{
"at": 8,
"do": "assert",
"at": 8,
"do": "assert",
"checks": [
{
"pos": [4, 1, 2],
"is": {"id": "minecraft:obsidian"}
}
{ "pos": [4, 1, 2], "is": {"id": "minecraft:obsidian"} }
]
}
]
}

Loading
Loading