12 changed files with 2859 additions and 2672 deletions
@ -1,188 +1,188 @@ |
|||||||
==Author== |
==Author== |
||||||
[mailto:schoen@defectivestudios.com Matt Schoen] of [http://www.defectivestudios.com Defective Studios] |
[mailto:schoen@defectivestudios.com Matt Schoen] of [http://www.defectivestudios.com Defective Studios] |
||||||
|
|
||||||
==Download== |
==Download== |
||||||
[[Media:JSONObject.zip|Download JSONObject.zip]] |
[[Media:JSONObject.zip|Download JSONObject.zip]] |
||||||
|
|
||||||
= Intro = |
= Intro = |
||||||
I came across the need to send structured data to and from a server on one of my projects, and figured it would be worth my while to use JSON. When I looked into the issue, I tried a few of the C# implementations listed on [http://json.org json.org], but found them to be too complicated to work with and expand upon. So, I've written a very simple JSONObject class, which can be generically used to encode/decode data into a simple container. This page assumes that you know what JSON is, and how it works. It's rather simple, just go to json.org for a visual description of the encoding format. |
I came across the need to send structured data to and from a server on one of my projects, and figured it would be worth my while to use JSON. When I looked into the issue, I tried a few of the C# implementations listed on [http://json.org json.org], but found them to be too complicated to work with and expand upon. So, I've written a very simple JSONObject class, which can be generically used to encode/decode data into a simple container. This page assumes that you know what JSON is, and how it works. It's rather simple, just go to json.org for a visual description of the encoding format. |
||||||
|
|
||||||
As an aside, this class is pretty central to the [[AssetCloud]] content management system, from Defective Studios. |
As an aside, this class is pretty central to the [[AssetCloud]] content management system, from Defective Studios. |
||||||
|
|
||||||
Update: The code has been updated to version 1.4 to incorporate user-submitted patches and bug reports. This fixes issues dealing with whitespace in the format, as well as empty arrays and objects, and escaped quotes within strings. |
Update: The code has been updated to version 1.4 to incorporate user-submitted patches and bug reports. This fixes issues dealing with whitespace in the format, as well as empty arrays and objects, and escaped quotes within strings. |
||||||
|
|
||||||
= Usage = |
= Usage = |
||||||
Users should not have to modify the JSONObject class themselves, and must follow the very simple proceedures outlined below: |
Users should not have to modify the JSONObject class themselves, and must follow the very simple proceedures outlined below: |
||||||
|
|
||||||
Sample data (in JSON format): |
Sample data (in JSON format): |
||||||
<nowiki> |
<nowiki> |
||||||
{ |
{ |
||||||
"TestObject": { |
"TestObject": { |
||||||
"SomeText": "Blah", |
"SomeText": "Blah", |
||||||
"SomeObject": { |
"SomeObject": { |
||||||
"SomeNumber": 42, |
"SomeNumber": 42, |
||||||
"SomeBool": true, |
"SomeBool": true, |
||||||
"SomeNull": null |
"SomeNull": null |
||||||
}, |
}, |
||||||
|
|
||||||
"SomeEmptyObject": { }, |
"SomeEmptyObject": { }, |
||||||
"SomeEmptyArray": [ ], |
"SomeEmptyArray": [ ], |
||||||
"EmbeddedObject": "{\"field\":\"Value with \\\"escaped quotes\\\"\"}" |
"EmbeddedObject": "{\"field\":\"Value with \\\"escaped quotes\\\"\"}" |
||||||
} |
} |
||||||
}</nowiki> |
}</nowiki> |
||||||
|
|
||||||
= Features = |
= Features = |
||||||
|
|
||||||
*Decode JSON-formatted strings into a usable data structure |
*Decode JSON-formatted strings into a usable data structure |
||||||
*Encode structured data into a JSON-formatted string |
*Encode structured data into a JSON-formatted string |
||||||
*Interoperable with Dictionary and WWWForm |
*Interoperable with Dictionary and WWWForm |
||||||
*Optimized parse/stringify functions -- minimal (unavoidable) garbage creation |
*Optimized parse/stringify functions -- minimal (unavoidable) garbage creation |
||||||
*Asynchronous stringify function for serializing lots of data without frame drops |
*Asynchronous stringify function for serializing lots of data without frame drops |
||||||
*MaxDepth parsing will skip over nested data that you don't need |
*MaxDepth parsing will skip over nested data that you don't need |
||||||
*Special (non-compliant) "Baked" object type can store stringified data within parsed objects |
*Special (non-compliant) "Baked" object type can store stringified data within parsed objects |
||||||
*Copy to new JSONObject |
*Copy to new JSONObject |
||||||
*Merge with another JSONObject (experimental) |
*Merge with another JSONObject (experimental) |
||||||
*Random access (with [int] or [string]) |
*Random access (with [int] or [string]) |
||||||
*ToString() returns JSON data with optional "pretty" flag to include newlines and tabs |
*ToString() returns JSON data with optional "pretty" flag to include newlines and tabs |
||||||
*Switch between double and float for numeric storage depending on level of precision needed (and to ensure that numbers are parsed/stringified correctly) |
*Switch between double and float for numeric storage depending on level of precision needed (and to ensure that numbers are parsed/stringified correctly) |
||||||
*Supports Infinity and NaN values |
*Supports Infinity and NaN values |
||||||
*JSONTemplates static class provides serialization functions for common classes like Vector3, Matrix4x4 |
*JSONTemplates static class provides serialization functions for common classes like Vector3, Matrix4x4 |
||||||
*Object pool implementation (experimental) |
*Object pool implementation (experimental) |
||||||
*Handy JSONChecker window to test parsing on sample data |
*Handy JSONChecker window to test parsing on sample data |
||||||
|
|
||||||
It should be pretty obvious what this parser can and cannot do. If anyone reading this is a JSON buff (is there such a thing?) please feel free to expand and modify the parser to be more compliant. Currently I am using the .NET System.Convert namespace functions for parsing the data itself. It parses strings and numbers, which was all that I needed of it, but unless the formatting is supported by System.Convert, it may not incorporate all proper JSON strings. Also, having never written a JSON parser before, I don't doubt that I could improve the efficiency or correctness of the parser. It serves my purpose, and hopefully will help you with your project! Let me know if you make any improvements :) |
It should be pretty obvious what this parser can and cannot do. If anyone reading this is a JSON buff (is there such a thing?) please feel free to expand and modify the parser to be more compliant. Currently I am using the .NET System.Convert namespace functions for parsing the data itself. It parses strings and numbers, which was all that I needed of it, but unless the formatting is supported by System.Convert, it may not incorporate all proper JSON strings. Also, having never written a JSON parser before, I don't doubt that I could improve the efficiency or correctness of the parser. It serves my purpose, and hopefully will help you with your project! Let me know if you make any improvements :) |
||||||
|
|
||||||
Also, you JSON buffs (really, who would admit to being a JSON buff...) might also notice from my feature list that this thing isn't exactly to specifications. Here is where it differs: |
Also, you JSON buffs (really, who would admit to being a JSON buff...) might also notice from my feature list that this thing isn't exactly to specifications. Here is where it differs: |
||||||
*"a string" is considered valid JSON. There is an optional "strict" parameter to the parser which will bomb out on such input, in case that matters to you. |
*"a string" is considered valid JSON. There is an optional "strict" parameter to the parser which will bomb out on such input, in case that matters to you. |
||||||
*The "Baked" mode is totally made up. |
*The "Baked" mode is totally made up. |
||||||
*The "MaxDepth" parsing is totally made up. |
*The "MaxDepth" parsing is totally made up. |
||||||
*NaN and Infinity aren't officially supported by JSON ([http://stackoverflow.com/questions/1423081/json-left-out-infinity-and-nan-json-status-in-ecmascript read more] about this issue... I lol'd @ the first comment on the first answer) |
*NaN and Infinity aren't officially supported by JSON ([http://stackoverflow.com/questions/1423081/json-left-out-infinity-and-nan-json-status-in-ecmascript read more] about this issue... I lol'd @ the first comment on the first answer) |
||||||
*I have no idea about edge cases in my parsing strategy. I have been using this code for about 3 years now and have only had to modify the parser because other people's use cases (still valid JSON) didn't parse correctly. In my experience, anything that this code generates is parsed just fine. |
*I have no idea about edge cases in my parsing strategy. I have been using this code for about 3 years now and have only had to modify the parser because other people's use cases (still valid JSON) didn't parse correctly. In my experience, anything that this code generates is parsed just fine. |
||||||
|
|
||||||
== Encoding == |
== Encoding == |
||||||
|
|
||||||
Encoding is something of a hard-coded process. This is because I have no idea what your data is! It would be great if this were some sort of interface for taking an entire class and encoding it's number/string fields, but it's not. I've come up with a few clever ways of using loops and/or recursive methods to cut down of the amount of code I have to write when I use this tool, but they're pretty project-specific. |
Encoding is something of a hard-coded process. This is because I have no idea what your data is! It would be great if this were some sort of interface for taking an entire class and encoding it's number/string fields, but it's not. I've come up with a few clever ways of using loops and/or recursive methods to cut down of the amount of code I have to write when I use this tool, but they're pretty project-specific. |
||||||
|
|
||||||
Note: This section used to be WRONG! And now it's OLD! Will update later... this will all still work, but there are now a couple of ways to skin this cat. |
Note: This section used to be WRONG! And now it's OLD! Will update later... this will all still work, but there are now a couple of ways to skin this cat. |
||||||
|
|
||||||
<syntaxhighlight lang="csharp"> |
<syntaxhighlight lang="csharp"> |
||||||
//Note: your data can only be numbers and strings. This is not a solution for object serialization or anything like that. |
//Note: your data can only be numbers and strings. This is not a solution for object serialization or anything like that. |
||||||
JSONObject j = new JSONObject(JSONObject.Type.OBJECT); |
JSONObject j = new JSONObject(JSONObject.Type.OBJECT); |
||||||
//number |
//number |
||||||
j.AddField("field1", 0.5); |
j.AddField("field1", 0.5); |
||||||
//string |
//string |
||||||
j.AddField("field2", "sampletext"); |
j.AddField("field2", "sampletext"); |
||||||
//array |
//array |
||||||
JSONObject arr = new JSONObject(JSONObject.Type.ARRAY); |
JSONObject arr = new JSONObject(JSONObject.Type.ARRAY); |
||||||
j.AddField("field3", arr); |
j.AddField("field3", arr); |
||||||
|
|
||||||
arr.Add(1); |
arr.Add(1); |
||||||
arr.Add(2); |
arr.Add(2); |
||||||
arr.Add(3); |
arr.Add(3); |
||||||
|
|
||||||
string encodedString = j.print(); |
string encodedString = j.print(); |
||||||
</syntaxhighlight> |
</syntaxhighlight> |
||||||
|
|
||||||
NEW! The constructor, Add, and AddField functions now support a nested delegate structure. This is useful if you need to create a nested JSONObject in a single line. For example: |
NEW! The constructor, Add, and AddField functions now support a nested delegate structure. This is useful if you need to create a nested JSONObject in a single line. For example: |
||||||
<syntaxhighlight lang="csharp"> |
<syntaxhighlight lang="csharp"> |
||||||
DoRequest(URL, new JSONObject(delegate(JSONObject request) { |
DoRequest(URL, new JSONObject(delegate(JSONObject request) { |
||||||
request.AddField("sort", delegate(JSONObject sort) { |
request.AddField("sort", delegate(JSONObject sort) { |
||||||
sort.AddField("_timestamp", "desc"); |
sort.AddField("_timestamp", "desc"); |
||||||
}); |
}); |
||||||
request.AddField("query", new JSONObject(delegate(JSONObject query) { |
request.AddField("query", new JSONObject(delegate(JSONObject query) { |
||||||
query.AddField("match_all", JSONObject.obj); |
query.AddField("match_all", JSONObject.obj); |
||||||
})); |
})); |
||||||
request.AddField("fields", delegate(JSONObject fields) { |
request.AddField("fields", delegate(JSONObject fields) { |
||||||
fields.Add("_timestamp"); |
fields.Add("_timestamp"); |
||||||
}); |
}); |
||||||
}).ToString()); |
}).ToString()); |
||||||
</syntaxhighlight> |
</syntaxhighlight> |
||||||
|
|
||||||
== Decoding == |
== Decoding == |
||||||
Decoding is much simpler on the input end, and again, what you do with the JSONObject will vary on a per-project basis. One of the more complicated way to extract the data is with a recursive function, as drafted below. Calling the constructor with a properly formatted JSON string will return the root object (or array) containing all of its children, in one neat reference! The data is in a public ArrayList called list, with a matching key list (called keys!) if the root is an Object. If that's confusing, take a glance over the following code and the print() method in the JSONOBject class. If there is an error in the JSON formatting (or if there's an error with my code!) the debug console will read "improper JSON formatting". |
Decoding is much simpler on the input end, and again, what you do with the JSONObject will vary on a per-project basis. One of the more complicated way to extract the data is with a recursive function, as drafted below. Calling the constructor with a properly formatted JSON string will return the root object (or array) containing all of its children, in one neat reference! The data is in a public ArrayList called list, with a matching key list (called keys!) if the root is an Object. If that's confusing, take a glance over the following code and the print() method in the JSONOBject class. If there is an error in the JSON formatting (or if there's an error with my code!) the debug console will read "improper JSON formatting". |
||||||
|
|
||||||
|
|
||||||
<syntaxhighlight lang="csharp"> |
<syntaxhighlight lang="csharp"> |
||||||
string encodedString = "{\"field1\": 0.5,\"field2\": \"sampletext\",\"field3\": [1,2,3]}"; |
string encodedString = "{\"field1\": 0.5,\"field2\": \"sampletext\",\"field3\": [1,2,3]}"; |
||||||
JSONObject j = new JSONObject(encodedString); |
JSONObject j = new JSONObject(encodedString); |
||||||
accessData(j); |
accessData(j); |
||||||
//access data (and print it) |
//access data (and print it) |
||||||
void accessData(JSONObject obj){ |
void accessData(JSONObject obj){ |
||||||
switch(obj.type){ |
switch(obj.type){ |
||||||
case JSONObject.Type.OBJECT: |
case JSONObject.Type.OBJECT: |
||||||
for(int i = 0; i < obj.list.Count; i++){ |
for(int i = 0; i < obj.list.Count; i++){ |
||||||
string key = (string)obj.keys[i]; |
string key = (string)obj.keys[i]; |
||||||
JSONObject j = (JSONObject)obj.list[i]; |
JSONObject j = (JSONObject)obj.list[i]; |
||||||
Debug.Log(key); |
Debug.Log(key); |
||||||
accessData(j); |
accessData(j); |
||||||
} |
} |
||||||
break; |
break; |
||||||
case JSONObject.Type.ARRAY: |
case JSONObject.Type.ARRAY: |
||||||
foreach(JSONObject j in obj.list){ |
foreach(JSONObject j in obj.list){ |
||||||
accessData(j); |
accessData(j); |
||||||
} |
} |
||||||
break; |
break; |
||||||
case JSONObject.Type.STRING: |
case JSONObject.Type.STRING: |
||||||
Debug.Log(obj.str); |
Debug.Log(obj.str); |
||||||
break; |
break; |
||||||
case JSONObject.Type.NUMBER: |
case JSONObject.Type.NUMBER: |
||||||
Debug.Log(obj.n); |
Debug.Log(obj.n); |
||||||
break; |
break; |
||||||
case JSONObject.Type.BOOL: |
case JSONObject.Type.BOOL: |
||||||
Debug.Log(obj.b); |
Debug.Log(obj.b); |
||||||
break; |
break; |
||||||
case JSONObject.Type.NULL: |
case JSONObject.Type.NULL: |
||||||
Debug.Log("NULL"); |
Debug.Log("NULL"); |
||||||
break; |
break; |
||||||
|
|
||||||
} |
} |
||||||
} |
} |
||||||
</syntaxhighlight> |
</syntaxhighlight> |
||||||
|
|
||||||
NEW! Decoding now also supports a delegate format which will automatically check if a field exists before processing the data, providing an optional parameter for an OnFieldNotFound response. For example: |
NEW! Decoding now also supports a delegate format which will automatically check if a field exists before processing the data, providing an optional parameter for an OnFieldNotFound response. For example: |
||||||
<syntaxhighlight lang="csharp"> |
<syntaxhighlight lang="csharp"> |
||||||
new JSONObject(data); |
new JSONObject(data); |
||||||
list.GetField("hits", delegate(JSONObject hits) { |
list.GetField("hits", delegate(JSONObject hits) { |
||||||
hits.GetField("hits", delegate(JSONObject hits2) { |
hits.GetField("hits", delegate(JSONObject hits2) { |
||||||
foreach (JSONObject gameSession in hits2.list) { |
foreach (JSONObject gameSession in hits2.list) { |
||||||
Debug.Log(gameSession); |
Debug.Log(gameSession); |
||||||
} |
} |
||||||
}); |
}); |
||||||
}, delegate(string name) { //"name" will be equal to the name of the missing field. In this case, "hits" |
}, delegate(string name) { //"name" will be equal to the name of the missing field. In this case, "hits" |
||||||
Debug.LogWarning("no game sessions"); |
Debug.LogWarning("no game sessions"); |
||||||
}); |
}); |
||||||
</syntaxhighlight> |
</syntaxhighlight> |
||||||
|
|
||||||
===Not So New! (O(n)) Random access!=== |
===Not So New! (O(n)) Random access!=== |
||||||
I've added a string and int [] index to the class, so you can now retrieve data as such (from above): |
I've added a string and int [] index to the class, so you can now retrieve data as such (from above): |
||||||
<syntaxhighlight lang="csharp"> |
<syntaxhighlight lang="csharp"> |
||||||
JSONObject arr = obj["field3"]; |
JSONObject arr = obj["field3"]; |
||||||
Debug.log(arr[2].n); //Should ouptut "3" |
Debug.log(arr[2].n); //Should ouptut "3" |
||||||
</syntaxhighlight> |
</syntaxhighlight> |
||||||
|
|
||||||
---- |
---- |
||||||
|
|
||||||
---Code omitted from readme--- |
---Code omitted from readme--- |
||||||
|
|
||||||
=Change Log= |
=Change Log= |
||||||
==v1.4== |
==v1.4== |
||||||
Big update! |
Big update! |
||||||
*Better GC performance. Enough of that garbage! |
*Better GC performance. Enough of that garbage! |
||||||
**Remaining culprits are internal garbage from StringBuilder.Append/AppendFormat, String.Substring, List.Add/GrowIfNeeded, Single.ToString |
**Remaining culprits are internal garbage from StringBuilder.Append/AppendFormat, String.Substring, List.Add/GrowIfNeeded, Single.ToString |
||||||
*Added asynchronous Stringify function for serializing large amounts of data at runtime without frame drops |
*Added asynchronous Stringify function for serializing large amounts of data at runtime without frame drops |
||||||
*Added Baked type |
*Added Baked type |
||||||
*Added MaxDepth to parsing function |
*Added MaxDepth to parsing function |
||||||
*Various cleanup refactors recommended by ReSharper |
*Various cleanup refactors recommended by ReSharper |
||||||
|
|
||||||
==v1.3.2== |
==v1.3.2== |
||||||
*Added support for NaN |
*Added support for NaN |
||||||
*Added strict mode to fail on purpose for improper formatting. Right now this just means that if the parse string doesn't start with [ or {, it will print a warning and return a null JO. |
*Added strict mode to fail on purpose for improper formatting. Right now this just means that if the parse string doesn't start with [ or {, it will print a warning and return a null JO. |
||||||
*Changed infinity and NaN implementation to use float and double instead of Mathf |
*Changed infinity and NaN implementation to use float and double instead of Mathf |
||||||
*Handles empty objects/arrays better |
*Handles empty objects/arrays better |
||||||
*Added a flag to print and ToString to turn on/off pretty print. The define on top is now an override to system-wide disable |
*Added a flag to print and ToString to turn on/off pretty print. The define on top is now an override to system-wide disable |
||||||
==Earlier Versions== |
==Earlier Versions== |
||||||
I'll fill these in later... |
I'll fill these in later... |
||||||
[[Category:C Sharp]] |
[[Category:C Sharp]] |
||||||
[[Category:Scripts]] |
[[Category:Scripts]] |
||||||
[[Category:Utility]] |
[[Category:Utility]] |
||||||
[[Category:JSON]] |
[[Category:JSON]] |
||||||
|
@ -0,0 +1,9 @@ |
|||||||
|
fileFormatVersion: 2 |
||||||
|
guid: 1b39a7374cafc4d698bac382a6ec8092 |
||||||
|
folderAsset: yes |
||||||
|
timeCreated: 1488287629 |
||||||
|
licenseType: Free |
||||||
|
DefaultImporter: |
||||||
|
userData: |
||||||
|
assetBundleName: |
||||||
|
assetBundleVariant: |
@ -0,0 +1,9 @@ |
|||||||
|
fileFormatVersion: 2 |
||||||
|
guid: 246e827fcb2f2445fab551623bf99ba3 |
||||||
|
folderAsset: yes |
||||||
|
timeCreated: 1481645890 |
||||||
|
licenseType: Free |
||||||
|
DefaultImporter: |
||||||
|
userData: |
||||||
|
assetBundleName: |
||||||
|
assetBundleVariant: |
@ -0,0 +1,159 @@ |
|||||||
|
//----------------------------------------------------------------------- |
||||||
|
// <summary> |
||||||
|
// Unity Editor tool that formats line endings to be consistent. |
||||||
|
// </summary> |
||||||
|
// <copyright file="LineEndingsEditMenu.cs" company="Tiaan.com"> |
||||||
|
// Copyright (c) 2014 Tiaan Geldenhuys |
||||||
|
// |
||||||
|
// Permission is hereby granted, free of charge, to any person |
||||||
|
// obtaining a copy of this software and associated documentation |
||||||
|
// files (the "Software"), to deal in the Software without |
||||||
|
// restriction, including without limitation the rights to use, |
||||||
|
// copy, modify, merge, publish, distribute, sublicense, and/or |
||||||
|
// sell copies of the Software, and to permit persons to whom the |
||||||
|
// Software is furnished to do so, subject to the following |
||||||
|
// conditions: |
||||||
|
// |
||||||
|
// The above copyright notice and this permission notice shall be |
||||||
|
// included in all copies or substantial portions of the Software. |
||||||
|
// |
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
||||||
|
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||||
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
||||||
|
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
||||||
|
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
||||||
|
// OTHER DEALINGS IN THE SOFTWARE. |
||||||
|
// </copyright> |
||||||
|
//----------------------------------------------------------------------- |
||||||
|
namespace TiaanDotCom.Unity3D.EditorTools |
||||||
|
{ |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.IO; |
||||||
|
using System.Text.RegularExpressions; |
||||||
|
using UnityEditor; |
||||||
|
using UnityEngine; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Implements menu items for the Unity Editor to perform |
||||||
|
/// end-of-line conversion and fix issues such as for the |
||||||
|
/// following: "There are inconsistent line endings in the |
||||||
|
/// 'Assets/.../*.cs' script. Some are Mac OS X (UNIX) and |
||||||
|
/// some are Windows. This might lead to incorrect line |
||||||
|
/// numbers in stacktraces and compiler errors." |
||||||
|
/// </summary> |
||||||
|
public static class LineEndingsEditMenu |
||||||
|
{ |
||||||
|
// [MenuItem("Tools/Fungus/Utilities/EOL Conversion (Windows)")] |
||||||
|
// public static void ConvertLineEndingsToWindowsFormat() |
||||||
|
// { |
||||||
|
// ConvertLineEndings(false); |
||||||
|
// } |
||||||
|
|
||||||
|
[MenuItem("Tools/Fungus/Utilities/Convert to Mac Line Endings")] |
||||||
|
public static void ConvertLineEndingsToMacFormat() |
||||||
|
{ |
||||||
|
ConvertLineEndings(true); |
||||||
|
} |
||||||
|
|
||||||
|
private static void ConvertLineEndings(bool isUnixFormat) |
||||||
|
{ |
||||||
|
string title = string.Format( |
||||||
|
"EOL Conversion to {0} Format", |
||||||
|
(isUnixFormat ? "UNIX" : "Windows")); |
||||||
|
if (!EditorUtility.DisplayDialog( |
||||||
|
title, |
||||||
|
"This operation may potentially modify " + |
||||||
|
"many files in the current project! " + |
||||||
|
"Hopefully you have backups of everything. " + |
||||||
|
"Are you sure you want to proceed?", |
||||||
|
"Yes", |
||||||
|
"No")) |
||||||
|
{ |
||||||
|
Debug.Log("EOL Conversion was not attempted."); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
var fileTypes = new string[] |
||||||
|
{ |
||||||
|
"*.txt", |
||||||
|
"*.cs", |
||||||
|
"*.js", |
||||||
|
"*.boo", |
||||||
|
"*.compute", |
||||||
|
"*.shader", |
||||||
|
"*.cginc", |
||||||
|
"*.glsl", |
||||||
|
"*.xml", |
||||||
|
"*.xaml", |
||||||
|
"*.json", |
||||||
|
"*.inc", |
||||||
|
"*.css", |
||||||
|
"*.htm", |
||||||
|
"*.html", |
||||||
|
}; |
||||||
|
|
||||||
|
string projectAssetsPath = Application.dataPath; |
||||||
|
int totalFileCount = 0; |
||||||
|
var changedFiles = new List<string>(); |
||||||
|
var regex = new Regex(@"(?<!\r)\n"); |
||||||
|
const string LineEnd = "\r\n"; |
||||||
|
var comparisonType = System.StringComparison.Ordinal; |
||||||
|
foreach (string fileType in fileTypes) |
||||||
|
{ |
||||||
|
string[] filenames = Directory.GetFiles( |
||||||
|
projectAssetsPath, |
||||||
|
fileType, |
||||||
|
SearchOption.AllDirectories); |
||||||
|
totalFileCount += filenames.Length; |
||||||
|
foreach (string filename in filenames) |
||||||
|
{ |
||||||
|
string originalText = File.ReadAllText(filename); |
||||||
|
string changedText; |
||||||
|
changedText = regex.Replace(originalText, LineEnd); |
||||||
|
if (isUnixFormat) |
||||||
|
{ |
||||||
|
changedText = |
||||||
|
changedText.Replace(LineEnd, "\n"); |
||||||
|
} |
||||||
|
|
||||||
|
bool isTextIdentical = string.Equals( |
||||||
|
changedText, originalText, comparisonType); |
||||||
|
if (!isTextIdentical) |
||||||
|
{ |
||||||
|
changedFiles.Add(filename); |
||||||
|
File.WriteAllText( |
||||||
|
filename, |
||||||
|
changedText, |
||||||
|
System.Text.Encoding.UTF8); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int changedFileCount = changedFiles.Count; |
||||||
|
int skippedFileCount = (totalFileCount - changedFileCount); |
||||||
|
string message = string.Format( |
||||||
|
"EOL Conversion skipped {0} " + |
||||||
|
"files and changed {1} files", |
||||||
|
skippedFileCount, |
||||||
|
changedFileCount); |
||||||
|
if (changedFileCount <= 0) |
||||||
|
{ |
||||||
|
message += "."; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
message += (":" + LineEnd); |
||||||
|
message += string.Join(LineEnd, changedFiles.ToArray()); |
||||||
|
} |
||||||
|
|
||||||
|
Debug.Log(message); |
||||||
|
if (changedFileCount > 0) |
||||||
|
{ |
||||||
|
// Recompile modified scripts. |
||||||
|
AssetDatabase.Refresh(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
fileFormatVersion: 2 |
||||||
|
guid: 71f72aa69e779c946beeee31eb72d4d3 |
||||||
|
MonoImporter: |
||||||
|
serializedVersion: 2 |
||||||
|
defaultReferences: [] |
||||||
|
executionOrder: 0 |
||||||
|
icon: {instanceID: 0} |
||||||
|
userData: |
||||||
|
assetBundleName: |
||||||
|
assetBundleVariant: |
File diff suppressed because it is too large
Load Diff
@ -1,21 +1,21 @@ |
|||||||
The MIT License (MIT) |
The MIT License (MIT) |
||||||
|
|
||||||
Copyright (c) 2013-2015 Rotorz Limited |
Copyright (c) 2013-2015 Rotorz Limited |
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||||
of this software and associated documentation files (the "Software"), to deal |
of this software and associated documentation files (the "Software"), to deal |
||||||
in the Software without restriction, including without limitation the rights |
in the Software without restriction, including without limitation the rights |
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||||
copies of the Software, and to permit persons to whom the Software is |
copies of the Software, and to permit persons to whom the Software is |
||||||
furnished to do so, subject to the following conditions: |
furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all |
The above copyright notice and this permission notice shall be included in all |
||||||
copies or substantial portions of the Software. |
copies or substantial portions of the Software. |
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||||
SOFTWARE. |
SOFTWARE. |
@ -1,139 +1,139 @@ |
|||||||
README |
README |
||||||
====== |
====== |
||||||
|
|
||||||
List control for Unity allowing editor developers to add reorderable list controls to |
List control for Unity allowing editor developers to add reorderable list controls to |
||||||
their GUIs. Supports generic lists and serialized property arrays, though additional |
their GUIs. Supports generic lists and serialized property arrays, though additional |
||||||
collection types can be supported by implementing `Rotorz.ReorderableList.IReorderableListAdaptor`. |
collection types can be supported by implementing `Rotorz.ReorderableList.IReorderableListAdaptor`. |
||||||
|
|
||||||
Licensed under the MIT license. See LICENSE file in the project root for full license |
Licensed under the MIT license. See LICENSE file in the project root for full license |
||||||
information. DO NOT contribute to this project unless you accept the terms of the |
information. DO NOT contribute to this project unless you accept the terms of the |
||||||
contribution agreement. |
contribution agreement. |
||||||
|
|
||||||
 |
 |
||||||
|
|
||||||
Features |
Features |
||||||
-------- |
-------- |
||||||
|
|
||||||
- Drag and drop reordering! |
- Drag and drop reordering! |
||||||
- Automatically scrolls if inside a scroll view whilst reordering. |
- Automatically scrolls if inside a scroll view whilst reordering. |
||||||
- Easily customized using flags. |
- Easily customized using flags. |
||||||
- Adaptors for `IList<T>` and `SerializedProperty`. |
- Adaptors for `IList<T>` and `SerializedProperty`. |
||||||
- Subscribe to add/remove item events. |
- Subscribe to add/remove item events. |
||||||
- Supports mixed item heights. |
- Supports mixed item heights. |
||||||
- Disable drag and/or removal on per-item basis. |
- Disable drag and/or removal on per-item basis. |
||||||
- [Drop insertion](<https://youtu.be/gtdPvLaGTNI>) (for use with `UnityEditor.DragAndDrop`). |
- [Drop insertion](<https://youtu.be/gtdPvLaGTNI>) (for use with `UnityEditor.DragAndDrop`). |
||||||
- Styles can be overridden on per-list basis if desired. |
- Styles can be overridden on per-list basis if desired. |
||||||
- Subclass list control to override context menu. |
- Subclass list control to override context menu. |
||||||
- Add drop-down to add menu (or instead of add menu). |
- Add drop-down to add menu (or instead of add menu). |
||||||
- Helper functionality to build element adder menus. |
- Helper functionality to build element adder menus. |
||||||
- User guide (Asset Path/Support/User Guide.pdf). |
- User guide (Asset Path/Support/User Guide.pdf). |
||||||
- API reference documentation (Asset Path/Support/API Reference.chm). |
- API reference documentation (Asset Path/Support/API Reference.chm). |
||||||
|
|
||||||
Installing scripts |
Installing scripts |
||||||
------------------ |
------------------ |
||||||
|
|
||||||
This control can be added to your project by importing the Unity package which |
This control can be added to your project by importing the Unity package which |
||||||
contains a compiled class library (DLL). This can be used by C# and UnityScript |
contains a compiled class library (DLL). This can be used by C# and UnityScript |
||||||
developers. |
developers. |
||||||
|
|
||||||
- [Download RotorzReorderableList_v0.4.3 Package (requires Unity 4.5.5+)](<https://bitbucket.org/rotorz/reorderable-list-editor-field-for-unity/downloads/RotorzReorderableList_v0.4.3.unitypackage>) |
- [Download RotorzReorderableList_v0.4.3 Package (requires Unity 4.5.5+)](<https://bitbucket.org/rotorz/reorderable-list-editor-field-for-unity/downloads/RotorzReorderableList_v0.4.3.unitypackage>) |
||||||
|
|
||||||
If you would prefer to use the non-compiled source code version in your project, |
If you would prefer to use the non-compiled source code version in your project, |
||||||
copy the contents of this repository somewhere into your project. |
copy the contents of this repository somewhere into your project. |
||||||
|
|
||||||
**Note to UnityScript (*.js) developers:** |
**Note to UnityScript (*.js) developers:** |
||||||
|
|
||||||
UnityScript will not work with the source code version of this project unless |
UnityScript will not work with the source code version of this project unless |
||||||
the contents of this repository is placed at the path "Assets/Plugins/ReorderableList" |
the contents of this repository is placed at the path "Assets/Plugins/ReorderableList" |
||||||
due to compilation ordering. |
due to compilation ordering. |
||||||
|
|
||||||
Example 1: Serialized array of strings (C#) |
Example 1: Serialized array of strings (C#) |
||||||
------------------------------------------- |
------------------------------------------- |
||||||
|
|
||||||
:::csharp |
:::csharp |
||||||
SerializedProperty _wishlistProperty; |
SerializedProperty _wishlistProperty; |
||||||
SerializedProperty _pointsProperty; |
SerializedProperty _pointsProperty; |
||||||
|
|
||||||
void OnEnable() { |
void OnEnable() { |
||||||
_wishlistProperty = serializedObject.FindProperty("wishlist"); |
_wishlistProperty = serializedObject.FindProperty("wishlist"); |
||||||
_pointsProperty = serializedObject.FindProperty("points"); |
_pointsProperty = serializedObject.FindProperty("points"); |
||||||
} |
} |
||||||
|
|
||||||
public override void OnInspectorGUI() { |
public override void OnInspectorGUI() { |
||||||
serializedObject.Update(); |
serializedObject.Update(); |
||||||
|
|
||||||
ReorderableListGUI.Title("Wishlist"); |
ReorderableListGUI.Title("Wishlist"); |
||||||
ReorderableListGUI.ListField(_wishlistProperty); |
ReorderableListGUI.ListField(_wishlistProperty); |
||||||
|
|
||||||
ReorderableListGUI.Title("Points"); |
ReorderableListGUI.Title("Points"); |
||||||
ReorderableListGUI.ListField(_pointsProperty, ReorderableListFlags.ShowIndices); |
ReorderableListGUI.ListField(_pointsProperty, ReorderableListFlags.ShowIndices); |
||||||
|
|
||||||
serializedObject.ApplyModifiedProperties(); |
serializedObject.ApplyModifiedProperties(); |
||||||
} |
} |
||||||
|
|
||||||
Example 2: List of strings (UnityScript) |
Example 2: List of strings (UnityScript) |
||||||
---------------------------------------- |
---------------------------------------- |
||||||
|
|
||||||
:::javascript |
:::javascript |
||||||
var yourList:List.<String> = new List.<String>(); |
var yourList:List.<String> = new List.<String>(); |
||||||
|
|
||||||
function OnGUI() { |
function OnGUI() { |
||||||
ReorderableListGUI.ListField(yourList, CustomListItem, DrawEmpty); |
ReorderableListGUI.ListField(yourList, CustomListItem, DrawEmpty); |
||||||
} |
} |
||||||
|
|
||||||
function CustomListItem(position:Rect, itemValue:String):String { |
function CustomListItem(position:Rect, itemValue:String):String { |
||||||
// Text fields do not like null values! |
// Text fields do not like null values! |
||||||
if (itemValue == null) |
if (itemValue == null) |
||||||
itemValue = ''; |
itemValue = ''; |
||||||
return EditorGUI.TextField(position, itemValue); |
return EditorGUI.TextField(position, itemValue); |
||||||
} |
} |
||||||
|
|
||||||
function DrawEmpty() { |
function DrawEmpty() { |
||||||
GUILayout.Label('No items in list.', EditorStyles.miniLabel); |
GUILayout.Label('No items in list.', EditorStyles.miniLabel); |
||||||
} |
} |
||||||
|
|
||||||
Refer to API reference for further examples! |
Refer to API reference for further examples! |
||||||
|
|
||||||
Submission to the Unity Asset Store |
Submission to the Unity Asset Store |
||||||
----------------------------------- |
----------------------------------- |
||||||
|
|
||||||
If you wish to include this asset as part of a package for the asset store, please |
If you wish to include this asset as part of a package for the asset store, please |
||||||
include the latest package version as-is to avoid conflict issues in user projects. |
include the latest package version as-is to avoid conflict issues in user projects. |
||||||
It is important that license and documentation files are included and remain intact. |
It is important that license and documentation files are included and remain intact. |
||||||
|
|
||||||
**To include a modified version within your package:** |
**To include a modified version within your package:** |
||||||
|
|
||||||
- Ensure that license and documentation files are included and remain intact. It should |
- Ensure that license and documentation files are included and remain intact. It should |
||||||
be clear that these relate to the reorderable list field library. |
be clear that these relate to the reorderable list field library. |
||||||
|
|
||||||
- Copyright and license information must remain intact in source files. |
- Copyright and license information must remain intact in source files. |
||||||
|
|
||||||
- Change the namespace `Rotorz.ReorderableList` to something unique and DO NOT use the |
- Change the namespace `Rotorz.ReorderableList` to something unique and DO NOT use the |
||||||
name "Rotorz". For example, `YourName.ReorderableList` or `YourName.Internal.ReorderableList`. |
name "Rotorz". For example, `YourName.ReorderableList` or `YourName.Internal.ReorderableList`. |
||||||
|
|
||||||
- Place files somewhere within your own asset folder to avoid causing conflicts with |
- Place files somewhere within your own asset folder to avoid causing conflicts with |
||||||
other assets which make use of this project. |
other assets which make use of this project. |
||||||
|
|
||||||
Useful links |
Useful links |
||||||
------------ |
------------ |
||||||
|
|
||||||
- [Rotorz Website](<http://rotorz.com>) |
- [Rotorz Website](<http://rotorz.com>) |
||||||
|
|
||||||
Contribution Agreement |
Contribution Agreement |
||||||
---------------------- |
---------------------- |
||||||
|
|
||||||
This project is licensed under the MIT license (see LICENSE). To be in the best |
This project is licensed under the MIT license (see LICENSE). To be in the best |
||||||
position to enforce these licenses the copyright status of this project needs to |
position to enforce these licenses the copyright status of this project needs to |
||||||
be as simple as possible. To achieve this the following terms and conditions |
be as simple as possible. To achieve this the following terms and conditions |
||||||
must be met: |
must be met: |
||||||
|
|
||||||
- All contributed content (including but not limited to source code, text, |
- All contributed content (including but not limited to source code, text, |
||||||
image, videos, bug reports, suggestions, ideas, etc.) must be the |
image, videos, bug reports, suggestions, ideas, etc.) must be the |
||||||
contributors own work. |
contributors own work. |
||||||
|
|
||||||
- The contributor disclaims all copyright and accepts that their contributed |
- The contributor disclaims all copyright and accepts that their contributed |
||||||
content will be released to the public domain. |
content will be released to the public domain. |
||||||
|
|
||||||
- The act of submitting a contribution indicates that the contributor agrees |
- The act of submitting a contribution indicates that the contributor agrees |
||||||
with this agreement. This includes (but is not limited to) pull requests, issues, |
with this agreement. This includes (but is not limited to) pull requests, issues, |
||||||
tickets, e-mails, newsgroups, blogs, forums, etc. |
tickets, e-mails, newsgroups, blogs, forums, etc. |
@ -1,207 +1,207 @@ |
|||||||
using System; |
using System; |
||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
using System.IO; |
using System.IO; |
||||||
using System.Linq; |
using System.Linq; |
||||||
using UnityEditor; |
using UnityEditor; |
||||||
using UnityEditorInternal; |
using UnityEditorInternal; |
||||||
using UnityEngine; |
using UnityEngine; |
||||||
using UnityTest.IntegrationTests; |
using UnityTest.IntegrationTests; |
||||||
#if UNITY_5_3_OR_NEWER |
#if UNITY_5_3_OR_NEWER |
||||||
using UnityEditor.SceneManagement; |
using UnityEditor.SceneManagement; |
||||||
#endif |
#endif |
||||||
|
|
||||||
namespace UnityTest |
namespace UnityTest |
||||||
{ |
{ |
||||||
public static partial class Batch |
public static partial class Batch |
||||||
{ |
{ |
||||||
const string k_ResultFilePathParam = "-resultFilePath="; |
const string k_ResultFilePathParam = "-resultFilePath="; |
||||||
private const string k_TestScenesParam = "-testscenes="; |
private const string k_TestScenesParam = "-testscenes="; |
||||||
private const string k_OtherBuildScenesParam = "-includeBuildScenes="; |
private const string k_OtherBuildScenesParam = "-includeBuildScenes="; |
||||||
const string k_TargetPlatformParam = "-targetPlatform="; |
const string k_TargetPlatformParam = "-targetPlatform="; |
||||||
const string k_ResultFileDirParam = "-resultsFileDirectory="; |
const string k_ResultFileDirParam = "-resultsFileDirectory="; |
||||||
|
|
||||||
public static int returnCodeTestsOk = 0; |
public static int returnCodeTestsOk = 0; |
||||||
public static int returnCodeTestsFailed = 2; |
public static int returnCodeTestsFailed = 2; |
||||||
public static int returnCodeRunError = 3; |
public static int returnCodeRunError = 3; |
||||||
|
|
||||||
public static void RunIntegrationTests() |
public static void RunIntegrationTests() |
||||||
{ |
{ |
||||||
var targetPlatform = GetTargetPlatform(); |
var targetPlatform = GetTargetPlatform(); |
||||||
var otherBuildScenes = GetSceneListFromParam (k_OtherBuildScenesParam); |
var otherBuildScenes = GetSceneListFromParam (k_OtherBuildScenesParam); |
||||||
|
|
||||||
var testScenes = GetSceneListFromParam(k_TestScenesParam); |
var testScenes = GetSceneListFromParam(k_TestScenesParam); |
||||||
if (testScenes.Count == 0) |
if (testScenes.Count == 0) |
||||||
testScenes = FindTestScenesInProject(); |
testScenes = FindTestScenesInProject(); |
||||||
|
|
||||||
RunIntegrationTests(targetPlatform, testScenes, otherBuildScenes); |
RunIntegrationTests(targetPlatform, testScenes, otherBuildScenes); |
||||||
} |
} |
||||||
|
|
||||||
public static void RunIntegrationTests(BuildTarget ? targetPlatform) |
public static void RunIntegrationTests(BuildTarget ? targetPlatform) |
||||||
{ |
{ |
||||||
var sceneList = FindTestScenesInProject(); |
var sceneList = FindTestScenesInProject(); |
||||||
RunIntegrationTests(targetPlatform, sceneList, new List<string>()); |
RunIntegrationTests(targetPlatform, sceneList, new List<string>()); |
||||||
} |
} |
||||||
|
|
||||||
|
|
||||||
public static void RunIntegrationTests(BuildTarget? targetPlatform, List<string> testScenes, List<string> otherBuildScenes) |
public static void RunIntegrationTests(BuildTarget? targetPlatform, List<string> testScenes, List<string> otherBuildScenes) |
||||||
{ |
{ |
||||||
if (targetPlatform.HasValue) |
if (targetPlatform.HasValue) |
||||||
BuildAndRun(targetPlatform.Value, testScenes, otherBuildScenes); |
BuildAndRun(targetPlatform.Value, testScenes, otherBuildScenes); |
||||||
else |
else |
||||||
RunInEditor(testScenes, otherBuildScenes); |
RunInEditor(testScenes, otherBuildScenes); |
||||||
} |
} |
||||||
|
|
||||||
private static void BuildAndRun(BuildTarget target, List<string> testScenes, List<string> otherBuildScenes) |
private static void BuildAndRun(BuildTarget target, List<string> testScenes, List<string> otherBuildScenes) |
||||||
{ |
{ |
||||||
var resultFilePath = GetParameterArgument(k_ResultFileDirParam); |
var resultFilePath = GetParameterArgument(k_ResultFileDirParam); |
||||||
|
|
||||||
const int port = 0; |
const int port = 0; |
||||||
var ipList = TestRunnerConfigurator.GetAvailableNetworkIPs(); |
var ipList = TestRunnerConfigurator.GetAvailableNetworkIPs(); |
||||||
|
|
||||||
var config = new PlatformRunnerConfiguration |
var config = new PlatformRunnerConfiguration |
||||||
{ |
{ |
||||||
buildTarget = target, |
buildTarget = target, |
||||||
buildScenes = otherBuildScenes, |
buildScenes = otherBuildScenes, |
||||||
testScenes = testScenes, |
testScenes = testScenes, |
||||||
projectName = "IntegrationTests", |
projectName = "IntegrationTests", |
||||||
resultsDir = resultFilePath, |
resultsDir = resultFilePath, |
||||||
sendResultsOverNetwork = InternalEditorUtility.inBatchMode, |
sendResultsOverNetwork = InternalEditorUtility.inBatchMode, |
||||||
ipList = ipList, |
ipList = ipList, |
||||||
port = port |
port = port |
||||||
}; |
}; |
||||||
|
|
||||||
if (Application.isWebPlayer) |
if (Application.isWebPlayer) |
||||||
{ |
{ |
||||||
config.sendResultsOverNetwork = false; |
config.sendResultsOverNetwork = false; |
||||||
Debug.Log("You can't use WebPlayer as active platform for running integration tests. Switching to Standalone"); |
Debug.Log("You can't use WebPlayer as active platform for running integration tests. Switching to Standalone"); |
||||||
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTarget.StandaloneWindows); |
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTarget.StandaloneWindows); |
||||||
} |
} |
||||||
|
|
||||||
PlatformRunner.BuildAndRunInPlayer(config); |
PlatformRunner.BuildAndRunInPlayer(config); |
||||||
} |
} |
||||||
|
|
||||||
private static void RunInEditor(List<string> testScenes, List<string> otherBuildScenes) |
private static void RunInEditor(List<string> testScenes, List<string> otherBuildScenes) |
||||||
{ |
{ |
||||||
CheckActiveBuildTarget(); |
CheckActiveBuildTarget(); |
||||||
|
|
||||||
NetworkResultsReceiver.StopReceiver(); |
NetworkResultsReceiver.StopReceiver(); |
||||||
if (testScenes == null || testScenes.Count == 0) |
if (testScenes == null || testScenes.Count == 0) |
||||||
{ |
{ |
||||||
Debug.Log("No test scenes on the list"); |
Debug.Log("No test scenes on the list"); |
||||||
EditorApplication.Exit(returnCodeRunError); |
EditorApplication.Exit(returnCodeRunError); |
||||||
return; |
return; |
||||||
} |
} |
||||||
|
|
||||||
string previousScenesXml = ""; |
string previousScenesXml = ""; |
||||||
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(EditorBuildSettingsScene[])); |
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(EditorBuildSettingsScene[])); |
||||||
using(StringWriter textWriter = new StringWriter()) |
using(StringWriter textWriter = new StringWriter()) |
||||||
{ |
{ |
||||||
serializer.Serialize(textWriter, EditorBuildSettings.scenes); |
serializer.Serialize(textWriter, EditorBuildSettings.scenes); |
||||||
previousScenesXml = textWriter.ToString(); |
previousScenesXml = textWriter.ToString(); |
||||||
} |
} |
||||||
|
|
||||||
EditorBuildSettings.scenes = (testScenes.Concat(otherBuildScenes).ToList()).Select(s => new EditorBuildSettingsScene(s, true)).ToArray(); |
EditorBuildSettings.scenes = (testScenes.Concat(otherBuildScenes).ToList()).Select(s => new EditorBuildSettingsScene(s, true)).ToArray(); |
||||||
|
|
||||||
#if UNITY_5_3_OR_NEWER |
#if UNITY_5_3_OR_NEWER |
||||||
EditorSceneManager.OpenScene(testScenes.First()); |
EditorSceneManager.OpenScene(testScenes.First()); |
||||||
#else |
#else |
||||||
EditorApplication.LoadLevelInPlayMode(testScenes.First()); |
EditorApplication.LoadLevelInPlayMode(testScenes.First()); |
||||||
#endif |
#endif |
||||||
GuiHelper.SetConsoleErrorPause(false); |
GuiHelper.SetConsoleErrorPause(false); |
||||||
|
|
||||||
var config = new PlatformRunnerConfiguration |
var config = new PlatformRunnerConfiguration |
||||||
{ |
{ |
||||||
resultsDir = GetParameterArgument(k_ResultFileDirParam), |
resultsDir = GetParameterArgument(k_ResultFileDirParam), |
||||||
ipList = TestRunnerConfigurator.GetAvailableNetworkIPs(), |
ipList = TestRunnerConfigurator.GetAvailableNetworkIPs(), |
||||||
port = PlatformRunnerConfiguration.TryToGetFreePort(), |
port = PlatformRunnerConfiguration.TryToGetFreePort(), |
||||||
runInEditor = true |
runInEditor = true |
||||||
}; |
}; |
||||||
|
|
||||||
var settings = new PlayerSettingConfigurator(true); |
var settings = new PlayerSettingConfigurator(true); |
||||||
settings.AddConfigurationFile(TestRunnerConfigurator.integrationTestsNetwork, string.Join("\n", config.GetConnectionIPs())); |
settings.AddConfigurationFile(TestRunnerConfigurator.integrationTestsNetwork, string.Join("\n", config.GetConnectionIPs())); |
||||||
settings.AddConfigurationFile(TestRunnerConfigurator.testScenesToRun, string.Join ("\n", testScenes.ToArray())); |
settings.AddConfigurationFile(TestRunnerConfigurator.testScenesToRun, string.Join ("\n", testScenes.ToArray())); |
||||||
settings.AddConfigurationFile(TestRunnerConfigurator.previousScenes, previousScenesXml); |
settings.AddConfigurationFile(TestRunnerConfigurator.previousScenes, previousScenesXml); |
||||||
|
|
||||||
NetworkResultsReceiver.StartReceiver(config); |
NetworkResultsReceiver.StartReceiver(config); |
||||||
|
|
||||||
EditorApplication.isPlaying = true; |
EditorApplication.isPlaying = true; |
||||||
} |
} |
||||||
|
|
||||||
private static string GetParameterArgument(string parameterName) |
private static string GetParameterArgument(string parameterName) |
||||||
{ |
{ |
||||||
foreach (var arg in Environment.GetCommandLineArgs()) |
foreach (var arg in Environment.GetCommandLineArgs()) |
||||||
{ |
{ |
||||||
if (arg.ToLower().StartsWith(parameterName.ToLower())) |
if (arg.ToLower().StartsWith(parameterName.ToLower())) |
||||||
{ |
{ |
||||||
return arg.Substring(parameterName.Length); |
return arg.Substring(parameterName.Length); |
||||||
} |
} |
||||||
} |
} |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
static void CheckActiveBuildTarget() |
static void CheckActiveBuildTarget() |
||||||
{ |
{ |
||||||
var notSupportedPlatforms = new[] { "MetroPlayer", "WebPlayer", "WebPlayerStreamed" }; |
var notSupportedPlatforms = new[] { "MetroPlayer", "WebPlayer", "WebPlayerStreamed" }; |
||||||
if (notSupportedPlatforms.Contains(EditorUserBuildSettings.activeBuildTarget.ToString())) |
if (notSupportedPlatforms.Contains(EditorUserBuildSettings.activeBuildTarget.ToString())) |
||||||
{ |
{ |
||||||
Debug.Log("activeBuildTarget can not be " |
Debug.Log("activeBuildTarget can not be " |
||||||
+ EditorUserBuildSettings.activeBuildTarget + |
+ EditorUserBuildSettings.activeBuildTarget + |
||||||
" use buildTarget parameter to open Unity."); |
" use buildTarget parameter to open Unity."); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
private static BuildTarget ? GetTargetPlatform() |
private static BuildTarget ? GetTargetPlatform() |
||||||
{ |
{ |
||||||
string platformString = null; |
string platformString = null; |
||||||
BuildTarget buildTarget; |
BuildTarget buildTarget; |
||||||
foreach (var arg in Environment.GetCommandLineArgs()) |
foreach (var arg in Environment.GetCommandLineArgs()) |
||||||
{ |
{ |
||||||
if (arg.ToLower().StartsWith(k_TargetPlatformParam.ToLower())) |
if (arg.ToLower().StartsWith(k_TargetPlatformParam.ToLower())) |
||||||
{ |
{ |
||||||
platformString = arg.Substring(k_ResultFilePathParam.Length); |
platformString = arg.Substring(k_ResultFilePathParam.Length); |
||||||
break; |
break; |
||||||
} |
} |
||||||
} |
} |
||||||
try |
try |
||||||
{ |
{ |
||||||
if (platformString == null) return null; |
if (platformString == null) return null; |
||||||
buildTarget = (BuildTarget)Enum.Parse(typeof(BuildTarget), platformString); |
buildTarget = (BuildTarget)Enum.Parse(typeof(BuildTarget), platformString); |
||||||
} |
} |
||||||
catch |
catch |
||||||
{ |
{ |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
return buildTarget; |
return buildTarget; |
||||||
} |
} |
||||||
|
|
||||||
private static List<string> FindTestScenesInProject() |
private static List<string> FindTestScenesInProject() |
||||||
{ |
{ |
||||||
var integrationTestScenePattern = "*Test?.unity"; |
var integrationTestScenePattern = "*Test?.unity"; |
||||||
return Directory.GetFiles("Assets", integrationTestScenePattern, SearchOption.AllDirectories).ToList(); |
return Directory.GetFiles("Assets", integrationTestScenePattern, SearchOption.AllDirectories).ToList(); |
||||||
} |
} |
||||||
|
|
||||||
private static List<string> GetSceneListFromParam(string param) |
private static List<string> GetSceneListFromParam(string param) |
||||||
{ |
{ |
||||||
var sceneList = new List<string>(); |
var sceneList = new List<string>(); |
||||||
foreach (var arg in Environment.GetCommandLineArgs()) |
foreach (var arg in Environment.GetCommandLineArgs()) |
||||||
{ |
{ |
||||||
if (arg.ToLower().StartsWith(param.ToLower())) |
if (arg.ToLower().StartsWith(param.ToLower())) |
||||||
{ |
{ |
||||||
var scenesFromParam = arg.Substring(param.Length).Split(','); |
var scenesFromParam = arg.Substring(param.Length).Split(','); |
||||||
foreach (var scene in scenesFromParam) |
foreach (var scene in scenesFromParam) |
||||||
{ |
{ |
||||||
var sceneName = scene; |
var sceneName = scene; |
||||||
if (!sceneName.EndsWith(".unity")) |
if (!sceneName.EndsWith(".unity")) |
||||||
sceneName += ".unity"; |
sceneName += ".unity"; |
||||||
var foundScenes = Directory.GetFiles(Directory.GetCurrentDirectory(), sceneName, SearchOption.AllDirectories); |
var foundScenes = Directory.GetFiles(Directory.GetCurrentDirectory(), sceneName, SearchOption.AllDirectories); |
||||||
if (foundScenes.Length == 1) |
if (foundScenes.Length == 1) |
||||||
sceneList.Add(foundScenes[0].Substring(Directory.GetCurrentDirectory().Length + 1)); |
sceneList.Add(foundScenes[0].Substring(Directory.GetCurrentDirectory().Length + 1)); |
||||||
else |
else |
||||||
Debug.Log(sceneName + " not found or multiple entries found"); |
Debug.Log(sceneName + " not found or multiple entries found"); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
return sceneList.Where(s => !string.IsNullOrEmpty(s)).Distinct().ToList(); |
return sceneList.Where(s => !string.IsNullOrEmpty(s)).Distinct().ToList(); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -1,221 +1,221 @@ |
|||||||
Version 1.5.9 |
Version 1.5.9 |
||||||
|
|
||||||
- Updated tools for Unity 5.4 |
- Updated tools for Unity 5.4 |
||||||
- Bugfixes |
- Bugfixes |
||||||
|
|
||||||
Version 1.5.8 |
Version 1.5.8 |
||||||
|
|
||||||
- Bugfixes |
- Bugfixes |
||||||
|
|
||||||
Version 1.5.7 |
Version 1.5.7 |
||||||
|
|
||||||
- Updated tools for Unity 5.3 |
- Updated tools for Unity 5.3 |
||||||
|
|
||||||
Version 1.5.6 |
Version 1.5.6 |
||||||
|
|
||||||
- Updated Mono.Cecil.dll and Mono.Cecil.Mdb.dll libraries |
- Updated Mono.Cecil.dll and Mono.Cecil.Mdb.dll libraries |
||||||
|
|
||||||
Version 1.5.5 |
Version 1.5.5 |
||||||
|
|
||||||
- Unit Tests Runner rendering improvments |
- Unit Tests Runner rendering improvments |
||||||
- Platform runner can include auxiliary scenes |
- Platform runner can include auxiliary scenes |
||||||
- other improvments and bugfixes |
- other improvments and bugfixes |
||||||
|
|
||||||
Version 1.5.4 |
Version 1.5.4 |
||||||
|
|
||||||
- APIs updates |
- APIs updates |
||||||
|
|
||||||
Version 1.5.3 |
Version 1.5.3 |
||||||
|
|
||||||
- Bug fixes |
- Bug fixes |
||||||
|
|
||||||
Version 1.5.2 |
Version 1.5.2 |
||||||
|
|
||||||
- Bug fixes |
- Bug fixes |
||||||
- Minor improvments |
- Minor improvments |
||||||
|
|
||||||
Version 1.5.1 |
Version 1.5.1 |
||||||
|
|
||||||
- removed redundant and not applicable options |
- removed redundant and not applicable options |
||||||
- fixed 5.0 related bugs |
- fixed 5.0 related bugs |
||||||
|
|
||||||
Version 1.5.0 |
Version 1.5.0 |
||||||
|
|
||||||
- Unity 5 related compatibility changes |
- Unity 5 related compatibility changes |
||||||
|
|
||||||
Version 1.4.6 |
Version 1.4.6 |
||||||
|
|
||||||
- Bug fixes |
- Bug fixes |
||||||
- Minor improvments |
- Minor improvments |
||||||
|
|
||||||
Version 1.4.5 |
Version 1.4.5 |
||||||
|
|
||||||
- Added "Pause on test failure" option for integration tests |
- Added "Pause on test failure" option for integration tests |
||||||
- bugfixes and code refactorization |
- bugfixes and code refactorization |
||||||
- fixed UI bug where test details were not refreshed is the label was focused |
- fixed UI bug where test details were not refreshed is the label was focused |
||||||
|
|
||||||
Version 1.4.4 |
Version 1.4.4 |
||||||
|
|
||||||
- Minimal supported Unity version is now 4.3 |
- Minimal supported Unity version is now 4.3 |
||||||
- UI changes |
- UI changes |
||||||
- code refactoring |
- code refactoring |
||||||
|
|
||||||
Version 1.4.3 |
Version 1.4.3 |
||||||
|
|
||||||
- Remove reference to Resources.LoadAssetAtPath from runtime code |
- Remove reference to Resources.LoadAssetAtPath from runtime code |
||||||
|
|
||||||
Version 1.4.2 |
Version 1.4.2 |
||||||
|
|
||||||
(assertion component) |
(assertion component) |
||||||
- fixed string comparer bug that prevented updating the value |
- fixed string comparer bug that prevented updating the value |
||||||
|
|
||||||
(unit tests) |
(unit tests) |
||||||
- unit test runner will log to stdout now |
- unit test runner will log to stdout now |
||||||
- fixes issues with opening tests in IDEs |
- fixes issues with opening tests in IDEs |
||||||
|
|
||||||
(integration tests) |
(integration tests) |
||||||
- transform component is now visible for integration tests components |
- transform component is now visible for integration tests components |
||||||
- added better support for mac's keyboard |
- added better support for mac's keyboard |
||||||
- fixed 'succeed on assertion' for code generated assertion |
- fixed 'succeed on assertion' for code generated assertion |
||||||
|
|
||||||
(other) |
(other) |
||||||
- minor bugfixes |
- minor bugfixes |
||||||
- general improvments |
- general improvments |
||||||
|
|
||||||
Version 1.4.1 |
Version 1.4.1 |
||||||
|
|
||||||
- Fixed platform compilation issues |
- Fixed platform compilation issues |
||||||
- Fixed typos in labels |
- Fixed typos in labels |
||||||
- Removed docs and left a link to online docs |
- Removed docs and left a link to online docs |
||||||
- Added Unity version and target platform to result files |
- Added Unity version and target platform to result files |
||||||
- Other bugfixes |
- Other bugfixes |
||||||
|
|
||||||
Version 1.4 |
Version 1.4 |
||||||
|
|
||||||
(integration tests) |
(integration tests) |
||||||
- Platform runner will send the results back to the editor via TCP now |
- Platform runner will send the results back to the editor via TCP now |
||||||
- Added naming convention for running tests in batch mode |
- Added naming convention for running tests in batch mode |
||||||
- It's possible to cancel the run in the editor in between the tests now |
- It's possible to cancel the run in the editor in between the tests now |
||||||
- Added message filtering for integration tests results |
- Added message filtering for integration tests results |
||||||
- Added check for RegisterLogCallback in case something else overrides it |
- Added check for RegisterLogCallback in case something else overrides it |
||||||
- Error messages will now fail integration tests |
- Error messages will now fail integration tests |
||||||
- Fixed dynamic integration tests not being properly reset |
- Fixed dynamic integration tests not being properly reset |
||||||
- Fixed platform runner for BlackBerry platform |
- Fixed platform runner for BlackBerry platform |
||||||
|
|
||||||
(assertion component) |
(assertion component) |
||||||
- fixed the component editor |
- fixed the component editor |
||||||
|
|
||||||
(common) |
(common) |
||||||
- Made settings to be saved per project |
- Made settings to be saved per project |
||||||
- Fixed resolving icons when there are more UnityTestTools folders in the project |
- Fixed resolving icons when there are more UnityTestTools folders in the project |
||||||
- Fixed process return code when running in batch mode |
- Fixed process return code when running in batch mode |
||||||
|
|
||||||
Version 1.3.2 |
Version 1.3.2 |
||||||
|
|
||||||
- Fixed integration tests performance issues |
- Fixed integration tests performance issues |
||||||
|
|
||||||
Version 1.3.1 |
Version 1.3.1 |
||||||
|
|
||||||
- Updated Japanese docs |
- Updated Japanese docs |
||||||
|
|
||||||
Version 1.3 |
Version 1.3 |
||||||
|
|
||||||
Fixes: |
Fixes: |
||||||
(unit tests) |
(unit tests) |
||||||
- nUnit will no longer change the Environment.CurrentDirectory when running tests |
- nUnit will no longer change the Environment.CurrentDirectory when running tests |
||||||
- fixed issues with asserting GameObject == null |
- fixed issues with asserting GameObject == null |
||||||
(integration tests) |
(integration tests) |
||||||
- fix the issue with passing or failing test in first frame |
- fix the issue with passing or failing test in first frame |
||||||
- fixed bug where ignored tests were still run in ITF |
- fixed bug where ignored tests were still run in ITF |
||||||
(assertion component) |
(assertion component) |
||||||
- fixed resolving properties to include derived types |
- fixed resolving properties to include derived types |
||||||
|
|
||||||
Improvements: |
Improvements: |
||||||
(unit tests) |
(unit tests) |
||||||
- refactored result renderer |
- refactored result renderer |
||||||
- reenabled Random attribute |
- reenabled Random attribute |
||||||
- added Category filter |
- added Category filter |
||||||
- NSubstitute updated to version 1.7.2 |
- NSubstitute updated to version 1.7.2 |
||||||
- result now will be dimmed after recompilation |
- result now will be dimmed after recompilation |
||||||
- running tests in background will now work without having the window focused |
- running tests in background will now work without having the window focused |
||||||
- all assemblies in the project referencing 'nunit.framework' will now be included in the test list |
- all assemblies in the project referencing 'nunit.framework' will now be included in the test list |
||||||
(integration tests) |
(integration tests) |
||||||
- updated platform exclusion mechanism |
- updated platform exclusion mechanism |
||||||
- refactored result renderer |
- refactored result renderer |
||||||
- the runner should work even if the runner window is not focused |
- the runner should work even if the runner window is not focused |
||||||
- added possibility to create integration tests from code |
- added possibility to create integration tests from code |
||||||
- the runner will now always run in background (if the window is not focused) |
- the runner will now always run in background (if the window is not focused) |
||||||
(assertion component) |
(assertion component) |
||||||
- added API for creating assertions from code |
- added API for creating assertions from code |
||||||
- added new example |
- added new example |
||||||
(common) |
(common) |
||||||
- GUI improvements |
- GUI improvements |
||||||
- you no longer need to change the path to icons when moving the tools to another directory |
- you no longer need to change the path to icons when moving the tools to another directory |
||||||
- made test details/results resizeable and scrollable |
- made test details/results resizeable and scrollable |
||||||
- added character escape for generated result XML |
- added character escape for generated result XML |
||||||
|
|
||||||
Version 1.2.1 |
Version 1.2.1 |
||||||
- Fixed Unit Test Batch runner |
- Fixed Unit Test Batch runner |
||||||
|
|
||||||
Version 1.2 |
Version 1.2 |
||||||
Fixes: |
Fixes: |
||||||
- Windows Store related compilation issues |
- Windows Store related compilation issues |
||||||
- other |
- other |
||||||
Improvements: |
Improvements: |
||||||
(unit tests) |
(unit tests) |
||||||
- unit test runner can run in background now without having the runner window open |
- unit test runner can run in background now without having the runner window open |
||||||
- unit test batch runner can take a result file path as a parameter |
- unit test batch runner can take a result file path as a parameter |
||||||
- changed undo system for unit test runner and UnityUnitTest base class |
- changed undo system for unit test runner and UnityUnitTest base class |
||||||
- execution time in now visible in test details |
- execution time in now visible in test details |
||||||
- fixed a bug with tests that inherit from a base test class |
- fixed a bug with tests that inherit from a base test class |
||||||
(integration tests) |
(integration tests) |
||||||
- added hierarchical structure for integration tests |
- added hierarchical structure for integration tests |
||||||
- added Player runner to automate running integration tests on platforms |
- added Player runner to automate running integration tests on platforms |
||||||
- Integration tests batch runner can take a result directory as a parameter |
- Integration tests batch runner can take a result directory as a parameter |
||||||
- Integration tests batch runner can run tests on platforms |
- Integration tests batch runner can run tests on platforms |
||||||
- results are rendered in a player |
- results are rendered in a player |
||||||
(assertion component) |
(assertion component) |
||||||
- changed default failure messages |
- changed default failure messages |
||||||
- it's possible to override failure action on comparer failure |
- it's possible to override failure action on comparer failure |
||||||
- added code stripper for assertions. |
- added code stripper for assertions. |
||||||
- vast performance improvement |
- vast performance improvement |
||||||
- fixed bugs |
- fixed bugs |
||||||
Other: |
Other: |
||||||
- "Hide in hierarchy" option was removed from integration test runner |
- "Hide in hierarchy" option was removed from integration test runner |
||||||
- "Focus on selection" option was removed from integration test runner |
- "Focus on selection" option was removed from integration test runner |
||||||
- "Hide test runner" option was removed from integration test runner |
- "Hide test runner" option was removed from integration test runner |
||||||
- result files for unit tests and integration tests are now not generated when running tests from the editor |
- result files for unit tests and integration tests are now not generated when running tests from the editor |
||||||
- UI improvements |
- UI improvements |
||||||
- removed UnityScript and Boo examples |
- removed UnityScript and Boo examples |
||||||
- WP8 compatibility fixes |
- WP8 compatibility fixes |
||||||
|
|
||||||
Version 1.1.1 |
Version 1.1.1 |
||||||
Other: |
Other: |
||||||
- Documentation in Japanese was added |
- Documentation in Japanese was added |
||||||
|
|
||||||
Version 1.1 |
Version 1.1 |
||||||
Fixes: |
Fixes: |
||||||
- fixed display error that happened when unit test class inherited from another TestFixture class |
- fixed display error that happened when unit test class inherited from another TestFixture class |
||||||
- fixed false positive result when "Succeed on assertions" was checked and no assertions were present in the test |
- fixed false positive result when "Succeed on assertions" was checked and no assertions were present in the test |
||||||
- fixed XmlResultWriter to be generate XML file compatible with XSD scheme |
- fixed XmlResultWriter to be generate XML file compatible with XSD scheme |
||||||
- XmlResultWriter result writer was rewritten to remove XML libraries dependency |
- XmlResultWriter result writer was rewritten to remove XML libraries dependency |
||||||
- Fixed an issue with a check that should be executed once after a specified frame in OnUpdate. |
- Fixed an issue with a check that should be executed once after a specified frame in OnUpdate. |
||||||
- added missing file UnityUnitTest.cs |
- added missing file UnityUnitTest.cs |
||||||
Improvements: |
Improvements: |
||||||
- Added Japanese translation of the documentation |
- Added Japanese translation of the documentation |
||||||
- ErrorPause value will be reverted to previous state after test run finishes |
- ErrorPause value will be reverted to previous state after test run finishes |
||||||
- Assertion Component will not copy reference to a GameObject if the GameObject is the same as the component is attached to. Instead, it will set the reference to the new GameObject. |
- Assertion Component will not copy reference to a GameObject if the GameObject is the same as the component is attached to. Instead, it will set the reference to the new GameObject. |
||||||
- Integration tests batch runner can now run multiple scenes |
- Integration tests batch runner can now run multiple scenes |
||||||
- Unit test runner will now include tests written in UnityScript and Boo |
- Unit test runner will now include tests written in UnityScript and Boo |
||||||
- Unit tests will not run automatically if the compilation failes |
- Unit tests will not run automatically if the compilation failes |
||||||
- Added scene auto-save option to the Unit Test Runner |
- Added scene auto-save option to the Unit Test Runner |
||||||
Other: |
Other: |
||||||
- changed icons |
- changed icons |
||||||
- restructured project files |
- restructured project files |
||||||
- moved XmlResultWriter to Common folder |
- moved XmlResultWriter to Common folder |
||||||
- added UnityScript and Boo unit tests examples |
- added UnityScript and Boo unit tests examples |
||||||
- added more unit tests examples |
- added more unit tests examples |
||||||
- Test runners visual adjustments |
- Test runners visual adjustments |
||||||
|
|
||||||
Version 1.0 |
Version 1.0 |
||||||
- Initial release |
- Initial release |
Loading…
Reference in new issue