Ver código fonte

reorganize server tests

Aleksandr Kuzmenko 5 anos atrás
pai
commit
eb3aecf3b1
43 arquivos alterados com 1157 adições e 822 exclusões
  1. 1 1
      tests/server/.vscode/settings.json
  2. 2 1
      tests/server/build.hxml
  3. 48 0
      tests/server/src/DisplayTestCase.hx
  4. 0 515
      tests/server/src/DisplayTests.hx
  5. 11 292
      tests/server/src/Main.hx
  6. 4 3
      tests/server/src/TestCase.hx
  7. 3 1
      tests/server/src/cases/ReplaceRanges.hx
  8. 240 0
      tests/server/src/cases/ServerTests.hx
  9. 20 0
      tests/server/src/cases/display/issues/Issue7262.hx
  10. 23 0
      tests/server/src/cases/display/issues/Issue7305.hx
  11. 21 0
      tests/server/src/cases/display/issues/Issue7317.hx
  12. 27 0
      tests/server/src/cases/display/issues/Issue7754.hx
  13. 20 0
      tests/server/src/cases/display/issues/Issue7923.hx
  14. 20 0
      tests/server/src/cases/display/issues/Issue8061.hx
  15. 23 0
      tests/server/src/cases/display/issues/Issue8194.hx
  16. 27 0
      tests/server/src/cases/display/issues/Issue8381.hx
  17. 19 0
      tests/server/src/cases/display/issues/Issue8438.hx
  18. 16 0
      tests/server/src/cases/display/issues/Issue8602.hx
  19. 17 0
      tests/server/src/cases/display/issues/Issue8644.hx
  20. 13 0
      tests/server/src/cases/display/issues/Issue8651.hx
  21. 13 0
      tests/server/src/cases/display/issues/Issue8657.hx
  22. 13 0
      tests/server/src/cases/display/issues/Issue8659.hx
  23. 40 0
      tests/server/src/cases/display/issues/Issue8666.hx
  24. 20 0
      tests/server/src/cases/display/issues/Issue8732.hx
  25. 15 0
      tests/server/src/cases/display/issues/Issue8805.hx
  26. 26 0
      tests/server/src/cases/display/issues/Issue8991.hx
  27. 19 0
      tests/server/src/cases/display/issues/Issue8992.hx
  28. 17 0
      tests/server/src/cases/display/issues/Issue9012.hx
  29. 27 0
      tests/server/src/cases/display/issues/Issue9039.hx
  30. 17 0
      tests/server/src/cases/display/issues/Issue9047.hx
  31. 31 0
      tests/server/src/cases/display/issues/Issue9082.hx
  32. 29 0
      tests/server/src/cases/display/issues/Issue9087.hx
  33. 16 0
      tests/server/src/cases/display/issues/Issue9115.hx
  34. 44 0
      tests/server/src/cases/display/issues/Issue9159.hx
  35. 19 0
      tests/server/src/cases/issues/Issue8738.hx
  36. 25 0
      tests/server/src/cases/issues/Issue8748.hx
  37. 15 0
      tests/server/src/cases/issues/Issue9029.hx
  38. 10 0
      tests/server/src/import.hx
  39. 88 0
      tests/server/src/utils/Markers.hx
  40. 2 0
      tests/server/src/utils/Vfs.hx
  41. 31 0
      tests/server/src/utils/macro/BuildHub.macro.hx
  42. 58 0
      tests/server/src/utils/macro/DisplayTestBuilder.macro.hx
  43. 27 9
      tests/server/src/utils/macro/TestBuilder.macro.hx

+ 1 - 1
tests/server/.vscode/settings.json

