Properties Never Seem to Change?

Apr 22, 2014 at 4:13 PM
Hello,
I am using Jurassic to test an API that we are creating for internal use. I have created a script object that looks something like this:
  public class EventScriptObject : ObjectInstance
  {
    private EventTypes _eventType;
    private uint? _messageId;
    private int? _number;

    public EventScriptObject(ScriptEngine engine)
      : base(engine)
    {
      PopulateFunctions();
      PopulateFields();
    }

    /// <summary>
    /// Sets the data for a received event.
    /// </summary>
    /// <param name="messageId">The message id of the event, to coordinate with other logs.</param>
    /// <param name="eventType">The type of the event.</param>
    /// <param name="number">The number for the event type, (i.e. Soft Event Number, Camera Number, etc.)</param>
    public void SetData(uint? messageId, FfpEvents eventType, int? number)
    {
      this._messageId = messageId;
      this._eventType = eventType;
      this._number = number;
    }

    [JSProperty(Name = "EventType", IsConfigurable = false)]
    public string EventType
    {
      get
      {
        return _eventType == null ? "none" : _eventType.ToString();
      }
    }

    [JSProperty(Name = "HasMessageId", IsConfigurable = false)]
    public bool HasMessageId
    {
      get
      {
        return this._messageId.HasValue;
      }
    }

    [JSProperty(Name = "MessageId", IsConfigurable = false)]
    public uint MessageId
    {
      get
      {
        if (this._messageId.HasValue)
        {
          return this._messageId.Value;
        }
        else
        {
          return 0;
        }
      }
    }

    [JSProperty(Name = "HasNumber", IsConfigurable = false)]
    public bool HasNumber
    {
      get
      {
        return this._number.HasValue;
      }
    }

    [JSProperty(Name = "Number", IsConfigurable = false)]
    public int Number
    {
      get
      {
        if (this._number.HasValue)
        {
          return this._number.Value;
        }
        else
        {
          return -1;
        }
      }
    }
  }
Against this object I am running a script like this:
var pass = true;
var pauseTime = 750;
console.log("Text Case 09 - Test START\n");
var eventTag = "Event[";
var tagName = "";
var eventName = "";
var tagNumber = 0;
var eventNumber = -1;
tagName = softEventTag+tagNumber+"]";
eventSource.SetValueByTag(tagName, 1);
eventName = scrObj.EventType == null ? "null" : scrObj.EventType;
  if( eventName == "TriggerOn")
  {
  }
  else
  {
    pass = false;
    console.log("Event "+eventName+" while trying to set Event "+eventNumber+" on.\n");
  }
  eventNumber = scrObj.EventNumber == null ? -1 : scrObj.EventNumber;
  if( eventNumber != softEventNumber)
  {
    pass = false;
    console.log("Event Number "+eventNumber+" while trying to set Event "+tagNumber+" on.\n");
  }
  eventSource.SetValueByTag(tagName, 0);
  eventName = scrObj.EventType == null ? "null" : scrObj.EventType;
  if( eventName == "EventOff")
  {
  }
  else
  {
    pass = false;
    console.log("Event "+eventName+" while trying to set Soft Event "+tagNumber+" off.\n");
  }
  eventNumber = scrObj.EventNumber == null ? -1 : scrObj.EventNumber;
  if( eventNumber != tagNumber)
  {
    pass = false;
    console.log("Event Number "+eventNumber+" while trying to set Soft Event "+tagNumber+" off.\n");
  }
}

// Overall Pass or Fail.
var overall = "PASS";
if(pass)
{
  overall = "PASSED";
}
else
{
  overall = "FAILED";
}
console.log("Text Case 09 - Test "+overall+"\n");
Every time I call EventType or EventNumber it is null. I have verified that the SetData method is being called. The debugger does not stop in any of the property methods. Am I missing something?

Pat O

P.S. I did simplify the script, so please excuse any places where the name changes were missed. It does run to completion without error. :-)
Coordinator
Apr 23, 2014 at 6:08 AM
I get a syntax error running the JS due to an extra "}". If I remove the extra brace then I get the error "softEventTag is not defined".

