This "IF" won't work for me. Why? - if-statement

I have written the following code:
function test() {
var spreadsheet = SpreadsheetApp.getActive();
var ui = SpreadsheetApp.getUi();
var testModeStatus = spreadsheet.getSheetByName("Students").getRange("P2:P2").getValues();
if (testModeStatus == 'FALSE') {
ui.alert("This is inside IF and Test Mode Status is "+testModeStatus);
};
ui.alert("This is outside IF and Test Mode Status is "+testModeStatus);
};
In the above code the variable testModeStatus refers to a sheet cell that is a checkbox and can have the value of either TRUE(checked) or FALSE(unchecked).
I want the code inside if to run only when the checkbox is unchecked. But no matter if the checkbox is checked or unchecked, the code inside if never runs and in both cases just the code outside if runs.
Moreover, in both cases the variable testModeStatus shows the correct value in the popping alert message. I mean if the checkbox is checked the variable shows TRUE and if it is unchecked the variable shows FALSE in the popping alert message.

you're comparing apples with oranges
.getValues() returns a bi-dimensional array and "FALSE" is a string.
Since you get a cell, you can use .getValue instead, but do note that GAS parses the boolean into a JS boolean, so, ultimately, the code should be:
function test() {
var spreadsheet = SpreadsheetApp.getActive();
var ui = SpreadsheetApp.getUi();
var testModeStatus = spreadsheet.getSheetByName("Students").getRange("P2:P2").getValue(); // getValue, not values
if (testModeStatus == false) { //false, not "FALSE"
ui.alert("This is inside IF and Test Mode Status is "+testModeStatus);
};
ui.alert("This is outside IF and Test Mode Status is "+testModeStatus);
};

Related

Calling get_position on KinematicBody2D causes a get_global_transform error