@@ -1,6 +1,6 @@
 {
 	"haxe.diagnosticsPathFilter": "${workspaceRoot}/src",
-	"editor.formatOnSave": true,
+	// "editor.formatOnSave": true,
 	"haxeTestExplorer.testCommand": [
 		"${haxe}",
 		"build.hxml",

+ 2 - 1
tests/server/build.hxml

@@ -4,4 +4,5 @@
 -js test.js
 -lib hxnodejs
 -lib utest
--lib haxeserver
+-lib haxeserver
+-D analyzer-optimize

+ 48 - 0
tests/server/src/DisplayTestCase.hx

@@ -0,0 +1,48 @@
+import haxe.display.Position;
+import haxe.Exception;
+import utils.Markers;
+import haxe.display.FsPath;
+
+/**
+	Display test should have a snippet with `{-N-}` markers
+	in the doc block.
+	The snippet will be automatically parsed.
+**/
+class DisplayTestCase extends TestCase {
+	/** The snippet with markers removed */
+	var source(get,never):String;
+	/** A file created for the snippet */
+	final file = new FsPath("Main.hx");
+	/** Data extracted from the snippet */
+	var markers(get, never):Markers;
+	@:noCompletion var _markers:Null<Markers>;
+
+	inline function get_markers():Markers
+		return switch _markers {
+			case null: throw new Exception('Markers are not initialized');
+			case m: m;
+		}
+
+	inline function get_source():String
+		return markers.source;
+
+	/**
+	 * Returns an offset of the n-th marker.
+	 * Amount of characters from the beginning of the parsed document excluding markers.
+	 */
+	public function offset(n:Int):Int
+		return markers.offset(n);
+
+	/**
+	 * Returns a position of n-th marker.
+	 * Line number and character number from the beginning of the line.
+	 */
+	public function pos(n:Int):Position
+		return markers.pos(n);
+
+	/**
+	 * Returns a range between positions of `startMarker` and `endMarker`
+	 */
+	public function range(startMarker:Int, endMarker:Int):Range
+		return markers.range(startMarker, endMarker);
+}

+ 0 - 515
tests/server/src/DisplayTests.hx

@@ -1,515 +0,0 @@
-import haxe.display.JsonModuleTypes;
-import haxe.display.Protocol;
-import haxe.PosInfos;
-import haxe.display.Server;
-import utest.Assert;
-import utest.Assert.*;
-import haxe.display.Display;
-import haxe.display.FsPath;
-
-@:timeout(5000)
-// TODO: somebody has to clean this up
-class DisplayTests extends HaxeServerTestCase {
-	function testIssue7262() {
-		var content = 'class Main {
-			static public function main() {
-				var x:haxe.extern.EitherType<haxe.PosInfos, () -> Void> = {-1-}
-			}
-		}';
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-		runHaxeJson([], DisplayMethods.Completion, {
-			file: new FsPath("Main.hx"),
-			offset: transform.markers[1],
-			wasAutoTriggered: true
-		});
-		var result = parseCompletion().result;
-		equals("TAnonymous", result.mode.args.expectedTypeFollowed.args.params[0].kind);
-	}
-
-	function testIssue7305() {
-		var content = 'class Main {
-	static public function main() {
-		new Map{-1-}
-	}
-}';
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-		runHaxeJson([], DisplayMethods.Completion, {
-			file: new FsPath("Main.hx"),
-			offset: transform.markers[1],
-			wasAutoTriggered: true
-		});
-		var result = parseCompletion();
-		assertHasCompletion(result, item -> switch (item.kind) {
-			case Type: item.args.path.pack.length == 0 && item.args.path.typeName == "Map";
-			case _: false;
-		});
-	}
-
-	function testIssue7317() {
-		var content = 'class Main {
-	public static function main() {
-		var obj = {};
-		obj.{-1-}
-	}
-}';
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-		runHaxeJson([], DisplayMethods.Completion, {
-			file: new FsPath("Main.hx"),
-			offset: transform.markers[1],
-			wasAutoTriggered: true
-		});
-		var result = parseCompletion();
-		Assert.equals("obj", result.result.mode.args.item.args.name);
-	}
-
-	function testIssue7923() {
-		vfs.putContent("TreeItem.hx", getTemplate("issues/Issue7923/TreeItem.hx"));
-		var content = getTemplate("issues/Issue7923/Main.hx");
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-		runHaxeJson([], DisplayMethods.Completion, {
-			file: new FsPath("Main.hx"),
-			offset: transform.markers[1],
-			wasAutoTriggered: true
-		});
-		var result = parseCompletion();
-		assertHasCompletion(result, item -> switch (item.kind) {
-			case EnumAbstractField: item.args.field.name == "Collapsed";
-			case _: false;
-		});
-	}
-
-	function testIssue8061() {
-		var content = 'class Main {
-	static function main() {
-		new sys.io.Process({-1-})
-	}
-}';
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-		runHaxeJson([], DisplayMethods.SignatureHelp, {
-			file: new FsPath("Main.hx"),
-			offset: transform.markers[1],
-			wasAutoTriggered: true
-		});
-		var result = parseSignatureHelp();
-		Assert.isTrue(result.result.signatures[0].documentation != null);
-	}
-
-	function testIssue8194() {
-		var content = 'class Main {
-	static function main() {
-		switch ("p") {
-			case "p"{-1-}
-				"foo";
-		}
-	}
-}';
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-		runHaxeJson([], DisplayMethods.Completion, {
-			file: new FsPath("Main.hx"),
-			offset: transform.markers[1],
-			wasAutoTriggered: true
-		});
-		var result = parseCompletion();
-		Assert.equals(null, result.result);
-	}
-
-	function testIssue8381() {
-		var content = 'class Main {
-	static function main() {
-		var f:Foo;
-		f.f{-1-}oo();
-		f.bar;
-	}
-}
-
-typedef Foo = {
-	/** Test **/
-	function foo():Void;
-
-	/** Test **/
-	var bar:Int;
-}';
-
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-		runHaxeJson([], DisplayMethods.Hover, {
-			file: new FsPath("Main.hx"),
-			offset: transform.markers[1]
-		});
-		var result = parseHover();
-		Assert.equals(DisplayItemKind.ClassField, result.result.item.kind);
-	}
-
-	function testIssue8438() {
-		var content = 'class Main {
-	static function main() {
-		" ".char{-1-}
-	}
-}';
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-		runHaxeJson([], DisplayMethods.Completion, {
-			file: new FsPath("Main.hx"),
-			offset: transform.markers[1],
-			wasAutoTriggered: true
-		});
-		var result = parseCompletion();
-		Assert.equals(6, result.result.replaceRange.start.character);
-		Assert.equals(10, result.result.replaceRange.end.character);
-	}
-
-	function testIssue8602() {
-		var content = "class Main {
-	static function main() {
-		haxe.ds.{-1-}
-	}
-}";
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-		runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("Main.hx"), offset: transform.markers[1], wasAutoTriggered: true});
-		var result = parseCompletion();
-		Assert.equals(Toplevel, result.result.mode.kind);
-	}
-
-	function testIssue8644() {
-		vfs.putContent("HelloJvm.hx", getTemplate("HelloJvm.hx"));
-		var args = ["-cp", ".", "--interp"];
-		runHaxeJson(args, ServerMethods.ReadClassPaths, null);
-		runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("HelloJvm.hx"), offset: 55, wasAutoTriggered: false});
-		var completion = parseCompletion();
-		assertHasNoCompletion(completion, module -> switch (module.kind) {
-			case Type: module.args.path.typeName == "Jvm";
-			case _: false;
-		});
-	}
-
-	function testIssue8651() {
-		var content = "class Main { static function main() { {-1-}buffer{-2-} } }";
-		vfs.putContent("Main.hx", content);
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-		runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("Main.hx"), offset: transform.markers[2], wasAutoTriggered: true});
-		var result = parseCompletion();
-		var r = result.result;
-		Assert.equals("buffer", r.filterString);
-		Assert.equals(transform.markers[1], r.replaceRange.start.character);
-		Assert.equals(transform.markers[2], r.replaceRange.end.character);
-	}
-
-	function testIssue8657() {
-		var content = "class Main { static function main() { var x:{-1-}stream{-2-} } }";
-		vfs.putContent("Main.hx", content);
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-		runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("Main.hx"), offset: transform.markers[2], wasAutoTriggered: true});
-		var result = parseCompletion();
-		var r = result.result;
-		Assert.equals("stream", r.filterString);
-		Assert.equals(transform.markers[1], r.replaceRange.start.character);
-		Assert.equals(transform.markers[2], r.replaceRange.end.character);
-	}
-
-	function testIssue8659() {
-		var content = "class Main extends {-1-}StreamTokenizer{-2-} { }";
-		vfs.putContent("Main.hx", content);
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-		runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("Main.hx"), offset: transform.markers[2], wasAutoTriggered: true});
-		var result = parseCompletion();
-		var r = result.result;
-		Assert.equals("StreamTokenizer", r.filterString);
-		Assert.equals(transform.markers[1], r.replaceRange.start.character);
-		Assert.equals(transform.markers[2], r.replaceRange.end.character);
-	}
-
-	function testIssue8666() {
-		vfs.putContent("cp1/HelloWorld.hx", getTemplate("HelloWorld.hx"));
-		vfs.putContent("cp2/MyClass.hx", "class MyClass { }");
-		var args = ["-cp", "cp1", "--interp"];
-		runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
-		var completion = parseCompletion();
-		assertHasNoCompletion(completion, module -> switch (module.kind) {
-			case Type: module.args.path.typeName == "MyClass";
-			case _: false;
-		});
-		runHaxeJson(args.concat(["-cp", "cp2"]), DisplayMethods.Completion, {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
-		var completion = parseCompletion();
-		assertHasCompletion(completion, module -> switch (module.kind) {
-			case Type: module.args.path.typeName == "MyClass";
-			case _: false;
-		});
-	}
-
-	function testIssue8666_lib() {
-		vfs.putContent("cp1/HelloWorld.hx", getTemplate("HelloWorld.hx"));
-		vfs.putContent("cp2/MyClass.hx", "class MyClass { }");
-		var args = ["-cp", "cp1", "--interp"];
-		runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
-		var completion = parseCompletion();
-		assertHasNoCompletion(completion, module -> switch (module.kind) {
-			case Type: module.args.path.typeName == "MyClass";
-			case _: false;
-		});
-		runHaxeJson(args.concat(["-cp", "cp2", "-D", "imalibrary"]), DisplayMethods.Completion,
-			{file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
-		var completion = parseCompletion();
-		assertHasCompletion(completion, module -> switch (module.kind) {
-			case Type: module.args.path.typeName == "MyClass";
-			case _: false;
-		});
-	}
-
-	function testIssue8732() {
-		var content = "class Main { static function main() { var ident = \"foo\"; {-1-}i{-2-}dent.{-3-} } }";
-		vfs.putContent("Main.hx", content);
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-		runHaxeJson([], Methods.Initialize, {maxCompletionItems: 50});
-		runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("Main.hx"), offset: transform.markers[2], wasAutoTriggered: true});
-		runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("Main.hx"), offset: transform.markers[3], wasAutoTriggered: true});
-		runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("Main.hx"), offset: transform.markers[1], wasAutoTriggered: true});
-		var result = parseCompletion();
-		assertHasNoCompletion(result, item -> switch (item.kind) {
-			case ClassField: item.args.field.name == "charAt";
-			case _: false;
-		});
-	}
-
-	function testIssue8805_gotoAbstractPropertyWithInlineGetter() {
-		vfs.putContent("Main.hx", getTemplate("issues/Issue8805/Main.hx"));
-		var args = ["-main", "Main"];
-		runHaxeJson(args, DisplayMethods.GotoDefinition, {file: new FsPath("Main.hx"), offset: 56});
-		var result = parseGotoDefinition();
-		if (result.result.length == 0) {
-			Assert.fail('display/definition failed');
-		} else {
-			Assert.same({"start": {"line": 7, "character": 12}, "end": {"line": 7, "character": 15}}, result.result[0].range);
-		}
-	}
-
-	function testIssue8992() {
-		var mainHx = Marker.extractMarkers('class Main {
-	static func{-1-}tion main() {
-	}
-}');
-		vfs.putContent("Main.hx", mainHx.source);
-
-		runHaxe(["--no-output", "-main", "Main"]);
-		runHaxeJson([], DisplayMethods.Hover, {file: new FsPath("Main.hx"), offset: mainHx.markers[1]});
-
-		var result = parseHover().result;
-		Assert.isNull(result);
-	}
-
-	function testIssue8991() {
-		var mainHx = 'class Main {
-	static function main() {
-		C.inst{-1-}ance;
-	}
-}';
-		var cHx = 'class C {
-	public static var instance:Int;
-}';
-		var mainHx = Marker.extractMarkers(mainHx);
-		vfs.putContent("Main.hx", mainHx.source);
-		vfs.putContent("C.hx", cHx);
-
-		runHaxe(["--no-output", "-main", "Main"]);
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("C.hx")});
-		runHaxeJson([], DisplayMethods.Hover, {file: new FsPath("Main.hx"), offset: mainHx.markers[1]});
-
-		var result = parseHover().result;
-		Assert.equals(DisplayItemKind.ClassField, result.item.kind);
-	}
-
-	function testIssue9012() {
-		vfs.putContent("Some.hx", "class Some { public static function func():String return 'hello'; }");
-
-		var content = "import Some.func; class Main { static function main() { fu{-1-}nc(); } }";
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-
-		runHaxe(["--no-output", "-main", "Main"]); // commenting this makes it work
-		runHaxeJson([], DisplayMethods.Hover, {file: new FsPath("Main.hx"), offset: transform.markers[1]});
-		var result = parseHover().result;
-
-		Assert.equals(DisplayItemKind.ClassField, result.item.kind);
-	}
-
-	function testIssue9039() {
-		vfs.putContent("I.hx", "interface I { var prop(get,never):Int; }");
-		vfs.putContent("Main.hx", "class Main { static function main() { var i:I = null; } }");
-
-		runHaxe(["--no-output", "-main", "Main"]);
-
-		var content = "class Main { static function main() { var i:I = null; i.{-1-} } }";
-		var transform = Marker.extractMarkers(content);
-
-		vfs.putContent("Main.hx", transform.source);
-		runHaxeJson([], DisplayMethods.Completion, {
-			file: new FsPath("Main.hx"),
-			offset: transform.markers[1],
-			wasAutoTriggered: true
-		});
-
-		assertHasNoCompletion(parseCompletion(), function(item) {
-			return switch item.kind {
-				case ClassField: item.args.field.name == "get_prop";
-				case _: false;
-			}
-		});
-	}
-
-	function testIssue9047() {
-		var transform = Marker.extractMarkers("interface Main { var field(never,s{-1-}et):Int; }");
-		vfs.putContent("Main.hx", transform.source);
-		var args = ["Main", "-js", "main.js"];
-		function parseGotoDefintion():GotoDefinitionResult {
-			return haxe.Json.parse(lastResult.stderr).result;
-		}
-		runHaxeJson(args, DisplayMethods.FindReferences, {file: new FsPath("Main.hx"), offset: transform.markers[1], contents: transform.source});
-		Assert.same([], parseGotoDefintion().result);
-		runHaxeJson(args, DisplayMethods.FindReferences, {file: new FsPath("Main.hx"), offset: transform.markers[1], contents: transform.source});
-		Assert.same([], parseGotoDefintion().result);
-	}
-
-	function testIssue9082() {
-		var args = ["-cp", ".", "--interp"];
-
-		vfs.putContent("org/Thing.hx", "package org; class Thing {}");
-		vfs.putContent("AThing.hx", "class AThing {}");
-		vfs.putContent("ThingB.hx", "class ThingB {}");
-		runHaxeJson(args, Methods.Initialize, {maxCompletionItems: 2});
-		runHaxeJson(args, ServerMethods.ReadClassPaths, null);
-
-		var transform = Marker.extractMarkers("class C extends Thing{-1-}");
-		vfs.putContent("C.hx", transform.source);
-		runHaxeJson(args, DisplayMethods.Completion, {
-			file: new FsPath("C.hx"),
-			offset: transform.markers[1],
-			wasAutoTriggered: true
-		});
-		var result = parseCompletion();
-		assertHasCompletion(result, function(item) {
-			return switch item {
-				case {kind: Type, args: {path: {pack: ["org"], typeName: "Thing"}}}: true;
-				case _: false;
-			}
-		});
-	}
-
-	function testIssue9087() {
-		var content = getTemplate("issues/Issue9087/A.hx");
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("A.hx", transform.source);
-		var args = ["A", "-js", "main.js"];
-		function parseGotoDefintion():GotoDefinitionResult {
-			return haxe.Json.parse(lastResult.stderr).result;
-		}
-		runHaxeJson(args, DisplayMethods.GotoImplementation, {file: new FsPath("A.hx"), offset: transform.markers[1], contents: transform.source});
-		var result = parseGotoDefintion().result;
-		// TODO: We should use the markers, but I forgot how to get lines and characters from offsets
-		// Also That Assert.same doesn't work
-		Assert.equals(9, result[0].range.start.line);
-		Assert.equals(19, result[0].range.start.character);
-		Assert.equals(9, result[0].range.end.line);
-		Assert.equals(23, result[0].range.end.character);
-		// Assert.same([
-		// 	{
-		// 		range: {
-		// 			start: {line: 9, character: 1},
-		// 			end: {line: 11, character: 2}
-		// 		}
-		// 	}
-		// ], result);
-	}
-
-	function testIssue9115() {
-		var content = getTemplate("issues/Issue9115/A.hx");
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("A.hx", transform.source);
-		runHaxe(["--no-output", "A"]);
-		runHaxeJson([], DisplayMethods.Hover, {
-			file: new FsPath("A.hx"),
-			offset: transform.markers[1]
-		});
-		var result = parseHover();
-		Assert.equals("A", result.result.item.type.args.path.typeName /* lol */);
-	}
-
-	function testIssue7754() {
-		var content = '
-			class Main {
-				static function main() {
-					Foo.foo({-1-});
-				}
-			}
-			extern class Foo {
-				@:overload(function(?s:String):Void {})
-				static function foo(?i:Int):Void;
-			}
-		';
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-		runHaxeJson([], DisplayMethods.SignatureHelp, {
-			file: new FsPath("Main.hx"),
-			offset: transform.markers[1],
-			wasAutoTriggered: true
-		});
-		var result = parseSignatureHelp();
-		var sigs = result.result.signatures;
-		Assert.equals(2, sigs.length);
-		Assert.equals('Null<String>', strType(sigs[0].args[0].t));
-		Assert.equals('Null<Int>', strType(sigs[1].args[0].t));
-	}
-
-	function testIssue9159() {
-		var content = '
-			@:structInit
-			class CustomConstructor {
-				public var nope1:String;
-				public function new(x:Int = 0) {}
-				public function nope2() {}
-			}
-
-			@:structInit
-			class AutoConstructor {
-				public var y:Float;
-				public function nope() {}
-			}
-
-			class Main {
-				static function main() {
-					var a:CustomConstructor = {-1-}{};
-					var b:AutoConstructor = {-2-}{};
-				}
-			}
-		';
-		var transform = Marker.extractMarkers(content);
-		vfs.putContent("Main.hx", transform.source);
-
-		runHaxeJson([], DisplayMethods.Completion, {
-			file: new FsPath("Main.hx"),
-			offset: transform.markers[1],
-			wasAutoTriggered: true
-		});
-		var result = parseCompletion().result;
-		Assert.equals(1, result.items.length);
-		Assert.equals('x', result.items[0].args.field.name);
-
-		runHaxeJson([], DisplayMethods.Completion, {
-			file: new FsPath("Main.hx"),
-			offset: transform.markers[2],
-			wasAutoTriggered: true
-		});
-		var result = parseCompletion().result;
-		Assert.equals(1, result.items.length);
-		Assert.equals('y', result.items[0].args.field.name);
-	}
-}

