MAXScript コードにアサーションを配置するために、Assert 関数を使用できます。これは、MAXScript の評価ツリーに行番号サポートが導入されたことによって可能になりました。3ds Max 2010 以降で使用可能です。
また、assert 関数の拡張セットおよび AssertReporter メッセージログ システムが 3ds Max 2012 に追加され、3ds Max の開発時に Autodesk によってテスト スイート用に使用されています。
概要:
アサーションは、開発者がその場所では常に評価が true になると想定してコード内に配置する述語(true|false ステートメント)です。
アサーションは、プログラミングの正しさを検証するために使用されます。
実行時にアサーションが false として評価されると、「アサーション エラー」が生成され、通常は実行が中止されます。これにより、論理矛盾が検出された場所に注目することができ、エラーを発生させずに処理を続行するよりも望ましい振る舞いだと考えることができます。
構文
assert <expression> [message:<string>] [options:#( #dialog | #listener | #debug_output_window | #debugBreak | #c_break | #all)] [showstack:<bool>]
1 番目の引数として関数に渡された式の結果が、コード内の特定の箇所で必ず true であることをアサートします。
式は、ブール値に解決される必要があります。そうでない場合は、MAXScript 例外が発生します。
式が true を返した場合には、コードは通常どおりに続行されます。
式が false を返した場合、次のオプションに応じて実行が中断されます。
message: このオプション キーワードを指定すると、アサートのメッセージとして文字列が表示されます。
options: - 次の MAXScript 名前オプションの配列です。配列が空の場合、既定は #listener となります。
#dialog - アプリケーションの実行を中断するモーダル ダイアログ ボックスを表示します。
#listener - 障害情報を MAXScript リスナーに出力します。
#debug_output_window - Visual Studio の出力デバッガ ウィンドウに出力します(存在する場合)。
#debugBreak - MAXScript デバッガでの実行を中断します。このオプションを指定すると、#dialog オプションは無視されます。このオプションは、抑制モードが false
の場合にのみ有効です。そうでない場合は何も起こりません。
#c_break : デバッガで Visual Studio での実行をブレークします。これは、3ds Max のデバッグ ビルドをデバッガで実行している場合にのみ動作します。指定すると、最初に #debug_output_window フラグが内部でオンになってデバッグが支援されます。 #debugBreak オプションと #dialog オプションは無視され、他のオプションがそれぞれのデータを出力できるよう、この動作は必ず最後に行われます。
#all - #dialog と #c_break を除く、上記のすべてが含まれます。
showstack: - 出力に MAXScript スタック トレースバックを含めるかどうかを定義します。このオプションは、 #listener オプションと #debug_output_window オプションにのみ適用されます。他のすべてのオプションについては、スタック情報は無視されます。既定値は false です。
例:
|
以下の例では、関数がシーン内のすべてのオブジェクトをループしてこれらの位置を累算します。最後に、結果の値をオブジェクトの数で割って、全オブジェクトの平均位置を算出しています。
スクリプト開発者は、シーンが空ではないことを前提としています。 このため、最終結果は有効な位置となります。オブジェクトの数がゼロである場合、ゼロによる除算でプログラムがクラッシュすることはありませんが、Point3
値[-1.#IND,-1.#IND,-1.#IND] が生成されます。
|
fn averageObjectPosition =
(
theSum = [0,0,0]
theCount = objects.count
for i = 1 to theCount do
(
theSum += objects[i].pos
)
assert (theCount > 0) message: "theCount expected to be positive, but was found not to be!" options:#(#all) showstack:true
theSum /= theCount
)
averageObjectPosition()
|
このようなコードでは他にも、theCount がゼロよりも大きいかどうかをチェックする IF ステートメントを追加する方法があります。 ただしこのケースでは、開発者が theCount が常にゼロよりも大きいことを条件とする assert() 呼び出しを使用し、この条件に当てはまらない場合はデバッガでコードの実行をブレークして、リスナーのスタックも表示することにしました。
この例では、 assert() 関数がどのように機能するかを示すデモンストレーションの目的でこの処理を行っています。ゼロによる除算全体を防げる IF テストの使用に比べてこの方法が優れているわけではありません。
実際には、どのようなケースをテストすればよいか予想できないために、IF テストで不正な値を補足するのが困難であるような複雑な計算では、一般に assert() を使用して値を検証します。加えて、 assert() にはいくつかの便利なレポート モードがあります。これらは IF テストでは簡単に真似できません(たとえば、3ds Max のデバッグ ビルドの実行時に C++ デバッガでブレークするなど)。
|
上の関数を空のシーンで実行すると、結果は以下のようになります。
|
|
テスト フレームワーク Assert 関数
3ds Max 2012 で、メッセージを管理するための多くの assert 関数および 1 つの AssertReporter 構造体が実装され、Autodesk での内部テストに使用できるようになりました。
これらの関数はすべての MAXScript ユーザが利用でき、カスタムのテスト フレームワークで使用してプログラム フローが正確かどうか確認することができます。
これらのテスト フレームワーク関数には、次のような利点があります。
- ファイルをレポートする。
- 行番号をレポートする。
- 関数呼び出しをレポートする。
- 必要な値と実際の値をレポートする。
すべての assert は自動的にレポートされます。
この新しいシステムでは、開発者は assert のメッセージで大量のエラー文字列が生成されないようにすることができるため、assert の表示を非常に見やすくすることができます(必要に応じてカスタム
メッセージを提供することもできます)。また、これらの assert は静的に実行され、メッセージは専用の AssertReporter に収集されてコードの実行後に照会および分析されるため、実際のテストの実行を妨げることはありません。
assert 関数は次のとおりです。
<boolean>assert_true <expression>expectedToBeTrue [message:<string>]
式の戻り値が true でない場合は false を返し、AssertReporter に assert エラー メッセージを記録します。
オプションの message: キーワード引数が指定されていない場合、 "Assert - Expected true, got false - (No File) in frame <No Stack frame>, at line
1" の形式で既定のメッセージを記録します。
<boolean>assert_false <expression>expectedToBeFalse [message:<string>]
式の戻り値が false でない場合は false を返し、AssertReporter に assert エラー メッセージを記録します。
オプションの message: キーワード引数が指定されていない場合、 "Assert - Expected false, got true - (No File) in frame <No Stack frame>, at line
1" の形式で既定のメッセージを記録します。
<boolean>assert_equal <value>expected <expression>actual [message:<string>]
2 つ目の引数として渡された式の戻り値が最初の引数として渡された必要な値と異なる場合は false を返し、AssertReporter に assert エラー
メッセージを記録します。
オプションの message: キーワード引数が指定されていない場合、 "Assert - Expected 1, got 2 - (No File) in frame <No Stack frame>, at line 1" の形式で既定のメッセージを記録します。
<boolean>assert_not_equal <value>expected <expression>actual [message:<string>]
2 つ目の引数として渡された式の戻り値が最初の引数として渡された実際の値と等しい場合は false を返し、AssertReporter に assert エラー
メッセージを記録します。
オプションの message: キーワード引数が指定されていない場合、 "Assert - Expected 1, got 1 - (No File) in frame <No Stack frame>, at line 1" の形式で既定のメッセージを記録します。
<boolean>assert_defined <expression>expectedToBeDefined [message:<string>]
式の戻り値が undefined の場合は false を返し、AssertReporter に assert エラー メッセージを記録します。
オプションの message: キーワード引数が指定されていない場合、 "Assert - Expected "defined", got undefined - (No File) in frame <No Stack frame>,
at line 1" の形式で既定のメッセージを記録します。
<boolean>assert_undefined <expression>expectedToBeUndefined [message:<string>]
式の戻り値が undefined でない場合は false を返し、AssertReporter に assert エラー メッセージを記録します。
オプションの message: キーワード引数が指定されていない場合、 "Assert - Expected undefined, got 1 - (No File) in frame <No Stack frame>, at line
1" の形式で既定のメッセージを記録します。
<boolean>assert_float <float>expected <expression>actual [tolerance:<float>delta] [message:<string>]
2 つ目の引数として渡された式の戻り値が必要な float 値でない場合は false を返し AssertReporter に assert エラー メッセージを記録します。
tolerance: オプション キーワード引数が指定され、実際の戻り値が必要な値と異なり、許容差値を超えている場合は false を返します。
オプションの message: キーワード引数が指定されていない場合、 "Assert - Expected 1.0, got 2 - (No File) in frame <No Stack frame>, at line 1" の形式で既定のメッセージを記録します。
<boolean>assert_string_equal <string>expected <exression>actual [ignorecase:<boolean>val]
[message:]
2 つ目の引数として渡された式の戻り値が、必要な文字列と異なる場合は false を返します。
オプションの ignorecase: キーワード引数の既定値は true です。大文字小文字を区別して比較を実行する場合は false として指定する必要があります。
オプションの message: キーワード引数が指定されていない場合、 "Assert - Expected "A", got "b" - (No File) in frame <No Stack frame>, at line 1" の形式で既定のメッセージを記録します。
<boolean>assert_point3_equal <point3>expected <expression>actual [tolerance:<float>delta]
[message:]
2 つ目の引数として渡された式の戻り値が必要な Point3 値と異なる場合は false を返します。
tolerance: オプション キーワード引数が指定され、実際の戻り値の構成要素のいずれかが必要な値と異なり、対応する構成要素が許容差値を超えている場合は false を返します。
オプションの message: キーワード引数が指定されていない場合、 "Assert - Expected [1,2,3], got [1.1,2.1,3.1] - (No File) in frame <No Stack frame>,
at line 1" の形式で既定のメッセージを記録します。
<boolean>assert_matrix_equal <matrix>expected <matrix>actual [tolerance:<float>delta]
[message:]
2 つ目の引数として渡されたこの式の戻り値が期待した行列値と異なる場合は false を返します
tolerance: オプション キーワード引数が指定され、実際の戻り値の構成要素のいずれかが必要な値と異なり、対応する構成要素が許容差値を超えている場合は false を返します。
オプションの message: キーワード引数が指定されていない場合、 "Assert - Expected (matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,0]), got (matrix3 [1,0,0]
[0,1,0] [0,0,1] [42.1234,43.8329,0]) - (No File) in frame <No Stack frame>, at line
1" の形式で既定のメッセージを記録します。
コンピュータの数値表現の精度が制限されているため、 assert_float() メソッドや assert_point3_equal() メソッドを使用しているときに、許容差ぎりぎりの値では assert が記録される場合と記録されない場合があります。
例:
|
floatVariable = 1.0
assert_float 1.1 floatVariable tolerance:0.1
-->"Assert - Expected 1.1, got 1.0 ..."
|
ただし、次のコードを使用すると、assert はありません。
|
point3Variable = [1,2,3]
assert_point3_equal [1.0,2.0,3.1] point3Variable tolerance:0.1
|
上記の結果では、最初のメソッドで必要な値と実際の値の差が許容値未満であるかどうかを確認しています。この例では、許容値未満ではありません。この 2 つの値は内部で double
に変換されて、先頭の 7 桁の小数位が同一(すべてゼロ)であるため、この差は許容差未満ではありません。
一方、2 つ目の例では、Point3 値[1.0,2.0,3.1]は実際に内部では[1.0,2.0,3.0999999]として表されます。したがって、3.0 と 3.0999999
の差は許容値を若干下回り、精度エラーにより、asset は true として渡します。
AssertReporter 構造体
グローバルな AssertReporter C++ 構造体は、アサートの結果を収集し、テストの実行値に結果を管理したり、結果にアクセスするためのメソッドを提供します。
一般的なメソッド:
<void>AssertReporter.Clear()
AssertReporter からすべてのアサーション エントリを削除し、すべてのエラーおよび例外の結果をゼロにリセットします。
レポート メソッド:
<string array>AssertReporter.GetAssertFailures()
AssertReporter に格納されている assert エラーを含む文字列の配列を返します。
<integer>AssertReporter.GetAssertFailuresCount()
AssertReporter に格納されている assert エラーの数を返します。これは、 (AssertReporter.GetAssertFailuresCount()).count を呼び出すよりも迅速に処理できます。
<string array>AssertReporter.GetExceptionFailures()
AssertReporter に記録されている例外を含む文字列の配列を返します。
<integer>AssertReporter.GetExceptionFailuresCount()
AssertReporter に格納されている例外エラーの数を返します。これは、 (AsserReporter.GetExceptionFailuresCount()).count を呼び出すよりも迅速に処理できます。
<array of strings>AssertReporter.GetMessages()
AssertReporter を通じて記録されているメッセージを含む文字列を、その種類に関係なく返します。
ログ メソッド:
<void>AssertReporter.LogMessage <string>Message
メッセージを AssertReporter に保存します。このメッセージは、 AssertReporter.GetMessages() を使用して後から取得できます。
<void>AssertReporter.LogException <string>Message
メッセージを例外として AssertReporter に保存します。例外メッセージは、 AssertReporter.GetExceptionFailures() を使用して後から取得できます。
<void>AssertReporter.LogAssertFailure <string>Message
メッセージを assert エラーとして AssertReporter に保存します。エラー メッセージは、 AssertReporter.GetAssertFailures() を使用して後から取得できます。
状態メソッド:
次の 2 つのメソッドを使用して、テストの実行中のいくつかの状態を保存できます。また、これらは将来の柔軟性のためにのみ提供されています。
<void>AssertReporter.SetUserData <string>UserData
ユーザ定義のカスタム文字列を AssertReporter に保存します。
<void>AssertReporter.GetUserData <value>argument
ユーザ定義のカスタム文字列を AssertReporter から取得します。
例:
|
次の例は、多くの変数が関数のローカル スコープで定義され、各変数がその値を検証するために 1 つの assert でテストされる人工テスト(これらのテストの多くは実際の
assert メッセージを生成するために設定されています)における assert 関数と AssertReporter の機能を示しています。
|
fn TestAsserts =
(
local undefinedValue
local booleanTrueVariable = true
local booleanFalseVariable = false
local floatVariable = 1.0
local stringVariable = "MAXScript"
local point3Variable = [1,2,3]
local matrix3Variable = matrix3 [1,0,0] [0,1,0] [0,0,1] [100,200,-300]
--this is line 10
AssertReporter.Clear()
AssertReporter.LogMessage "Asserts Demo Start..."
AssertReporter.SetUserData ("Tested Values Were:"+ undefinedValue as string + "," + booleanTrueVariable as string + "," + booleanFalseVariable as string + "," + floatVariable as string + ","+stringVariable+","+point3Variable as string + ","+matrix3Variable as string)
assert_true booleanFalseVariable
assert_false booleanTrueVariable
assert_equal 2.0 floatVariable
assert_not_equal 2.0 floatVariable
assert_defined undefinedValue
assert_undefined floatVariable
assert_float 1.1 floatVariable tolerance:0.01
assert_float 1.1 floatVariable tolerance:0.2
assert_string_equal "Python" stringVariable
assert_string_equal "maxscript" stringVariable ignorecase:false message:(" MAXScript is usually case-insensitive, but this assert isn't!")
assert_point3_equal [1.0,2.0,3.1] point3Variable
assert_point3_equal [1.0,2.0,3.1] point3Variable tolerance:0.1
assert_matrix_equal (matrix3 1) matrix3Variable
if floatVariable > 0.0 do AssertReporter.LogAssertFailure "FloatVariable seems to be positive, I am upset!"
AssertReporter.LogException "Nothing Really Worked!"
AssertReporter.LogMessage "Asserts Demo End."
--this is line 30
format "--All Logged Messages:\n"
print (AssertReporter.GetMessages())
format "--User Data:\n"
print (AssertReporter.GetUserData 0)
format "--Failures: %\n" (AssertReporter.GetAssertFailuresCount())
print (AssertReporter.GetAssertFailures())
format "--Exceptions: %\n" (AssertReporter.GetExceptionFailuresCount())
print (AssertReporter.GetExceptionFailures())
)
TestAsserts()
|
上記のコードを "c:¥temp¥TestAsserts.ms" という名前のファイルに保存し、スクリプトを評価すると、次のような出力が生成されます。
|
TestAsserts()
--All Logged Messages:
"Asserts Demo Start..."
"Assert - Expected true, got false - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 14"
"Assert - Expected false, got true - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 15"
"Assert - Expected 2.0, got 1.0 - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 16"
"Assert - Expected "defined", got undefined - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 18"
"Assert - Expected undefined, got 1.0 - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 19"
"Assert - Expected 1.1, got 1.0 - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 20"
"Assert - Expected "Python", got "MAXScript" - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 22"
"Assert - MAXScript is usually case-insensitive, but this assert isn't! - Expected "maxscript", got "MAXScript" (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 23"
"Assert - Expected [1,2,3.1], got [1,2,3] - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 24"
"Assert - Expected (matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,0]), got (matrix3 [1,0,0] [0,1,0] [0,0,1] [100,200,-300]) - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 26"
"FloatVariable seems to be positive, I am upset!"
"Nothing Really Worked!"
"Asserts Demo End."
--User Data:
"Tested Values Were:undefined,true,false,1.0,MAXScript,[1,2,3],(matrix3 [1,0,0] [0,1,0] [0,0,1] [100,200,-300])"
--Failures: 11
"Assert - Expected true, got false - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 14"
"Assert - Expected false, got true - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 15"
"Assert - Expected 2.0, got 1.0 - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 16"
"Assert - Expected "defined", got undefined - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 18"
"Assert - Expected undefined, got 1.0 - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 19"
"Assert - Expected 1.1, got 1.0 - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 20"
"Assert - Expected "Python", got "MAXScript" - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 22"
"Assert - MAXScript is usually case-insensitive, but this assert isn't! - Expected "maxscript", got "MAXScript" (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 23"
"Assert - Expected [1,2,3.1], got [1,2,3] - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 24"
"Assert - Expected (matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,0]), got (matrix3 [1,0,0] [0,1,0] [0,0,1] [100,200,-300]) - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 26"
"FloatVariable seems to be positive, I am upset!"
--Exceptions: 1
"Nothing Really Worked!"
OK
|
21 行目の assert はエラーを生成していません。これは、tolerance が 0.2 に設定され、前の 20 行目の Assert で許可されなかった 1.1
に対し、1.0 でテストに成功しているからです。
23 行目では、既定のメッセージの前にカスタム メッセージが追加されています。 25 行目も、許容差の値が大きく設定されているため、成功しています。 このように、これらの assert 関数を使用すると、さまざまな値型の変数の状態に関するデータを収集したり、式の値を返したり、AssertReporter で情報を収集してコードのテスト実行後に分析したり、ログ
ファイルにダンプして後から処理することができます。
|