Summary
I'm trying write a unit test using Gut for my player in gdscript but calling get_position() on the player (a KinematicBody2D) is causing the following error:
ERROR: get_global_transform: Condition "!is_inside_tree()" is true. Returned: get_transform()
At: scene/2d/canvas_item.cpp:467.
ERROR: body_test_motion: Condition "!body->get_space()" is true. Returned: false
At: servers/physics_2d/physics_2d_server_sw.cpp:1046.
ERROR: get_global_transform: Condition "!is_inside_tree()" is true. Returned: get_transform()
At: scene/2d/canvas_item.cpp:467.
ERROR: body_test_ray_separation: Condition "!body->get_space()" is true. Returned: false
At: servers/physics_2d/physics_2d_server_sw.cpp:1058.
Expectation
I was expecting that after _physics_process() I would be able to get the updated position of my player but it returns Vector2(0, 0).
Resources
This is my first time using GDScript so I have been using a mixture of the following resources in an attempt to write this first test:
8-way movement
TDD and PONG Episode 1
GUT Command-line
Stubbing Input Class
Failed solutions
I think I may need to make the player a child of something else but I'm unsure how to do this within my test.
I tried searching the Gut issues on how to use add_child() within a test but I couldn't find an answer.
I also tried making the player a child of an Area2D but that didn't seem to work either:
var player := Player.new(input)
var area := Area2D.new()
area.add_child(player)
Code
This is the code that is causing the error when calling gut from the command line:
test/unit/actors/test_player.gd
extends "res://addons/gut/test.gd"
func test_can_create_player() -> void:
var input = MockInput.new()
var player := Player.new(input)
assert_not_null(player)
func test_can_move_player_up() -> void:
var input = MockInput.new()
input.press("ui_up")
var player := Player.new(input)
simulate(player, 1, .1)
assert_eq(player.get_position(), Vector2(200, 0))
test/mock_input.gd
class_name MockInput
var _pressed: Dictionary = {}
func press(key: String) -> void:
_pressed[key] = true
func release(key: String) -> void:
_pressed[key] = false
func is_action_pressed(key: String) -> bool:
if _pressed.has(key):
return _pressed.get(key)
return false
entities/actors/player.gd
extends KinematicBody2D
class_name Player
export var speed: int = 200
var _input: Object = Input
var _velocity: Vector2 = Vector2()
func _init(input: Object = Input):
_input = input
func _physics_process(_delta: float) -> void:
_velocity = Vector2()
if _input.is_action_pressed("ui_right"):
_velocity.x += 1
if _input.is_action_pressed("ui_left"):
_velocity.x -= 1
if _input.is_action_pressed("ui_down"):
_velocity.y += 1
if _input.is_action_pressed("ui_up"):
_velocity.y -= 1
_velocity = _velocity.normalized() * speed
_velocity = move_and_slide(_velocity)
The error is telling you !is_inside_tree(). The problem is not -only- that the node does not have a parent. The problem is that it is not inside a SceneTree.
You can create your own instance of SceneTree. You can even extend it. For example, this would work:
var node := KinematicBody2D.new()
var tree := SceneTree.new()
tree.get_root().add_child(node)
yield(tree, "idle_frame")
print(node.get_global_transform())
Now, about Gut… Your tests will be running inside a SceneTree. Thus, you can add the nodes you want to test as children. Just remember to do proper teardown (remove the nodes). Because Gut will not do it for you, and if children nodes linger from one test to another, then they aren't units anymore.
Addendum: You can use add_child_autofree to add a child, and also queue it for freeing right after the test ends.
The rest of the answer is me going over how Gut runs tests to confirm they run inside a SceneTree.
The file gut_cmdln.gd is actually an extended SceneTree. It will load gut.gd (here) and add it as a node to itself (here).
In turn, gut.gd is in charge of running the tests, which is handled by _test_the_scripts. What I want you to look is this:
var test_script = the_script.get_new()
var script_result = null
_setup_script(test_script)
There the_script is a TestScript object. The get_new call will return an instance. And _setup_script…
func _setup_script(test_script):
test_script.gut = self
test_script.set_logger(_lgr)
add_child(test_script)
_test_script_objects.append(test_script)
Will add it as child (of gud.gd).
Afterwards _test_the_scripts will go into a loop (here) and call _run_test or _run_parameterized_test (which calls _run_test) to actually run the test. And _run_test will use call on the instance to run the test method (with extra steps).
Huzza! Your tests will be running in a custom SceneTree.
I found something that worked for my purposes (I'm a little bit annoyed that I missed this the first time).
As I suspected, the player needs to be a child of another Node.
In the test/unit/actors/test_player.gd after the player variable has been defined it can be added as a child of the test itself using:
self.add_child_autofree(player)
With the complete unit test as the following:
func test_can_move_player_up() -> void:
var input = MockInput.new()
input.press("ui_up")
var player := Player.new(input)
self.add_child_autofree(player)
simulate(player, 1, 0)
assert_eq(player.get_position().round(), Vector2(0, -30))

Google Sheets Scripts, IF date of a cell

I ve been getting some issues trying to use IF statement using items on the sheets as answers, mostly i been trying either using as firt statement a string directly or using another cell of the sheets with the statement comparing to the one i ve been trying to detect with out any results. Mostly my objective would be to, with a daly trigger, use an IF statement to detect every day if the date of today is the same as a date marked on a cell, my only current solution is and only thing is to make it detect if a cell is empty or not, so i just been using google Formulas that do the detect of the date, and if True make it empty, and if not make something appear
Here are some of the tests I ve been trying
Test 1:
var Sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SheetName");
else if (Sheet.getRange(1, 1).getValue() == "2/2/2020"){}
(cell A1=2/2/2020)
Test 2:
var Sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SheetName");
else if (Sheet.getRange(1, 1).getValue() == Sheet.getRange(1, 2).getValue()){}
(cell A1=2/2/2020)
(cell B1=2/2/2020)
Here are two solutions depending on what you are trying to accomplish.
This first one gets the values, formats them to a date format, and then compares them
function myFunction() {
var tz = Session.getScriptTimeZone();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('SheetName');
var data = sheet.getDataRange().getValues();
var aVal = Utilities.formatDate(data[0][0],tz,'MM/dd/YYYY');
var bVal = Utilities.formatDate(data[0][1],tz,'MM/dd/YYYY');
Logger.log([aVal,bVal])
if(aVal == bVal) {
//do something
}
}
This second section gets the display values and compares them. The first solution compares the date values while this second solution compares the dates as a string. Good luck!
function myFunction1() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('SheetName');
var data = sheet.getDataRange().getDisplayValues();
var aVal = data[0][0]
var bVal = data[0][1]
Logger.log([aVal,bVal])
if(aVal == bVal) {
//do something
}
}

Unable to set array as environment variable - Postman test