+ 11 - 292
tests/server/src/Main.hx

@@ -1,297 +1,16 @@
-import haxe.io.Path;
-import sys.io.File;
-import haxe.display.Display;
-import haxe.display.FsPath;
-import haxe.display.Server;
-import utest.Assert;
-
-using StringTools;
-using Lambda;
-
-@:timeout(10000)
-class ServerTests extends HaxeServerTestCase {
-	function testNoModification() {
-		vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
-		var args = ["-main", "HelloWorld.hx", "--no-output", "-js", "no.js"];
-		runHaxe(args);
-		runHaxe(args);
-		assertReuse("HelloWorld");
-		runHaxe(args);
-		assertReuse("HelloWorld");
-	}
-
-	function testModification() {
-		vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
-		var args = ["-main", "HelloWorld.hx", "--no-output", "-js", "no.js"];
-		runHaxe(args);
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("HelloWorld.hx")});
-		runHaxe(args);
-		assertSkipping("HelloWorld");
-		// assertNotCacheModified("HelloWorld");
-	}
-
-	function testDependency() {
-		vfs.putContent("WithDependency.hx", getTemplate("WithDependency.hx"));
-		vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
-		var args = ["-main", "WithDependency.hx", "--no-output", "-js", "no.js"];
-		runHaxe(args);
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
-		runHaxe(args);
-		assertSkipping("WithDependency", "Dependency");
-		// assertNotCacheModified("Dependency");
-		runHaxe(args);
-		assertReuse("Dependency");
-		assertReuse("WithDependency");
-	}
-
-	function testMacro() {
-		vfs.putContent("MacroMain.hx", getTemplate("MacroMain.hx"));
-		vfs.putContent("Macro.hx", getTemplate("Macro.hx"));
-		var args = ["-main", "MacroMain.hx", "--no-output", "-js", "no.js"];
-		runHaxe(args);
-		assertHasPrint("1");
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("MacroMain.hx")});
-		runHaxe(args);
-		assertHasPrint("1");
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Macro.hx")});
-		runHaxe(args);
-		assertHasPrint("1");
-		vfs.putContent("Macro.hx", getTemplate("Macro.hx").replace("1", "2"));
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Macro.hx")});
-		runHaxe(args);
-		assertHasPrint("2");
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("MacroMain.hx")});
-		runHaxe(args);
-		assertHasPrint("2");
-	}
-
-	function testDceEmpty() {
-		vfs.putContent("Empty.hx", getTemplate("Empty.hx"));
-		var args = ["-main", "Empty", "--no-output", "-java", "java"];
-		runHaxe(args);
-		runHaxeJson(args, cast "typer/compiledTypes" /* TODO */, {});
-		assertHasField("", "Type", "enumIndex", true);
-	}
-
-	function testBuildMacro() {
-		vfs.putContent("BuildMacro.hx", getTemplate("BuildMacro.hx"));
-		vfs.putContent("BuiltClass.hx", getTemplate("BuiltClass.hx"));
-		var args = ["-main", "BuiltClass.hx", "--interp"];
-		runHaxe(args);
-		runHaxe(args);
-		assertReuse("BuiltClass");
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("BuildMacro.hx")});
-		runHaxe(args);
-		// assertNotCacheModified("BuildMacro");
-		assertSkipping("BuiltClass", "BuildMacro");
-		assertSkipping("BuildMacro");
-	}
-
-	function testBrokenSyntaxDiagnostics() {
-		vfs.putContent("BrokenSyntax.hx", getTemplate("BrokenSyntax.hx"));
-		vfs.putContent("Empty.hx", getTemplate("Empty.hx"));
-		var args = ["-main", "BrokenSyntax.hx", "--interp", "--no-output"];
-		runHaxe(args);
-		assertErrorMessage("Expected }");
-		runHaxe(args.concat(["--display", "Empty.hx@0@diagnostics"]));
-		runHaxe(args);
-		assertErrorMessage("Expected }");
-	}
-
-	function testGlobalBuildMacro_subsequentCompilations() {
-		vfs.putContent("GlobalBuildMacro.hx", getTemplate("GlobalBuildMacro.hx"));
-		var args = ["--macro", "GlobalBuildMacro.use()", "--run", "GlobalBuildMacro"];
-		runHaxe(args);
-		runHaxe(args);
-		assertSuccess();
-	}
-
-	#if false // @see https://github.com/HaxeFoundation/haxe/issues/8596#issuecomment-518815594
-	function testDisplayModuleRecache() {
-		vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
-		var args = ["--main", "HelloWorld", "--interp"];
-		runHaxe(args);
-		runHaxe(args);
-		assertReuse("HelloWorld");
-
-		var args2 = ["--main", "HelloWorld", "--interp", "--display", "HelloWorld.hx@64@type"];
-		runHaxe(args2);
-
-		runHaxe(args);
-		assertReuse("HelloWorld");
-
-		// make sure we still invalidate if the file does change
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("HelloWorld.hx")});
-		runHaxe(args2);
-
-		runHaxe(args);
-		assertSkipping("HelloWorld");
-	}
-	#end
-
-	#if false // @see https://github.com/HaxeFoundation/haxe/issues/8596#issuecomment-518815594
-	function testMutuallyDependent() {
-		vfs.putContent("MutuallyDependent1.hx", getTemplate("MutuallyDependent1.hx"));
-		vfs.putContent("MutuallyDependent2.hx", getTemplate("MutuallyDependent2.hx"));
-
-		var args = ["MutuallyDependent1", "MutuallyDependent2"];
-		runHaxe(args);
-
-		args = args.concat(["--display", "MutuallyDependent1.hx@44@type"]);
-		runHaxe(args);
-		assertSuccess();
-	}
-	#end
-
-	function testSyntaxCache() {
-		vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
-		runHaxeJson(["-cp", "."], ServerMethods.ReadClassPaths, null);
-		vfs.putContent("Empty.hx", "");
-		runHaxeJson([], ServerMethods.ModuleCreated, {file: new FsPath("Empty.hx")});
-		vfs.putContent("Empty.hx", getTemplate("Empty.hx"));
-		runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
-		var completion = parseCompletion();
-		assertHasCompletion(completion, module -> switch (module.kind) {
-			case Type: module.args.path.typeName == "HelloWorld";
-			case _: false;
-		});
-		assertHasCompletion(completion, module -> switch (module.kind) {
-			case Type: module.args.path.typeName == "Empty";
-			case _: false;
-		});
-		// check removal
-		vfs.putContent("Empty.hx", "");
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Empty.hx")});
-		runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
-		var completion = parseCompletion();
-		assertHasCompletion(completion, module -> switch (module.kind) {
-			case Type: module.args.path.typeName == "HelloWorld";
-			case _: false;
-		});
-		assertHasNoCompletion(completion, module -> switch (module.kind) {
-			case Type: module.args.path.typeName == "Empty";
-			case _: false;
-		});
-	}
-
-	function testSyntaxCache2() {
-		vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
-		var args = ["-cp", ".", "--interp"];
-		runHaxeJson(args, ServerMethods.ReadClassPaths, null);
-		vfs.putContent("Empty.hx", getTemplate("Empty.hx"));
-		runHaxeJson([] /* No args here because file watchers don't generally know */, ServerMethods.ModuleCreated, {file: new FsPath("Empty.hx")});
-		runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
-		var completion = parseCompletion();
-		assertHasCompletion(completion, module -> switch (module.kind) {
-			case Type: module.args.path.typeName == "Empty";
-			case _: false;
-		});
-	}
-
-	function testVectorInliner() {
-		vfs.putContent("Vector.hx", getTemplate("Vector.hx"));
-		vfs.putContent("VectorInliner.hx", getTemplate("VectorInliner.hx"));
-		var args = ["-main", "VectorInliner", "--interp"];
-		runHaxe(args);
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("VectorInliner.hx")});
-		runHaxeJson(args, cast "typer/compiledTypes" /* TODO */, {});
-		var type = getStoredType("", "VectorInliner");
-		function moreHack(s:String) {
-			return ~/[\r\n\t]/g.replace(s, "");
-		}
-		utest.Assert.equals("function() {_Vector.Vector_Impl_.toIntVector(null);}", moreHack(type.args.statics[0].expr.testHack)); // lmao
-	}
-
-	// See https://github.com/HaxeFoundation/haxe/issues/8368#issuecomment-525379060
-	#if false
-	function testXRedefinedFromX() {
-		vfs.putContent("Main.hx", getTemplate("issues/Issue8368/Main.hx"));
-		vfs.putContent("MyMacro.hx", getTemplate("issues/Issue8368/MyMacro.hx"));
-		vfs.putContent("Type1.hx", getTemplate("issues/Issue8368/Type1.hx"));
-		vfs.putContent("Type2.hx", getTemplate("issues/Issue8368/Type2.hx"));
-		var args = ["-main", "Main", "--macro", "define('whatever')"];
-		runHaxe(args);
-		runHaxe(args);
-		assertSuccess();
-	}
-	#end
-
-	function testMacroStaticsReset() {
-		vfs.putContent("Main.hx", getTemplate("issues/Issue8631/Main.hx"));
-		vfs.putContent("Init.hx", getTemplate("issues/Issue8631/Init.hx"));
-		vfs.putContent("Macro.hx", getTemplate("issues/Issue8631/Macro.hx"));
-		var hxml = ["-main", "Main", "--macro", "Init.callMacro()", "--interp"];
-		runHaxe(hxml);
-		runHaxe(hxml);
-		var counter = vfs.getContent("counter.txt");
-		utest.Assert.equals('2', counter);
-	}
-
-	function testIssue8738() {
-		vfs.putContent("Base.hx", getTemplate("issues/Issue8738/Base.hx"));
-		vfs.putContent("Main.hx", getTemplate("issues/Issue8738/Main1.hx"));
-		var args = ["-main", "Main", "--interp"];
-		runHaxe(args);
-		assertSuccess();
-		vfs.putContent("Main.hx", getTemplate("issues/Issue8738/Main2.hx"));
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")});
-		runHaxe(args);
-		assertErrorMessage("Cannot force inline-call to test because it is overridden");
-		vfs.putContent("Main.hx", getTemplate("issues/Issue8738/Main3.hx"));
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")});
-		runHaxe(args);
-		assertSuccess();
-	}
-
-	function testIssue8748() {
-		vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
-		vfs.putContent("WithDependency.hx", getTemplate("WithDependency.hx"));
-		vfs.putContent("res/dep.dep", "");
-		var args = [
-			"-main",
-			"WithDependency",
-			"--interp",
-			"--macro",
-			"haxe.macro.Context.registerModuleDependency(\"Dependency\", \"res/dep.dep\")"
-		];
-		runHaxeJson(args, ServerMethods.Configure, {noModuleChecks: true});
-		runHaxe(args);
-		runHaxeJson(args, DisplayMethods.Hover, {file: new FsPath("WithDependency.hx"), offset: 65});
-		assertReuse("Dependency");
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("res/dep.dep")});
-		runHaxeJson(args, DisplayMethods.Hover, {file: new FsPath("WithDependency.hx"), offset: 65});
-		// check messages manually because module file contains awkward absolute path
-		var r = ~/skipping Dependency\(.*dep.dep\)/;
-		Assert.isTrue(messages.exists(message -> r.match(message)));
-	}
-
-	function testIssue9029_analyzer_preventPurityOnOverridden() {
-		vfs.putContent("Main.hx", getTemplate("issues/Issue9029/Main.hx"));
-		vfs.putContent("Game.hx", getTemplate("issues/Issue9029/Game.hx"));
-		vfs.putContent("Screen.hx", getTemplate("issues/Issue9029/Screen.hx"));
-		var args = ["-main", "Main", "-D", "analyzer-optimize", "--interp"];
-		runHaxe(args);
-		vfs.putContent("Game.hx", getTemplate("issues/Issue9029/Game.hx.modified"));
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Game.hx")});
-		runHaxe(args);
-		assertSuccess();
-	}
-
-	// function testIssue8616() {
-	// 	vfs.putContent("Main.hx", getTemplate("issues/Issue8616/Main.hx"));
-	// 	vfs.putContent("A.hx", getTemplate("issues/Issue8616/A.hx"));
-	// 	var args = ["-main", "Main", "-js", "out.js"];
-	// 	runHaxe(args);
-	// 	runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")});
-	// 	runHaxe(args);
-	// 	var content = File.getContent(Path.join([testDir, "out.js"]));
-	// 	Assert.isTrue(content.indexOf("this1.use(v1)") != -1);
-	// }
-}
+import utest.ui.Report;
+import utest.Runner;
+import utils.Vfs;
 
 class Main {
 	static public function main() {
 		Vfs.removeDir("test/cases");
-		utest.UTest.run([new ServerTests(), new DisplayTests(), new ReplaceRanges()]);
+
+		var runner = new Runner();
+		runner.addCases('cases');
+		var report = Report.create(runner);
+		report.displayHeader = AlwaysShowHeader;
+		report.displaySuccessResults = NeverShowSuccessResults;
+		runner.run();
 	}
-}
+}

