Просмотр исходного кода

added specification for Std.hx

Simon Krajewski 12 лет назад
Родитель
Сommit
17d72d471b
5 измененных файлов с 187 добавлено и 83 удалено
  1. 46 5
      std/Std.hx
  2. 1 0
      tests/unit/Test.hx
  3. 28 70
      tests/unit/TestBasetypes.hx
  4. 0 8
      tests/unit/TestMisc.hx
  5. 112 0
      tests/unit/TestSpecification.hx

+ 46 - 5
std/Std.hx

@@ -29,32 +29,73 @@
 extern class Std {
 
 	/**
-		Tells if a value v is of the type t.
+		Tells if a value v is of the type t. Returns false if v or t are null.
 	**/
 	public static function is( v : Dynamic, t : Dynamic ) : Bool;
 
 	/**
-		Convert any value to a String
+		Converts any value to a String.
+		
+		If s is of String, Int, Float or Bool, its value is returned.
+		
+		If s is an instance of a class and that class or one of its parent classes has
+		a toString() method, that method is called. If no such method is present, the result
+		is unspecified.
+		
+		If s is an enum constructor without argument, the constructor's name is returned. If
+		arguments exists, the constructor's name followed by the String representations of
+		the arguments is returned.
+		
+		If s is a structure, the field names along with their values are returned. The field order
+		and the operator separating field names and values are unspecified.
+		
+		If s is null, "null" is returned.
 	**/
 	public static function string( s : Dynamic ) : String;
 
 	/**
-		Convert a Float to an Int, rounded down.
+		Converts a Float to an Int, rounded down.
+		
+		If x is NaN, NEGATIVE_INFINITY or POSITIVE_INFINITY, the result is unspecified.
 	**/
 	public static function int( x : Float ) : Int;
 
 	/**
-		Convert a String to an Int, parsing different possible representations. Returns [null] if could not be parsed.
+		Converts a String to an Int.
+		
+		Leading whitespaces are ignored.
+		
+		If x starts with 0x or 0X, hexadecimal notation is recognized where the following digits may
+		contain 0-9 and A-F.
+		
+		Otherwise x is read as decimal number with 0-9 being allowed characters. x may also start with
+		a - to denote a negative value.
+		
+		In decimal mode, parsing continues until an invalid character is detected, in which case the
+		result up to that point is returned. For hexadecimal notation, the effect of invalid characters
+		is unspecified.
+		
+		Leading 0s that are not part of the 0x/0X hexadecimal notation are ignored, which means octal
+		notation is not supported.
+		
+		If the input cannot be recognized, the result is null.
 	**/
 	public static function parseInt( x : String ) : Null<Int>;
 
 	/**
-		Convert a String to a Float, parsing different possible reprensations.
+		Converts a String to a Float.
+		
+		The parsing rules for parseInt() apply here as well, with the exception of invalid input
+		resulting in a NaN value instead of null.
+		
+		Additionally, decimal notation may contain a single . to denote the start of the fractions.
 	**/
 	public static function parseFloat( x : String ) : Float;
 
 	/**
 		Return a random integer between 0 included and x excluded.
+		
+		If x is <= 1, the result is always 0.
 	**/
 	public static function random( x : Int ) : Int;
 

+ 1 - 0
tests/unit/Test.hx

@@ -230,6 +230,7 @@ package unit;
 			#if !no_pattern_matching
 			new TestMatch(),
 			#end
+			new TestSpecification(),
 			#if cs
 			//new TestCSharp(),
 			#end

+ 28 - 70
tests/unit/TestBasetypes.hx

@@ -44,14 +44,14 @@ class TestBasetypes extends Test {
 		eq( abc[0], "a" );
 		eq( abc[1], "b" );
 		eq( abc[2], "c" );
-		
+
 		var str = "abc";
 		eq( str.charCodeAt(0), "a".code );
 		eq( str.charCodeAt(1), "b".code );
 		eq( str.charCodeAt(2), "c".code );
 		eq( str.charCodeAt(-1), null );
 		eq( str.charCodeAt(3), null );
-		
+
 		// substr tests
 		var sentence:String = "Pack my box with five dozen liquor jugs.";
 		eq(sentence.substr(0, 4), "Pack");
@@ -65,7 +65,7 @@ class TestBasetypes extends Test {
 		eq(sentence.substr(-42), sentence);
 		eq(sentence.substr(4, 0), "");
 		eq(sentence.substr(0, -36), "Pack");
-		
+
 		// null should not be swallowed
 		eq("hello" +null, "hellonull");
 		eq(null + "hello", "nullhello");
@@ -75,7 +75,7 @@ class TestBasetypes extends Test {
 		var x:String = null;
 		eq("hello" +x, "hellonull");
 		eq(x + "hello", "nullhello");
-		
+
 		var x = { hello:"world", val:5 };
 		var xs = "" + x;
 		// Output should contain hello followed by world, and val followed by 5.
@@ -92,7 +92,7 @@ class TestBasetypes extends Test {
 		eq(5 + "5", "55");
 		eq("5" + 5, "55");
 		eq("5" + 5.1, "55.1");
-		
+
 		// Some precedence checks.
 		eq(1 + 1 + 1 + 1 + "1", "41");
 		eq("1" + 1 + 1 + 1 + 1, "11111");
@@ -101,17 +101,17 @@ class TestBasetypes extends Test {
 		// check recursive formating
 		var x = [[1], [2, 3]];
 		eq("" + x, "[[1],[2,3]]");
-		
+
 		// Brackets around array values should not be stripped.
 		var x : Array<Dynamic> = [1, "hello"];
 		eq("" + x, "[1,hello]");
 		eq(x + "", "" + x);
-		
+
 		// This is also true for iterables that are arrays.
 		var x:Iterable<Dynamic> = x;
 		eq("" + x, "[1,hello]");
 		eq(x + "", "" + x);
-		
+
 		// I don't think this should throw an exception on PHP.
 		try {
 			"" + x.iterator();
@@ -122,12 +122,12 @@ class TestBasetypes extends Test {
 		var str = "he\nlo\"'";
 		eq( Std.string(str), str);
 		eq( Std.string([str]), "[" + str + "]");
-		
+
 		var e = MyEnum.C(0, "h");
 		eq( Std.string(e), "C(0,h)");
-		
+
 		eq(Std.string([e]), "[C(0,h)]");
-		
+
 		var tester:String = "show me the (show me!) index of show me";
 		eq(tester.lastIndexOf("show me"), 32);
 		eq(tester.lastIndexOf("show me", 1), 0);
@@ -135,15 +135,6 @@ class TestBasetypes extends Test {
 	}
 
 	function testMath() {
-		eq( Std.int(-1.7), -1 );
-		eq( Std.int(-1.2), -1 );
-		eq( Std.int(1.7), 1 );
-		eq( Std.int(1.2), 1 );
-		eq( Std.int(-0.7), 0 );
-		eq( Std.int(-0.2), 0 );
-		eq( Std.int(0.7), 0 );
-		eq( Std.int(0.2), 0 );
-
 		eq( Math.floor(-1.7), -2 );
 		eq( Math.floor(-1.5), -2 );
 		eq( Math.floor(-1.2), -2 );
@@ -163,22 +154,22 @@ class TestBasetypes extends Test {
 		eq( Math.round(1.5), 2 );
 		eq( Math.round(1.2), 1 );
 
-		
+
 		eq( Std.int( -10000000000.7), 0xABF41C00 );
-		
+
 		#if (js || flash8)
-		
+
 		// higher Int resolution : should we fix this or not ?
 		eq( Math.floor( -10000000000.7)*1.0, -10000000001. );
 		eq( Math.ceil( -10000000000.7)*1.0, -10000000000. );
 		eq( Math.round( -10000000000.7)*1.0, -10000000001. );
-		
+
 		#else
-		
+
 		eq( Math.floor( -10000000000.7), 0xABF41BFF);
 		eq( Math.ceil( -10000000000.7), 0xABF41C00);
 		eq( Math.round( -10000000000.7), 0xABF41BFF);
-	
+
 		#end
 
 		#if !as3
@@ -189,39 +180,6 @@ class TestBasetypes extends Test {
 
 	}
 
-	function testParse() {
-		eq( Std.parseInt("0"), 0 );
-		eq( Std.parseInt("   5"), 5 );
-		eq( Std.parseInt("0001"), 1 );
-		eq( Std.parseInt("0010"), 10 );
-		eq( Std.parseInt("100"), 100 );
-		eq( Std.parseInt("-100"), -100 );
-		eq( Std.parseInt("100x123"), 100 );
-		eq( Std.parseInt(""), null );
-		eq( Std.parseInt("abcd"), null );
-		eq( Std.parseInt("a10"), null );
-		eq( Std.parseInt(null), null );
-		eq( Std.parseInt("0xFF"), 255 );
-		eq( Std.parseInt("0x123"), 291 );
-		eq( Std.parseInt("0XFF"), 255 );
-		eq( Std.parseInt("0X123"), 291 );
-		unspec(function() Std.parseInt("0xFG"));
-
-		eq( Std.parseFloat("0"), 0. );
-		eq( Std.parseFloat("   5.3"), 5.3 );
-		eq( Std.parseFloat("0001"), 1. );
-		eq( Std.parseFloat("100.45"), 100.45 );
-		eq( Std.parseFloat("-100.01"), -100.01 );
-		eq( Std.parseFloat("100x123"), 100. );
-		t( Math.isNaN(Std.parseFloat("")) );
-		t( Math.isNaN(Std.parseFloat("abcd")) );
-		t( Math.isNaN(Std.parseFloat("a10")) );
-		t( Math.isNaN(Std.parseFloat(null)) );
-		eq( Std.parseFloat("5.3 "), 5.3 );
-		eq( Std.parseFloat("0.0"), 0. );
-		eq( Std.parseFloat("5.3 1"), 5.3 );
-	}
-
 	function testHash() {
 		var h = new Hash<Null<Int>>();
 		h.set("x", -1);
@@ -233,11 +191,11 @@ class TestBasetypes extends Test {
 		var k = Lambda.array(h);
 		k.sort(Reflect.compare);
 		eq( k.join("#"), "-1#8546" );
-		
+
 		var k = Lambda.array( { iterator : h.keys } );
 		k.sort(Reflect.compare);
 		eq( k.join("#"), "abcd#x" );
-		
+
 		t( h.exists("x") );
 		t( h.exists("abcd") );
 		f( h.exists("e") );
@@ -246,7 +204,7 @@ class TestBasetypes extends Test {
 		f( h.exists("abcd") );
 		f( h.exists("e") );
 		eq( h.get("abcd"), null);
-		
+
 		h.set("x", null);
 		t( h.exists("x") );
 		t( h.remove("x") );
@@ -264,11 +222,11 @@ class TestBasetypes extends Test {
 		var k = Lambda.array(h);
 		k.sort(Reflect.compare);
 		eq( k.join("#"), "-1#8546" );
-		
+
 		var k = Lambda.array( { iterator : h.keys } );
 		k.sort(Reflect.compare);
 		eq( k.join("#"), "-4815#0" );
-		
+
 		t( h.exists(0) );
 		t( h.exists(-4815) );
 		f( h.exists(456) );
@@ -277,19 +235,19 @@ class TestBasetypes extends Test {
 		f( h.exists(-4815) );
 		f( h.exists(456) );
 		eq( h.get( -4815), null);
-		
+
 		h.set(65, null);
 		t( h.exists(65) );
 		t( h.remove(65) );
 		f( h.remove(65) );
-		
+
 		var h = new IntHash();
 		h.set(1, ['a', 'b']);
 		t( h.exists(1) );
 		t( h.remove(1) );
 		f( h.remove(1) );
 	}
-	
+
 	function testObjectKeyword() {
 		// new is a keyword in Haxe
 		var l = { "new": "test" };
@@ -301,17 +259,17 @@ class TestBasetypes extends Test {
 		eq(o.const, 6);
 		eq(Reflect.field(o, prefix+"const"), 6);
 	}
-	
+
 	function testFormat() {
 		eq('', "");
 		eq('$', "$");
 		eq('$$', "$");
 		eq('x$*', "x$*");
-		
+
 		var x = 5, y = [];
 		eq('$x', "5");
 		eq('a$x$', "a5$");
-		
+
 		eq('${5}', "5");
 		eq('${5}${2}', "52");
 		eq('a${x}b', "a5b");

+ 0 - 8
tests/unit/TestMisc.hx

@@ -511,14 +511,6 @@ class TestMisc extends Test {
 	}
 	#end
 
-	function testRandom() {
-		var x = Std.random(2);
-		t( x == 0 || x == 1);
-		eq(Std.random(1), 0);
-		eq(Std.random(0), 0);
-		eq(Std.random(-100), 0);
-	}
-
 	function testJSon() {
 		var str = haxe.Json.stringify( { x : -4500, y : 1.456, a : ["hello", "wor'\"\n\t\rd"] } );
 		str = str.substr(1, str.length - 2); // remove {}

+ 112 - 0
tests/unit/TestSpecification.hx

@@ -0,0 +1,112 @@
+package unit;
+
+class TestSpecification extends Test 
+{
+	public function testStdIs() {
+		// null subject
+		var known:String = null;
+		f(Std.is(known, String));
+		
+		var unknown = null;
+		f(Std.is(unknown, String));
+		
+		f(Std.is(null, String));
+		
+		// null class
+		f(Std.is("foo", null));
+	}
+	
+	public function testStdString() {
+		var cwts = new ClassWithToString();
+		var cwtsc = new ClassWithToStringChild();
+		var cwtsc2 = new ClassWithToStringChild2();
+		
+		eq(Std.string(cwts), "ClassWithToString.toString()");
+		eq(Std.string(cwtsc), "ClassWithToString.toString()");
+		eq(Std.string(cwtsc2), "ClassWithToStringChild2.toString()");
+		
+		eq(Std.string(SomeEnum.NoArguments), "NoArguments");
+		eq(Std.string(SomeEnum.OneArgument("foo")), "OneArgument(foo)");
+		
+		eq(Std.string(null), "null");
+	}
+	
+	public function testStdInt() {
+		eq( Std.int(-1.7), -1 );
+		eq( Std.int(-1.2), -1 );
+		eq( Std.int(1.7), 1 );
+		eq( Std.int(1.2), 1 );
+		eq( Std.int(-0.7), 0 );
+		eq( Std.int(-0.2), 0 );
+		eq( Std.int(0.7), 0 );
+		eq( Std.int(0.2), 0 );
+	}
+	
+	public function testStdParseInt() {
+		eq( Std.parseInt("0"), 0 );
+		eq( Std.parseInt("   5"), 5 );
+		eq( Std.parseInt("0001"), 1 );
+		eq( Std.parseInt("0010"), 10 );
+		eq( Std.parseInt("100"), 100 );
+		eq( Std.parseInt("-100"), -100 );
+		eq( Std.parseInt("100x123"), 100 );
+		eq( Std.parseInt("12foo13"), 12 );
+		eq( Std.parseInt(""), null );
+		eq( Std.parseInt("abcd"), null );
+		eq( Std.parseInt("a10"), null );
+		eq( Std.parseInt(null), null );
+		eq( Std.parseInt("0xFF"), 255 );
+		eq( Std.parseInt("0x123"), 291 );
+		eq( Std.parseInt("0XFF"), 255 );
+		eq( Std.parseInt("0X123"), 291 );	
+		eq( Std.parseInt("0X01"), 1 );
+		eq( Std.parseInt("0x01"), 1 );
+		unspec(function() Std.parseInt("0xFG"));		
+	}
+	
+	public function testStdParseFloat() {
+		eq( Std.parseFloat("0"), 0. );
+		eq( Std.parseFloat("   5.3"), 5.3 );
+		eq( Std.parseFloat("0001"), 1. );
+		eq( Std.parseFloat("100.45"), 100.45 );
+		eq( Std.parseFloat("-100.01"), -100.01 );
+		eq( Std.parseFloat("100x123"), 100. );
+		t( Math.isNaN(Std.parseFloat("")) );
+		t( Math.isNaN(Std.parseFloat("abcd")) );
+		t( Math.isNaN(Std.parseFloat("a10")) );
+		t( Math.isNaN(Std.parseFloat(null)) );
+		eq( Std.parseFloat("5.3 "), 5.3 );
+		eq( Std.parseFloat("0.0"), 0. );
+		eq( Std.parseFloat("5.3 1"), 5.3 );		
+	}
+	
+	function testStdRandom() {
+		var x = Std.random(2);
+		t( x == 0 || x == 1);
+		eq(Std.random(1), 0);
+		eq(Std.random(0), 0);
+		eq(Std.random(-100), 0);
+	}	
+}
+
+private class EmptyClass {
+	public function new() { }
+}
+
+private class ClassWithToString {
+	public function new() { }
+	public function toString() return "ClassWithToString.toString()"
+}
+
+private class ClassWithToStringChild extends ClassWithToString {
+	
+}
+
+private class ClassWithToStringChild2 extends ClassWithToString {
+	public override function toString() return "ClassWithToStringChild2.toString()"
+}
+
+private enum SomeEnum<T> {
+	NoArguments;
+	OneArgument(t:T);
+}