Is the problem possibly that SetData does not have a [JsFunction] attribute? If not, then please correct your JS, thanks :-)
Apr 23, 2014 at 9:47 PM
I will put together some sample code as I have time.
Apr 24, 2014 at 7:29 PM
So my frustration level increases. :-)

I have created a separate project/solution so I don't need to snip out the companies code. Here are the remain points through the error I am getting has changed:

Script Object:
  public enum EventType
  {
    TriggerOn,
    TriggerOff
  }

  public class ScriptObject : ObjectInstance
  {
    private EventType _eventType;
    private uint? _messageId;
    private int? _eventNumber;

    public ScriptObject(ScriptEngine engine)
      : base(engine)
    {
      PopulateFunctions();
      PopulateFields();
    }

    public void SetData(uint? messageId, EventType eventType, int? eventNumber)
    {
      this._messageId = messageId;
      this._eventType = eventType;
      this._eventNumber = eventNumber;
    }

    [JSProperty(Name = "EventType", IsConfigurable = false)]
    public string EventType
    {
      get
      {
        return this._eventType.ToString();
      }
    }

    [JSProperty(Name = "HasMessageId", IsConfigurable = false)]
    public bool HasMessageId
    {
      get
      {
        return this._messageId.HasValue;
      }
    }

    [JSProperty(Name = "MessageId", IsConfigurable = false)]
    public uint MessageId
    {
      get
      {
        if (this._messageId.HasValue)
        {
          return this._messageId.Value;
        }
        else
        {
          return 0;
        }
      }
    }

    [JSProperty(Name = "HasEventNumber", IsConfigurable = false)]
    public bool HasEventNumber
    {
      get
      {
        return this._eventNumber.HasValue;
      }
    }

    [JSProperty(Name = "EventNumber", IsConfigurable = false)]
    public int EventNumber
    {
      get
      {
        if (this._eventNumber.HasValue)
        {
          return this._eventNumber.Value;
        }
        else
        {
          return -1;
        }
      }
    }
  }
Event Source:
  public class EventSource : ObjectInstance
  {
    private BlockingCollection<EventDesc> _events;
    private int _evtNum;

    public EventSource(BlockingCollection<EventDesc> evts, ScriptEngine engine)
      : base(engine)
    {
      _events = evts;
      _evtNum = 1;
      PopulateFunctions();
      PopulateFields();
    }

    [JSProperty(Name = "EventNumber", IsConfigurable = false)]
    public int EventNumber
    {
      get
      {
        return 42;
      }
    }

    [JSFunction(Name = "setValueByTag", IsConfigurable = false)]
    void SetValueByTag(string tagName, int val)
    {
      if (val == 0)
      {
        tagName = "TriggerOff";
      }
      else
      {
        tagName = "TriggerOn";
      }
      _events.Add(new EventDesc() { TagName = tagName, Value = (uint)val, Number = _evtNum });
      _evtNum++;
    }
  }
And the Main method:
  class Program
  {
    static ScriptObject _scriptObject;
    static BlockingCollection<EventDesc> _events;
    static bool _running;
    static void Main(string[] args)
    {
      // Prepare for the pump
      _events = new BlockingCollection<EventDesc>();

      // Prep for running the script
      TextWriter output = new StringWriter();
      string scriptFileName;
      if (File.Exists("./Script.js") == false)
      {
        Console.Error.WriteLine("Script not found");
        return;
      }
      else
      {
        scriptFileName = Path.GetFullPath("./Script.js");
      }
      string scriptText = System.IO.File.ReadAllText(scriptFileName);
      TextReader script = new StringReader(scriptText);

      // Setup the scripting environment
      ScriptEngine scriptEngine = new ScriptEngine();
      FirebugConsole scriptConsole = new Jurassic.Library.FirebugConsole(scriptEngine);
      scriptConsole.Output = new TextWriterConsole(output);
      scriptEngine.SetGlobalValue("console", scriptConsole);

      _scriptObject = new ScriptObject(scriptEngine);
      scriptEngine.SetGlobalValue("scrObj", _scriptObject);
      EventSource evtSrc = new EventSource(_events, scriptEngine);
      scriptEngine.SetGlobalValue("eventSource", evtSrc);

      // Start the pump
      _running = true;
      Thread pump = new Thread(MessagePump);
      pump.Start();

      try
      {
        // Run Script
        using (ReaderScriptSource src = new ReaderScriptSource(script))
        {
          scriptEngine.Execute(src);
        }

        _running = false;
      }
      catch (Exception ex)
      {
        output.WriteLine(ex.Message);
        output.WriteLine(ex.StackTrace);
      }
      finally
      {
        System.Console.Write(output.ToString());
        output.Dispose();
        _running = false;
      }
    }

    static void MessagePump()
    {
      while (_running)
      {
        EventDesc evt;
        if (_events.TryTake(out evt, 250) == false)
        {
          // To keep from running away with the CPU.
          Thread.Sleep(10);
          continue;
        }
        else
        {
          EventType et = EventType.TriggerOff;
          if ("TriggerOn".Equals(evt.TagName))
          {
            et = EventType.TriggerOn;
          }
          _scriptObject.SetData(evt.Value, et, evt.Number);
        }
      }
    }
  }