+ 4 - 3
tests/server/src/HaxeServerTestCase.hx → tests/server/src/TestCase.hx

@@ -7,12 +7,13 @@ import haxeserver.process.HaxeServerProcessNode;
 import haxeserver.HaxeServerAsync;
 import utest.Assert;
 import utest.ITest;
+import utils.Vfs;
 
 using StringTools;
 using Lambda;
 
-@:autoBuild(AsyncMacro.build())
-class HaxeServerTestCase implements ITest {
+@:autoBuild(utils.macro.BuildHub.build())
+class TestCase implements ITest {
 	var server:HaxeServerAsync;
 	var vfs:Vfs;
 	var testDir:String;
@@ -196,7 +197,7 @@ class HaxeServerTestCase implements ITest {
 		var params = t.args.params;
 		var parts = path.pack.concat([path.typeName]);
 		var s = parts.join('.');
-		if(params.length == 0) {
+		if (params.length == 0) {
 			return s;
 		}
 		var sParams = params.map(strType).join('.');

+ 3 - 1
tests/server/src/ReplaceRanges.hx → tests/server/src/cases/ReplaceRanges.hx

@@ -1,3 +1,5 @@
+package cases;
+
 import haxe.PosInfos;
 import haxe.display.FsPath;
 import haxe.display.Display;
@@ -5,7 +7,7 @@ import utest.Assert.*;
 
 @:timeout(5000)
 // TODO: somebody has to clean this up
-class ReplaceRanges extends HaxeServerTestCase {
+class ReplaceRanges extends TestCase {
 	function complete<S, T>(content:String, markerIndex:Int, cb:(response:CompletionResponse<S, T>, markers:Map<Int, Int>) -> Void) {
 		var transform = Marker.extractMarkers(content);
 		vfs.putContent("Main.hx", transform.source);

+ 240 - 0
tests/server/src/cases/ServerTests.hx

@@ -0,0 +1,240 @@
+package cases;
+
+import haxe.display.Display;
+import haxe.display.FsPath;
+import haxe.display.Server;
+import utest.Assert;
+
+using StringTools;
+using Lambda;
+
+@:timeout(10000)
+class ServerTests extends TestCase {
+	function testNoModification() {
+		vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
+		var args = ["-main", "HelloWorld.hx", "--no-output", "-js", "no.js"];
+		runHaxe(args);
+		runHaxe(args);
+		assertReuse("HelloWorld");
+		runHaxe(args);
+		assertReuse("HelloWorld");
+	}
+
+	function testModification() {
+		vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
+		var args = ["-main", "HelloWorld.hx", "--no-output", "-js", "no.js"];
+		runHaxe(args);
+		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("HelloWorld.hx")});
+		runHaxe(args);
+		assertSkipping("HelloWorld");
+		// assertNotCacheModified("HelloWorld");
+	}
+
+	function testDependency() {
+		vfs.putContent("WithDependency.hx", getTemplate("WithDependency.hx"));
+		vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
+		var args = ["-main", "WithDependency.hx", "--no-output", "-js", "no.js"];
+		runHaxe(args);
+		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
+		runHaxe(args);
+		assertSkipping("WithDependency", "Dependency");
+		// assertNotCacheModified("Dependency");
+		runHaxe(args);
+		assertReuse("Dependency");
+		assertReuse("WithDependency");
+	}
+
+	function testMacro() {
+		vfs.putContent("MacroMain.hx", getTemplate("MacroMain.hx"));
+		vfs.putContent("Macro.hx", getTemplate("Macro.hx"));
+		var args = ["-main", "MacroMain.hx", "--no-output", "-js", "no.js"];
+		runHaxe(args);
+		assertHasPrint("1");
+		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("MacroMain.hx")});
+		runHaxe(args);
+		assertHasPrint("1");
+		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Macro.hx")});
+		runHaxe(args);
+		assertHasPrint("1");
+		vfs.putContent("Macro.hx", getTemplate("Macro.hx").replace("1", "2"));
+		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Macro.hx")});
+		runHaxe(args);
+		assertHasPrint("2");
+		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("MacroMain.hx")});
+		runHaxe(args);
+		assertHasPrint("2");
+	}
+
+	function testDceEmpty() {
+		vfs.putContent("Empty.hx", getTemplate("Empty.hx"));
+		var args = ["-main", "Empty", "--no-output", "-java", "java"];
+		runHaxe(args);
+		runHaxeJson(args, cast "typer/compiledTypes" /* TODO */, {});
+		assertHasField("", "Type", "enumIndex", true);
+	}
+
+	function testBuildMacro() {
+		vfs.putContent("BuildMacro.hx", getTemplate("BuildMacro.hx"));
+		vfs.putContent("BuiltClass.hx", getTemplate("BuiltClass.hx"));
+		var args = ["-main", "BuiltClass.hx", "--interp"];
+		runHaxe(args);
+		runHaxe(args);
+		assertReuse("BuiltClass");
+		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("BuildMacro.hx")});
+		runHaxe(args);
+		// assertNotCacheModified("BuildMacro");
+		assertSkipping("BuiltClass", "BuildMacro");
+		assertSkipping("BuildMacro");
+	}
+
+	function testBrokenSyntaxDiagnostics() {
+		vfs.putContent("BrokenSyntax.hx", getTemplate("BrokenSyntax.hx"));
+		vfs.putContent("Empty.hx", getTemplate("Empty.hx"));
+		var args = ["-main", "BrokenSyntax.hx", "--interp", "--no-output"];
+		runHaxe(args);
+		assertErrorMessage("Expected }");
+		runHaxe(args.concat(["--display", "Empty.hx@0@diagnostics"]));
+		runHaxe(args);
+		assertErrorMessage("Expected }");
+	}
+
+	function testGlobalBuildMacro_subsequentCompilations() {
+		vfs.putContent("GlobalBuildMacro.hx", getTemplate("GlobalBuildMacro.hx"));
+		var args = ["--macro", "GlobalBuildMacro.use()", "--run", "GlobalBuildMacro"];
+		runHaxe(args);
+		runHaxe(args);
+		assertSuccess();
+	}
+
+	#if false // @see https://github.com/HaxeFoundation/haxe/issues/8596#issuecomment-518815594
+	function testDisplayModuleRecache() {
+		vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
+		var args = ["--main", "HelloWorld", "--interp"];
+		runHaxe(args);
+		runHaxe(args);
+		assertReuse("HelloWorld");
+
+		var args2 = ["--main", "HelloWorld", "--interp", "--display", "HelloWorld.hx@64@type"];
+		runHaxe(args2);
+
+		runHaxe(args);
+		assertReuse("HelloWorld");
+
+		// make sure we still invalidate if the file does change
+		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("HelloWorld.hx")});
+		runHaxe(args2);
+
+		runHaxe(args);
+		assertSkipping("HelloWorld");
+	}
+	#end
+
+	#if false // @see https://github.com/HaxeFoundation/haxe/issues/8596#issuecomment-518815594
+	function testMutuallyDependent() {
+		vfs.putContent("MutuallyDependent1.hx", getTemplate("MutuallyDependent1.hx"));
+		vfs.putContent("MutuallyDependent2.hx", getTemplate("MutuallyDependent2.hx"));
+
+		var args = ["MutuallyDependent1", "MutuallyDependent2"];
+		runHaxe(args);
+
+		args = args.concat(["--display", "MutuallyDependent1.hx@44@type"]);
+		runHaxe(args);
+		assertSuccess();
+	}
+	#end
+
+	function testSyntaxCache() {
+		vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
+		runHaxeJson(["-cp", "."], ServerMethods.ReadClassPaths, null);
+		vfs.putContent("Empty.hx", "");
+		runHaxeJson([], ServerMethods.ModuleCreated, {file: new FsPath("Empty.hx")});
+		vfs.putContent("Empty.hx", getTemplate("Empty.hx"));
+		runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
+		var completion = parseCompletion();
+		assertHasCompletion(completion, module -> switch (module.kind) {
+			case Type: module.args.path.typeName == "HelloWorld";
+			case _: false;
+		});
+		assertHasCompletion(completion, module -> switch (module.kind) {
+			case Type: module.args.path.typeName == "Empty";
+			case _: false;
+		});
+		// check removal
+		vfs.putContent("Empty.hx", "");
+		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Empty.hx")});
+		runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
+		var completion = parseCompletion();
+		assertHasCompletion(completion, module -> switch (module.kind) {
+			case Type: module.args.path.typeName == "HelloWorld";
+			case _: false;
+		});
+		assertHasNoCompletion(completion, module -> switch (module.kind) {
+			case Type: module.args.path.typeName == "Empty";
+			case _: false;
+		});
+	}
+
+	function testSyntaxCache2() {
+		vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
+		var args = ["-cp", ".", "--interp"];
+		runHaxeJson(args, ServerMethods.ReadClassPaths, null);
+		vfs.putContent("Empty.hx", getTemplate("Empty.hx"));
+		runHaxeJson([] /* No args here because file watchers don't generally know */, ServerMethods.ModuleCreated, {file: new FsPath("Empty.hx")});
+		runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
+		var completion = parseCompletion();
+		assertHasCompletion(completion, module -> switch (module.kind) {
+			case Type: module.args.path.typeName == "Empty";
+			case _: false;
+		});
+	}
+
+	function testVectorInliner() {
+		vfs.putContent("Vector.hx", getTemplate("Vector.hx"));
+		vfs.putContent("VectorInliner.hx", getTemplate("VectorInliner.hx"));
+		var args = ["-main", "VectorInliner", "--interp"];
+		runHaxe(args);
+		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("VectorInliner.hx")});
+		runHaxeJson(args, cast "typer/compiledTypes" /* TODO */, {});
+		var type = getStoredType("", "VectorInliner");
+		function moreHack(s:String) {
+			return ~/[\r\n\t]/g.replace(s, "");
+		}
+		utest.Assert.equals("function() {_Vector.Vector_Impl_.toIntVector(null);}", moreHack(type.args.statics[0].expr.testHack)); // lmao
+	}
+
+	// See https://github.com/HaxeFoundation/haxe/issues/8368#issuecomment-525379060
+	#if false
+	function testXRedefinedFromX() {
+		vfs.putContent("Main.hx", getTemplate("issues/Issue8368/Main.hx"));
+		vfs.putContent("MyMacro.hx", getTemplate("issues/Issue8368/MyMacro.hx"));
+		vfs.putContent("Type1.hx", getTemplate("issues/Issue8368/Type1.hx"));
+		vfs.putContent("Type2.hx", getTemplate("issues/Issue8368/Type2.hx"));
+		var args = ["-main", "Main", "--macro", "define('whatever')"];
+		runHaxe(args);
+		runHaxe(args);
+		assertSuccess();
+	}
+	#end
+
+	function testMacroStaticsReset() {
+		vfs.putContent("Main.hx", getTemplate("issues/Issue8631/Main.hx"));
+		vfs.putContent("Init.hx", getTemplate("issues/Issue8631/Init.hx"));
+		vfs.putContent("Macro.hx", getTemplate("issues/Issue8631/Macro.hx"));
+		var hxml = ["-main", "Main", "--macro", "Init.callMacro()", "--interp"];
+		runHaxe(hxml);
+		runHaxe(hxml);
+		var counter = vfs.getContent("counter.txt");
+		utest.Assert.equals('2', counter);
+	}
+
+	// function testIssue8616() {
+	// 	vfs.putContent("Main.hx", getTemplate("issues/Issue8616/Main.hx"));
+	// 	vfs.putContent("A.hx", getTemplate("issues/Issue8616/A.hx"));
+	// 	var args = ["-main", "Main", "-js", "out.js"];
+	// 	runHaxe(args);
+	// 	runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")});
+	// 	runHaxe(args);
+	// 	var content = sys.io.File.getContent(haxe.io.Path.join([testDir, "out.js"]));
+	// 	Assert.isTrue(content.indexOf("this1.use(v1)") != -1);
+	// }
+}