I am trying to set an array as an environmental variable in postman.
But it stores the first value of the array rather than the array.
var aDataEntry = postman.pm.environment.get('data_set_entries');
if(aDataEntry == null) {
aDataEntry = [];
}
var jsonData = pm.response.json();
aDataEntry.push(jsonData.dataEntry.id);
// a console.log here confirms that aDataEntry is an array
postman.pm.environment.set('data_entry',aDataEntry);
As mentioned in the comment of the code, the variable is coming as an array,
but when I again get the environment variable in the second run, it is not
of type array. But just contains the first element in the array.
What's wrong here?
How can set the array and use it from the postman environment variable.
It seems like pm.environment.set calls toString to set an environment value. You can use the below code to work-around that:
var aDataEntry = pm.environment.get('data_set_entries');
if(aDataEntry == null) {
aDataEntry = [];
} else {
aDataEntry = JSON.parse(aDataEntry);
}
var jsonData = pm.response.json();
aDataEntry.push(jsonData.dataEntry.id);
// a console.log here confirms that aDataEntry is an array
pm.environment.set('data_entry',JSON.stringify(aDataEntry));
Edit 1:
As mentioned in the Postman reference docs, it is suggested that one use JSON.stringify() and JSON.parse() for storing complex objects. I have updated the code accordingly.
I'm not sure of how you intend to use the array, but to dynamically generate an array for use in a Body > raw > JSON POST, as in the answer above you do need to actually store the var as a string.
Here's an example of that and it's use in the POST Body. I had a long list of IDs, and I'm using Postman to do some bulk user profile updates.
In the Pre-request Script, generate the string to be POSTed as an array.
var externalIds = [111,222,333,444];
var attrString = "";
externalIds.forEach(userId => {
attrString += `,{"external_id": ${userId},"my_first_attribute": false,"my_next_attribute": true}`;
});
attrString = attrString.replace(',',''); // strip out that 1st unwanted comma
pm.environment.set("attributeArray",attrString);
The saved "array", Postman console logged:
"{"external_id": 111,"my_first_attribute": false,"my_next_attribute": true},
{"external_id": 222,"my_first_attribute": false,"my_next_attribute": true},
{"external_id": 333,"my_first_attribute": false,"my_next_attribute": true},
{"external_id": 444,"my_first_attribute": false,"my_next_attribute": true}"
Looks like bad, nested double quotes, but the format is actually valid.
My Body > raw looks like:
{
"api_key": "{{api_key}}",
"attributes": [{{attributeArray}}]
}
Note the Postman variable is wrapped in "[" and "]".
If my externalIds array needed to be a pm variable, I'd store that as a string, and .split() it when using it in the Script tab.
The Postman console really helps get past the syntax mistakes.

Scala.js js.Dynamic usage leads to a recursively infinite data structure

I'm trying to use Google Visualizations from Scala.js. I generated the type definitions using TS importer and the relevant portion it generated is:
#js.native
trait ColumnChartOptions extends js.Object {
var aggregationTarget: String = js.native
var animation: TransitionAnimation = js.native
var annotations: ChartAnnotations = js.native
// ... more
}
#js.native
trait TransitionAnimation extends js.Object {
var duration: Double = js.native
var easing: String = js.native
var startup: Boolean = js.native
}
Now, I'm trying to figure out how to actually use this and came up with:
val options = js.Dynamic.literal.asInstanceOf[ColumnChartOptions]
options.animation = js.Dynamic.literal.asInstanceOf[TransitionAnimation] // comment this and the next line and chart will appear
options.animation.duration = 2000
options.title = "Test Chart"
options.width = 400
options.height = 300
This works if I don't set the animation settings, but fails with the chart showing "Maximum call stack size exceeded" if I do.
I debugged, and found the following:
So animation contains a reference to itself, but I don't feel like this should happen based on the code above.
Ideas how to fix it?
Any other suggestions on how to best use the generated types to provide a type-safe way of creating the JavaScript objects which Google Visualizations expects? I tried new ColumnChartOptions {} which looks cleaner than js.Dynamic but that failed with "A Scala.js-defined JS class cannot directly extend a native JS trait."
P.S. I'd like to note that
options.animation = js.Dynamic.literal(
easing = "inAndOut",
startup = true,
duration = 2000
).asInstanceOf[TransitionAnimation]
actually works, but isn't type-safe (a mis-spelling of duration to durration won't be caught).
Your code lacks () when calling literal(), so the fix would be:
val options = js.Dynamic.literal().asInstanceOf[ColumnChartOptions]
options.animation = js.Dynamic.literal().asInstanceOf[TransitionAnimation] // comment this and the next line and chart will appear
In Scala (and therefore in Scala.js), the presence or absence of () is sometimes meaningful. literal is the singleton object literal, whereas literal() calls the method apply() of said object.

Assert a method was called whilst verifying the parameters are correct

Given the following snippet from my test:
var mockProvider = MockRepository.GenerateMock<IItemProvider>();
var target = new ItemService(mockProvider);
target.SaveItem(item);
Internally target.SaveItem makes a call like this:
provider.SaveItem(new SaveContract(item.Id, user, contents)); where provider is the local name for the mockProvider passed in.
How do I:
Verify provider.SaveItem is called whilst also
Asserting that the values of item.Id, user and contents are as they should be.
I think I might be able to use mockProvider.AssertWasCalled but can't figure out the syntax to set the condition of the parameters passed to the constructor of SaveContract.
TIA
Ok so based on this I did something like the following:
var mockProvider = MockRepository.GenerateMock<IItemProvider>();
var target = new ItemService(mockProvider);
Item testItem = null;
mockProvider.Expect(c => c.SaveItem(Arg<Item>.Is.Anything))
.WhenCalled(call =>
{
testItem = (Item)call.Arguments[0];
});
target.SaveItem(item);//item initialised elsewhere
Assert.AreEqual(item.Id, testItem.Id);