I am now getting the error that setValueByTag is not a function. Please help me clear that up and we shall see if the properties change or not.
Apr 24, 2014 at 7:33 PM
Just noticed that I did not include the new Script File:
var pass = true;
var pauseTime = 750;
console.log("Text Case 09 - Test START\n");
var eventTag = "Event[";
var tagName = "";
var eventName = "";
var tagNumber = 0;
var eventNumber = -1;
tagName = eventTag + tagNumber + "]";
console.log("Setting Trigger On\n");
var stringValue = "The event number is " + eventSource.EventNumber + ".\n";
console.log(stringValue);
eventSource.setValueByTag(tagName, 1);
eventName = scrObj.EventType == null ? "null" : scrObj.EventType;
if( eventName != "TriggerOn")
{
  pass = false;
  console.log("Event "+eventName+" while trying to set Event "+eventNumber+" on.\n");
}
eventNumber = scrObj.EventNumber == null ? -1 : scrObj.EventNumber;
if (eventNumber != eventNumber)
{
  pass = false;
  console.log("Event Number "+eventNumber+" while trying to set Event "+tagNumber+" on.\n");
}
console.log("Setting Trigger Off\n");
eventSource.setValueByTag(tagName, 0);
eventName = scrObj.EventType == null ? "null" : scrObj.EventType;
if (eventName != "TriggerOff")
{
  pass = false;
  console.log("Event "+eventName+" while trying to set Soft Event "+tagNumber+" off.\n");
}
eventNumber = scrObj.EventNumber == null ? -1 : scrObj.EventNumber;
if( eventNumber != tagNumber)
{
  pass = false;
  console.log("Event Number "+eventNumber+" while trying to set Soft Event "+tagNumber+" off.\n");
}

// Overall Pass or Fail.
var overall = "PASS";
if(pass)
{
  overall = "PASSED";
}
else
{
  overall = "FAILED";
}
console.log("Text Case 09 - Test "+overall+"\n");
The output when run looks like this:
Text Case 09 - Test START
Setting Trigger On
The event number is 42.
TypeError: 'eventSource.setValueByTag' is not a function
   at global_(ScriptEngine , Scope , Object )
   at Jurassic.Compiler.GlobalMethodGenerator.Execute()
   at Jurassic.ScriptEngine.Execute(ScriptSource source)
   at JavaScriptTest.Program.Main(String[] args) in c:\Views\JavaScriptTest\JavaScriptTest\Program.cs:line 60
Let me know if you want to see any of the other classes. I left them out for brevity.

Pat O
Apr 24, 2014 at 7:57 PM
Found it. The method "SetValueByTag" was not public. Therefore it was not added as a JSFunction. And it all works now, so there must be something about my code which is odd. I will go back to looking at it.
Apr 25, 2014 at 10:18 AM
So it turned out to be user error. :-)
Our test environment has been growing "organically" I was referencing the wrong global script object. Since Javascript returns null as the value of a non-existent property, it appeared that the property value was never changing. Sorry for the distraction.

Pat O