+ 20 - 0
tests/server/src/cases/display/issues/Issue7262.hx

@@ -0,0 +1,20 @@
+package cases.display.issues;
+
+class Issue7262 extends DisplayTestCase {
+	/**
+		class Main {
+			static public function main() {
+				var x:haxe.extern.EitherType<haxe.PosInfos, () -> Void> = {-1-}
+			}
+		}
+	**/
+	function test(_) {
+		runHaxeJson([], DisplayMethods.Completion, {
+			file: file,
+			offset: offset(1),
+			wasAutoTriggered: true
+		});
+		var result = parseCompletion().result;
+		Assert.equals("TAnonymous", result.mode.args.expectedTypeFollowed.args.params[0].kind);
+	}
+}

+ 23 - 0
tests/server/src/cases/display/issues/Issue7305.hx

@@ -0,0 +1,23 @@
+package cases.display.issues;
+
+class Issue7305 extends DisplayTestCase {
+	/**
+		class Main {
+			static public function main() {
+				new Map{-1-}
+			}
+		}
+	**/
+	function test(_) {
+		runHaxeJson([], DisplayMethods.Completion, {
+			file: file,
+			offset: offset(1),
+			wasAutoTriggered: true
+		});
+		var result = parseCompletion();
+		assertHasCompletion(result, item -> switch (item.kind) {
+			case Type: item.args.path.pack.length == 0 && item.args.path.typeName == "Map";
+			case _: false;
+		});
+	}
+}

+ 21 - 0
tests/server/src/cases/display/issues/Issue7317.hx

@@ -0,0 +1,21 @@
+package cases.display.issues;
+
+class Issue7317 extends DisplayTestCase {
+	/**
+		class Main {
+			public static function main() {
+				var obj = {};
+				obj.{-1-}
+			}
+		}
+	**/
+	function test(_) {
+		runHaxeJson([], DisplayMethods.Completion, {
+			file: file,
+			offset: offset(1),
+			wasAutoTriggered: true
+		});
+		var result = parseCompletion();
+		Assert.equals("obj", result.result.mode.args.item.args.name);
+	}
+}

+ 27 - 0
tests/server/src/cases/display/issues/Issue7754.hx

@@ -0,0 +1,27 @@
+package cases.display.issues;
+
+class Issue7754 extends DisplayTestCase {
+	/**
+		class Main {
+			static function main() {
+				Foo.foo({-1-});
+			}
+		}
+		extern class Foo {
+			@:overload(function(?s:String):Void {})
+			static function foo(?i:Int):Void;
+		}
+	**/
+	function test(_) {
+		runHaxeJson([], DisplayMethods.SignatureHelp, {
+			file: file,
+			offset: offset(1),
+			wasAutoTriggered: true
+		});
+		var result = parseSignatureHelp();
+		var sigs = result.result.signatures;
+		Assert.equals(2, sigs.length);
+		Assert.equals('Null<String>', strType(sigs[0].args[0].t));
+		Assert.equals('Null<Int>', strType(sigs[1].args[0].t));
+	}
+}

+ 20 - 0
tests/server/src/cases/display/issues/Issue7923.hx

@@ -0,0 +1,20 @@
+package cases.display.issues;
+
+class Issue7923 extends DisplayTestCase {
+	function test(_) {
+		vfs.putContent("TreeItem.hx", getTemplate("issues/Issue7923/TreeItem.hx"));
+		var content = getTemplate("issues/Issue7923/Main.hx");
+		var transform = Marker.extractMarkers(content);
+		vfs.putContent("Main.hx", transform.source);
+		runHaxeJson([], DisplayMethods.Completion, {
+			file: new FsPath("Main.hx"),
+			offset: transform.markers[1],
+			wasAutoTriggered: true
+		});
+		var result = parseCompletion();
+		assertHasCompletion(result, item -> switch (item.kind) {
+			case EnumAbstractField: item.args.field.name == "Collapsed";
+			case _: false;
+		});
+	}
+}

+ 20 - 0
tests/server/src/cases/display/issues/Issue8061.hx

@@ -0,0 +1,20 @@
+package cases.display.issues;
+
+class Issue8061 extends DisplayTestCase {
+	/**
+		class Main {
+			static function main() {
+				new sys.io.Process({-1-})
+			}
+		}
+	**/
+	function test(_) {
+		runHaxeJson([], DisplayMethods.SignatureHelp, {
+			file: file,
+			offset: offset(1),
+			wasAutoTriggered: true
+		});
+		var result = parseSignatureHelp();
+		Assert.isTrue(result.result.signatures[0].documentation != null);
+	}
+}

+ 23 - 0
tests/server/src/cases/display/issues/Issue8194.hx

@@ -0,0 +1,23 @@
+package cases.display.issues;
+
+class Issue8194 extends DisplayTestCase {
+	/**
+		class Main {
+			static function main() {
+				switch ("p") {
+					case "p"{-1-}
+						"foo";
+				}
+			}
+		}
+	**/
+	function test(_) {
+		runHaxeJson([], DisplayMethods.Completion, {
+			file: file,
+			offset: offset(1),
+			wasAutoTriggered: true
+		});
+		var result = parseCompletion();
+		Assert.equals(null, result.result);
+	}
+}

+ 27 - 0
tests/server/src/cases/display/issues/Issue8381.hx

@@ -0,0 +1,27 @@
+package cases.display.issues;
+
+class Issue8381 extends DisplayTestCase {
+	/**
+		class Main {
+			static function main() {
+				var f:Foo;
+				f.f{-1-}oo();
+				f.bar;
+			}
+		}
+
+		typedef Foo = {
+			function foo():Void;
+
+			var bar:Int;
+		}
+	**/
+	function test(_) {
+		runHaxeJson([], DisplayMethods.Hover, {
+			file: file,
+			offset: offset(1)
+		});
+		var result = parseHover();
+		Assert.equals(DisplayItemKind.ClassField, result.result.item.kind);
+	}
+}

+ 19 - 0
tests/server/src/cases/display/issues/Issue8438.hx

@@ -0,0 +1,19 @@
+package cases.display.issues;
+
+class Issue8438 extends DisplayTestCase {
+	/**class Main {
+	static function main() {
+		" ".char{-1-}
+	}
+}**/
+	function test(_) {
+		runHaxeJson([], DisplayMethods.Completion, {
+			file: file,
+			offset: offset(1),
+			wasAutoTriggered: true
+		});
+		var result = parseCompletion();
+		Assert.equals(6, result.result.replaceRange.start.character);
+		Assert.equals(10, result.result.replaceRange.end.character);
+	}
+}

+ 16 - 0
tests/server/src/cases/display/issues/Issue8602.hx

@@ -0,0 +1,16 @@
+package cases.display.issues;
+
+class Issue8602 extends DisplayTestCase {
+	/**
+		class Main {
+			static function main() {
+				haxe.ds.{-1-}
+			}
+		}
+	**/
+	function test(_) {
+		runHaxeJson([], DisplayMethods.Completion, {file: file, offset: offset(1), wasAutoTriggered: true});
+		var result = parseCompletion();
+		Assert.equals(Toplevel, result.result.mode.kind);
+	}
+}

+ 17 - 0
tests/server/src/cases/display/issues/Issue8644.hx

@@ -0,0 +1,17 @@
+package cases.display.issues;
+
+import haxe.display.Server.ServerMethods;
+
+class Issue8644 extends DisplayTestCase {
+	function test(_) {
+		vfs.putContent("HelloJvm.hx", getTemplate("HelloJvm.hx"));
+		var args = ["-cp", ".", "--interp"];
+		runHaxeJson(args, ServerMethods.ReadClassPaths, null);
+		runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("HelloJvm.hx"), offset: 55, wasAutoTriggered: false});
+		var completion = parseCompletion();
+		assertHasNoCompletion(completion, module -> switch (module.kind) {
+			case Type: module.args.path.typeName == "Jvm";
+			case _: false;
+		});
+	}
+}

+ 13 - 0
tests/server/src/cases/display/issues/Issue8651.hx

@@ -0,0 +1,13 @@
+package cases.display.issues;
+
+class Issue8651 extends DisplayTestCase {
+	/**class Main { static function main() { {-1-}buffer{-2-} } }**/
+	function test(_) {
+		runHaxeJson([], DisplayMethods.Completion, {file: file, offset: offset(2), wasAutoTriggered: true});
+		var result = parseCompletion();
+		var r = result.result;
+		Assert.equals("buffer", r.filterString);
+		Assert.equals(offset(1), r.replaceRange.start.character);
+		Assert.equals(offset(2), r.replaceRange.end.character);
+	}
+}

+ 13 - 0
tests/server/src/cases/display/issues/Issue8657.hx

@@ -0,0 +1,13 @@
+package cases.display.issues;
+
+class Issue8657 extends DisplayTestCase {
+	/**class Main { static function main() { var x:{-1-}stream{-2-} } }**/
+	function test(_) {
+		runHaxeJson([], DisplayMethods.Completion, {file: file, offset: offset(2), wasAutoTriggered: true});
+		var result = parseCompletion();
+		var r = result.result;
+		Assert.equals("stream", r.filterString);
+		Assert.equals(offset(1), r.replaceRange.start.character);
+		Assert.equals(offset(2), r.replaceRange.end.character);
+	}
+}

+ 13 - 0
tests/server/src/cases/display/issues/Issue8659.hx

@@ -0,0 +1,13 @@
+package cases.display.issues;
+
+class Issue8659 extends DisplayTestCase {
+	/**class Main extends {-1-}StreamTokenizer{-2-} { }**/
+	function test(_) {
+		runHaxeJson([], DisplayMethods.Completion, {file: file, offset: offset(2), wasAutoTriggered: true});
+		var result = parseCompletion();
+		var r = result.result;
+		Assert.equals("StreamTokenizer", r.filterString);
+		Assert.equals(offset(1), r.replaceRange.start.character);
+		Assert.equals(offset(2), r.replaceRange.end.character);
+	}
+}

+ 40 - 0
tests/server/src/cases/display/issues/Issue8666.hx

@@ -0,0 +1,40 @@
+package cases.display.issues;
+
+class Issue8666 extends DisplayTestCase {
+	function test(_) {
+		vfs.putContent("cp1/HelloWorld.hx", getTemplate("HelloWorld.hx"));
+		vfs.putContent("cp2/MyClass.hx", "class MyClass { }");
+		var args = ["-cp", "cp1", "--interp"];
+		runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
+		var completion = parseCompletion();
+		assertHasNoCompletion(completion, module -> switch (module.kind) {
+			case Type: module.args.path.typeName == "MyClass";
+			case _: false;
+		});
+		runHaxeJson(args.concat(["-cp", "cp2"]), DisplayMethods.Completion, {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
+		var completion = parseCompletion();
+		assertHasCompletion(completion, module -> switch (module.kind) {
+			case Type: module.args.path.typeName == "MyClass";
+			case _: false;
+		});
+	}
+
+	function testLib(_) {
+		vfs.putContent("cp1/HelloWorld.hx", getTemplate("HelloWorld.hx"));
+		vfs.putContent("cp2/MyClass.hx", "class MyClass { }");
+		var args = ["-cp", "cp1", "--interp"];
+		runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
+		var completion = parseCompletion();
+		assertHasNoCompletion(completion, module -> switch (module.kind) {
+			case Type: module.args.path.typeName == "MyClass";
+			case _: false;
+		});
+		runHaxeJson(args.concat(["-cp", "cp2", "-D", "imalibrary"]), DisplayMethods.Completion,
+			{file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
+		var completion = parseCompletion();
+		assertHasCompletion(completion, module -> switch (module.kind) {
+			case Type: module.args.path.typeName == "MyClass";
+			case _: false;
+		});
+	}
+}

+ 20 - 0
tests/server/src/cases/display/issues/Issue8732.hx

@@ -0,0 +1,20 @@
+package cases.display.issues;
+
+import haxe.display.Protocol;
+
+class Issue8732 extends DisplayTestCase {
+	/**
+		class Main { static function main() { var ident = "foo"; {-1-}i{-2-}dent.{-3-} } }
+	**/
+	function test(_) {
+		runHaxeJson([], Methods.Initialize, {maxCompletionItems: 50});
+		runHaxeJson([], DisplayMethods.Completion, {file: file, offset: offset(2), wasAutoTriggered: true});
+		runHaxeJson([], DisplayMethods.Completion, {file: file, offset: offset(3), wasAutoTriggered: true});
+		runHaxeJson([], DisplayMethods.Completion, {file: file, offset: offset(1), wasAutoTriggered: true});
+		var result = parseCompletion();
+		assertHasNoCompletion(result, item -> switch (item.kind) {
+			case ClassField: item.args.field.name == "charAt";
+			case _: false;
+		});
+	}
+}

+ 15 - 0
tests/server/src/cases/display/issues/Issue8805.hx

@@ -0,0 +1,15 @@
+package cases.display.issues;
+
+class Issue8805 extends DisplayTestCase {
+	function testIssue8805_gotoAbstractPropertyWithInlineGetter(_) {
+		vfs.putContent("Main.hx", getTemplate("issues/Issue8805/Main.hx"));
+		var args = ["-main", "Main"];
+		runHaxeJson(args, DisplayMethods.GotoDefinition, {file: file, offset: 56});
+		var result = parseGotoDefinition();
+		if (result.result.length == 0) {
+			Assert.fail('display/definition failed');
+		} else {
+			Assert.same({"start": {"line": 7, "character": 12}, "end": {"line": 7, "character": 15}}, result.result[0].range);
+		}
+	}
+}

+ 26 - 0
tests/server/src/cases/display/issues/Issue8991.hx

@@ -0,0 +1,26 @@
+package cases.display.issues;
+
+import haxe.display.Server;
+
+class Issue8991 extends DisplayTestCase {
+	function test(_) {
+		var mainHx = 'class Main {
+	static function main() {
+		C.inst{-1-}ance;
+	}
+}';
+		var cHx = 'class C {
+	public static var instance:Int;
+}';
+		var mainHx = Marker.extractMarkers(mainHx);
+		vfs.putContent("Main.hx", mainHx.source);
+		vfs.putContent("C.hx", cHx);
+
+		runHaxe(["--no-output", "-main", "Main"]);
+		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("C.hx")});
+		runHaxeJson([], DisplayMethods.Hover, {file: file, offset: mainHx.markers[1]});
+
+		var result = parseHover().result;
+		Assert.equals(DisplayItemKind.ClassField, result.item.kind);
+	}
+}

+ 19 - 0
tests/server/src/cases/display/issues/Issue8992.hx

@@ -0,0 +1,19 @@
+package cases.display.issues;
+
+import haxe.display.Protocol;
+
+class Issue8992 extends DisplayTestCase {
+	/**
+		class Main {
+			static func{-1-}tion main() {
+			}
+		}
+	**/
+	function test(_) {
+		runHaxe(["--no-output", "-main", "Main"]);
+		runHaxeJson([], DisplayMethods.Hover, {file: file, offset: offset(1)});
+
+		var result = parseHover().result;
+		Assert.isNull(result);
+	}
+}

+ 17 - 0
tests/server/src/cases/display/issues/Issue9012.hx

@@ -0,0 +1,17 @@
+package cases.display.issues;
+
+class Issue9012 extends DisplayTestCase {
+	function test(_) {
+		vfs.putContent("Some.hx", "class Some { public static function func():String return 'hello'; }");
+
+		var content = "import Some.func; class Main { static function main() { fu{-1-}nc(); } }";
+		var transform = Marker.extractMarkers(content);
+		vfs.putContent("Main.hx", transform.source);
+
+		runHaxe(["--no-output", "-main", "Main"]); // commenting this makes it work
+		runHaxeJson([], DisplayMethods.Hover, {file: file, offset: transform.markers[1]});
+		var result = parseHover().result;
+
+		Assert.equals(DisplayItemKind.ClassField, result.item.kind);
+	}
+}

+ 27 - 0
tests/server/src/cases/display/issues/Issue9039.hx

@@ -0,0 +1,27 @@
+package cases.display.issues;
+
+class Issue9039 extends DisplayTestCase {
+	function test(_) {
+		vfs.putContent("I.hx", "interface I { var prop(get,never):Int; }");
+		vfs.putContent("Main.hx", "class Main { static function main() { var i:I = null; } }");
+
+		runHaxe(["--no-output", "-main", "Main"]);
+
+		var content = "class Main { static function main() { var i:I = null; i.{-1-} } }";
+		var transform = Marker.extractMarkers(content);
+
+		vfs.putContent("Main.hx", transform.source);
+		runHaxeJson([], DisplayMethods.Completion, {
+			file: file,
+			offset: transform.markers[1],
+			wasAutoTriggered: true
+		});
+
+		assertHasNoCompletion(parseCompletion(), function(item) {
+			return switch item.kind {
+				case ClassField: item.args.field.name == "get_prop";
+				case _: false;
+			}
+		});
+	}
+}

+ 17 - 0
tests/server/src/cases/display/issues/Issue9047.hx

@@ -0,0 +1,17 @@
+package cases.display.issues;
+
+class Issue9047 extends DisplayTestCase {
+	/**
+		interface Main { var field(never,s{-1-}et):Int; }
+	**/
+	function test(_) {
+		var args = ["Main", "-js", "main.js"];
+		function parseGotoDefintion():GotoDefinitionResult {
+			return haxe.Json.parse(lastResult.stderr).result;
+		}
+		runHaxeJson(args, DisplayMethods.FindReferences, {file: file, offset: offset(1), contents: source});
+		Assert.same([], parseGotoDefintion().result);
+		runHaxeJson(args, DisplayMethods.FindReferences, {file: file, offset: offset(1), contents: source});
+		Assert.same([], parseGotoDefintion().result);
+	}
+}

+ 31 - 0
tests/server/src/cases/display/issues/Issue9082.hx

@@ -0,0 +1,31 @@
+package cases.display.issues;
+
+import haxe.display.Server;
+import haxe.display.Protocol;
+
+class Issue9082 extends DisplayTestCase {
+	function test(_) {
+		var args = ["-cp", ".", "--interp"];
+
+		vfs.putContent("org/Thing.hx", "package org; class Thing {}");
+		vfs.putContent("AThing.hx", "class AThing {}");
+		vfs.putContent("ThingB.hx", "class ThingB {}");
+		runHaxeJson(args, Methods.Initialize, {maxCompletionItems: 2});
+		runHaxeJson(args, ServerMethods.ReadClassPaths, null);
+
+		var markers = Markers.parse("class C extends Thing{-1-}");
+		vfs.putContent("C.hx", markers.source);
+		runHaxeJson(args, DisplayMethods.Completion, {
+			file: new FsPath("C.hx"),
+			offset: markers.offset(1),
+			wasAutoTriggered: true
+		});
+		var result = parseCompletion();
+		assertHasCompletion(result, function(item) {
+			return switch item {
+				case {kind: Type, args: {path: {pack: ["org"], typeName: "Thing"}}}: true;
+				case _: false;
+			}
+		});
+	}
+}

+ 29 - 0
tests/server/src/cases/display/issues/Issue9087.hx

@@ -0,0 +1,29 @@
+package cases.display.issues;
+
+class Issue9087 extends DisplayTestCase {
+	function test(_) {
+		var content = getTemplate("issues/Issue9087/A.hx");
+		var markers = Markers.parse(content);
+		vfs.putContent("A.hx", markers.source);
+		var args = ["A", "-js", "main.js"];
+		function parseGotoDefintion():GotoDefinitionResult {
+			return haxe.Json.parse(lastResult.stderr).result;
+		}
+		runHaxeJson(args, DisplayMethods.GotoImplementation, {file: new FsPath("A.hx"), offset: markers.offset(1), contents: markers.source});
+		var result = parseGotoDefintion().result;
+		// TODO: We should use the markers, but I forgot how to get lines and characters from offsets
+		// Also That Assert.same doesn't work
+		Assert.equals(9, result[0].range.start.line);
+		Assert.equals(19, result[0].range.start.character);
+		Assert.equals(9, result[0].range.end.line);
+		Assert.equals(23, result[0].range.end.character);
+		// Assert.same([
+		// 	{
+		// 		range: {
+		// 			start: {line: 9, character: 1},
+		// 			end: {line: 11, character: 2}
+		// 		}
+		// 	}
+		// ], result);
+	}
+}

+ 16 - 0
tests/server/src/cases/display/issues/Issue9115.hx

@@ -0,0 +1,16 @@
+package cases.display.issues;
+
+class Issue9115 extends DisplayTestCase {
+	function test(_) {
+		var content = getTemplate("issues/Issue9115/A.hx");
+		var markers = Markers.parse(content);
+		vfs.putContent("A.hx", markers.source);
+		runHaxe(["--no-output", "A"]);
+		runHaxeJson([], DisplayMethods.Hover, {
+			file: new FsPath("A.hx"),
+			offset: markers.offset(1)
+		});
+		var result = parseHover();
+		Assert.equals("A", result.result.item.type.args.path.typeName /* lol */);
+	}
+}

+ 44 - 0
tests/server/src/cases/display/issues/Issue9159.hx

@@ -0,0 +1,44 @@
+package cases.display.issues;
+
+class Issue9159 extends DisplayTestCase {
+	/**
+		@:structInit
+		class CustomConstructor {
+			public var nope1:String;
+			public function new(x:Int = 0) {}
+			public function nope2() {}
+		}
+
+		@:structInit
+		class AutoConstructor {
+			public var y:Float;
+			public function nope() {}
+		}
+
+		class Main {
+			static function main() {
+				var a:CustomConstructor = {-1-}{};
+				var b:AutoConstructor = {-2-}{};
+			}
+		}
+	**/
+	function test(_) {
+		runHaxeJson([], DisplayMethods.Completion, {
+			file: file,
+			offset: offset(1),
+			wasAutoTriggered: true
+		});
+		var result = parseCompletion().result;
+		Assert.equals(1, result.items.length);
+		Assert.equals('x', result.items[0].args.field.name);
+
+		runHaxeJson([], DisplayMethods.Completion, {
+			file: file,
+			offset: offset(2),
+			wasAutoTriggered: true
+		});
+		var result = parseCompletion().result;
+		Assert.equals(1, result.items.length);
+		Assert.equals('y', result.items[0].args.field.name);
+	}
+}

+ 19 - 0
tests/server/src/cases/issues/Issue8738.hx

@@ -0,0 +1,19 @@
+package cases.issues;
+
+class Issue8738 extends TestCase {
+	function test(_) {
+		vfs.putContent("Base.hx", getTemplate("issues/Issue8738/Base.hx"));
+		vfs.putContent("Main.hx", getTemplate("issues/Issue8738/Main1.hx"));
+		var args = ["-main", "Main", "--interp"];
+		runHaxe(args);
+		assertSuccess();
+		vfs.putContent("Main.hx", getTemplate("issues/Issue8738/Main2.hx"));
+		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")});
+		runHaxe(args);
+		assertErrorMessage("Cannot force inline-call to test because it is overridden");
+		vfs.putContent("Main.hx", getTemplate("issues/Issue8738/Main3.hx"));
+		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")});
+		runHaxe(args);
+		assertSuccess();
+	}
+}

+ 25 - 0
tests/server/src/cases/issues/Issue8748.hx

@@ -0,0 +1,25 @@
+package cases.issues;
+
+class Issue8748 extends TestCase {
+	function test(_) {
+		vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
+		vfs.putContent("WithDependency.hx", getTemplate("WithDependency.hx"));
+		vfs.putContent("res/dep.dep", "");
+		var args = [
+			"-main",
+			"WithDependency",
+			"--interp",
+			"--macro",
+			"haxe.macro.Context.registerModuleDependency(\"Dependency\", \"res/dep.dep\")"
+		];
+		runHaxeJson(args, ServerMethods.Configure, {noModuleChecks: true});
+		runHaxe(args);
+		runHaxeJson(args, DisplayMethods.Hover, {file: new FsPath("WithDependency.hx"), offset: 65});
+		assertReuse("Dependency");
+		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("res/dep.dep")});
+		runHaxeJson(args, DisplayMethods.Hover, {file: new FsPath("WithDependency.hx"), offset: 65});
+		// check messages manually because module file contains awkward absolute path
+		var r = ~/skipping Dependency\(.*dep.dep\)/;
+		Assert.isTrue(messages.exists(message -> r.match(message)));
+	}
+}

+ 15 - 0
tests/server/src/cases/issues/Issue9029.hx

@@ -0,0 +1,15 @@
+package cases.issues;
+
+class Issue9029 extends TestCase {
+	function testIssue9029_analyzer_preventPurityOnOverridden(_) {
+		vfs.putContent("Main.hx", getTemplate("issues/Issue9029/Main.hx"));
+		vfs.putContent("Game.hx", getTemplate("issues/Issue9029/Game.hx"));
+		vfs.putContent("Screen.hx", getTemplate("issues/Issue9029/Screen.hx"));
+		var args = ["-main", "Main", "-D", "analyzer-optimize", "--interp"];
+		runHaxe(args);
+		vfs.putContent("Game.hx", getTemplate("issues/Issue9029/Game.hx.modified"));
+		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Game.hx")});
+		runHaxe(args);
+		assertSuccess();
+	}
+}

+ 10 - 0
tests/server/src/import.hx

@@ -0,0 +1,10 @@
+package cases.display;
+
+import haxe.display.Display;
+import haxe.display.FsPath;
+import haxe.display.Server;
+import utest.Assert;
+import utils.Markers;
+
+using Lambda;
+using StringTools;

+ 88 - 0
tests/server/src/utils/Markers.hx

@@ -0,0 +1,88 @@
+package utils;
+
+import haxe.Exception;
+import haxe.display.Position;
+
+/**
+ * Parses a document with markers.
+ * Marker format: `{-N-}`, where `N` is an integer number.
+ */
+class Markers {
+	/** Parsed document with all markers removed. */
+	public final source:String;
+
+	final offsets:Array<Int>;
+	final positions:Array<Position>;
+
+	static public function parse(doc:String):Markers {
+		var positions = [];
+		var offsets = [];
+		var line = 0;
+		var lastNewLinePos = 0;
+		var markersLengthSum = 0;
+		var markersLengthSinceNewLine = 0;
+		var source = ~/{-(\d+)-}|\n/g.map(doc, function(r) {
+			var p = r.matchedPos();
+			var replacement = switch r.matched(0) {
+				case '\n':
+					line++;
+					lastNewLinePos = p.pos;
+					markersLengthSinceNewLine = 0;
+					'\n';
+				case _:
+					var name = r.matched(1);
+					switch Std.parseInt(name) {
+						case null:
+							throw new Exception('Invalid marker name: {-$name-}');
+						case n:
+							offsets[n] = p.pos - markersLengthSum;
+							var character = p.pos - (lastNewLinePos + 1) - markersLengthSinceNewLine;
+							positions[n] = {line: line, character: character};
+					}
+					markersLengthSum += p.len;
+					markersLengthSinceNewLine += p.len;
+					"";
+			}
+			return replacement;
+		});
+		return new Markers(source, offsets, positions);
+	}
+
+	function new(source:String, offsets:Array<Int>, positions:Array<Position>) {
+		this.source = source;
+		this.offsets = offsets;
+		this.positions = positions;
+	}
+
+	/**
+	 * Returns an offset of the n-th marker.
+	 * Amount of characters from the beginning of the parsed document excluding markers.
+	 */
+	public function offset(n:Int):Int {
+		return switch offsets[n] {
+			case null: throw new Exception('Marker {-$n-} not found');
+			case pos: pos;
+		}
+	}
+
+	/**
+	 * Returns a position of n-th marker.
+	 * Line number and character number from the beginning of the line.
+	 */
+	public function pos(n:Int):Position {
+		return switch positions[n] {
+			case null: throw new Exception('Marker {-$n-} not found');
+			case pos: pos;
+		}
+	}
+
+	/**
+	 * Returns a range between positions of `startMarker` and `endMarker`
+	 */
+	public function range(startMarker:Int, endMarker:Int):Range {
+		return {
+			start: pos(startMarker),
+			end: pos(endMarker)
+		}
+	}
+}

+ 2 - 0
tests/server/src/Vfs.hx → tests/server/src/utils/Vfs.hx

@@ -1,3 +1,5 @@
+package utils;
+
 import js.node.Fs;
 import sys.FileSystem;
 import haxe.io.Path;

+ 31 - 0
tests/server/src/utils/macro/BuildHub.macro.hx

@@ -0,0 +1,31 @@
+package utils.macro;
+
+import haxe.macro.Context;
+import haxe.macro.Expr;
+import haxe.macro.Type;
+
+class BuildHub {
+	macro static public function build():Array<Field> {
+		var fields = Context.getBuildFields();
+
+		switch Context.getLocalClass() {
+			case null:
+			case _.get() => cls:
+				if(isDisplayTest(cls)) {
+					fields = DisplayTestBuilder.build(fields);
+				}
+		}
+
+		return TestBuilder.build(fields);
+	}
+
+	static function isDisplayTest(cls:ClassType):Bool {
+		if(cls.pack.length == 0 && cls.name == "DisplayTestCase") {
+			return true;
+		}
+		return switch cls.superClass {
+			case null: false;
+			case _.t.get() => cls: isDisplayTest(cls);
+		}
+	}
+}

+ 58 - 0
tests/server/src/utils/macro/DisplayTestBuilder.macro.hx

@@ -0,0 +1,58 @@
+package utils.macro;
+
+import haxe.macro.Context;
+import haxe.macro.Expr;
+import haxe.Exception;
+
+using StringTools;
+
+private class BuilderException extends Exception {
+	override function toString():String {
+		return message;
+	}
+}
+
+class DisplayTestBuilder {
+	static public function build(fields:Array<Field>):Array<Field> {
+		for (field in fields) {
+			if (field.name.startsWith('test')) {
+				try {
+					patchExpr(field);
+				} catch (e) {
+					Context.error('Failed to build display test: $e', field.pos);
+				}
+			}
+		}
+		return fields;
+	}
+
+	static function patchExpr(field:Field) {
+		switch field.kind {
+			case FFun(fn):
+				switch fn.expr {
+					case null:
+					case { expr:EBlock(exprs) }:
+						exprs.unshift(generateInit(field));
+					case e:
+						fn.expr = macro {
+							${generateInit(field)};
+							$e;
+						}
+				}
+			case _:
+		}
+	}
+
+	static function generateInit(field:Field):Expr {
+		return switch field.doc {
+			case null:
+				macro async.setTimeout(5000);
+			case src:
+				macro {
+					async.setTimeout(5000);
+					_markers = utils.Markers.parse($v{src});
+					vfs.putContent("Main.hx", markers.source);
+				}
+		}
+	}
+}

+ 27 - 9
tests/server/src/AsyncMacro.hx → tests/server/src/utils/macro/TestBuilder.macro.hx

@@ -1,27 +1,45 @@
+package utils.macro;
+
 import haxe.macro.Expr;
 import haxe.macro.Context;
 
 using StringTools;
 
-class AsyncMacro {
-	static public macro function build():Array<Field> {
-		var fields = Context.getBuildFields();
+class TestBuilder {
+	static public function build(fields:Array<Field>):Array<Field> {
 		for (field in fields) {
 			if (!field.name.startsWith("test")) {
 				continue;
 			}
 			switch (field.kind) {
 				case FFun(f):
-					f.args.push({
-						name: "async",
-						type: macro:utest.Async
-					});
+					var asyncName = switch f.args {
+						case []:
+							var name = "async";
+							f.args.push({
+								name: name,
+								type: macro:utest.Async
+							});
+							name;
+						case [arg]:
+							if(arg.name == "_") {
+								arg.name = "async";
+								arg.type = macro:utest.Async;
+							}
+							arg.name;
+						case _:
+							Context.fatalError('Unexpected amount of test arguments', field.pos);
+							"";
+					}
 					switch (f.expr.expr) {
 						case EBlock(el):
 							var posInfos = Context.getPosInfos(f.expr.pos);
 							var pos = Context.makePosition({min: posInfos.max, max: posInfos.max, file: posInfos.file});
-							el.push(macro @:pos(pos) async.done());
-							f.expr = transformHaxeCalls(el);
+							el.push(macro @:pos(pos) $i{asyncName}.done());
+							f.expr = macro {
+								$i{asyncName}.setTimeout(10000);
+								${transformHaxeCalls(el)};
+							}
 						case _:
 							Context.error("Block expression expected", f.expr.pos);
 					}